diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2022-09-17 22:03:44 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2022-09-17 22:03:44 +0300 |
commit | 49726f2627f20969d8e6358fc107bdf139c87f99 (patch) | |
tree | f94d610e293cb577fbf973b1d0ac07c005c948d0 | |
parent | e4065899cddff8a7bde3bc774f33e9b6bebd961c (diff) | |
download | ydb-49726f2627f20969d8e6358fc107bdf139c87f99.tar.gz |
Update contrib/restricted/boost/interprocess to 1.80.0
89 files changed, 9682 insertions, 2290 deletions
diff --git a/contrib/restricted/boost/container/include/boost/container/detail/container_or_allocator_rebind.hpp b/contrib/restricted/boost/container/include/boost/container/detail/container_or_allocator_rebind.hpp new file mode 100644 index 0000000000..1525e41d9d --- /dev/null +++ b/contrib/restricted/boost/container/include/boost/container/detail/container_or_allocator_rebind.hpp @@ -0,0 +1,53 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_CONTAINER_OR_ALLOCATOR_REBIND_HPP +#define BOOST_CONTAINER_DETAIL_CONTAINER_OR_ALLOCATOR_REBIND_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include <boost/container/allocator_traits.hpp> +#include <boost/container/detail/container_rebind.hpp> +#include <boost/container/detail/is_container.hpp> + +namespace boost { +namespace container { +namespace dtl { + +template<class AllocatorOrContainer, class ToType, bool = is_container<AllocatorOrContainer>::value> +struct container_or_allocator_rebind_impl + : container_rebind<AllocatorOrContainer, ToType> +{}; + +template<class AllocatorOrContainer, class ToType> +struct container_or_allocator_rebind_impl<AllocatorOrContainer, ToType, false> + : allocator_traits<AllocatorOrContainer>::template portable_rebind_alloc<ToType> +{}; + +template<class ToType> +struct container_or_allocator_rebind_impl<void, ToType, false> + : real_allocator<ToType, void> +{}; + +template<class AllocatorOrContainer, class ToType> +struct container_or_allocator_rebind + : container_or_allocator_rebind_impl<AllocatorOrContainer, ToType> +{}; + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_CONTAINER_OR_ALLOCATOR_REBIND_HPP diff --git a/contrib/restricted/boost/container/include/boost/container/detail/container_rebind.hpp b/contrib/restricted/boost/container/include/boost/container/detail/container_rebind.hpp new file mode 100644 index 0000000000..854291ae7c --- /dev/null +++ b/contrib/restricted/boost/container/include/boost/container/detail/container_rebind.hpp @@ -0,0 +1,163 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_CONTAINER_REBIND_HPP +#define BOOST_CONTAINER_DETAIL_CONTAINER_REBIND_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include <boost/container/allocator_traits.hpp> +#include <boost/container/container_fwd.hpp> + + +namespace boost { +namespace container { +namespace dtl { + + template <class Cont, class U> + struct container_rebind; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template <template <class, class, class...> class Cont, typename V, typename A, class... An, class U> + struct container_rebind<Cont<V, A, An...>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, An...> type; + }; + + //Needed for non-conforming compilers like GCC 4.3 + template <template <class, class> class Cont, typename V, typename A, class U> + struct container_rebind<Cont<V, A>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type> type; + }; + + template <template <class> class Cont, typename V, class U> + struct container_rebind<Cont<V>, U> + { + typedef Cont<U> type; + }; + +#else //C++03 compilers + + template <template <class> class Cont //0arg + , typename V + , class U> + struct container_rebind<Cont<V>, U> + { + typedef Cont<U> type; + }; + + template <template <class, class> class Cont //0arg + , typename V, typename A + , class U> + struct container_rebind<Cont<V, A>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type> type; + }; + + template <template <class, class, class> class Cont //1arg + , typename V, typename A, class P0 + , class U> + struct container_rebind<Cont<V, A, P0>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0> type; + }; + + template <template <class, class, class, class> class Cont //2arg + , typename V, typename A, class P0, class P1 + , class U> + struct container_rebind<Cont<V, A, P0, P1>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1> type; + }; + + template <template <class, class, class, class, class> class Cont //3arg + , typename V, typename A, class P0, class P1, class P2 + , class U> + struct container_rebind<Cont<V, A, P0, P1, P2>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2> type; + }; + + template <template <class, class, class, class, class, class> class Cont //4arg + , typename V, typename A, class P0, class P1, class P2, class P3 + , class U> + struct container_rebind<Cont<V, A, P0, P1, P2, P3>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3> type; + }; + + template <template <class, class, class, class, class, class, class> class Cont //5arg + , typename V, typename A, class P0, class P1, class P2, class P3, class P4 + , class U> + struct container_rebind<Cont<V, A, P0, P1, P2, P3, P4>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4> type; + }; + + template <template <class, class, class, class, class, class, class, class> class Cont //6arg + , typename V, typename A, class P0, class P1, class P2, class P3, class P4, class P5 + , class U> + struct container_rebind<Cont<V, A, P0, P1, P2, P3, P4, P5>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5> type; + }; + + template <template <class, class, class, class, class, class, class, class, class> class Cont //7arg + , typename V, typename A, class P0, class P1, class P2, class P3, class P4, class P5, class P6 + , class U> + struct container_rebind<Cont<V, A, P0, P1, P2, P3, P4, P5, P6>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5, P6> type; + }; + + template <template <class, class, class, class, class, class, class, class, class, class> class Cont //8arg + , typename V, typename A, class P0, class P1, class P2, class P3, class P4, class P5, class P6, class P7 + , class U> + struct container_rebind<Cont<V, A, P0, P1, P2, P3, P4, P5, P6, P7>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5, P6, P7> type; + }; + + template <template <class, class, class, class, class, class, class, class, class, class, class> class Cont //9arg + , typename V, typename A, class P0, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8 + , class U> + struct container_rebind<Cont<V, A, P0, P1, P2, P3, P4, P5, P6, P7, P8>, U> + { + typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5, P6, P7, P8> type; + }; + +#endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //for small_vector,static_vector + + template <typename V, std::size_t N, typename A, typename O, class U> + struct container_rebind<small_vector<V, N, A, O>, U> + { + typedef small_vector<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, O> type; + }; + + template <typename V, std::size_t N, typename O, class U> + struct container_rebind<static_vector<V, N, O>, U> + { + typedef static_vector<U, N, O> type; + }; + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_CONTAINER_REBIND_HPP diff --git a/contrib/restricted/boost/container/include/boost/container/detail/flat_tree.hpp b/contrib/restricted/boost/container/include/boost/container/detail/flat_tree.hpp new file mode 100644 index 0000000000..bbc89589b5 --- /dev/null +++ b/contrib/restricted/boost/container/include/boost/container/detail/flat_tree.hpp @@ -0,0 +1,1698 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_FLAT_TREE_HPP +#define BOOST_CONTAINER_FLAT_TREE_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + +#include <boost/container/container_fwd.hpp> + +#include <boost/move/utility_core.hpp> + +#include <boost/container/detail/pair.hpp> +#include <boost/container/vector.hpp> +#include <boost/container/allocator_traits.hpp> + +#include <boost/container/detail/value_init.hpp> +#include <boost/container/detail/destroyers.hpp> +#include <boost/container/detail/algorithm.hpp> //algo_equal(), algo_lexicographical_compare +#include <boost/container/detail/iterator.hpp> +#include <boost/container/detail/is_sorted.hpp> +#include <boost/container/detail/type_traits.hpp> +#include <boost/container/detail/iterators.hpp> +#include <boost/container/detail/mpl.hpp> +#include <boost/container/detail/is_contiguous_container.hpp> +#include <boost/container/detail/is_container.hpp> + +#include <boost/intrusive/detail/minimal_pair_header.hpp> //pair + +#include <boost/move/make_unique.hpp> +#include <boost/move/iterator.hpp> +#include <boost/move/adl_move_swap.hpp> +#include <boost/move/detail/force_ptr.hpp> +#include <boost/move/algo/adaptive_sort.hpp> +#include <boost/move/algo/detail/pdqsort.hpp> + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include <boost/move/detail/fwd_macros.hpp> +#endif + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" +#endif + +//merge_unique +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME merge_unique +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 3 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 3 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//merge_equal +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME merge +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 3 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 3 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//index_of +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME index_of +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//nth +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME nth +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//reserve +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME reserve +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic pop +#endif + + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +namespace boost { +namespace container { +namespace dtl { + +/////////////////////////////////////// +// +// Helper functions to merge elements +// +/////////////////////////////////////// + +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(stored_allocator_type) + +/////////////////////////////////////// +// +// flat_tree_container_inplace_merge +// +/////////////////////////////////////// +template<class SequenceContainer, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_container_inplace_merge //is_contiguous_container == true + (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::true_) +{ + typedef typename SequenceContainer::value_type value_type; + value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin()); + value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it); + value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end()); + boost::movelib::adaptive_merge + (braw, iraw, eraw, comp, eraw, back_free_capacity<SequenceContainer>::get(dest)); +} + +template<class SequenceContainer, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_container_inplace_merge //is_contiguous_container == false + (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::false_) +{ + boost::movelib::adaptive_merge(dest.begin(), it, dest.end(), comp); +} + +/////////////////////////////////////// +// +// flat_tree_container_inplace_sort_ending +// +/////////////////////////////////////// +template<class SequenceContainer, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_container_inplace_sort_ending //is_contiguous_container == true + (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp, dtl::true_) +{ + typedef typename SequenceContainer::value_type value_type; + value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it); + value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end()); + boost::movelib::adaptive_sort + (iraw, eraw, comp, eraw, back_free_capacity<SequenceContainer>::get(dest)); +} + +template<class SequenceContainer, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_container_inplace_sort_ending //is_contiguous_container == false + (SequenceContainer& dest, typename SequenceContainer::iterator it, Compare comp , dtl::false_) +{ + boost::movelib::adaptive_sort(it, dest.end(), comp); +} + +/////////////////////////////////////// +// +// flat_tree_merge +// +/////////////////////////////////////// +template<class SequenceContainer, class Iterator, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal + (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_) +{ + dest.merge(first, last, comp); +} + +template<class SequenceContainer, class Iterator, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal //has_merge_unique == false + (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_) +{ + typedef typename SequenceContainer::iterator iterator; + iterator const it = dest.insert( dest.end(), first, last ); + dtl::bool_<is_contiguous_container<SequenceContainer>::value> contiguous_tag; + (flat_tree_container_inplace_merge)(dest, it, comp, contiguous_tag); +} + +/////////////////////////////////////// +// +// flat_tree_merge_unique +// +/////////////////////////////////////// +template<class SequenceContainer, class Iterator, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == true + (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::true_) +{ + dest.merge_unique(first, last, comp); +} + +template<class SequenceContainer, class Iterator, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique //has_merge_unique == false + (SequenceContainer& dest, Iterator first, Iterator last, Compare comp, dtl::false_) +{ + typedef typename SequenceContainer::iterator iterator; + typedef typename SequenceContainer::size_type size_type; + typedef typename SequenceContainer::difference_type difference_type; + + size_type const old_sz = dest.size(); + iterator const first_new = dest.insert(dest.cend(), first, last ); + iterator e = boost::movelib::inplace_set_unique_difference(first_new, dest.end(), dest.begin(), first_new, comp); + dest.erase(e, dest.end()); + dtl::bool_<is_contiguous_container<SequenceContainer>::value> contiguous_tag; + (flat_tree_container_inplace_merge)(dest, dest.begin() + difference_type(old_sz), comp, contiguous_tag); +} + +/////////////////////////////////////// +// +// flat_tree_index_of +// +/////////////////////////////////////// +template<class SequenceContainer, class Iterator> +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type + flat_tree_index_of // has_index_of == true + (SequenceContainer& cont, Iterator p, dtl::true_) +{ + return cont.index_of(p); +} + +template<class SequenceContainer, class Iterator> +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type + flat_tree_index_of // has_index_of == false + (SequenceContainer& cont, Iterator p, dtl::false_) +{ + typedef typename SequenceContainer::size_type size_type; + return static_cast<size_type>(p - cont.begin()); +} + +/////////////////////////////////////// +// +// flat_tree_nth +// +/////////////////////////////////////// +template<class Iterator, class SequenceContainer> +BOOST_CONTAINER_FORCEINLINE Iterator + flat_tree_nth // has_nth == true + (SequenceContainer& cont, typename SequenceContainer::size_type n, dtl::true_) +{ + return cont.nth(n); +} + +template<class Iterator, class SequenceContainer> +BOOST_CONTAINER_FORCEINLINE Iterator + flat_tree_nth // has_nth == false + (SequenceContainer& cont, typename SequenceContainer::size_type n, dtl::false_) +{ + return cont.begin()+ typename SequenceContainer::difference_type(n); +} + +/////////////////////////////////////// +// +// flat_tree_get_stored_allocator +// +/////////////////////////////////////// +template<class SequenceContainer> +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::stored_allocator_type & + flat_tree_get_stored_allocator // has_get_stored_allocator == true + (SequenceContainer& cont, dtl::true_) +{ + return cont.get_stored_allocator(); +} + +template<class SequenceContainer> +BOOST_CONTAINER_FORCEINLINE const typename SequenceContainer::stored_allocator_type & + flat_tree_get_stored_allocator // has_get_stored_allocator == true + (const SequenceContainer& cont, dtl::true_) +{ + return cont.get_stored_allocator(); +} + +template<class SequenceContainer> +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::allocator_type + flat_tree_get_stored_allocator // has_get_stored_allocator == false + (SequenceContainer& cont, dtl::false_) +{ + return cont.get_allocator(); +} + +/////////////////////////////////////// +// +// flat_tree_adopt_sequence_equal +// +/////////////////////////////////////// +template<class SequenceContainer, class Compare> +void flat_tree_sort_contiguous_to_adopt // is_contiguous_container == true + (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp) +{ + if(tseq.capacity() >= (seq.capacity() - seq.size())) { + tseq.clear(); + boost::movelib::adaptive_sort + (boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , comp + , boost::movelib::iterator_to_raw_pointer(tseq.begin()) + , tseq.capacity()); + } + else{ + boost::movelib::adaptive_sort + (boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , comp + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , seq.capacity() - seq.size()); + } +} + +template<class SequenceContainer, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_adopt_sequence_equal // is_contiguous_container == true + (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_) +{ + flat_tree_sort_contiguous_to_adopt(tseq, boost::move(seq), comp); + tseq = boost::move(seq); +} + +template<class SequenceContainer, class Compare> +BOOST_CONTAINER_FORCEINLINE void flat_tree_adopt_sequence_equal // is_contiguous_container == false + (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::false_) +{ + boost::movelib::adaptive_sort(seq.begin(), seq.end(), comp); + tseq = boost::move(seq); +} + +/////////////////////////////////////// +// +// flat_tree_adopt_sequence_unique +// +/////////////////////////////////////// +template<class SequenceContainer, class Compare> +void flat_tree_adopt_sequence_unique// is_contiguous_container == true + (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::true_) +{ + boost::movelib::pdqsort + ( boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , comp); + seq.erase(boost::movelib::unique + (seq.begin(), seq.end(), boost::movelib::negate<Compare>(comp)), seq.cend()); + tseq = boost::move(seq); +} + +template<class SequenceContainer, class Compare> +void flat_tree_adopt_sequence_unique// is_contiguous_container == false + (SequenceContainer &tseq, BOOST_RV_REF(SequenceContainer) seq, Compare comp, dtl::false_) +{ + boost::movelib::pdqsort(seq.begin(), seq.end(), comp); + seq.erase(boost::movelib::unique + (seq.begin(), seq.end(), boost::movelib::negate<Compare>(comp)), seq.cend()); + tseq = boost::move(seq); +} + +/////////////////////////////////////// +// +// flat_tree_reserve +// +/////////////////////////////////////// +template<class SequenceContainer> +BOOST_CONTAINER_FORCEINLINE void // has_reserve == true + flat_tree_reserve(SequenceContainer &tseq, typename SequenceContainer::size_type cap, dtl::true_) +{ + tseq.reserve(cap); +} + +template<class SequenceContainer> +BOOST_CONTAINER_FORCEINLINE void // has_reserve == false + flat_tree_reserve(SequenceContainer &, typename SequenceContainer::size_type, dtl::false_) +{ +} + +/////////////////////////////////////// +// +// flat_tree_capacity +// +/////////////////////////////////////// +template<class SequenceContainer> // has_capacity == true +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type + flat_tree_capacity(const SequenceContainer &tseq, dtl::true_) +{ + return tseq.capacity(); +} + +template<class SequenceContainer> // has_capacity == false +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type + flat_tree_capacity(const SequenceContainer &tseq, dtl::false_) +{ + return tseq.size(); +} + +/////////////////////////////////////// +// +// flat_tree_value_compare +// +/////////////////////////////////////// + +template<class Compare, class Value, class KeyOfValue> +class flat_tree_value_compare + : private Compare +{ + typedef Value first_argument_type; + typedef Value second_argument_type; + typedef bool return_type; + public: + BOOST_CONTAINER_FORCEINLINE flat_tree_value_compare() + : Compare() + {} + + BOOST_CONTAINER_FORCEINLINE flat_tree_value_compare(const Compare &pred) + : Compare(pred) + {} + + BOOST_CONTAINER_FORCEINLINE bool operator()(const Value& lhs, const Value& rhs) const + { + KeyOfValue key_extract; + return Compare::operator()(key_extract(lhs), key_extract(rhs)); + } + + BOOST_CONTAINER_FORCEINLINE const Compare &get_comp() const + { return *this; } + + BOOST_CONTAINER_FORCEINLINE Compare &get_comp() + { return *this; } +}; + + +/////////////////////////////////////// +// +// select_container_type +// +/////////////////////////////////////// +template < class Value, class AllocatorOrContainer + , bool = boost::container::dtl::is_container<AllocatorOrContainer>::value + > +struct select_container_type +{ + typedef AllocatorOrContainer type; +}; + +template <class Value, class AllocatorOrContainer> +struct select_container_type<Value, AllocatorOrContainer, false> +{ + typedef boost::container::vector<Value, typename real_allocator<Value, AllocatorOrContainer>::type> type; +}; + + +/////////////////////////////////////// +// +// flat_tree +// +/////////////////////////////////////// +template <class Value, class KeyOfValue, + class Compare, class AllocatorOrContainer> +class flat_tree +{ + public: + typedef typename select_container_type<Value, AllocatorOrContainer>::type container_type; + typedef container_type sequence_type; //For backwards compatibility + + private: + typedef typename container_type::allocator_type allocator_t; + typedef allocator_traits<allocator_t> allocator_traits_type; + + public: + typedef flat_tree_value_compare<Compare, Value, KeyOfValue> value_compare; + + private: + + struct Data + //Inherit from value_compare to do EBO + : public value_compare + { + BOOST_COPYABLE_AND_MOVABLE(Data) + + public: + BOOST_CONTAINER_FORCEINLINE Data() + : value_compare(), m_seq() + {} + + BOOST_CONTAINER_FORCEINLINE explicit Data(const allocator_t &alloc) + : value_compare(), m_seq(alloc) + {} + + BOOST_CONTAINER_FORCEINLINE explicit Data(const Compare &comp) + : value_compare(comp), m_seq() + {} + + BOOST_CONTAINER_FORCEINLINE Data(const Compare &comp, const allocator_t &alloc) + : value_compare(comp), m_seq(alloc) + {} + + BOOST_CONTAINER_FORCEINLINE explicit Data(const Data &d) + : value_compare(static_cast<const value_compare&>(d)), m_seq(d.m_seq) + {} + + BOOST_CONTAINER_FORCEINLINE Data(BOOST_RV_REF(Data) d) + : value_compare(boost::move(static_cast<value_compare&>(d))), m_seq(boost::move(d.m_seq)) + {} + + BOOST_CONTAINER_FORCEINLINE Data(const Data &d, const allocator_t &a) + : value_compare(static_cast<const value_compare&>(d)), m_seq(d.m_seq, a) + {} + + BOOST_CONTAINER_FORCEINLINE Data(BOOST_RV_REF(Data) d, const allocator_t &a) + : value_compare(boost::move(static_cast<value_compare&>(d))), m_seq(boost::move(d.m_seq), a) + {} + + Data& operator=(BOOST_COPY_ASSIGN_REF(Data) d) + { + this->value_compare::operator=(d); + m_seq = d.m_seq; + return *this; + } + + Data& operator=(BOOST_RV_REF(Data) d) + { + this->value_compare::operator=(boost::move(static_cast<value_compare &>(d))); + m_seq = boost::move(d.m_seq); + return *this; + } + + void swap(Data &d) + { + value_compare& mycomp = *this, & othercomp = d; + boost::adl_move_swap(mycomp, othercomp); + this->m_seq.swap(d.m_seq); + } + + container_type m_seq; + }; + + Data m_data; + BOOST_COPYABLE_AND_MOVABLE(flat_tree) + + public: + + typedef typename container_type::value_type value_type; + typedef typename container_type::pointer pointer; + typedef typename container_type::const_pointer const_pointer; + typedef typename container_type::reference reference; + typedef typename container_type::const_reference const_reference; + typedef typename KeyOfValue::type key_type; + typedef Compare key_compare; + typedef typename container_type::allocator_type allocator_type; + typedef typename container_type::size_type size_type; + typedef typename container_type::difference_type difference_type; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::reverse_iterator reverse_iterator; + typedef typename container_type::const_reverse_iterator const_reverse_iterator; + + //!Standard extension + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT + (boost::container::dtl::, container_type + ,stored_allocator_type, allocator_type) stored_allocator_type; + + static const bool has_stored_allocator_type = + BOOST_INTRUSIVE_HAS_TYPE(boost::container::dtl::, container_type, stored_allocator_type); + + private: + typedef allocator_traits<stored_allocator_type> stored_allocator_traits; + + public: + typedef typename dtl::if_c + <has_stored_allocator_type, const stored_allocator_type &, allocator_type>::type get_stored_allocator_const_return_t; + + typedef typename dtl::if_c + <has_stored_allocator_type, stored_allocator_type &, allocator_type>::type get_stored_allocator_noconst_return_t; + + BOOST_CONTAINER_FORCEINLINE flat_tree() + : m_data() + { } + + BOOST_CONTAINER_FORCEINLINE explicit flat_tree(const Compare& comp) + : m_data(comp) + { } + + BOOST_CONTAINER_FORCEINLINE explicit flat_tree(const allocator_type& a) + : m_data(a) + { } + + BOOST_CONTAINER_FORCEINLINE flat_tree(const Compare& comp, const allocator_type& a) + : m_data(comp, a) + { } + + BOOST_CONTAINER_FORCEINLINE flat_tree(const flat_tree& x) + : m_data(x.m_data) + { } + + BOOST_CONTAINER_FORCEINLINE flat_tree(BOOST_RV_REF(flat_tree) x) + BOOST_NOEXCEPT_IF(boost::container::dtl::is_nothrow_move_constructible<Compare>::value) + : m_data(boost::move(x.m_data)) + { } + + BOOST_CONTAINER_FORCEINLINE flat_tree(const flat_tree& x, const allocator_type &a) + : m_data(x.m_data, a) + { } + + BOOST_CONTAINER_FORCEINLINE flat_tree(BOOST_RV_REF(flat_tree) x, const allocator_type &a) + : m_data(boost::move(x.m_data), a) + { } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( ordered_range_t, InputIterator first, InputIterator last) + : m_data() + { + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( ordered_range_t, InputIterator first, InputIterator last, const Compare& comp) + : m_data(comp) + { + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( ordered_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) + : m_data(comp, a) + { + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last) + : m_data() + { + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp) + : m_data(comp) + { + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) + : m_data(comp, a) + { + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( bool unique_insertion, InputIterator first, InputIterator last) + : m_data() + { + this->priv_range_insertion_construct(unique_insertion, first, last); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( bool unique_insertion, InputIterator first, InputIterator last + , const Compare& comp) + : m_data(comp) + { + this->priv_range_insertion_construct(unique_insertion, first, last); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( bool unique_insertion, InputIterator first, InputIterator last + , const allocator_type& a) + : m_data(a) + { + this->priv_range_insertion_construct(unique_insertion, first, last); + } + + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_tree( bool unique_insertion, InputIterator first, InputIterator last + , const Compare& comp, const allocator_type& a) + : m_data(comp, a) + { + this->priv_range_insertion_construct(unique_insertion, first, last); + } + + BOOST_CONTAINER_FORCEINLINE ~flat_tree() + {} + + BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_COPY_ASSIGN_REF(flat_tree) x) + { m_data = x.m_data; return *this; } + + BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_RV_REF(flat_tree) x) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::dtl::is_nothrow_move_assignable<Compare>::value) + { m_data = boost::move(x.m_data); return *this; } + + BOOST_CONTAINER_FORCEINLINE const value_compare &priv_value_comp() const + { return static_cast<const value_compare &>(this->m_data); } + + BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp() + { return static_cast<value_compare &>(this->m_data); } + + BOOST_CONTAINER_FORCEINLINE const key_compare &priv_key_comp() const + { return this->priv_value_comp().get_comp(); } + + BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp() + { return this->priv_value_comp().get_comp(); } + + struct insert_commit_data + { + const_iterator position; + }; + + public: + // accessors: + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + Compare key_comp() const + { return this->m_data.get_comp(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + value_compare value_comp() const + { return this->m_data; } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + allocator_type get_allocator() const + { return this->m_data.m_seq.get_allocator(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + get_stored_allocator_const_return_t get_stored_allocator() const + { + return flat_tree_get_stored_allocator(this->m_data.m_seq, dtl::bool_<has_stored_allocator_type>()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + get_stored_allocator_noconst_return_t get_stored_allocator() + { + return flat_tree_get_stored_allocator(this->m_data.m_seq, dtl::bool_<has_stored_allocator_type>()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator begin() + { return this->m_data.m_seq.begin(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator begin() const + { return this->cbegin(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator cbegin() const + { return this->m_data.m_seq.begin(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator end() + { return this->m_data.m_seq.end(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator end() const + { return this->cend(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator cend() const + { return this->m_data.m_seq.end(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + reverse_iterator rbegin() + { return reverse_iterator(this->end()); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator rbegin() const + { return this->crbegin(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator crbegin() const + { return const_reverse_iterator(this->cend()); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + reverse_iterator rend() + { return reverse_iterator(this->begin()); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator rend() const + { return this->crend(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator crend() const + { return const_reverse_iterator(this->cbegin()); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + bool empty() const + { return this->m_data.m_seq.empty(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type size() const + { return this->m_data.m_seq.size(); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type max_size() const + { return this->m_data.m_seq.max_size(); } + + BOOST_CONTAINER_FORCEINLINE void swap(flat_tree& other) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable<Compare>::value ) + { this->m_data.swap(other.m_data); } + + public: + // insert/erase + std::pair<iterator,bool> insert_unique(const value_type& val) + { + std::pair<iterator,bool> ret; + insert_commit_data data; + ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data); + ret.first = ret.second ? this->priv_insert_commit(data, val) + : this->begin() + (data.position - this->cbegin()); + //: iterator(vector_iterator_get_ptr(data.position)); + return ret; + } + + std::pair<iterator,bool> insert_unique(BOOST_RV_REF(value_type) val) + { + std::pair<iterator,bool> ret; + insert_commit_data data; + ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data); + ret.first = ret.second ? this->priv_insert_commit(data, boost::move(val)) + : this->begin() + (data.position - this->cbegin()); + //: iterator(vector_iterator_get_ptr(data.position)); + return ret; + } + + iterator insert_equal(const value_type& val) + { + iterator i = this->upper_bound(KeyOfValue()(val)); + i = this->m_data.m_seq.insert(i, val); + return i; + } + + iterator insert_equal(BOOST_RV_REF(value_type) mval) + { + iterator i = this->upper_bound(KeyOfValue()(mval)); + i = this->m_data.m_seq.insert(i, boost::move(mval)); + return i; + } + + iterator insert_unique(const_iterator hint, const value_type& val) + { + BOOST_ASSERT(this->priv_in_range_or_end(hint)); + insert_commit_data data; + return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data) + ? this->priv_insert_commit(data, val) + : this->begin() + (data.position - this->cbegin()); + //: iterator(vector_iterator_get_ptr(data.position)); + } + + iterator insert_unique(const_iterator hint, BOOST_RV_REF(value_type) val) + { + BOOST_ASSERT(this->priv_in_range_or_end(hint)); + insert_commit_data data; + return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data) + ? this->priv_insert_commit(data, boost::move(val)) + : this->begin() + (data.position - this->cbegin()); + //: iterator(vector_iterator_get_ptr(data.position)); + } + + iterator insert_equal(const_iterator hint, const value_type& val) + { + BOOST_ASSERT(this->priv_in_range_or_end(hint)); + insert_commit_data data; + this->priv_insert_equal_prepare(hint, val, data); + return this->priv_insert_commit(data, val); + } + + iterator insert_equal(const_iterator hint, BOOST_RV_REF(value_type) mval) + { + BOOST_ASSERT(this->priv_in_range_or_end(hint)); + insert_commit_data data; + this->priv_insert_equal_prepare(hint, mval, data); + return this->priv_insert_commit(data, boost::move(mval)); + } + + template <class InIt> + void insert_unique(InIt first, InIt last) + { + dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag; + container_type &seq = this->m_data.m_seq; + value_compare &val_cmp = this->priv_value_comp(); + + //Step 1: put new elements in the back + typename container_type::iterator const it = seq.insert(seq.cend(), first, last); + + //Step 2: sort them + boost::movelib::pdqsort(it, seq.end(), val_cmp); + + //Step 3: only left unique values from the back not already present in the original range + typename container_type::iterator const e = boost::movelib::inplace_set_unique_difference + (it, seq.end(), seq.begin(), it, val_cmp); + + seq.erase(e, seq.cend()); + //it might be invalidated by erasing [e, seq.end) if e == it + if (it != e) + { + //Step 4: merge both ranges + (flat_tree_container_inplace_merge)(seq, it, this->priv_value_comp(), contiguous_tag); + } + } + + template <class InIt> + void insert_equal(InIt first, InIt last) + { + dtl::bool_<is_contiguous_container<container_type>::value> contiguous_tag; + container_type &seq = this->m_data.m_seq; + typename container_type::iterator const it = seq.insert(seq.cend(), first, last); + (flat_tree_container_inplace_sort_ending)(seq, it, this->priv_value_comp(), contiguous_tag); + (flat_tree_container_inplace_merge) (seq, it, this->priv_value_comp(), contiguous_tag); + } + + //Ordered + + template <class InIt> + void insert_equal(ordered_range_t, InIt first, InIt last) + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value; + (flat_tree_merge_equal)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_<value>()); + } + + template <class InIt> + void insert_unique(ordered_unique_range_t, InIt first, InIt last) + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_merge_unique<container_type, InIt, InIt, value_compare>::value; + (flat_tree_merge_unique)(this->m_data.m_seq, first, last, this->priv_value_comp(), dtl::bool_<value>()); + } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template <class... Args> + std::pair<iterator, bool> emplace_unique(BOOST_FWD_REF(Args)... args) + { + typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v; + get_stored_allocator_noconst_return_t a = this->get_stored_allocator(); + stored_allocator_traits::construct(a, move_detail::force_ptr<value_type *>(&v), ::boost::forward<Args>(args)... ); + value_type *pval = move_detail::force_ptr<value_type *>(&v); + value_destructor<stored_allocator_type, value_type> d(a, *pval); + return this->insert_unique(::boost::move(*pval)); + } + + template <class... Args> + iterator emplace_hint_unique(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + //hint checked in insert_unique + typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v; + get_stored_allocator_noconst_return_t a = this->get_stored_allocator(); + stored_allocator_traits::construct(a, move_detail::force_ptr<value_type *>(&v), ::boost::forward<Args>(args)... ); + value_type *pval = move_detail::force_ptr<value_type *>(&v); + value_destructor<stored_allocator_type, value_type> d(a, *pval); + return this->insert_unique(hint, ::boost::move(*pval)); + } + + template <class... Args> + iterator emplace_equal(BOOST_FWD_REF(Args)... args) + { + typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v; + get_stored_allocator_noconst_return_t a = this->get_stored_allocator(); + stored_allocator_traits::construct(a, move_detail::force_ptr<value_type *>(&v), ::boost::forward<Args>(args)... ); + value_type *pval = move_detail::force_ptr<value_type *>(&v); + value_destructor<stored_allocator_type, value_type> d(a, *pval); + return this->insert_equal(::boost::move(*pval)); + } + + template <class... Args> + iterator emplace_hint_equal(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + //hint checked in insert_equal + typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v; + get_stored_allocator_noconst_return_t a = this->get_stored_allocator(); + stored_allocator_traits::construct(a, move_detail::force_ptr<value_type *>(&v), ::boost::forward<Args>(args)... ); + value_type *pval = move_detail::force_ptr<value_type *>(&v); + value_destructor<stored_allocator_type, value_type> d(a, *pval); + return this->insert_equal(hint, ::boost::move(*pval)); + } + + template <class KeyType, class... Args> + BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> try_emplace + (const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(Args)... args) + { + std::pair<iterator,bool> ret; + insert_commit_data data; + const key_type & k = key; + ret.second = hint == const_iterator() + ? this->priv_insert_unique_prepare(k, data) + : this->priv_insert_unique_prepare(hint, k, data); + + if(!ret.second){ + ret.first = this->nth(size_type(data.position - this->cbegin())); + } + else{ + ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward<KeyType>(key), ::boost::forward<Args>(args)...); + } + return ret; + } + + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + #define BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + std::pair<iterator, bool> emplace_unique(BOOST_MOVE_UREF##N)\ + {\ + typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\ + get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\ + stored_allocator_traits::construct(a, move_detail::force_ptr<value_type *>(&v) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + value_type *pval = move_detail::force_ptr<value_type *>(&v);\ + value_destructor<stored_allocator_type, value_type> d(a, *pval);\ + return this->insert_unique(::boost::move(*pval));\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace_hint_unique(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\ + get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\ + stored_allocator_traits::construct(a, move_detail::force_ptr<value_type *>(&v) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + value_type *pval = move_detail::force_ptr<value_type *>(&v);\ + value_destructor<stored_allocator_type, value_type> d(a, *pval);\ + return this->insert_unique(hint, ::boost::move(*pval));\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace_equal(BOOST_MOVE_UREF##N)\ + {\ + typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\ + get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\ + stored_allocator_traits::construct(a, move_detail::force_ptr<value_type *>(&v) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + value_type *pval = move_detail::force_ptr<value_type *>(&v);\ + value_destructor<stored_allocator_type, value_type> d(a, *pval);\ + return this->insert_equal(::boost::move(*pval));\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace_hint_equal(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + typename dtl::aligned_storage <sizeof(value_type), dtl::alignment_of<value_type>::value>::type v;\ + get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\ + stored_allocator_traits::construct(a, move_detail::force_ptr<value_type *>(&v) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + value_type *pval = move_detail::force_ptr<value_type *>(&v);\ + value_destructor<stored_allocator_type, value_type> d(a, *pval);\ + return this->insert_equal(hint, ::boost::move(*pval));\ + }\ + template <class KeyType BOOST_MOVE_I##N BOOST_MOVE_CLASS##N>\ + BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool>\ + try_emplace(const_iterator hint, BOOST_FWD_REF(KeyType) key BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + std::pair<iterator,bool> ret;\ + insert_commit_data data;\ + const key_type & k = key;\ + ret.second = hint == const_iterator()\ + ? this->priv_insert_unique_prepare(k, data)\ + : this->priv_insert_unique_prepare(hint, k, data);\ + \ + if(!ret.second){\ + ret.first = this->nth(size_type(data.position - this->cbegin()));\ + }\ + else{\ + ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward<KeyType>(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + return ret;\ + }\ + // + BOOST_MOVE_ITERATE_0TO7(BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE) + #undef BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE + + #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template<class KeyType, class M> + std::pair<iterator, bool> insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj) + { + const key_type& k = key; + std::pair<iterator,bool> ret; + insert_commit_data data; + ret.second = hint == const_iterator() + ? this->priv_insert_unique_prepare(k, data) + : this->priv_insert_unique_prepare(hint, k, data); + if(!ret.second){ + ret.first = this->nth(size_type(data.position - this->cbegin())); + ret.first->second = boost::forward<M>(obj); + } + else{ + ret.first = this->m_data.m_seq.emplace(data.position, boost::forward<KeyType>(key), boost::forward<M>(obj)); + } + return ret; + } + + BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator position) + { return this->m_data.m_seq.erase(position); } + + size_type erase(const key_type& k) + { + std::pair<iterator,iterator > itp = this->equal_range(k); + size_type ret = static_cast<size_type>(itp.second-itp.first); + if (ret){ + this->m_data.m_seq.erase(itp.first, itp.second); + } + return ret; + } + + size_type erase_unique(const key_type& k) + { + iterator i = this->find(k); + size_type ret = static_cast<size_type>(i != this->end()); + if (ret) + this->erase(i); + return ret; + } + + BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator first, const_iterator last) + { return this->m_data.m_seq.erase(first, last); } + + BOOST_CONTAINER_FORCEINLINE void clear() + { this->m_data.m_seq.clear(); } + + //! <b>Effects</b>: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws. + //! + //! <b>Complexity</b>: Linear to size(). + BOOST_CONTAINER_FORCEINLINE void shrink_to_fit() + { this->m_data.m_seq.shrink_to_fit(); } + + BOOST_CONTAINER_FORCEINLINE iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_nth<container_type, size_type>::value; + return flat_tree_nth<iterator>(this->m_data.m_seq, n, dtl::bool_<value>()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_nth<container_type, size_type>::value; + return flat_tree_nth<const_iterator>(this->m_data.m_seq, n, dtl::bool_<value>()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_index_of<container_type, iterator>::value; + return flat_tree_index_of(this->m_data.m_seq, p, dtl::bool_<value>()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_index_of<container_type, const_iterator>::value; + return flat_tree_index_of(this->m_data.m_seq, p, dtl::bool_<value>()); + } + + // set operations: + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + iterator find(const key_type& k) + { + iterator i = this->lower_bound(k); + iterator end_it = this->end(); + if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){ + i = end_it; + } + return i; + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + const_iterator find(const key_type& k) const + { + const_iterator i = this->lower_bound(k); + + const_iterator end_it = this->cend(); + if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){ + i = end_it; + } + return i; + } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + typename dtl::enable_if_transparent<key_compare, K, iterator>::type + find(const K& k) + { + iterator i = this->lower_bound(k); + iterator end_it = this->end(); + if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){ + i = end_it; + } + return i; + } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type + find(const K& k) const + { + const_iterator i = this->lower_bound(k); + + const_iterator end_it = this->cend(); + if (i != end_it && this->m_data.get_comp()(k, KeyOfValue()(*i))){ + i = end_it; + } + return i; + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + size_type count(const key_type& k) const + { + std::pair<const_iterator, const_iterator> p = this->equal_range(k); + size_type n = size_type(p.second - p.first); + return n; + } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD + typename dtl::enable_if_transparent<key_compare, K, size_type>::type + count(const K& k) const + { + std::pair<const_iterator, const_iterator> p = this->equal_range(k); + size_type n = size_type(p.second - p.first); + return n; + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE bool contains(const key_type& x) const + { return this->find(x) != this->cend(); } + + template<typename K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K, bool>::type + contains(const K& x) const + { return this->find(x) != this->cend(); } + + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source) + { + this->insert_unique( boost::make_move_iterator(source.begin()) + , boost::make_move_iterator(source.end())); + } + + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge_equal(flat_tree<Value, KeyOfValue, C2, AllocatorOrContainer>& source) + { + this->insert_equal( boost::make_move_iterator(source.begin()) + , boost::make_move_iterator(source.end())); + } + + BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree& source) + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_merge_unique<container_type, iterator, iterator, value_compare>::value; + (flat_tree_merge_unique) + ( this->m_data.m_seq + , boost::make_move_iterator(source.m_data.m_seq.begin()) + , boost::make_move_iterator(source.m_data.m_seq.end()) + , this->priv_value_comp() + , dtl::bool_<value>()); + } + + BOOST_CONTAINER_FORCEINLINE void merge_equal(flat_tree& source) + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_merge<container_type, iterator, iterator, value_compare>::value; + (flat_tree_merge_equal) + ( this->m_data.m_seq + , boost::make_move_iterator(source.m_data.m_seq.begin()) + , boost::make_move_iterator(source.m_data.m_seq.end()) + , this->priv_value_comp() + , dtl::bool_<value>()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator lower_bound(const key_type& k) + { return this->priv_lower_bound(this->begin(), this->end(), k); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator lower_bound(const key_type& k) const + { return this->priv_lower_bound(this->cbegin(), this->cend(), k); } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K, iterator>::type + lower_bound(const K& k) + { return this->priv_lower_bound(this->begin(), this->end(), k); } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K, const_iterator>::type + lower_bound(const K& k) const + { return this->priv_lower_bound(this->cbegin(), this->cend(), k); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator upper_bound(const key_type& k) + { return this->priv_upper_bound(this->begin(), this->end(), k); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator upper_bound(const key_type& k) const + { return this->priv_upper_bound(this->cbegin(), this->cend(), k); } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K,iterator>::type + upper_bound(const K& k) + { return this->priv_upper_bound(this->begin(), this->end(), k); } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K,const_iterator>::type + upper_bound(const K& k) const + { return this->priv_upper_bound(this->cbegin(), this->cend(), k); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<iterator,iterator> equal_range(const key_type& k) + { return this->priv_equal_range(this->begin(), this->end(), k); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const + { return this->priv_equal_range(this->cbegin(), this->cend(), k); } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K, std::pair<iterator,iterator> >::type + equal_range(const K& k) + { return this->priv_equal_range(this->begin(), this->end(), k); } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K,std::pair<const_iterator,const_iterator> >::type + equal_range(const K& k) const + { return this->priv_equal_range(this->cbegin(), this->cend(), k); } + + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<iterator, iterator> lower_bound_range(const key_type& k) + { return this->priv_lower_bound_range(this->begin(), this->end(), k); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<const_iterator, const_iterator> lower_bound_range(const key_type& k) const + { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K,std::pair<iterator,iterator> >::type + lower_bound_range(const K& k) + { return this->priv_lower_bound_range(this->begin(), this->end(), k); } + + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + typename dtl::enable_if_transparent<key_compare, K,std::pair<const_iterator,const_iterator> >::type + lower_bound_range(const K& k) const + { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type capacity() const + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_capacity<container_type>::value; + return (flat_tree_capacity)(this->m_data.m_seq, dtl::bool_<value>()); + } + + BOOST_CONTAINER_FORCEINLINE + void reserve(size_type cnt) + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_reserve<container_type, size_type>::value; + (flat_tree_reserve)(this->m_data.m_seq, cnt, dtl::bool_<value>()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + container_type extract_sequence() + { return boost::move(m_data.m_seq); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + container_type &get_sequence_ref() + { return m_data.m_seq; } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const container_type &get_sequence_cref() const + { return m_data.m_seq; } + + BOOST_CONTAINER_FORCEINLINE void adopt_sequence_equal(BOOST_RV_REF(container_type) seq) + { + (flat_tree_adopt_sequence_equal)( m_data.m_seq, boost::move(seq), this->priv_value_comp() + , dtl::bool_<is_contiguous_container<container_type>::value>()); + } + + BOOST_CONTAINER_FORCEINLINE void adopt_sequence_unique(BOOST_RV_REF(container_type) seq) + { + (flat_tree_adopt_sequence_unique)(m_data.m_seq, boost::move(seq), this->priv_value_comp() + , dtl::bool_<is_contiguous_container<container_type>::value>()); + } + + void adopt_sequence_equal(ordered_range_t, BOOST_RV_REF(container_type) seq) + { + BOOST_ASSERT((is_sorted)(seq.cbegin(), seq.cend(), this->priv_value_comp())); + m_data.m_seq = boost::move(seq); + } + + void adopt_sequence_unique(ordered_unique_range_t, BOOST_RV_REF(container_type) seq) + { + BOOST_ASSERT((is_sorted_and_unique)(seq.cbegin(), seq.cend(), this->priv_value_comp())); + m_data.m_seq = boost::move(seq); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator==(const flat_tree& x, const flat_tree& y) + { + return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator<(const flat_tree& x, const flat_tree& y) + { + return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); + } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator!=(const flat_tree& x, const flat_tree& y) + { return !(x == y); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator>(const flat_tree& x, const flat_tree& y) + { return y < x; } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator<=(const flat_tree& x, const flat_tree& y) + { return !(y < x); } + + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator>=(const flat_tree& x, const flat_tree& y) + { return !(x < y); } + + BOOST_CONTAINER_FORCEINLINE friend void swap(flat_tree& x, flat_tree& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) + { x.swap(y); } + + private: + + template <class InputIterator> + void priv_range_insertion_construct( bool unique_insertion, InputIterator first, InputIterator last) + { + //Use cend() as hint to achieve linear time for + //ordered ranges as required by the standard + //for the constructor + //Call end() every iteration as reallocation might have invalidated iterators + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + this->insert_equal (first, last); + } + } + + BOOST_CONTAINER_FORCEINLINE bool priv_in_range_or_end(const_iterator pos) const + { + return (this->begin() <= pos) && (pos <= this->end()); + } + + // insert/erase + void priv_insert_equal_prepare + (const_iterator pos, const value_type& val, insert_commit_data &data) + { + // N1780 + // To insert val at pos: + // if pos == end || val <= *pos + // if pos == begin || val >= *(pos-1) + // insert val before pos + // else + // insert val before upper_bound(val) + // else + // insert val before lower_bound(val) + const value_compare &val_cmp = this->m_data; + + if(pos == this->cend() || !val_cmp(*pos, val)){ + if (pos == this->cbegin() || !val_cmp(val, pos[-1])){ + data.position = pos; + } + else{ + data.position = + this->priv_upper_bound(this->cbegin(), pos, KeyOfValue()(val)); + } + } + else{ + data.position = + this->priv_lower_bound(pos, this->cend(), KeyOfValue()(val)); + } + } + + bool priv_insert_unique_prepare + (const_iterator b, const_iterator e, const key_type& k, insert_commit_data &commit_data) + { + const key_compare &key_cmp = this->priv_key_comp(); + commit_data.position = this->priv_lower_bound(b, e, k); + return commit_data.position == e || key_cmp(k, KeyOfValue()(*commit_data.position)); + } + + BOOST_CONTAINER_FORCEINLINE bool priv_insert_unique_prepare + (const key_type& k, insert_commit_data &commit_data) + { return this->priv_insert_unique_prepare(this->cbegin(), this->cend(), k, commit_data); } + + bool priv_insert_unique_prepare + (const_iterator pos, const key_type& k, insert_commit_data &commit_data) + { + //N1780. Props to Howard Hinnant! + //To insert k at pos: + //if pos == end || k <= *pos + // if pos == begin || k >= *(pos-1) + // insert k before pos + // else + // insert k before upper_bound(k) + //else if pos+1 == end || k <= *(pos+1) + // insert k after pos + //else + // insert k before lower_bound(k) + const key_compare &key_cmp = this->priv_key_comp(); + const const_iterator cend_it = this->cend(); + if(pos == cend_it || key_cmp(k, KeyOfValue()(*pos))){ //Check if k should go before end + const const_iterator cbeg = this->cbegin(); + commit_data.position = pos; + if(pos == cbeg){ //If container is empty then insert it in the beginning + return true; + } + const_iterator prev(pos); + --prev; + if(key_cmp(KeyOfValue()(*prev), k)){ //If previous element was less, then it should go between prev and pos + return true; + } + else if(!key_cmp(k, KeyOfValue()(*prev))){ //If previous was equal then insertion should fail + commit_data.position = prev; + return false; + } + else{ //Previous was bigger so insertion hint was pointless, dispatch to hintless insertion + //but reduce the search between beg and prev as prev is bigger than k + return this->priv_insert_unique_prepare(cbeg, prev, k, commit_data); + } + } + else{ + //The hint is before the insertion position, so insert it + //in the remaining range [pos, end) + return this->priv_insert_unique_prepare(pos, cend_it, k, commit_data); + } + } + + template<class Convertible> + BOOST_CONTAINER_FORCEINLINE iterator priv_insert_commit + (insert_commit_data &commit_data, BOOST_FWD_REF(Convertible) convertible) + { + return this->m_data.m_seq.insert + ( commit_data.position + , boost::forward<Convertible>(convertible)); + } + + template <class RanIt, class K> + RanIt priv_lower_bound(RanIt first, const RanIt last, + const K & key) const + { + const Compare &key_cmp = this->m_data.get_comp(); + KeyOfValue key_extract; + size_type len = static_cast<size_type>(last - first); + RanIt middle; + + while (len) { + size_type step = len >> 1; + middle = first; + middle += difference_type(step); + + if (key_cmp(key_extract(*middle), key)) { + first = ++middle; + len -= step + 1; + } + else{ + len = step; + } + } + return first; + } + + template <class RanIt, class K> + RanIt priv_upper_bound + (RanIt first, const RanIt last,const K & key) const + { + const Compare &key_cmp = this->m_data.get_comp(); + KeyOfValue key_extract; + size_type len = static_cast<size_type>(last - first); + RanIt middle; + + while (len) { + size_type step = len >> 1; + middle = first; + middle += difference_type(step); + + if (key_cmp(key, key_extract(*middle))) { + len = step; + } + else{ + first = ++middle; + len -= step + 1; + } + } + return first; + } + + template <class RanIt, class K> + std::pair<RanIt, RanIt> + priv_equal_range(RanIt first, RanIt last, const K& key) const + { + const Compare &key_cmp = this->m_data.get_comp(); + KeyOfValue key_extract; + size_type len = static_cast<size_type>(last - first); + RanIt middle; + + while (len) { + size_type step = len >> 1; + middle = first; + middle += difference_type(step); + + if (key_cmp(key_extract(*middle), key)){ + first = ++middle; + len -= step + 1; + } + else if (key_cmp(key, key_extract(*middle))){ + len = step; + } + else { + //Middle is equal to key + last = first; + last += difference_type(len); + RanIt const first_ret = this->priv_lower_bound(first, middle, key); + return std::pair<RanIt, RanIt> + ( first_ret, this->priv_upper_bound(++middle, last, key)); + } + } + return std::pair<RanIt, RanIt>(first, first); + } + + template<class RanIt, class K> + std::pair<RanIt, RanIt> priv_lower_bound_range(RanIt first, RanIt last, const K& k) const + { + const Compare &key_cmp = this->m_data.get_comp(); + KeyOfValue key_extract; + RanIt lb(this->priv_lower_bound(first, last, k)), ub(lb); + if(lb != last && !key_cmp(k, key_extract(*lb))){ + ++ub; + } + return std::pair<RanIt, RanIt>(lb, ub); + } +}; + +} //namespace dtl { + +} //namespace container { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template <class T, class KeyOfValue, +class Compare, class AllocatorOrContainer> +struct has_trivial_destructor_after_move<boost::container::dtl::flat_tree<T, KeyOfValue, Compare, AllocatorOrContainer> > +{ + typedef boost::container::dtl::flat_tree<T, KeyOfValue, Compare, AllocatorOrContainer> flat_tree; + typedef typename flat_tree::container_type container_type; + typedef typename flat_tree::key_compare key_compare; + static const bool value = ::boost::has_trivial_destructor_after_move<container_type>::value && + ::boost::has_trivial_destructor_after_move<key_compare>::value; +}; + +} //namespace boost { + +#include <boost/container/detail/config_end.hpp> + +#endif // BOOST_CONTAINER_FLAT_TREE_HPP diff --git a/contrib/restricted/boost/container/include/boost/container/detail/is_container.hpp b/contrib/restricted/boost/container/include/boost/container/detail/is_container.hpp new file mode 100644 index 0000000000..8ef0274d7a --- /dev/null +++ b/contrib/restricted/boost/container/include/boost/container/detail/is_container.hpp @@ -0,0 +1,72 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_IS_CONTAINER_HPP +#define BOOST_CONTAINER_DETAIL_IS_CONTAINER_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" +#endif + +//empty +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME empty +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace is_container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//size +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME size +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace is_container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//#pragma GCC diagnostic ignored "-Wunused-result" +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic pop +#endif + +namespace boost { +namespace container { +namespace dtl { + +template <class Container> +struct is_container +{ + static const bool value = + boost::container::is_container_detail:: + has_member_function_callable_with_size <const Container>::value && + boost::container::is_container_detail:: + has_member_function_callable_with_empty<const Container>::value; +}; + +template <> +struct is_container<void> +{ + static const bool value = false; +}; + + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_IS_CONTAINER_HPP diff --git a/contrib/restricted/boost/container/include/boost/container/detail/is_contiguous_container.hpp b/contrib/restricted/boost/container/include/boost/container/detail/is_contiguous_container.hpp new file mode 100644 index 0000000000..045de843a6 --- /dev/null +++ b/contrib/restricted/boost/container/include/boost/container/detail/is_contiguous_container.hpp @@ -0,0 +1,82 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_IS_CONTIGUOUS_CONTAINER_HPP +#define BOOST_CONTAINER_DETAIL_IS_CONTIGUOUS_CONTAINER_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" +#endif + +//data +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME data +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace is_contiguous_container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//back_free_capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME back_free_capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace back_free_capacity_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include <boost/intrusive/detail/has_member_function_callable_with.hpp> + +//#pragma GCC diagnostic ignored "-Wunused-result" +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic pop +#endif + +namespace boost { +namespace container { +namespace dtl { + +template <class Container> +struct is_contiguous_container +{ + static const bool value = + boost::container::is_contiguous_container_detail:: + has_member_function_callable_with_data<Container>::value && + boost::container::is_contiguous_container_detail:: + has_member_function_callable_with_data<const Container>::value; +}; + + +template < class Container + , bool = boost::container::back_free_capacity_detail:: + has_member_function_callable_with_back_free_capacity<const Container>::value> +struct back_free_capacity +{ + static typename Container::size_type get(const Container &c) + { return c.back_free_capacity(); } +}; + +template < class Container> +struct back_free_capacity<Container, false> +{ + static typename Container::size_type get(const Container &c) + { return c.capacity() - c.size(); } +}; + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_IS_CONTIGUOUS_CONTAINER_HPP diff --git a/contrib/restricted/boost/container/include/boost/container/detail/is_sorted.hpp b/contrib/restricted/boost/container/include/boost/container/detail/is_sorted.hpp new file mode 100644 index 0000000000..315bab54d7 --- /dev/null +++ b/contrib/restricted/boost/container/include/boost/container/detail/is_sorted.hpp @@ -0,0 +1,57 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2016-2016. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_IS_SORTED_HPP +#define BOOST_CONTAINER_DETAIL_IS_SORTED_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +namespace boost { +namespace container { +namespace dtl { + +template <class ForwardIterator, class Pred> +bool is_sorted (ForwardIterator first, ForwardIterator last, Pred pred) +{ + if(first != last){ + ForwardIterator next = first; + while (++next != last){ + if(pred(*next, *first)) + return false; + ++first; + } + } + return true; +} + +template <class ForwardIterator, class Pred> +bool is_sorted_and_unique (ForwardIterator first, ForwardIterator last, Pred pred) +{ + if(first != last){ + ForwardIterator next = first; + while (++next != last){ + if(!pred(*first, *next)) + return false; + ++first; + } + } + return true; +} + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_IS_SORTED_HPP diff --git a/contrib/restricted/boost/container/include/boost/container/flat_map.hpp b/contrib/restricted/boost/container/include/boost/container/flat_map.hpp new file mode 100644 index 0000000000..0a85b9db4a --- /dev/null +++ b/contrib/restricted/boost/container/include/boost/container/flat_map.hpp @@ -0,0 +1,3069 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_FLAT_MAP_HPP +#define BOOST_CONTAINER_FLAT_MAP_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> +// container +#include <boost/container/allocator_traits.hpp> +#include <boost/container/container_fwd.hpp> +#include <boost/container/new_allocator.hpp> //new_allocator +#include <boost/container/throw_exception.hpp> +// container/detail +#include <boost/container/detail/flat_tree.hpp> +#include <boost/container/detail/type_traits.hpp> +#include <boost/container/detail/mpl.hpp> +#include <boost/container/detail/algorithm.hpp> //equal() +#include <boost/container/detail/container_or_allocator_rebind.hpp> +// move +#include <boost/move/utility_core.hpp> +#include <boost/move/traits.hpp> +// move/detail +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include <boost/move/detail/fwd_macros.hpp> +#endif +#include <boost/move/detail/move_helpers.hpp> +#include <boost/move/detail/force_ptr.hpp> +// intrusive +#include <boost/intrusive/detail/minimal_pair_header.hpp> //pair +#include <boost/intrusive/detail/minimal_less_equal_header.hpp>//less, equal +//others +#include <boost/core/no_exceptions_support.hpp> + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +#include <initializer_list> +#endif + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +template <class Key, class T, class Compare, class AllocatorOrContainer> +class flat_multimap; + +namespace dtl{ + +template<class D, class S> +BOOST_CONTAINER_FORCEINLINE static D &force(S &s) +{ return *move_detail::force_ptr<D*>(&s); } + +template<class D, class S> +BOOST_CONTAINER_FORCEINLINE static const D &force(const S &s) +{ return *move_detail::force_ptr<const D*>(&s); } + +template<class D, class S> +BOOST_CONTAINER_FORCEINLINE static D force_copy(const S &s) +{ + const D *const vp = move_detail::force_ptr<const D *>(&s); + D ret_val(*vp); + return ret_val; +} + +} //namespace dtl{ + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! A flat_map is a kind of associative container that supports unique keys (contains at +//! most one of each key value) and provides for fast retrieval of values of another +//! type T based on the keys. +//! +//! A flat_map satisfies all of the requirements of a container, a reversible +//! container and an associative container. A flat_map also provides +//! most operations described for unique keys. For a +//! flat_map<Key,T> the key_type is Key and the value_type is std::pair<Key,T> +//! (unlike std::map<Key, T> which value_type is std::pair<<b>const</b> Key, T>). +//! +//! flat_map is similar to std::map but it's implemented by as an ordered sequence container. +//! The underlying sequence container is by default <i>vector</i> but it can also work +//! user-provided vector-like SequenceContainers (like <i>static_vector</i> or <i>small_vector</i>). +//! +//! Using vector-like sequence containers means that inserting a new element into a flat_map might invalidate +//! previous iterators and references (unless that sequence container is <i>stable_vector</i> or a similar +//! container that offers stable pointers and references). Similarly, erasing an element might invalidate +//! iterators and references pointing to elements that come after (their keys are bigger) the erased element. +//! +//! This container provides random-access iterators. +//! +//! \tparam Key is the key_type of the map +//! \tparam Value is the <code>mapped_type</code> +//! \tparam Compare is the ordering function for Keys (e.g. <i>std::less<Key></i>). +//! \tparam AllocatorOrContainer is either: +//! - The allocator to allocate <code>value_type</code>s (e.g. <i>allocator< std::pair<Key, T> > </i>). +//! (in this case <i>sequence_type</i> will be vector<value_type, AllocatorOrContainer>) +//! - The SequenceContainer to be used as the underlying <i>sequence_type</i>. It must be a vector-like +//! sequence container with random-access iterators. +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED +template <class Key, class T, class Compare = std::less<Key>, class AllocatorOrContainer = new_allocator< std::pair< Key, T> > > +#else +template <class Key, class T, class Compare, class AllocatorOrContainer> +#endif +class flat_map +{ + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + BOOST_COPYABLE_AND_MOVABLE(flat_map) + //This is the tree that we should store if pair was movable + typedef dtl::flat_tree< + std::pair<Key, T>, + dtl::select1st<Key>, + Compare, + AllocatorOrContainer> tree_t; + + //This is the real tree stored here. It's based on a movable pair + typedef dtl::flat_tree< + dtl::pair<Key, T>, + dtl::select1st<Key>, + Compare, + typename dtl::container_or_allocator_rebind<AllocatorOrContainer, dtl::pair<Key, T> >::type + > impl_tree_t; + impl_tree_t m_flat_tree; // flat tree representing flat_map + + typedef typename impl_tree_t::value_type impl_value_type; + typedef typename impl_tree_t::const_iterator impl_const_iterator; + typedef typename impl_tree_t::iterator impl_iterator; + typedef typename impl_tree_t::allocator_type impl_allocator_type; + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef std::initializer_list<impl_value_type> impl_initializer_list; + #endif + + typedef dtl::flat_tree_value_compare + < Compare + , dtl::select1st<Key> + , std::pair<Key, T> > value_compare_t; + typedef typename tree_t::iterator iterator_t; + typedef typename tree_t::const_iterator const_iterator_t; + typedef typename tree_t::reverse_iterator reverse_iterator_t; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator_t; + + public: + typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + typedef typename impl_tree_t::sequence_type impl_sequence_type; + + BOOST_CONTAINER_FORCEINLINE impl_tree_t &tree() + { return m_flat_tree; } + + BOOST_CONTAINER_FORCEINLINE const impl_tree_t &tree() const + { return m_flat_tree; } + + private: + typedef typename tree_t::get_stored_allocator_const_return_t get_stored_allocator_const_return_t; + typedef typename tree_t::get_stored_allocator_noconst_return_t get_stored_allocator_noconst_return_t; + typedef typename impl_tree_t::get_stored_allocator_const_return_t impl_get_stored_allocator_const_return_t; + typedef typename impl_tree_t::get_stored_allocator_noconst_return_t impl_get_stored_allocator_noconst_return_t; + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// + typedef Key key_type; + typedef T mapped_type; + typedef Compare key_compare; + typedef std::pair<Key, T> value_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; + typedef typename sequence_type::allocator_type allocator_type; + typedef ::boost::container::allocator_traits<allocator_type> allocator_traits_type; + typedef typename sequence_type::pointer pointer; + typedef typename sequence_type::const_pointer const_pointer; + typedef typename sequence_type::reference reference; + typedef typename sequence_type::const_reference const_reference; + typedef typename sequence_type::size_type size_type; + typedef typename sequence_type::difference_type difference_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::stored_allocator_type) stored_allocator_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::value_compare) value_compare; + + typedef typename sequence_type::iterator iterator; + typedef typename sequence_type::const_iterator const_iterator; + typedef typename sequence_type::reverse_iterator reverse_iterator; + typedef typename sequence_type::const_reverse_iterator const_reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(impl_value_type) movable_value_type; + + //AllocatorOrContainer::value_type must be std::pair<Key, T> + BOOST_STATIC_ASSERT((dtl::is_same<std::pair<Key, T>, value_type>::value)); + + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// + + //! <b>Effects</b>: Default constructs an empty flat_map. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE flat_map() BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<AllocatorOrContainer>::value && + dtl::is_nothrow_default_constructible<Compare>::value) + : m_flat_tree() + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified allocator. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE explicit flat_map(const allocator_type& a) + : m_flat_tree(dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified + //! comparison object. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE explicit flat_map(const Compare& comp) + : m_flat_tree(comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified + //! comparison object and allocator. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE flat_map(const Compare& comp, const allocator_type& a) + : m_flat_tree(comp, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_map and + //! and inserts elements from the range [first ,last ). + //! + //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE flat_map(InputIterator first, InputIterator last) + : m_flat_tree(true, first, last) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified + //! allocator, and inserts elements from the range [first ,last ). + //! + //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE flat_map(InputIterator first, InputIterator last, const allocator_type& a) + : m_flat_tree(true, first, last, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! and inserts elements from the range [first ,last ). + //! + //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE flat_map(InputIterator first, InputIterator last, const Compare& comp) + : m_flat_tree(true, first, last, comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE flat_map(InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) + : m_flat_tree(true, first, last, comp, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_map + //! and inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_map(ordered_unique_range_t, InputIterator first, InputIterator last) + : m_flat_tree(ordered_range, first, last) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_map(ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp) + : m_flat_tree(ordered_range, first, last, comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! allocator, and inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_map(ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) + : m_flat_tree(ordered_range, first, last, comp, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified allocator and + //! inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_map(ordered_unique_range_t, InputIterator first, InputIterator last, const allocator_type& a) + : m_flat_tree(ordered_range, first, last, Compare(), a) + {} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! <b>Effects</b>: Constructs an empty flat_map and + //! inserts elements from the range [il.begin() ,il.end()). + //! + //! <b>Complexity</b>: Linear in N if the range [il.begin(), il.end()) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + BOOST_CONTAINER_FORCEINLINE flat_map(std::initializer_list<value_type> il) + : m_flat_tree( true + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end()) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified + //! allocator, and inserts elements from the range [il.begin() ,il.end()). + //! + //! <b>Complexity</b>: Linear in N if the range [il.begin(), il.end()) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + BOOST_CONTAINER_FORCEINLINE flat_map(std::initializer_list<value_type> il, const allocator_type& a) + : m_flat_tree( true + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end() + , dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! inserts elements from the range [il.begin() ,il.end()). + //! + //! <b>Complexity</b>: Linear in N if the range [il.begin(), il.end()) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + BOOST_CONTAINER_FORCEINLINE flat_map(std::initializer_list<value_type> il, const Compare& comp) + : m_flat_tree(true + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end() + , comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! allocator, and inserts elements from the range [il.begin() ,il.end()). + //! + //! <b>Complexity</b>: Linear in N if the range [il.begin(), il.end()) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + BOOST_CONTAINER_FORCEINLINE flat_map(std::initializer_list<value_type> il, const Compare& comp, const allocator_type& a) + : m_flat_tree(true + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end() + , comp + , dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using and + //! inserts elements from the ordered unique range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate and must be + //! unique values. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE flat_map(ordered_unique_range_t, std::initializer_list<value_type> il) + : m_flat_tree(ordered_unique_range + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end()) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! inserts elements from the ordered unique range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate and must be + //! unique values. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE flat_map(ordered_unique_range_t, std::initializer_list<value_type> il, const Compare& comp) + : m_flat_tree(ordered_unique_range + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end() + , comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! allocator, and inserts elements from the ordered unique range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate and must be + //! unique values. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE flat_map(ordered_unique_range_t, std::initializer_list<value_type> il, const Compare& comp, const allocator_type& a) + : m_flat_tree( ordered_unique_range + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end() + , comp + , dtl::force<const impl_allocator_type>(a)) + {} +#endif + + //! <b>Effects</b>: Copy constructs a flat_map. + //! + //! <b>Complexity</b>: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE flat_map(const flat_map& x) + : m_flat_tree(x.m_flat_tree) + {} + + //! <b>Effects</b>: Move constructs a flat_map. + //! Constructs *this using x's resources. + //! + //! <b>Complexity</b>: Constant. + //! + //! <b>Postcondition</b>: x is emptied. + BOOST_CONTAINER_FORCEINLINE flat_map(BOOST_RV_REF(flat_map) x) + BOOST_NOEXCEPT_IF(boost::container::dtl::is_nothrow_move_constructible<Compare>::value) + : m_flat_tree(boost::move(x.m_flat_tree)) + {} + + //! <b>Effects</b>: Copy constructs a flat_map using the specified allocator. + //! + //! <b>Complexity</b>: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE flat_map(const flat_map& x, const allocator_type &a) + : m_flat_tree(x.m_flat_tree, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Move constructs a flat_map using the specified allocator. + //! Constructs *this using x's resources. + //! + //! <b>Complexity</b>: Constant if x.get_allocator() == a, linear otherwise. + BOOST_CONTAINER_FORCEINLINE flat_map(BOOST_RV_REF(flat_map) x, const allocator_type &a) + : m_flat_tree(boost::move(x.m_flat_tree), dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Makes *this a copy of x. + //! + //! <b>Complexity</b>: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE flat_map& operator=(BOOST_COPY_ASSIGN_REF(flat_map) x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! <b>Effects</b>: Move constructs a flat_map. + //! Constructs *this using x's resources. + //! + //! <b>Throws</b>: If allocator_traits_type::propagate_on_container_move_assignment + //! is false and (allocation throws or value_type's move constructor throws) + //! + //! <b>Complexity</b>: Constant if allocator_traits_type:: + //! propagate_on_container_move_assignment is true or + //! this->get>allocator() == x.get_allocator(). Linear otherwise. + BOOST_CONTAINER_FORCEINLINE flat_map& operator=(BOOST_RV_REF(flat_map) x) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::dtl::is_nothrow_move_assignable<Compare>::value) + { m_flat_tree = boost::move(x.m_flat_tree); return *this; } + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! <b>Effects</b>: Assign elements from il to *this + flat_map& operator=(std::initializer_list<value_type> il) + { + this->clear(); + this->insert(il.begin(), il.end()); + return *this; + } +#endif + + //! <b>Effects</b>: Returns a copy of the allocator that + //! was passed to the object's constructor. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<allocator_type>(m_flat_tree.get_allocator()); } + + //! <b>Effects</b>: Returns a reference to the internal allocator. + //! + //! <b>Throws</b>: Nothing + //! + //! <b>Complexity</b>: Constant. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + get_stored_allocator_noconst_return_t get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW + { + impl_get_stored_allocator_noconst_return_t r = m_flat_tree.get_stored_allocator(); + return dtl::force<stored_allocator_type>(r); + } + + //! <b>Effects</b>: Returns a reference to the internal allocator. + //! + //! <b>Throws</b>: Nothing + //! + //! <b>Complexity</b>: Constant. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + get_stored_allocator_const_return_t get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + { + impl_get_stored_allocator_const_return_t r = m_flat_tree.get_stored_allocator(); + return dtl::force<const stored_allocator_type>(r); + } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + + //! <b>Effects</b>: Returns an iterator to the first element contained in the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator begin() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<iterator>(m_flat_tree.begin()); } + + //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_iterator>(m_flat_tree.begin()); } + + //! <b>Effects</b>: Returns an iterator to the end of the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator end() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<iterator>(m_flat_tree.end()); } + + //! <b>Effects</b>: Returns a const_iterator to the end of the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_iterator>(m_flat_tree.end()); } + + //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<reverse_iterator>(m_flat_tree.rbegin()); } + + //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_reverse_iterator>(m_flat_tree.rbegin()); } + + //! <b>Effects</b>: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<reverse_iterator>(m_flat_tree.rend()); } + + //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_reverse_iterator>(m_flat_tree.rend()); } + + //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_iterator>(m_flat_tree.cbegin()); } + + //! <b>Effects</b>: Returns a const_iterator to the end of the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_iterator>(m_flat_tree.cend()); } + + //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_reverse_iterator>(m_flat_tree.crbegin()); } + + //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_reverse_iterator>(m_flat_tree.crend()); } + + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! <b>Effects</b>: Returns true if the container contains no elements. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + bool empty() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.empty(); } + + //! <b>Effects</b>: Returns the number of the elements contained in the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type size() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.size(); } + + //! <b>Effects</b>: Returns the largest possible size of the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.max_size(); } + + //! <b>Effects</b>: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.capacity(); } + + //! <b>Effects</b>: If n is less than or equal to capacity(), or the + //! underlying container has no `reserve` member, this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws. + //! + //! <b>Note</b>: If capacity() is less than "cnt", iterators and references to + //! to values might be invalidated. + BOOST_CONTAINER_FORCEINLINE void reserve(size_type cnt) + { m_flat_tree.reserve(cnt); } + + //! <b>Effects</b>: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws. + //! + //! <b>Complexity</b>: Linear to size(). + BOOST_CONTAINER_FORCEINLINE void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: If there is no key equivalent to x in the flat_map, inserts + //! value_type(x, T()) into the flat_map. + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present. + mapped_type &operator[](const key_type& k); + + //! Effects: If there is no key equivalent to x in the flat_map, inserts + //! value_type(move(x), T()) into the flat_map (the key is move-constructed) + //! + //! Returns: A reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present. + mapped_type &operator[](key_type &&k); + #elif defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN) + //in compilers like GCC 3.4, we can't catch temporaries + BOOST_CONTAINER_FORCEINLINE mapped_type& operator[](const key_type &k) { return this->priv_subscript(k); } + BOOST_CONTAINER_FORCEINLINE mapped_type& operator[](BOOST_RV_REF(key_type) k) { return this->priv_subscript(::boost::move(k)); } + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript) + #endif + + //! Effects: If a key equivalent to k already exists in the container, assigns forward<M>(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, forward<M>(obj)). + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic search time plus linear insertion time in case no equivalent key is present. + template <class M> + BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> insert_or_assign(const key_type& k, BOOST_FWD_REF(M) obj) + { + return dtl::force_copy< std::pair<iterator, bool> > + (this->m_flat_tree.insert_or_assign + ( impl_const_iterator(), k, ::boost::forward<M>(obj)) + ); + } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward<M>(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, move(obj)). + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container. + template <class M> + BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> insert_or_assign(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) + { + return dtl::force_copy< std::pair<iterator, bool> > + (this->m_flat_tree.insert_or_assign + ( impl_const_iterator(), ::boost::move(k), ::boost::forward<M>(obj)) + ); + } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward<M>(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, forward<M>(obj)) and the new element + //! to the container as close as possible to the position just before hint. + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container in general, but amortized constant if + //! the new element is inserted just before hint. + template <class M> + BOOST_CONTAINER_FORCEINLINE iterator insert_or_assign(const_iterator hint, const key_type& k, BOOST_FWD_REF(M) obj) + { + return dtl::force_copy<iterator> + (this->m_flat_tree.insert_or_assign + ( dtl::force_copy<impl_const_iterator>(hint) + , k, ::boost::forward<M>(obj)).first + ); + } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward<M>(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, move(obj)) and the new element + //! to the container as close as possible to the position just before hint. + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container in general, but amortized constant if + //! the new element is inserted just before hint. + template <class M> + BOOST_CONTAINER_FORCEINLINE iterator insert_or_assign(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) + { + return dtl::force_copy<iterator> + (this->m_flat_tree.insert_or_assign + ( dtl::force_copy<impl_const_iterator>(hint) + , ::boost::move(k), ::boost::forward<M>(obj)).first + ); + } + + //! @copydoc ::boost::container::flat_set::nth(size_type) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<iterator>(m_flat_tree.nth(n)); } + + //! @copydoc ::boost::container::flat_set::nth(size_type) const + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<iterator>(m_flat_tree.nth(n)); } + + //! @copydoc ::boost::container::flat_set::index_of(iterator) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.index_of(dtl::force_copy<impl_iterator>(p)); } + + //! @copydoc ::boost::container::flat_set::index_of(const_iterator) const + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.index_of(dtl::force_copy<impl_const_iterator>(p)); } + + //! Returns: A reference to the element whose key is equivalent to x. + //! + //! Throws: An exception object of type out_of_range if no such element is present. + //! + //! Complexity: logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD T& at(const key_type& k) + { + iterator i = this->find(k); + if(i == this->end()){ + throw_out_of_range("flat_map::at key not found"); + } + return i->second; + } + + //! Returns: A reference to the element whose key is equivalent to x. + //! + //! Throws: An exception object of type out_of_range if no such element is present. + //! + //! Complexity: logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD const T& at(const key_type& k) const + { + const_iterator i = this->find(k); + if(i == this->end()){ + throw_out_of_range("flat_map::at key not found"); + } + return i->second; + } + + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! <b>Effects</b>: Inserts an object x of type T constructed with + //! std::forward<Args>(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! <b>Returns</b>: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template <class... Args> + BOOST_CONTAINER_FORCEINLINE std::pair<iterator,bool> emplace(BOOST_FWD_REF(Args)... args) + { return dtl::force_copy< std::pair<iterator, bool> >(m_flat_tree.emplace_unique(boost::forward<Args>(args)...)); } + + //! <b>Effects</b>: Inserts an object of type T constructed with + //! std::forward<Args>(args)... in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! <b>Returns</b>: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template <class... Args> + BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return dtl::force_copy<iterator> + (m_flat_tree.emplace_hint_unique( dtl::force_copy<impl_const_iterator>(hint) + , boost::forward<Args>(args)...)); + } + + //! <b>Requires</b>: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...). + //! + //! <b>Effects</b>: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), + //! forward_as_tuple(forward<Args>(args)...). + //! + //! <b>Returns</b>: The bool component of the returned pair is true if and only if the + //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. + //! + //! <b>Complexity</b>: Logarithmic. + template <class... Args> + BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> try_emplace(const key_type& k, BOOST_FWD_REF(Args)... args) + { + return dtl::force_copy< std::pair<iterator, bool> >( + m_flat_tree.try_emplace(impl_const_iterator(), k, boost::forward<Args>(args)...)); + } + + //! <b>Requires</b>: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...). + //! + //! <b>Effects</b>: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), + //! forward_as_tuple(forward<Args>(args)...). + //! + //! <b>Returns</b>: The returned iterator points to the map element whose key is equivalent to k. + //! + //! <b>Complexity</b>: Logarithmic in general, but amortized constant if value + //! is inserted right before p. + template <class... Args> + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, const key_type &k, BOOST_FWD_REF(Args)... args) + { + return dtl::force_copy<iterator>(m_flat_tree.try_emplace + (dtl::force_copy<impl_const_iterator>(hint), k, boost::forward<Args>(args)...).first); + } + + //! <b>Requires</b>: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...). + //! + //! <b>Effects</b>: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)), + //! forward_as_tuple(forward<Args>(args)...). + //! + //! <b>Returns</b>: The bool component of the returned pair is true if and only if the + //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. + //! + //! <b>Complexity</b>: Logarithmic search time plus linear insertion time in case the key is not present. + template <class... Args> + BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> try_emplace(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) + { + return dtl::force_copy< std::pair<iterator, bool> > + (m_flat_tree.try_emplace(impl_const_iterator(), boost::move(k), boost::forward<Args>(args)...)); + } + + //! <b>Requires</b>: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...). + //! + //! <b>Effects</b>: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)), + //! forward_as_tuple(forward<Args>(args)...). + //! + //! <b>Returns</b>: The returned iterator points to the map element whose key is equivalent to k. + //! + //! <b>Complexity</b>: Logarithmic in general, but amortized constant if value + //! is inserted right before p. Linear insertion time in case no equivalent key is present. + template <class... Args> + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) + { + return dtl::force_copy<iterator> + (m_flat_tree.try_emplace(dtl::force_copy + <impl_const_iterator>(hint), boost::move(k), boost::forward<Args>(args)...).first); + } + + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + #define BOOST_CONTAINER_FLAT_MAP_EMPLACE_CODE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE std::pair<iterator,bool> emplace(BOOST_MOVE_UREF##N)\ + {\ + return dtl::force_copy< std::pair<iterator, bool> >\ + (m_flat_tree.emplace_unique(BOOST_MOVE_FWD##N));\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + return dtl::force_copy<iterator>(m_flat_tree.emplace_hint_unique\ + (dtl::force_copy<impl_const_iterator>(hint) BOOST_MOVE_I##N BOOST_MOVE_FWD##N));\ + }\ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> try_emplace(const key_type& k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + return dtl::force_copy< std::pair<iterator, bool> >\ + (m_flat_tree.try_emplace(impl_const_iterator(), k BOOST_MOVE_I##N BOOST_MOVE_FWD##N));\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, const key_type &k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { return dtl::force_copy<iterator>(m_flat_tree.try_emplace\ + (dtl::force_copy<impl_const_iterator>(hint), k BOOST_MOVE_I##N BOOST_MOVE_FWD##N).first); }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE std::pair<iterator, bool> try_emplace(BOOST_RV_REF(key_type) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + return dtl::force_copy< std::pair<iterator, bool> >\ + (m_flat_tree.try_emplace(impl_const_iterator(), boost::move(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N));\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { return dtl::force_copy<iterator>(m_flat_tree.try_emplace\ + (dtl::force_copy<impl_const_iterator>(hint), boost::move(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N).first); }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_FLAT_MAP_EMPLACE_CODE) + #undef BOOST_CONTAINER_FLAT_MAP_EMPLACE_CODE + + #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //! <b>Effects</b>: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! <b>Returns</b>: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + BOOST_CONTAINER_FORCEINLINE std::pair<iterator,bool> insert(const value_type& x) + { return dtl::force_copy<std::pair<iterator,bool> >( + m_flat_tree.insert_unique(dtl::force<const impl_value_type>(x))); } + + //! <b>Effects</b>: Inserts a new value_type move constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! <b>Returns</b>: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + BOOST_CONTAINER_FORCEINLINE std::pair<iterator,bool> insert(BOOST_RV_REF(value_type) x) + { + return dtl::force_copy<std::pair<iterator,bool> >( + m_flat_tree.insert_unique(boost::move(dtl::force<impl_value_type>(x)))); + } + + //! <b>Effects</b>: Inserts a new value_type constructed from the pair if and + //! only if there is no element in the container with key equivalent to the key of x. + //! + //! <b>Returns</b>: The bool component of the returned pair is true if and only + //! if the insertion takes place, and the iterator component of the pair + //! points to the element with key equivalent to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template <class Pair> + BOOST_CONTAINER_FORCEINLINE BOOST_CONTAINER_DOC1ST + ( std::pair<iterator BOOST_MOVE_I bool> + , typename dtl::enable_if_c<dtl::is_convertible<Pair BOOST_MOVE_I impl_value_type>::value + BOOST_MOVE_I std::pair<iterator BOOST_MOVE_I bool> >::type) + insert(BOOST_FWD_REF(Pair) x) + { + return dtl::force_copy<std::pair<iterator,bool> > + (m_flat_tree.emplace_unique(boost::forward<Pair>(x))); + } + + //! <b>Effects</b>: Inserts a copy of x in the container if and only if there is + //! no element in the container with key equivalent to the key of x. + //! p is a hint pointing to where the insert should start to search. + //! + //! <b>Returns</b>: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, const value_type& x) + { + return dtl::force_copy<iterator>( + m_flat_tree.insert_unique( dtl::force_copy<impl_const_iterator>(p) + , dtl::force<const impl_value_type>(x))); + } + + //! <b>Effects</b>: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, BOOST_RV_REF(value_type) x) + { + return dtl::force_copy<iterator> + (m_flat_tree.insert_unique( dtl::force_copy<impl_const_iterator>(p) + , boost::move(dtl::force<impl_value_type>(x)))); + } + + //! <b>Effects</b>: Inserts an element constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template <class Pair> + BOOST_CONTAINER_FORCEINLINE BOOST_CONTAINER_DOC1ST + ( iterator + , typename dtl::enable_if_c<dtl::is_convertible<Pair BOOST_MOVE_I impl_value_type>::value + BOOST_MOVE_I iterator>::type) + insert(const_iterator p, BOOST_FWD_REF(Pair) x) + { + return dtl::force_copy<iterator>( + m_flat_tree.emplace_hint_unique(dtl::force_copy<impl_const_iterator>(p), boost::forward<Pair>(x))); + } + + //! <b>Requires</b>: first, last are not iterators into *this. + //! + //! <b>Effects</b>: inserts each element from the range [first,last) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! <b>Complexity</b>: N log(size()+N). + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_unique(first, last); } + + //! <b>Requires</b>: first, last are not iterators into *this. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate and must be + //! unique values. + //! + //! <b>Effects</b>: inserts each element from the range [first,last) if and only + //! if there is no element with key equivalent to the key of that element. This + //! function is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Complexity</b>: Linear. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE void insert(ordered_unique_range_t, InputIterator first, InputIterator last) + { m_flat_tree.insert_unique(ordered_unique_range, first, last); } + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) if and only + //! if there is no element with key equivalent to the key of that element. + //! + //! <b>Complexity</b>: N log(N). + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list<value_type> il) + { + m_flat_tree.insert_unique( dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end()); + } + + //! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate and must be + //! unique values. + //! + //! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) if and only + //! if there is no element with key equivalent to the key of that element. This + //! function is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Complexity</b>: Linear. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE void insert(ordered_unique_range_t, std::initializer_list<value_type> il) + { + m_flat_tree.insert_unique(ordered_unique_range + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end()); + } +#endif + + //! <b>Requires</b>: this->get_allocator() == source.get_allocator(). + //! + //! <b>Effects</b>: Move-inserts each element from source into *this a using + //! the comparison object of *this. If there is an element in a with key equivalent to the + //! key of an element from source, then that element is not moved from source. + //! + //! <b>Complexity</b>: Linear in this->size() + source.size(). + //! + //! <b>Note</b>: Invalidates all iterators and references. + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge(flat_map<Key, T, C2, AllocatorOrContainer>& source) + { m_flat_tree.merge_unique(source.tree()); } + + //! @copydoc ::boost::container::flat_map::merge(flat_map<Key, T, C2, AllocatorOrContainer>&) + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_map<Key, T, C2, AllocatorOrContainer> BOOST_RV_REF_END source) + { return this->merge(static_cast<flat_map<Key, T, C2, AllocatorOrContainer>&>(source)); } + + //! @copydoc ::boost::container::flat_map::merge(flat_map<Key, T, C2, AllocatorOrContainer>&) + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap<Key, T, C2, AllocatorOrContainer>& source) + { m_flat_tree.merge_unique(source.tree()); } + + //! @copydoc ::boost::container::flat_map::merge(flat_map<Key, T, C2, AllocatorOrContainer>&) + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multimap<Key, T, C2, AllocatorOrContainer> BOOST_RV_REF_END source) + { return this->merge(static_cast<flat_multimap<Key, T, C2, AllocatorOrContainer>&>(source)); } + + //! <b>Effects</b>: Erases the element pointed to by p. + //! + //! <b>Returns</b>: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! <b>Complexity</b>: Linear to the elements with keys bigger than p + //! + //! <b>Note</b>: Invalidates elements with keys + //! not less than the erased element. + BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator p) + { + return dtl::force_copy<iterator> + (m_flat_tree.erase(dtl::force_copy<impl_const_iterator>(p))); + } + + //! <b>Effects</b>: If present, erases the element in the container with key equivalent to x. + //! + //! <b>Returns</b>: Returns the number of erased elements (0/1). + //! + //! <b>Complexity</b>: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + BOOST_CONTAINER_FORCEINLINE size_type erase(const key_type& x) + { return m_flat_tree.erase_unique(x); } + + //! <b>Effects</b>: Erases all the elements in the range [first, last). + //! + //! <b>Returns</b>: Returns last. + //! + //! <b>Complexity</b>: size()*N where N is the distance from first to last. + //! + //! <b>Complexity</b>: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator first, const_iterator last) + { + return dtl::force_copy<iterator>( + m_flat_tree.erase( dtl::force_copy<impl_const_iterator>(first) + , dtl::force_copy<impl_const_iterator>(last))); + } + + //! <b>Effects</b>: Swaps the contents of *this and x. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE void swap(flat_map& x) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable<Compare>::value ) + { m_flat_tree.swap(x.m_flat_tree); } + + //! <b>Effects</b>: erase(begin(),end()). + //! + //! <b>Postcondition</b>: size() == 0. + //! + //! <b>Complexity</b>: linear in size(). + BOOST_CONTAINER_FORCEINLINE void clear() BOOST_NOEXCEPT_OR_NOTHROW + { m_flat_tree.clear(); } + + ////////////////////////////////////////////// + // + // observers + // + ////////////////////////////////////////////// + + //! <b>Effects</b>: Returns the comparison object out + //! of which a was constructed. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + key_compare key_comp() const + { return dtl::force_copy<key_compare>(m_flat_tree.key_comp()); } + + //! <b>Effects</b>: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + value_compare value_comp() const + { return value_compare(dtl::force_copy<key_compare>(m_flat_tree.key_comp())); } + + ////////////////////////////////////////////// + // + // map operations + // + ////////////////////////////////////////////// + + //! <b>Returns</b>: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator find(const key_type& x) + { return dtl::force_copy<iterator>(m_flat_tree.find(x)); } + + //! <b>Returns</b>: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator find(const key_type& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator find(const K& x) + { return dtl::force_copy<iterator>(m_flat_tree.find(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator find(const K& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); } + + //! <b>Returns</b>: The number of elements with key equivalent to x. + //! + //! <b>Complexity</b>: log(size())+count(k) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type count(const key_type& x) const + { return static_cast<size_type>(m_flat_tree.find(x) != m_flat_tree.end()); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: The number of elements with key equivalent to x. + //! + //! <b>Complexity</b>: log(size())+count(k) + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type count(const K& x) const + //Don't use find() != end optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) + { return m_flat_tree.count(x); } + + //! <b>Returns</b>: Returns true if there is an element with key + //! equivalent to key in the container, otherwise false. + //! + //! <b>Complexity</b>: log(size()). + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + bool contains(const key_type& x) const + { return m_flat_tree.find(x) != m_flat_tree.end(); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: Returns true if there is an element with key + //! equivalent to key in the container, otherwise false. + //! + //! <b>Complexity</b>: log(size()). + template<typename K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + bool contains(const K& x) const + { return m_flat_tree.find(x) != m_flat_tree.end(); } + + //! <b>Returns</b>: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator lower_bound(const key_type& x) + { return dtl::force_copy<iterator>(m_flat_tree.lower_bound(x)); } + + //! <b>Returns</b>: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator lower_bound(const key_type& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator lower_bound(const K& x) + { return dtl::force_copy<iterator>(m_flat_tree.lower_bound(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator lower_bound(const K& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); } + + //! <b>Returns</b>: An iterator pointing to the first element with key greater + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator upper_bound(const key_type& x) + { return dtl::force_copy<iterator>(m_flat_tree.upper_bound(x)); } + + //! <b>Returns</b>: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator upper_bound(const key_type& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: An iterator pointing to the first element with key greater + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator upper_bound(const K& x) + { return dtl::force_copy<iterator>(m_flat_tree.upper_bound(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator upper_bound(const K& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); } + + //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<iterator,iterator> equal_range(const key_type& x) + { return dtl::force_copy<std::pair<iterator,iterator> >(m_flat_tree.lower_bound_range(x)); } + + //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const + { return dtl::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.lower_bound_range(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<iterator,iterator> equal_range(const K& x) + //Don't use lower_bound_range optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) + { return dtl::force_copy<std::pair<iterator,iterator> >(m_flat_tree.equal_range(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<const_iterator, const_iterator> equal_range(const K& x) const + //Don't use lower_bound_range optimization here as transparent comparators with key K might + //return a different range than key_type (which can only return a single element range) + { return dtl::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.equal_range(x)); } + + //! <b>Effects</b>: Extracts the internal sequence container. + //! + //! <b>Complexity</b>: Same as the move constructor of sequence_type, usually constant. + //! + //! <b>Postcondition</b>: this->empty() + //! + //! <b>Throws</b>: If secuence_type's move constructor throws + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE sequence_type extract_sequence() + { + return boost::move(dtl::force<sequence_type>(m_flat_tree.get_sequence_ref())); + } + + //! <b>Effects</b>: Discards the internally hold sequence container and adopts the + //! one passed externally using the move assignment. Erases non-unique elements. + //! + //! <b>Complexity</b>: Assuming O(1) move assignment, O(NlogN) with N = seq.size() + //! + //! <b>Throws</b>: If the comparison or the move constructor throws + BOOST_CONTAINER_FORCEINLINE void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_unique(boost::move(dtl::force<impl_sequence_type>(seq))); } + + //! <b>Requires</b>: seq shall be ordered according to this->compare() + //! and shall contain unique elements. + //! + //! <b>Effects</b>: Discards the internally hold sequence container and adopts the + //! one passed externally using the move assignment. + //! + //! <b>Complexity</b>: Assuming O(1) move assignment, O(1) + //! + //! <b>Throws</b>: If the move assignment throws + BOOST_CONTAINER_FORCEINLINE void adopt_sequence(ordered_unique_range_t, BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_unique(ordered_unique_range_t(), boost::move(dtl::force<impl_sequence_type>(seq))); } + + //! <b>Effects</b>: Returns a const view of the underlying sequence. + //! + //! <b>Complexity</b>: Constant + //! + //! <b>Throws</b>: Nothing + BOOST_CONTAINER_FORCEINLINE const sequence_type & sequence() const BOOST_NOEXCEPT + { return dtl::force<sequence_type>(m_flat_tree.get_sequence_cref()); } + + //! <b>Effects</b>: Returns true if x and y are equal + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator==(const flat_map& x, const flat_map& y) + { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } + + //! <b>Effects</b>: Returns true if x and y are unequal + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator!=(const flat_map& x, const flat_map& y) + { return !(x == y); } + + //! <b>Effects</b>: Returns true if x is less than y + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator<(const flat_map& x, const flat_map& y) + { return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + //! <b>Effects</b>: Returns true if x is greater than y + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator>(const flat_map& x, const flat_map& y) + { return y < x; } + + //! <b>Effects</b>: Returns true if x is equal or less than y + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator<=(const flat_map& x, const flat_map& y) + { return !(y < x); } + + //! <b>Effects</b>: Returns true if x is equal or greater than y + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator>=(const flat_map& x, const flat_map& y) + { return !(x < y); } + + //! <b>Effects</b>: x.swap(y) + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE friend void swap(flat_map& x, flat_map& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) + { x.swap(y); } + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + mapped_type &priv_subscript(const key_type& k) + { + iterator i = this->lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)){ + dtl::value_init<mapped_type> m; + impl_value_type v(k, ::boost::move(m.m_t)); + i = this->insert(i, ::boost::move(v)); + } + return (*i).second; + } + mapped_type &priv_subscript(BOOST_RV_REF(key_type) mk) + { + key_type &k = mk; + iterator i = this->lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)){ + dtl::value_init<mapped_type> m; + impl_value_type v(::boost::move(k), ::boost::move(m.m_t)); + i = this->insert(i, ::boost::move(v)); + } + return (*i).second; + } + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +}; + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + +template <typename InputIterator> +flat_map(InputIterator, InputIterator) -> + flat_map< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator>>; + +template < typename InputIterator, typename AllocatorOrCompare> + flat_map(InputIterator, InputIterator, AllocatorOrCompare const&) -> + flat_map< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator> + , typename dtl::if_c< // Compare + dtl::is_allocator<AllocatorOrCompare>::value + , std::less<it_based_non_const_first_type_t<InputIterator>> + , AllocatorOrCompare + >::type + , typename dtl::if_c< // Allocator + dtl::is_allocator<AllocatorOrCompare>::value + , AllocatorOrCompare + , new_allocator<std::pair<it_based_non_const_first_type_t<InputIterator>, it_based_second_type_t<InputIterator>>> + >::type + >; + +template < typename InputIterator, typename Compare, typename Allocator + , typename = dtl::require_nonallocator_t<Compare> + , typename = dtl::require_allocator_t<Allocator>> +flat_map(InputIterator, InputIterator, Compare const&, Allocator const&) -> + flat_map< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator> + , Compare + , Allocator>; + +template <typename InputIterator> +flat_map(ordered_unique_range_t, InputIterator, InputIterator) -> + flat_map< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator>>; + +template < typename InputIterator, typename AllocatorOrCompare> +flat_map(ordered_unique_range_t, InputIterator, InputIterator, AllocatorOrCompare const&) -> + flat_map< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator> + , typename dtl::if_c< // Compare + dtl::is_allocator<AllocatorOrCompare>::value + , std::less<it_based_non_const_first_type_t<InputIterator>> + , AllocatorOrCompare + >::type + , typename dtl::if_c< // Allocator + dtl::is_allocator<AllocatorOrCompare>::value + , AllocatorOrCompare + , new_allocator<std::pair<it_based_non_const_first_type_t<InputIterator>, it_based_second_type_t<InputIterator>>> + >::type + >; + +template < typename InputIterator, typename Compare, typename Allocator + , typename = dtl::require_nonallocator_t<Compare> + , typename = dtl::require_allocator_t<Allocator>> +flat_map(ordered_unique_range_t, InputIterator, InputIterator, Compare const&, Allocator const&) -> + flat_map< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator> + , Compare + , Allocator>; + +#endif + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +} //namespace container { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template <class Key, class T, class Compare, class AllocatorOrContainer> +struct has_trivial_destructor_after_move<boost::container::flat_map<Key, T, Compare, AllocatorOrContainer> > +{ + typedef ::boost::container::dtl::pair<Key, T> value_t; + typedef typename ::boost::container::dtl::container_or_allocator_rebind<AllocatorOrContainer, value_t>::type alloc_or_cont_t; + typedef ::boost::container::dtl::flat_tree<value_t,::boost::container::dtl::select1st<Key>, Compare, alloc_or_cont_t> tree; + static const bool value = ::boost::has_trivial_destructor_after_move<tree>::value; +}; + +namespace container { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! A flat_multimap is a kind of associative container that supports equivalent keys +//! (possibly containing multiple copies of the same key value) and provides for +//! fast retrieval of values of another type T based on the keys. +//! +//! A flat_multimap satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! flat_multimap<Key,T> the key_type is Key and the value_type is std::pair<Key,T> +//! (unlike std::multimap<Key, T> which value_type is std::pair<<b>const</b> Key, T>). +//! +//! flat_multimap is similar to std::multimap but it's implemented by as an ordered sequence container. +//! The underlying sequence container is by default <i>vector</i> but it can also work +//! user-provided vector-like SequenceContainers (like <i>static_vector</i> or <i>small_vector</i>). +//! +//! Using vector-like sequence containers means that inserting a new element into a flat_multimap might invalidate +//! previous iterators and references (unless that sequence container is <i>stable_vector</i> or a similar +//! container that offers stable pointers and references). Similarly, erasing an element might invalidate +//! iterators and references pointing to elements that come after (their keys are bigger) the erased element. +//! +//! This container provides random-access iterators. +//! +//! \tparam Key is the key_type of the map +//! \tparam Value is the <code>mapped_type</code> +//! \tparam Compare is the ordering function for Keys (e.g. <i>std::less<Key></i>). +//! \tparam AllocatorOrContainer is either: +//! - The allocator to allocate <code>value_type</code>s (e.g. <i>allocator< std::pair<Key, T> > </i>). +//! (in this case <i>sequence_type</i> will be vector<value_type, AllocatorOrContainer>) +//! - The SequenceContainer to be used as the underlying <i>sequence_type</i>. It must be a vector-like +//! sequence container with random-access iterators. +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED +template <class Key, class T, class Compare = std::less<Key>, class AllocatorOrContainer = new_allocator< std::pair< Key, T> > > +#else +template <class Key, class T, class Compare, class AllocatorOrContainer> +#endif +class flat_multimap +{ + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + BOOST_COPYABLE_AND_MOVABLE(flat_multimap) + typedef dtl::flat_tree< + std::pair<Key, T>, + dtl::select1st<Key>, + Compare, + AllocatorOrContainer> tree_t; + //This is the real tree stored here. It's based on a movable pair + typedef dtl::flat_tree< + dtl::pair<Key, T>, + dtl::select1st<Key>, + Compare, + typename dtl::container_or_allocator_rebind<AllocatorOrContainer, dtl::pair<Key, T> >::type + > impl_tree_t; + impl_tree_t m_flat_tree; // flat tree representing flat_map + + typedef typename impl_tree_t::value_type impl_value_type; + typedef typename impl_tree_t::const_iterator impl_const_iterator; + typedef typename impl_tree_t::iterator impl_iterator; + typedef typename impl_tree_t::allocator_type impl_allocator_type; + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef std::initializer_list<impl_value_type> impl_initializer_list; + #endif + + typedef dtl::flat_tree_value_compare + < Compare + , dtl::select1st<Key> + , std::pair<Key, T> > value_compare_t; + typedef typename tree_t::iterator iterator_t; + typedef typename tree_t::const_iterator const_iterator_t; + typedef typename tree_t::reverse_iterator reverse_iterator_t; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator_t; + + public: + typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + typedef typename impl_tree_t::sequence_type impl_sequence_type; + + BOOST_CONTAINER_FORCEINLINE impl_tree_t &tree() + { return m_flat_tree; } + + BOOST_CONTAINER_FORCEINLINE const impl_tree_t &tree() const + { return m_flat_tree; } + + private: + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// + typedef Key key_type; + typedef T mapped_type; + typedef Compare key_compare; + typedef std::pair<Key, T> value_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; + typedef typename sequence_type::allocator_type allocator_type; + typedef ::boost::container::allocator_traits<allocator_type> allocator_traits_type; + typedef typename sequence_type::pointer pointer; + typedef typename sequence_type::const_pointer const_pointer; + typedef typename sequence_type::reference reference; + typedef typename sequence_type::const_reference const_reference; + typedef typename sequence_type::size_type size_type; + typedef typename sequence_type::difference_type difference_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::stored_allocator_type) stored_allocator_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::value_compare) value_compare; + + typedef typename sequence_type::iterator iterator; + typedef typename sequence_type::const_iterator const_iterator; + typedef typename sequence_type::reverse_iterator reverse_iterator; + typedef typename sequence_type::const_reverse_iterator const_reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(impl_value_type) movable_value_type; + + //AllocatorOrContainer::value_type must be std::pair<Key, T> + BOOST_STATIC_ASSERT((dtl::is_same<std::pair<Key, T>, value_type>::value)); + + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// + + //! <b>Effects</b>: Default constructs an empty flat_map. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE flat_multimap() + BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<AllocatorOrContainer>::value && + dtl::is_nothrow_default_constructible<Compare>::value) + : m_flat_tree() + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified allocator. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE explicit flat_multimap(const allocator_type& a) + : m_flat_tree(dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison + //! object . + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE explicit flat_multimap(const Compare& comp) + : m_flat_tree(comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison + //! object and allocator. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(const Compare& comp, const allocator_type& a) + : m_flat_tree(comp, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap + //! and inserts elements from the range [first ,last ). + //! + //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_multimap(InputIterator first, InputIterator last) + : m_flat_tree(false, first, last) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified + //! allocator, and inserts elements from the range [first ,last ). + //! + //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_multimap(InputIterator first, InputIterator last, const allocator_type& a) + : m_flat_tree(false, first, last, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison object + //! and inserts elements from the range [first ,last ). + //! + //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_multimap(InputIterator first, InputIterator last, const Compare& comp) + : m_flat_tree(false, first, last, comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_multimap(InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) + : m_flat_tree(false, first, last, comp, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap + //! and inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_multimap(ordered_range_t, InputIterator first, InputIterator last) + : m_flat_tree(ordered_range, first, last) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison object and + //! inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp) + : m_flat_tree(ordered_range, first, last, comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison object and + //! allocator, and inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) + : m_flat_tree(ordered_range, first, last, comp, a) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison object and + //! inserts elements from the ordered range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE + flat_multimap(ordered_range_t, InputIterator first, InputIterator last, const allocator_type &a) + : m_flat_tree(ordered_range, first, last, Compare(), a) + {} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! <b>Effects</b>: Constructs an empty flat_map and + //! inserts elements from the range [il.begin(), il.end()). + //! + //! <b>Complexity</b>: Linear in N if the range [il.begin(), il.end()) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(std::initializer_list<value_type> il) + : m_flat_tree( false + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end()) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified + //! allocator, and inserts elements from the range [il.begin(), il.end()). + //! + //! <b>Complexity</b>: Linear in N if the range [il.begin(), il.end()) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(std::initializer_list<value_type> il, const allocator_type& a) + : m_flat_tree(false + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end() + , dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! inserts elements from the range [il.begin(), il.end()). + //! + //! <b>Complexity</b>: Linear in N if the range [il.begin(), il.end()) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(std::initializer_list<value_type> il, const Compare& comp) + : m_flat_tree(false + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end(), comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and + //! allocator, and inserts elements from the range [il.begin(), il.end()). + //! + //! <b>Complexity</b>: Linear in N if the range [il.begin(), il.end()) is already sorted using + //! the predicate and otherwise N logN, where N is last - first. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(std::initializer_list<value_type> il, const Compare& comp, const allocator_type& a) + : m_flat_tree( false + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end() + , comp, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap and + //! inserts elements from the ordered range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(ordered_range_t, std::initializer_list<value_type> il) + : m_flat_tree( ordered_range + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end()) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison object and + //! inserts elements from the ordered range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(ordered_range_t, std::initializer_list<value_type> il, const Compare& comp) + : m_flat_tree( ordered_range + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end(), comp) + {} + + //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison object and + //! allocator, and inserts elements from the ordered range [il.begin(), il.end()). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate. + //! + //! <b>Complexity</b>: Linear in N. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(ordered_range_t, std::initializer_list<value_type> il, const Compare& comp, const allocator_type& a) + : m_flat_tree( ordered_range + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end() + , comp, dtl::force<const impl_allocator_type>(a)) + {} +#endif + + //! <b>Effects</b>: Copy constructs a flat_multimap. + //! + //! <b>Complexity</b>: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE + flat_multimap(const flat_multimap& x) + : m_flat_tree(x.m_flat_tree) + {} + + //! <b>Effects</b>: Move constructs a flat_multimap. Constructs *this using x's resources. + //! + //! <b>Complexity</b>: Constant. + //! + //! <b>Postcondition</b>: x is emptied. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(BOOST_RV_REF(flat_multimap) x) + BOOST_NOEXCEPT_IF(boost::container::dtl::is_nothrow_move_constructible<Compare>::value) + : m_flat_tree(boost::move(x.m_flat_tree)) + {} + + //! <b>Effects</b>: Copy constructs a flat_multimap using the specified allocator. + //! + //! <b>Complexity</b>: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE + flat_multimap(const flat_multimap& x, const allocator_type &a) + : m_flat_tree(x.m_flat_tree, dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Move constructs a flat_multimap using the specified allocator. + //! Constructs *this using x's resources. + //! + //! <b>Complexity</b>: Constant if a == x.get_allocator(), linear otherwise. + BOOST_CONTAINER_FORCEINLINE + flat_multimap(BOOST_RV_REF(flat_multimap) x, const allocator_type &a) + : m_flat_tree(boost::move(x.m_flat_tree), dtl::force<const impl_allocator_type>(a)) + {} + + //! <b>Effects</b>: Makes *this a copy of x. + //! + //! <b>Complexity</b>: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE + flat_multimap& operator=(BOOST_COPY_ASSIGN_REF(flat_multimap) x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! <b>Effects</b>: this->swap(x.get()). + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE + flat_multimap& operator=(BOOST_RV_REF(flat_multimap) x) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::dtl::is_nothrow_move_assignable<Compare>::value) + { m_flat_tree = boost::move(x.m_flat_tree); return *this; } + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! <b>Effects</b>: Assign content of il to *this + //! + //! <b>Complexity</b>: Linear in il.size(). + BOOST_CONTAINER_FORCEINLINE + flat_multimap& operator=(std::initializer_list<value_type> il) + { + this->clear(); + this->insert(il.begin(), il.end()); + return *this; + } +#endif + + //! <b>Effects</b>: Returns a copy of the allocator that + //! was passed to the object's constructor. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<allocator_type>(m_flat_tree.get_allocator()); } + + //! <b>Effects</b>: Returns a reference to the internal allocator. + //! + //! <b>Throws</b>: Nothing + //! + //! <b>Complexity</b>: Constant. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force<stored_allocator_type>(m_flat_tree.get_stored_allocator()); } + + //! <b>Effects</b>: Returns a reference to the internal allocator. + //! + //! <b>Throws</b>: Nothing + //! + //! <b>Complexity</b>: Constant. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force<const stored_allocator_type>(m_flat_tree.get_stored_allocator()); } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + + //! <b>Effects</b>: Returns an iterator to the first element contained in the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator begin() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<iterator>(m_flat_tree.begin()); } + + //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_iterator>(m_flat_tree.begin()); } + + //! <b>Effects</b>: Returns an iterator to the end of the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator end() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<iterator>(m_flat_tree.end()); } + + //! <b>Effects</b>: Returns a const_iterator to the end of the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_iterator>(m_flat_tree.end()); } + + //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<reverse_iterator>(m_flat_tree.rbegin()); } + + //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_reverse_iterator>(m_flat_tree.rbegin()); } + + //! <b>Effects</b>: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<reverse_iterator>(m_flat_tree.rend()); } + + //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_reverse_iterator>(m_flat_tree.rend()); } + + //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_iterator>(m_flat_tree.cbegin()); } + + //! <b>Effects</b>: Returns a const_iterator to the end of the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_iterator>(m_flat_tree.cend()); } + + //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_reverse_iterator>(m_flat_tree.crbegin()); } + + //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<const_reverse_iterator>(m_flat_tree.crend()); } + + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! <b>Effects</b>: Returns true if the container contains no elements. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + bool empty() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.empty(); } + + //! <b>Effects</b>: Returns the number of the elements contained in the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type size() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.size(); } + + //! <b>Effects</b>: Returns the largest possible size of the container. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.max_size(); } + + //! <b>Effects</b>: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type capacity() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.capacity(); } + + //! <b>Effects</b>: If n is less than or equal to capacity(), or the + //! underlying container has no `reserve` member, this call has no + //! effect. Otherwise, it is a request for allocation of additional memory. + //! If the request is successful, then capacity() is greater than or equal to + //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged. + //! + //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws. + //! + //! <b>Note</b>: If capacity() is less than "cnt", iterators and references to + //! to values might be invalidated. + BOOST_CONTAINER_FORCEINLINE + void reserve(size_type cnt) + { m_flat_tree.reserve(cnt); } + + //! <b>Effects</b>: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws. + //! + //! <b>Complexity</b>: Linear to size(). + BOOST_CONTAINER_FORCEINLINE + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! @copydoc ::boost::container::flat_set::nth(size_type) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<iterator>(m_flat_tree.nth(n)); } + + //! @copydoc ::boost::container::flat_set::nth(size_type) const + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { return dtl::force_copy<iterator>(m_flat_tree.nth(n)); } + + //! @copydoc ::boost::container::flat_set::index_of(iterator) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.index_of(dtl::force_copy<impl_iterator>(p)); } + + //! @copydoc ::boost::container::flat_set::index_of(const_iterator) const + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + { return m_flat_tree.index_of(dtl::force_copy<impl_const_iterator>(p)); } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! <b>Effects</b>: Inserts an object of type T constructed with + //! std::forward<Args>(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! <b>Complexity</b>: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template <class... Args> + BOOST_CONTAINER_FORCEINLINE + iterator emplace(BOOST_FWD_REF(Args)... args) + { return dtl::force_copy<iterator>(m_flat_tree.emplace_equal(boost::forward<Args>(args)...)); } + + //! <b>Effects</b>: Inserts an object of type T constructed with + //! std::forward<Args>(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! <b>Returns</b>: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template <class... Args> + BOOST_CONTAINER_FORCEINLINE + iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) + { + return dtl::force_copy<iterator>(m_flat_tree.emplace_hint_equal + (dtl::force_copy<impl_const_iterator>(hint), boost::forward<Args>(args)...)); + } + + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + #define BOOST_CONTAINER_FLAT_MULTIMAP_EMPLACE_CODE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator emplace(BOOST_MOVE_UREF##N)\ + { return dtl::force_copy<iterator>(m_flat_tree.emplace_equal(BOOST_MOVE_FWD##N)); }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + return dtl::force_copy<iterator>(m_flat_tree.emplace_hint_equal\ + (dtl::force_copy<impl_const_iterator>(hint) BOOST_MOVE_I##N BOOST_MOVE_FWD##N));\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_FLAT_MULTIMAP_EMPLACE_CODE) + #undef BOOST_CONTAINER_FLAT_MULTIMAP_EMPLACE_CODE + + #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //! <b>Effects</b>: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! <b>Complexity</b>: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + BOOST_CONTAINER_FORCEINLINE iterator insert(const value_type& x) + { + return dtl::force_copy<iterator>( + m_flat_tree.insert_equal(dtl::force<const impl_value_type>(x))); + } + + //! <b>Effects</b>: Inserts a new value constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! <b>Complexity</b>: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template<class Pair> + BOOST_CONTAINER_FORCEINLINE BOOST_CONTAINER_DOC1ST + ( iterator + , typename dtl::enable_if_c<dtl::is_convertible<Pair BOOST_MOVE_I impl_value_type>::value + BOOST_MOVE_I iterator >::type) + insert(BOOST_FWD_REF(Pair) x) + { return dtl::force_copy<iterator>(m_flat_tree.emplace_equal(boost::forward<Pair>(x))); } + + //! <b>Effects</b>: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! <b>Returns</b>: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, const value_type& x) + { + return dtl::force_copy<iterator> + (m_flat_tree.insert_equal( dtl::force_copy<impl_const_iterator>(p) + , dtl::force<const impl_value_type>(x))); + } + + //! <b>Effects</b>: Inserts a value constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! <b>Returns</b>: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! <b>Complexity</b>: Logarithmic search time (constant time if the value + //! is to be inserted before p) plus linear insertion + //! to the elements with bigger keys than x. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template<class Pair> + BOOST_CONTAINER_FORCEINLINE BOOST_CONTAINER_DOC1ST + ( iterator + , typename dtl::enable_if_c<dtl::is_convertible<Pair BOOST_MOVE_I impl_value_type>::value + BOOST_MOVE_I iterator>::type) + insert(const_iterator p, BOOST_FWD_REF(Pair) x) + { + return dtl::force_copy<iterator>( + m_flat_tree.emplace_hint_equal(dtl::force_copy<impl_const_iterator>(p), boost::forward<Pair>(x))); + } + + //! <b>Requires</b>: first, last are not iterators into *this. + //! + //! <b>Effects</b>: inserts each element from the range [first,last) . + //! + //! <b>Complexity</b>: N log(N). + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_equal(first, last); } + + //! <b>Requires</b>: first, last are not iterators into *this. + //! + //! <b>Requires</b>: [first ,last) must be ordered according to the predicate. + //! + //! <b>Effects</b>: inserts each element from the range [first,last) if and only + //! if there is no element with key equivalent to the key of that element. This + //! function is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Complexity</b>: Linear. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + //! + //! <b>Note</b>: Non-standard extension. + template <class InputIterator> + BOOST_CONTAINER_FORCEINLINE void insert(ordered_range_t, InputIterator first, InputIterator last) + { m_flat_tree.insert_equal(ordered_range, first, last); } + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) . + //! + //! <b>Complexity</b>: N log(N). + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list<value_type> il) + { + m_flat_tree.insert_equal( dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end()); + } + + //! <b>Requires</b>: [il.begin(), il.end()) must be ordered according to the predicate. + //! + //! <b>Effects</b>: inserts each element from the range [il.begin(), il.end()) if and only + //! if there is no element with key equivalent to the key of that element. This + //! function is more efficient than the normal range creation for ordered ranges. + //! + //! <b>Complexity</b>: Linear. + //! + //! <b>Note</b>: If an element is inserted it might invalidate elements. + //! + //! <b>Note</b>: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE void insert(ordered_range_t, std::initializer_list<value_type> il) + { + m_flat_tree.insert_equal( ordered_range + , dtl::force<impl_initializer_list>(il).begin() + , dtl::force<impl_initializer_list>(il).end()); + } +#endif + + //! <b>Requires</b>: this->get_allocator() == source.get_allocator(). + //! + //! <b>Effects</b>: Move-inserts each element from source into *this a using + //! the comparison object of *this. + //! + //! <b>Complexity</b>: Linear in this->size() + source.size(). + //! + //! <b>Note</b>: Invalidates all iterators and references. + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap<Key, T, C2, AllocatorOrContainer>& source) + { m_flat_tree.merge_equal(source.tree()); } + + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap<Key, T, C2, AllocatorOrContainer>&) + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multimap<Key, T, C2, AllocatorOrContainer> BOOST_RV_REF_END source) + { return this->merge(static_cast<flat_multimap<Key, T, C2, AllocatorOrContainer>&>(source)); } + + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap<Key, T, C2, AllocatorOrContainer>&) + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge(flat_map<Key, T, C2, AllocatorOrContainer>& source) + { m_flat_tree.merge_equal(source.tree()); } + + //! @copydoc ::boost::container::flat_multimap::merge(flat_map<Key, T, C2, AllocatorOrContainer>&) + template<class C2> + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_map<Key, T, C2, AllocatorOrContainer> BOOST_RV_REF_END source) + { return this->merge(static_cast<flat_map<Key, T, C2, AllocatorOrContainer>&>(source)); } + + //! <b>Effects</b>: Erases the element pointed to by p. + //! + //! <b>Returns</b>: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! <b>Complexity</b>: Linear to the elements with keys bigger than p + //! + //! <b>Note</b>: Invalidates elements with keys + //! not less than the erased element. + BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator p) + { + return dtl::force_copy<iterator>( + m_flat_tree.erase(dtl::force_copy<impl_const_iterator>(p))); + } + + //! <b>Effects</b>: Erases all elements in the container with key equivalent to x. + //! + //! <b>Returns</b>: Returns the number of erased elements. + //! + //! <b>Complexity</b>: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + BOOST_CONTAINER_FORCEINLINE size_type erase(const key_type& x) + { return m_flat_tree.erase(x); } + + //! <b>Effects</b>: Erases all the elements in the range [first, last). + //! + //! <b>Returns</b>: Returns last. + //! + //! <b>Complexity</b>: size()*N where N is the distance from first to last. + //! + //! <b>Complexity</b>: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator first, const_iterator last) + { + return dtl::force_copy<iterator> + (m_flat_tree.erase( dtl::force_copy<impl_const_iterator>(first) + , dtl::force_copy<impl_const_iterator>(last))); + } + + //! <b>Effects</b>: Swaps the contents of *this and x. + //! + //! <b>Throws</b>: Nothing. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE void swap(flat_multimap& x) + BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value + && boost::container::dtl::is_nothrow_swappable<Compare>::value ) + { m_flat_tree.swap(x.m_flat_tree); } + + //! <b>Effects</b>: erase(begin(),end()). + //! + //! <b>Postcondition</b>: size() == 0. + //! + //! <b>Complexity</b>: linear in size(). + BOOST_CONTAINER_FORCEINLINE void clear() BOOST_NOEXCEPT_OR_NOTHROW + { m_flat_tree.clear(); } + + ////////////////////////////////////////////// + // + // observers + // + ////////////////////////////////////////////// + + //! <b>Effects</b>: Returns the comparison object out + //! of which a was constructed. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + key_compare key_comp() const + { return dtl::force_copy<key_compare>(m_flat_tree.key_comp()); } + + //! <b>Effects</b>: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + value_compare value_comp() const + { return value_compare(dtl::force_copy<key_compare>(m_flat_tree.key_comp())); } + + ////////////////////////////////////////////// + // + // map operations + // + ////////////////////////////////////////////// + + //! <b>Returns</b>: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator find(const key_type& x) + { return dtl::force_copy<iterator>(m_flat_tree.find(x)); } + + //! <b>Returns</b>: An const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator find(const key_type& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator find(const K& x) + { return dtl::force_copy<iterator>(m_flat_tree.find(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: An const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic. + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator find(const K& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.find(x)); } + + //! <b>Returns</b>: The number of elements with key equivalent to x. + //! + //! <b>Complexity</b>: log(size())+count(k) + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type count(const key_type& x) const + { return m_flat_tree.count(x); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: The number of elements with key equivalent to x. + //! + //! <b>Complexity</b>: log(size())+count(k) + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + size_type count(const K& x) const + { return m_flat_tree.count(x); } + + //! <b>Returns</b>: Returns true if there is an element with key + //! equivalent to key in the container, otherwise false. + //! + //! <b>Complexity</b>: log(size()). + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + bool contains(const key_type& x) const + { return m_flat_tree.find(x) != m_flat_tree.end(); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: Returns true if there is an element with key + //! equivalent to key in the container, otherwise false. + //! + //! <b>Complexity</b>: log(size()). + template<typename K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + bool contains(const K& x) const + { return m_flat_tree.find(x) != m_flat_tree.end(); } + + //! <b>Returns</b>: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator lower_bound(const key_type& x) + { return dtl::force_copy<iterator>(m_flat_tree.lower_bound(x)); } + + //! <b>Returns</b>: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator lower_bound(const key_type& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator lower_bound(const K& x) + { return dtl::force_copy<iterator>(m_flat_tree.lower_bound(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator lower_bound(const K& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.lower_bound(x)); } + + //! <b>Returns</b>: An iterator pointing to the first element with key greater + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator upper_bound(const key_type& x) + {return dtl::force_copy<iterator>(m_flat_tree.upper_bound(x)); } + + //! <b>Returns</b>: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator upper_bound(const key_type& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: An iterator pointing to the first element with key greater + //! than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + iterator upper_bound(const K& x) + {return dtl::force_copy<iterator>(m_flat_tree.upper_bound(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Returns</b>: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. + //! + //! <b>Complexity</b>: Logarithmic + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + const_iterator upper_bound(const K& x) const + { return dtl::force_copy<const_iterator>(m_flat_tree.upper_bound(x)); } + + //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! <b>Complexity</b>: Logarithmic + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<iterator,iterator> equal_range(const key_type& x) + { return dtl::force_copy<std::pair<iterator,iterator> >(m_flat_tree.equal_range(x)); } + + //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! <b>Complexity</b>: Logarithmic + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<const_iterator, const_iterator> equal_range(const key_type& x) const + { return dtl::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.equal_range(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! <b>Complexity</b>: Logarithmic + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<iterator,iterator> equal_range(const K& x) + { return dtl::force_copy<std::pair<iterator,iterator> >(m_flat_tree.equal_range(x)); } + + //! <b>Requires</b>: This overload is available only if + //! key_compare::is_transparent exists. + //! + //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! <b>Complexity</b>: Logarithmic + template<class K> + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + std::pair<const_iterator, const_iterator> equal_range(const K& x) const + { return dtl::force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.equal_range(x)); } + + //! <b>Effects</b>: Extracts the internal sequence container. + //! + //! <b>Complexity</b>: Same as the move constructor of sequence_type, usually constant. + //! + //! <b>Postcondition</b>: this->empty() + //! + //! <b>Throws</b>: If secuence_type's move constructor throws + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + sequence_type extract_sequence() + { return boost::move(dtl::force<sequence_type>(m_flat_tree.get_sequence_ref())); } + + //! <b>Effects</b>: Discards the internally hold sequence container and adopts the + //! one passed externally using the move assignment. + //! + //! <b>Complexity</b>: Assuming O(1) move assignment, O(NlogN) with N = seq.size() + //! + //! <b>Throws</b>: If the comparison or the move constructor throws + BOOST_CONTAINER_FORCEINLINE void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_equal(boost::move(dtl::force<impl_sequence_type>(seq))); } + + //! <b>Requires</b>: seq shall be ordered according to this->compare(). + //! + //! <b>Effects</b>: Discards the internally hold sequence container and adopts the + //! one passed externally using the move assignment. + //! + //! <b>Complexity</b>: Assuming O(1) move assignment, O(1) + //! + //! <b>Throws</b>: If the move assignment throws + BOOST_CONTAINER_FORCEINLINE void adopt_sequence(ordered_range_t, BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_equal(ordered_range_t(), boost::move(dtl::force<impl_sequence_type>(seq))); } + + //! <b>Effects</b>: Returns a const view of the underlying sequence. + //! + //! <b>Complexity</b>: Constant + //! + //! <b>Throws</b>: Nothing + BOOST_CONTAINER_FORCEINLINE const sequence_type & sequence() const BOOST_NOEXCEPT + { return dtl::force<sequence_type>(m_flat_tree.get_sequence_cref()); } + + //! <b>Effects</b>: Returns true if x and y are equal + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator==(const flat_multimap& x, const flat_multimap& y) + { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } + + //! <b>Effects</b>: Returns true if x and y are unequal + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator!=(const flat_multimap& x, const flat_multimap& y) + { return !(x == y); } + + //! <b>Effects</b>: Returns true if x is less than y + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator<(const flat_multimap& x, const flat_multimap& y) + { return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + //! <b>Effects</b>: Returns true if x is greater than y + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator>(const flat_multimap& x, const flat_multimap& y) + { return y < x; } + + //! <b>Effects</b>: Returns true if x is equal or less than y + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator<=(const flat_multimap& x, const flat_multimap& y) + { return !(y < x); } + + //! <b>Effects</b>: Returns true if x is equal or greater than y + //! + //! <b>Complexity</b>: Linear to the number of elements in the container. + BOOST_CONTAINER_ATTRIBUTE_NODISCARD BOOST_CONTAINER_FORCEINLINE + friend bool operator>=(const flat_multimap& x, const flat_multimap& y) + { return !(x < y); } + + //! <b>Effects</b>: x.swap(y) + //! + //! <b>Complexity</b>: Constant. + BOOST_CONTAINER_FORCEINLINE friend void swap(flat_multimap& x, flat_multimap& y) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) + { x.swap(y); } +}; + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD + +template <typename InputIterator> +flat_multimap(InputIterator, InputIterator) -> + flat_multimap< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator>>; + +template < typename InputIterator, typename AllocatorOrCompare> +flat_multimap(InputIterator, InputIterator, AllocatorOrCompare const&) -> + flat_multimap< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator> + , typename dtl::if_c< // Compare + dtl::is_allocator<AllocatorOrCompare>::value + , std::less<it_based_non_const_first_type_t<InputIterator>> + , AllocatorOrCompare + >::type + , typename dtl::if_c< // Allocator + dtl::is_allocator<AllocatorOrCompare>::value + , AllocatorOrCompare + , new_allocator<std::pair<it_based_non_const_first_type_t<InputIterator>, it_based_second_type_t<InputIterator>>> + >::type + >; + +template < typename InputIterator, typename Compare, typename Allocator + , typename = dtl::require_nonallocator_t<Compare> + , typename = dtl::require_allocator_t<Allocator>> +flat_multimap(InputIterator, InputIterator, Compare const&, Allocator const&) -> + flat_multimap< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator> + , Compare + , Allocator>; + +template <typename InputIterator> +flat_multimap(ordered_range_t, InputIterator, InputIterator) -> + flat_multimap< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator>>; + +template < typename InputIterator, typename AllocatorOrCompare> +flat_multimap(ordered_range_t, InputIterator, InputIterator, AllocatorOrCompare const&) -> + flat_multimap< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator> + , typename dtl::if_c< // Compare + dtl::is_allocator<AllocatorOrCompare>::value + , std::less<it_based_non_const_first_type_t<InputIterator>> + , AllocatorOrCompare + >::type + , typename dtl::if_c< // Allocator + dtl::is_allocator<AllocatorOrCompare>::value + , AllocatorOrCompare + , new_allocator<std::pair<it_based_non_const_first_type_t<InputIterator>, it_based_second_type_t<InputIterator>>> + >::type + >; + +template < typename InputIterator, typename Compare, typename Allocator + , typename = dtl::require_nonallocator_t<Compare> + , typename = dtl::require_allocator_t<Allocator>> +flat_multimap(ordered_range_t, InputIterator, InputIterator, Compare const&, Allocator const&) -> + flat_multimap< it_based_non_const_first_type_t<InputIterator> + , it_based_second_type_t<InputIterator> + , Compare + , Allocator>; + +#endif + +}} + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +namespace boost { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template <class Key, class T, class Compare, class AllocatorOrContainer> +struct has_trivial_destructor_after_move< boost::container::flat_multimap<Key, T, Compare, AllocatorOrContainer> > +{ + typedef ::boost::container::dtl::pair<Key, T> value_t; + typedef typename ::boost::container::dtl::container_or_allocator_rebind<AllocatorOrContainer, value_t>::type alloc_or_cont_t; + typedef ::boost::container::dtl::flat_tree<value_t,::boost::container::dtl::select1st<Key>, Compare, alloc_or_cont_t> tree; + static const bool value = ::boost::has_trivial_destructor_after_move<tree>::value; +}; + +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +#include <boost/container/detail/config_end.hpp> + +#endif // BOOST_CONTAINER_FLAT_MAP_HPP diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/allocators/detail/allocator_common.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/allocators/detail/allocator_common.hpp index 7939404696..bb301ebfbb 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -220,8 +220,7 @@ class cache_impl BOOST_CATCH(...){ this->cached_deallocation(chain); BOOST_RETHROW - } - BOOST_CATCH_END + } BOOST_CATCH_END } void cached_deallocation(void *ptr) diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/containers/allocation_type.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/containers/allocation_type.hpp index 7175207473..d99b7ab51d 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/containers/allocation_type.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/containers/allocation_type.hpp @@ -26,7 +26,7 @@ namespace boost { namespace interprocess { #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -typedef int allocation_type; +using boost::container::allocation_type; #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED static const allocation_type allocate_new = boost::container::allocate_new; static const allocation_type expand_fwd = boost::container::expand_fwd; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/atomic.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/atomic.hpp index f02a11a386..3dda5c4031 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/atomic.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/atomic.hpp @@ -27,6 +27,14 @@ #include <boost/interprocess/detail/workaround.hpp> #include <boost/cstdint.hpp> +#if !defined(_AIX) +#define BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL(label) label ":\n\t" +#define BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP(insn, label, offset) insn " " label "\n\t" +#else +#define BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL(label) +#define BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP(insn, label, offset) insn " $" offset "\n\t" +#endif + namespace boost{ namespace interprocess{ namespace ipcdetail{ @@ -64,7 +72,12 @@ inline boost::uint32_t atomic_cas32 #if defined( _MSC_VER ) extern "C" void _ReadWriteBarrier(void); #pragma intrinsic(_ReadWriteBarrier) - #define BOOST_INTERPROCESS_READ_WRITE_BARRIER _ReadWriteBarrier() + +#define BOOST_INTERPROCESS_READ_WRITE_BARRIER \ + BOOST_INTERPROCESS_DISABLE_DEPRECATED_WARNING \ + _ReadWriteBarrier() \ + BOOST_INTERPROCESS_RESTORE_WARNING + #elif defined(__GNUC__) #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 #define BOOST_INTERPROCESS_READ_WRITE_BARRIER __sync_synchronize() @@ -81,13 +94,13 @@ namespace ipcdetail{ //! "mem": pointer to the atomic value //! Returns the old value pointed to by mem inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) -{ return winapi::interlocked_decrement(reinterpret_cast<volatile long*>(mem)) + 1; } +{ return (boost::uint32_t)winapi::interlocked_decrement(reinterpret_cast<volatile long*>(mem)) + 1; } //! Atomically increment an apr_uint32_t by 1 //! "mem": pointer to the object //! Returns the old value pointed to by mem inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) -{ return winapi::interlocked_increment(reinterpret_cast<volatile long*>(mem))-1; } +{ return (boost::uint32_t)winapi::interlocked_increment(reinterpret_cast<volatile long*>(mem))-1; } //! Atomically read an boost::uint32_t from memory inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) @@ -101,7 +114,7 @@ inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) //! "mem": pointer to the object //! "param": val value that the object will assume inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) -{ winapi::interlocked_exchange(reinterpret_cast<volatile long*>(mem), val); } +{ winapi::interlocked_exchange(reinterpret_cast<volatile long*>(mem), (long)val); } //! Compare an boost::uint32_t's value with "cmp". //! If they are the same swap the value with "with" @@ -111,7 +124,7 @@ inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) //! Returns the old value of *mem inline boost::uint32_t atomic_cas32 (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) -{ return winapi::interlocked_compare_exchange(reinterpret_cast<volatile long*>(mem), with, cmp); } +{ return (boost::uint32_t)winapi::interlocked_compare_exchange(reinterpret_cast<volatile long*>(mem), (long)with, (long)cmp); } } //namespace ipcdetail{ } //namespace interprocess{ @@ -153,7 +166,7 @@ inline boost::uint32_t atomic_add32 // int r = *pw; // *mem += val; // return r; - int r; + boost::uint32_t r; asm volatile ( @@ -218,14 +231,17 @@ inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32 { boost::uint32_t prev, temp; - asm volatile ("1:\n\t" - "lwarx %0,0,%2\n\t" - "add %1,%0,%3\n\t" - "stwcx. %1,0,%2\n\t" - "bne- 1b" - : "=&r" (prev), "=&r" (temp) - : "b" (mem), "r" (val) - : "cc", "memory"); + asm volatile + ( + BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL("1") + "lwarx %0,0,%2\n\t" + "add %1,%0,%3\n\t" + "stwcx. %1,0,%2\n\t" + BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP("bne-", "1b", "-12") + : "=&r" (prev), "=&r" (temp) + : "b" (mem), "r" (val) + : "cc", "memory" + ); return prev; } @@ -240,16 +256,19 @@ inline boost::uint32_t atomic_cas32 { boost::uint32_t prev; - asm volatile ("1:\n\t" - "lwarx %0,0,%1\n\t" - "cmpw %0,%3\n\t" - "bne- 2f\n\t" - "stwcx. %2,0,%1\n\t" - "bne- 1b\n\t" - "2:" - : "=&r"(prev) - : "b" (mem), "r" (with), "r" (cmp) - : "cc", "memory"); + asm volatile + ( + BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL("1") + "lwarx %0,0,%1\n\t" + "cmpw %0,%3\n\t" + BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP("bne-", "2f", "+12") + "stwcx. %2,0,%1\n\t" + BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP("bne-", "1b", "-16") + BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL("2") + : "=&r"(prev) + : "b" (mem), "r" (with), "r" (cmp) + : "cc", "memory" + ); return prev; } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/char_wchar_holder.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/char_wchar_holder.hpp new file mode 100644 index 0000000000..8831aa202d --- /dev/null +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/char_wchar_holder.hpp @@ -0,0 +1,127 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2020-2021. Distributed under the 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_CHAR_WCHAR_HOLDER_HPP +#define BOOST_INTERPROCESS_DETAIL_CHAR_WCHAR_HOLDER_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> + +#include <cwchar> +#include <cstring> + +namespace boost { +namespace interprocess { + +class char_wchar_holder +{ + public: + char_wchar_holder() + : m_str(), m_is_wide() + { + m_str.n = 0; + } + + char_wchar_holder(const char *nstr) + : m_str(), m_is_wide() + { + m_str.n = new char [std::strlen(nstr)+1]; + std::strcpy(m_str.n, nstr); + } + + char_wchar_holder(const wchar_t *wstr) + : m_str(), m_is_wide(true) + { + m_str.w = new wchar_t [std::wcslen(wstr)+1]; + std::wcscpy(m_str.w, wstr); + } + + char_wchar_holder& operator=(const char *nstr) + { + char *tmp = new char [std::strlen(nstr)+1]; + this->delete_mem(); + m_str.n = tmp; + std::strcpy(m_str.n, nstr); + return *this; + } + + char_wchar_holder& operator=(const wchar_t *wstr) + { + wchar_t *tmp = new wchar_t [std::wcslen(wstr)+1]; + this->delete_mem(); + m_str.w = tmp; + std::wcscpy(m_str.w, wstr); + return *this; + } + + char_wchar_holder& operator=(const char_wchar_holder &other) + { + if (other.m_is_wide) + *this = other.getn(); + else + *this = other.getw(); + return *this; + } + + ~char_wchar_holder() + { + this->delete_mem(); + } + + wchar_t *getw() const + { return m_is_wide ? m_str.w : 0; } + + char *getn() const + { return !m_is_wide ? m_str.n : 0; } + + void swap(char_wchar_holder& other) + { + char_wchar tmp; + std::memcpy(&tmp, &m_str, sizeof(char_wchar)); + std::memcpy(&m_str, &other.m_str, sizeof(char_wchar)); + std::memcpy(&other.m_str, &tmp, sizeof(char_wchar)); + // + bool b_tmp(m_is_wide); + m_is_wide = other.m_is_wide; + other.m_is_wide = b_tmp; + } + + private: + + void delete_mem() + { + if(m_is_wide) + delete [] m_str.w; + else + delete [] m_str.n; + } + + union char_wchar + { + char *n; + wchar_t *w; + } m_str; + bool m_is_wide; +}; + +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //BOOST_INTERPROCESS_DETAIL_CHAR_WCHAR_HOLDER_HPP diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/config_external_begin.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/config_external_begin.hpp index fb578ef013..67c0556807 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/config_external_begin.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/config_external_begin.hpp @@ -15,4 +15,9 @@ #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wshadow" +# pragma GCC diagnostic ignored "-Wsign-conversion" +# pragma GCC diagnostic ignored "-Wconversion" +# if (BOOST_GCC >= 100000) +# pragma GCC diagnostic ignored "-Warith-conversion" +# endif #endif diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/in_place_interface.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/in_place_interface.hpp index 367f9dca3d..6ba6229bfc 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/in_place_interface.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/in_place_interface.hpp @@ -54,14 +54,14 @@ struct placement_destroy : public in_place_interface : in_place_interface(::boost::container::dtl::alignment_of<T>::value, sizeof(T), typeid(T).name()) {} - virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) + virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) BOOST_OVERRIDE { T* memory = static_cast<T*>(mem); for(destroyed = 0; destroyed < num; ++destroyed) (memory++)->~T(); } - virtual void construct_n(void *, std::size_t, std::size_t &) {} + virtual void construct_n(void *, std::size_t, std::size_t &) BOOST_OVERRIDE {} private: void destroy(void *mem) diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/intermodule_singleton_common.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/intermodule_singleton_common.hpp index 392db1f86b..2218cd9b9f 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/intermodule_singleton_common.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/intermodule_singleton_common.hpp @@ -34,6 +34,7 @@ #include <cstdlib> #include <cstring> #include <string> +#include <typeinfo> #include <sstream> namespace boost{ @@ -120,7 +121,7 @@ class intermodule_singleton_common } } if(previous_module_singleton_initialized == Uninitialized){ - try{ + BOOST_TRY{ //Now initialize the global map, this function must solve concurrency //issues between threads of several modules initialize_global_map_handle(); @@ -142,11 +143,11 @@ class intermodule_singleton_common //before this one. Now marked as initialized atomic_write32(&this_module_singleton_initialized, Initialized); } - catch(...){ + BOOST_CATCH(...){ //Mark singleton failed to initialize atomic_write32(&this_module_singleton_initialized, Broken); - throw; - } + BOOST_RETHROW + } BOOST_CATCH_END } //If previous state was initializing, this means that another winner thread is //trying to initialize the singleton. Just wait until completes its work. @@ -231,7 +232,7 @@ class intermodule_singleton_common } else{ //(tmp == Uninitialized) //If not initialized try it again? - try{ + BOOST_TRY{ //Remove old global map from the system intermodule_singleton_helpers::thread_safe_global_map_dependant<ThreadSafeGlobalMap>::remove_old_gmem(); //in-place construction of the global map class @@ -254,10 +255,10 @@ class intermodule_singleton_common break; } } - catch(...){ + BOOST_CATCH(...){ // - throw; - } + BOOST_RETHROW + } BOOST_CATCH_END } } } @@ -405,17 +406,17 @@ class intermodule_singleton_impl <ThreadSafeGlobalMap>::find(m_map, typeid(C).name()); if(!rcount){ C *p = new C; - try{ + BOOST_TRY{ ref_count_ptr val(p, 0u); rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant <ThreadSafeGlobalMap>::insert(m_map, typeid(C).name(), val); } - catch(...){ + BOOST_CATCH(...){ intermodule_singleton_helpers::thread_safe_global_map_dependant <ThreadSafeGlobalMap>::erase(m_map, typeid(C).name()); delete p; - throw; - } + BOOST_RETHROW + } BOOST_CATCH_END } //if(Phoenix){ std::atexit(&atexit_work); diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/os_file_functions.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/os_file_functions.hpp index 7a41868188..5e3a5a0ddd 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/os_file_functions.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/os_file_functions.hpp @@ -24,22 +24,22 @@ #include <boost/interprocess/errors.hpp> #include <boost/interprocess/permissions.hpp> -#include <string> -#include <limits> #include <climits> +#include <string> #include <boost/move/detail/type_traits.hpp> //make_unsigned #if defined (BOOST_INTERPROCESS_WINDOWS) # include <boost/interprocess/detail/win32_api.hpp> +# include <wchar.h> //wcsxxx() #else # ifdef BOOST_HAS_UNISTD_H # include <fcntl.h> # include <unistd.h> # include <sys/types.h> # include <sys/stat.h> -# include <errno.h> -# include <cstdio> # include <dirent.h> +# include <cerrno> +# include <cstdio> # if 0 # include <sys/file.h> # endif @@ -99,10 +99,26 @@ inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd) inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) { return hnd.handle; } -inline bool create_directory(const char *path) +template<class CharT> +inline bool create_directory(const CharT *path) { return winapi::create_directory(path); } -inline bool remove_directory(const char *path) +template<class CharT> +inline bool open_or_create_directory(const CharT *path) +{ + //If fails, check that it's because it already exists + return create_directory(path) + || error_info(system_error_code()).get_error_code() == already_exists_error; +} + +template<class CharT> +inline bool open_or_create_shared_directory(const CharT *path) +{ + return open_or_create_directory(path); +} + +template <class CharT> +inline bool remove_directory(const CharT *path) { return winapi::remove_directory(path); } inline bool get_temporary_path(char *buffer, std::size_t buf_len, std::size_t &required_len) @@ -115,15 +131,33 @@ inline bool get_temporary_path(char *buffer, std::size_t buf_len, std::size_t &r return false; } required_len = winapi::get_temp_path(buf_len, buffer); - const bool ret = !(buf_len < required_len); + const bool ret = required_len && (buf_len > required_len); if(ret && buffer[required_len-1] == '\\'){ - buffer[required_len-1] = 0; + buffer[required_len-1] = '\0'; } return ret; } +inline bool get_temporary_path(wchar_t *buffer, std::size_t buf_len, std::size_t &required_len) +{ + required_len = 0; + //std::size_t is always bigger or equal than unsigned long in Windows systems + //In case std::size_t is bigger than unsigned long + unsigned long buf = buf_len; + if(buf_len != buf){ //maybe overflowed + return false; + } + required_len = winapi::get_temp_path(buf_len, buffer); + const bool ret = !(buf_len < required_len); + if(ret && buffer[required_len-1] == L'\\'){ + buffer[required_len-1] = L'\0'; + } + return ret; +} + +template<class CharT> inline file_handle_t create_new_file - (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) + (const CharT *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) { unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; return winapi::create_file @@ -131,8 +165,9 @@ inline file_handle_t create_new_file , (winapi::interprocess_security_attributes*)perm.get_permissions()); } +template <class CharT> inline file_handle_t create_or_open_file - (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) + (const CharT *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) { unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; return winapi::create_file @@ -140,8 +175,9 @@ inline file_handle_t create_or_open_file , (winapi::interprocess_security_attributes*)perm.get_permissions()); } +template<class CharT> inline file_handle_t open_existing_file - (const char *name, mode_t mode, bool temporary = false) + (const CharT *name, mode_t mode, bool temporary = false) { unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; return winapi::create_file @@ -151,6 +187,9 @@ inline file_handle_t open_existing_file inline bool delete_file(const char *name) { return winapi::unlink_file(name); } +inline bool delete_file(const wchar_t *name) +{ return winapi::unlink_file(name); } + inline bool truncate_file (file_handle_t hnd, std::size_t size) { offset_t filesize; @@ -158,8 +197,8 @@ inline bool truncate_file (file_handle_t hnd, std::size_t size) return false; typedef ::boost::move_detail::make_unsigned<offset_t>::type uoffset_t; - const uoffset_t max_filesize = uoffset_t((std::numeric_limits<offset_t>::max)()); - const uoffset_t uoff_size = uoffset_t(size); + const uoffset_t max_filesize = uoffset_t(-1)/2u; + const uoffset_t uoff_size = uoffset_t(size); //Avoid unused variable warnings in 32 bit systems if(uoff_size > max_filesize){ winapi::set_last_error(winapi::error_file_too_large); @@ -167,12 +206,12 @@ inline bool truncate_file (file_handle_t hnd, std::size_t size) } if(offset_t(size) > filesize){ - if(!winapi::set_file_pointer_ex(hnd, filesize, 0, winapi::file_begin)){ + if(!winapi::set_file_pointer(hnd, filesize, 0, winapi::file_begin)){ return false; } //We will write zeros in the end of the file //since set_end_of_file does not guarantee this - for(std::size_t remaining = size - filesize, write_size = 0 + for(std::size_t remaining = size - std::size_t(filesize), write_size = 0 ;remaining > 0 ;remaining -= write_size){ const std::size_t DataSize = 512; @@ -186,7 +225,7 @@ inline bool truncate_file (file_handle_t hnd, std::size_t size) } } else{ - if(!winapi::set_file_pointer_ex(hnd, size, 0, winapi::file_begin)){ + if(!winapi::set_file_pointer(hnd, size, 0, winapi::file_begin)){ return false; } if(!winapi::set_end_of_file(hnd)){ @@ -200,10 +239,10 @@ inline bool get_file_size(file_handle_t hnd, offset_t &size) { return winapi::get_file_size(hnd, size); } inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos) -{ return winapi::set_file_pointer_ex(hnd, off, 0, (unsigned long) pos); } +{ return winapi::set_file_pointer(hnd, off, 0, (unsigned long) pos); } inline bool get_file_pointer(file_handle_t hnd, offset_t &off) -{ return winapi::set_file_pointer_ex(hnd, 0, &off, winapi::file_current); } +{ return winapi::set_file_pointer(hnd, 0, &off, winapi::file_current); } inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata) { @@ -239,7 +278,8 @@ inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) acquired = false, true : false; } - return (acquired = true); + acquired = true; + return true; } inline bool release_file_lock(file_handle_t hnd) @@ -268,32 +308,75 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) return winapi::get_last_error() == winapi::error_lock_violation ? acquired = false, true : false; } - return (acquired = true); + + acquired = true; + return true; } inline bool release_file_lock_sharable(file_handle_t hnd) { return release_file_lock(hnd); } +template<class CharT> +struct os_file_traits; + +template<> +struct os_file_traits<char> +{ + static const char *any_file() + { return "\\*.*"; } + + static const char *backslash() + { return "\\"; } + + static char dot() + { return '.'; } + + typedef winapi::win32_find_data_a win32_find_data_t; + + static int cmp(const char *a, const char *b) + { return std::strcmp(a, b); } +}; + +template<> +struct os_file_traits<wchar_t> +{ + static const wchar_t *any_file() + { return L"\\*.*"; } + + static const wchar_t *backslash() + { return L"\\"; } + + static wchar_t dot() + { return L'.'; } + + typedef winapi::win32_find_data_w win32_find_data_t; + + static int cmp(const wchar_t *a, const wchar_t *b) + { return std::wcscmp(a, b); } +}; + +template<class CharT> inline bool delete_subdirectories_recursive - (const std::string &refcstrRootDirectory, const char *dont_delete_this, unsigned int count) + (const std::basic_string<CharT> &refcstrRootDirectory, const CharT *dont_delete_this, unsigned int count) { bool bSubdirectory = false; // Flag, indicating whether // subdirectories have been found void * hFile; // Handle to directory - std::string strFilePath; // Filepath - std::string strPattern; // Pattern - winapi::win32_find_data FileInformation; // File information + std::basic_string<CharT> strFilePath; // Filepath + std::basic_string<CharT> strPattern; // Pattern + typedef os_file_traits<CharT> traits_t; + typename traits_t::win32_find_data_t FileInformation; // File information //Find all files and directories - strPattern = refcstrRootDirectory + "\\*.*"; + strPattern = refcstrRootDirectory + traits_t::any_file(); hFile = winapi::find_first_file(strPattern.c_str(), &FileInformation); if(hFile != winapi::invalid_handle_value){ do{ //If it's not "." or ".." or the pointed root_level dont_delete_this erase it - if(FileInformation.cFileName[0] != '.' && - !(dont_delete_this && count == 0 && std::strcmp(dont_delete_this, FileInformation.cFileName) == 0)){ + if(FileInformation.cFileName[0] != traits_t::dot() && + !(dont_delete_this && count == 0 && traits_t::cmp(dont_delete_this, FileInformation.cFileName) == 0)){ strFilePath.erase(); - strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName; + strFilePath = refcstrRootDirectory + traits_t::backslash() + FileInformation.cFileName; //If it's a directory, go recursive if(FileInformation.dwFileAttributes & winapi::file_attribute_directory){ @@ -340,7 +423,8 @@ inline bool delete_subdirectories_recursive } //This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this" -inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this) +template <class CharT> +inline bool delete_subdirectories(const std::basic_string<CharT> &refcstrRootDirectory, const CharT *dont_delete_this) { return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this, 0u); } @@ -350,7 +434,7 @@ template<class Function> inline bool for_each_file_in_dir(const char *dir, Function f) { void * hFile; // Handle to directory - winapi::win32_find_data FileInformation; // File information + winapi::win32_find_data_a FileInformation; // File information //Get base directory std::string str(dir); @@ -423,7 +507,27 @@ inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) { return hnd.handle; } inline bool create_directory(const char *path) -{ return ::mkdir(path, 0777) == 0 && ::chmod(path, 0777) == 0; } +{ + ::mode_t m = ::mode_t(0777); + return ::mkdir(path, m) == 0; +} + +inline bool open_or_create_directory(const char *path) +{ + ::mode_t m = ::mode_t(0777); + return ::mkdir(path, m) == 0 || (errno == EEXIST); +} + +inline bool open_or_create_shared_directory(const char *path) +{ + const ::mode_t m = ::mode_t(01777); + const bool created = ::mkdir(path, m) == 0; + const bool created_or_exists = created || (errno == EEXIST); + //Try to maximize the chance that the sticky bit is set in shared dirs + //created with old versions that did not set it (for security reasons) + const bool chmoded = ::chmod(path, m) == 0; + return created ? chmoded : created_or_exists; +} inline bool remove_directory(const char *path) { return ::rmdir(path) == 0; } @@ -457,7 +561,7 @@ inline file_handle_t create_or_open_file int ret = -1; //We need a loop to change permissions correctly using fchmod, since //with "O_CREAT only" ::open we don't know if we've created or opened the file. - while(1){ + while(true){ ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions()); if(ret >= 0){ ::fchmod(ret, perm.get_permissions()); @@ -488,7 +592,8 @@ inline bool delete_file(const char *name) inline bool truncate_file (file_handle_t hnd, std::size_t size) { typedef boost::move_detail::make_unsigned<off_t>::type uoff_t; - if(uoff_t((std::numeric_limits<off_t>::max)()) < size){ + BOOST_STATIC_ASSERT(( sizeof(uoff_t) >= sizeof(std::size_t) )); + if( uoff_t(-1)/2u < uoff_t(size) ){ errno = EINVAL; return false; } @@ -543,7 +648,7 @@ inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) int ret = ::fcntl(hnd, F_SETLK, &lock); if(ret == -1){ return (errno == EAGAIN || errno == EACCES) ? - acquired = false, true : false; + (acquired = false, true) : false; } return (acquired = true); } @@ -578,7 +683,7 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) int ret = ::fcntl(hnd, F_SETLK, &lock); if(ret == -1){ return (errno == EAGAIN || errno == EACCES) ? - acquired = false, true : false; + (acquired = false, true) : false; } return (acquired = true); } @@ -711,23 +816,26 @@ inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const #endif //#if defined (BOOST_INTERPROCESS_WINDOWS) -inline bool open_or_create_directory(const char *dir_name) +inline std::string get_temporary_path() { - //If fails, check that it's because it already exists - if(!create_directory(dir_name)){ - error_info info(system_error_code()); - if(info.get_error_code() != already_exists_error){ - return false; - } + std::size_t required_len = 0; + get_temporary_path((char*)0, 0, required_len); + std::string ret_str(required_len, char(0)); + get_temporary_path(&ret_str[0], ret_str.size(), required_len); + while(!ret_str.empty() && !ret_str[ret_str.size()-1]){ + ret_str.erase(ret_str.size()-1); } - return true; + + return ret_str; } -inline std::string get_temporary_path() +#ifdef BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES + +inline std::wstring get_temporary_wpath() { std::size_t required_len = 0; - get_temporary_path(0, 0, required_len); - std::string ret_str(required_len, char(0)); + get_temporary_path((wchar_t*)0, 0, required_len); + std::wstring ret_str(required_len, char(0)); get_temporary_path(&ret_str[0], ret_str.size(), required_len); while(!ret_str.empty() && !ret_str[ret_str.size()-1]){ ret_str.erase(ret_str.size()-1); @@ -736,6 +844,8 @@ inline std::string get_temporary_path() return ret_str; } +#endif + } //namespace ipcdetail{ } //namespace interprocess { } //namespace boost { diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/os_thread_functions.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/os_thread_functions.hpp index ff1ed1ac02..7d88b4dd30 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/os_thread_functions.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/os_thread_functions.hpp @@ -33,13 +33,12 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> #include <boost/interprocess/streams/bufferstream.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <cstddef> #include <ostream> #if defined(BOOST_INTERPROCESS_WINDOWS) # include <boost/interprocess/detail/win32_api.hpp> -# include <process.h> +# include <boost/winapi/thread.hpp> #else # include <pthread.h> # include <unistd.h> @@ -158,7 +157,7 @@ inline OS_highres_count_t get_current_system_highres_count() if(!winapi::query_performance_counter(&count)){ count = winapi::get_tick_count(); } - return count; + return (OS_highres_count_t)count; } inline void zero_highres_count(OS_highres_count_t &count) @@ -229,7 +228,7 @@ inline long double get_current_process_creation_time() inline unsigned int get_num_cores() { - winapi::system_info sysinfo; + winapi::interprocess_system_info sysinfo; winapi::get_system_info( &sysinfo ); //in Windows dw is long which is equal in bits to int return static_cast<unsigned>(sysinfo.dwNumberOfProcessors); @@ -422,7 +421,7 @@ inline void thread_sleep_tick() struct timespec rqt; //Sleep for the half of the tick time rqt.tv_sec = 0; - rqt.tv_nsec = get_system_tick_ns()/2; + rqt.tv_nsec = (long)get_system_tick_ns()/2; ::nanosleep(&rqt, 0); } @@ -519,9 +518,9 @@ inline void get_pid_str(pid_str_t &pid_str) #if defined(BOOST_INTERPROCESS_WINDOWS) -inline int thread_create( OS_thread_t * thread, unsigned (__stdcall * start_routine) (void*), void* arg ) +inline int thread_create( OS_thread_t * thread, boost::ipwinapiext::LPTHREAD_START_ROUTINE_ start_routine, void* arg ) { - void* h = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); + void* h = boost::ipwinapiext::CreateThread(0, 0, start_routine, arg, 0, 0); if( h != 0 ){ thread->m_handle = h; @@ -530,9 +529,6 @@ inline int thread_create( OS_thread_t * thread, unsigned (__stdcall * start_rout else{ return 1; } - - thread->m_handle = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); - return thread->m_handle != 0; } inline void thread_join( OS_thread_t thread) @@ -576,7 +572,7 @@ class os_thread_func_ptr_deleter #if defined(BOOST_INTERPROCESS_WINDOWS) -inline unsigned __stdcall launch_thread_routine( void * pv ) +inline boost::winapi::DWORD_ __stdcall launch_thread_routine(boost::winapi::LPVOID_ pv) { os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) ); pt->run(); @@ -605,7 +601,7 @@ class launch_thread_impl : f_( f ) {} - void run() + virtual void run() BOOST_OVERRIDE { f_(); } private: diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/posix_time_types_wrk.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/posix_time_types_wrk.hpp deleted file mode 100644 index 5a12d83d76..0000000000 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/posix_time_types_wrk.hpp +++ /dev/null @@ -1,51 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/interprocess for documentation. -// -////////////////////////////////////////////////////////////////////////////// - -#ifndef BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP -#define BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP - -#ifndef BOOST_CONFIG_HPP -# include <boost/config.hpp> -#endif -# -#if defined(BOOST_HAS_PRAGMA_ONCE) -# pragma once -#endif - -//workaround to avoid winsock redefines when using date-time - -#ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN -#endif //#ifndef WIN32_LEAN_AND_MEAN -#endif //#ifdef _WIN32 - -#include <boost/date_time/microsec_time_clock.hpp> -#include <boost/date_time/posix_time/ptime.hpp> -#include <boost/date_time/posix_time/posix_time_duration.hpp> - -namespace boost { -namespace interprocess { - -typedef boost::date_time::microsec_clock<boost::posix_time::ptime> microsec_clock; - -} -} - -#ifdef _WIN32 -#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN -#undef WIN32_LEAN_AND_MEAN -#undef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN -#endif //#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN -#endif //#ifdef _WIN32 - -#endif //#ifndef BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP - diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/segment_manager_helper.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/segment_manager_helper.hpp index 96ccf227fe..036dab5cc7 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -35,6 +35,7 @@ #include <boost/intrusive/pointer_traits.hpp> // move/detail #include <boost/move/detail/type_traits.hpp> //make_unsigned +#include <boost/move/detail/force_ptr.hpp> // other boost #include <boost/assert.hpp> //BOOST_ASSERT #include <boost/core/no_exceptions_support.hpp> @@ -92,7 +93,7 @@ struct block_header : m_value_bytes(val_bytes) , m_num_char((unsigned short)num_char) , m_value_alignment((unsigned char)val_alignment) - , m_alloc_type_sizeof_char( (al_type << 5u) | ((unsigned char)szof_char & 0x1F) ) + , m_alloc_type_sizeof_char( (unsigned char)((al_type << 5u) | ((unsigned char)szof_char & 0x1F)) ) {}; template<class T> @@ -102,7 +103,7 @@ struct block_header size_type total_size() const { if(alloc_type() != anonymous_type){ - return name_offset() + (m_num_char+1)*sizeof_char(); + return name_offset() + (m_num_char+1u)*sizeof_char(); } else{ return this->value_offset() + m_value_bytes; @@ -130,7 +131,7 @@ struct block_header template<class CharType> CharType *name() const { - return const_cast<CharType*>(reinterpret_cast<const CharType*> + return const_cast<CharType*>(move_detail::force_ptr<const CharType*> (reinterpret_cast<const char*>(this) + name_offset())); } @@ -175,7 +176,7 @@ struct block_header { block_header * hdr = const_cast<block_header*> - (reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) - + (move_detail::force_ptr<const block_header*>(reinterpret_cast<const char*>(value) - get_rounded_size(sizeof(block_header), algn))); (void)sz; //Some sanity checks @@ -188,7 +189,7 @@ struct block_header static block_header<size_type> *from_first_header(Header *header) { block_header<size_type> * hdr = - reinterpret_cast<block_header<size_type>*>(reinterpret_cast<char*>(header) + + move_detail::force_ptr<block_header<size_type>*>(reinterpret_cast<char*>(header) + get_rounded_size( size_type(sizeof(Header)) , size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value))); //Some sanity checks @@ -199,7 +200,7 @@ struct block_header static Header *to_first_header(block_header<size_type> *bheader) { Header * hdr = - reinterpret_cast<Header*>(reinterpret_cast<char*>(bheader) - + move_detail::force_ptr<Header*>(reinterpret_cast<char*>(bheader) - get_rounded_size( size_type(sizeof(Header)) , size_type(::boost::container::dtl::alignment_of<block_header<size_type> >::value))); //Some sanity checks @@ -219,8 +220,7 @@ inline void array_construct(void *mem, std::size_t num, in_place_interface &tabl std::size_t destroyed = 0; table.destroy_n(mem, constructed, destroyed); BOOST_RETHROW - } - BOOST_CATCH_END + } BOOST_CATCH_END } template<class CharT> @@ -280,7 +280,7 @@ struct intrusive_value_type_impl block_header<size_type> *get_block_header() const { return const_cast<block_header<size_type>*> - (reinterpret_cast<const block_header<size_type> *>(reinterpret_cast<const char*>(this) + + (move_detail::force_ptr<const block_header<size_type> *>(reinterpret_cast<const char*>(this) + get_rounded_size(size_type(sizeof(*this)), size_type(BlockHdrAlignment)))); } @@ -292,7 +292,7 @@ struct intrusive_value_type_impl static intrusive_value_type_impl *get_intrusive_value_type(block_header<size_type> *hdr) { - return reinterpret_cast<intrusive_value_type_impl *>(reinterpret_cast<char*>(hdr) - + return move_detail::force_ptr<intrusive_value_type_impl*>(reinterpret_cast<char*>(hdr) - get_rounded_size(size_type(sizeof(intrusive_value_type_impl)), size_type(BlockHdrAlignment))); } @@ -472,7 +472,7 @@ class segment_manager_iterator_value_adaptor<Iterator, false> const void *value() const { - return reinterpret_cast<block_header<size_type>*> + return move_detail::force_ptr<block_header<size_type>*> (to_raw_pointer(m_val->second.m_ptr))->value(); } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/shared_dir_helpers.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/shared_dir_helpers.hpp index 0fcd898dcb..8d9d36f2db 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/shared_dir_helpers.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/shared_dir_helpers.hpp @@ -34,9 +34,33 @@ namespace boost { namespace interprocess { namespace ipcdetail { +template<class CharT> +struct shared_dir_constants; + +template<> +struct shared_dir_constants<char> +{ + static char dir_separator() + { return '/'; } + + static const char *dir_interprocess() + { return "/boost_interprocess"; } +}; + +template<> +struct shared_dir_constants<wchar_t> +{ + static wchar_t dir_separator() + { return L'/'; } + + static const wchar_t *dir_interprocess() + { return L"/boost_interprocess"; } +}; + #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) #if defined(BOOST_INTERPROCESS_WINDOWS) //This type will initialize the stamp + template<class CharT> struct windows_bootstamp { windows_bootstamp() @@ -49,12 +73,13 @@ namespace ipcdetail { } //Use std::string. Even if this will be constructed in shared memory, all //modules/dlls are from this process so internal raw pointers to heap are always valid - std::string stamp; + std::basic_string<CharT> stamp; }; - inline void get_bootstamp(std::string &s, bool add = false) + template <class CharT> + inline void get_bootstamp(std::basic_string<CharT> &s, bool add = false) { - const windows_bootstamp &bootstamp = windows_intermodule_singleton<windows_bootstamp>::get(); + const windows_bootstamp<CharT> &bootstamp = windows_intermodule_singleton<windows_bootstamp<CharT> >::get(); if(add){ s += bootstamp.stamp; } @@ -102,7 +127,8 @@ namespace ipcdetail { #endif #endif //#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) -inline void get_shared_dir_root(std::string &dir_path) +template <class CharT> +inline void get_shared_dir_root(std::basic_string<CharT> &dir_path) { #if defined (BOOST_INTERPROCESS_WINDOWS) winapi::get_shared_documents_folder(dir_path); @@ -115,8 +141,8 @@ inline void get_shared_dir_root(std::string &dir_path) error_info err = system_error_code(); throw interprocess_exception(err); } - //Remove final null. - dir_path += "/boost_interprocess"; + + dir_path += shared_dir_constants<CharT>::dir_interprocess(); } #if defined(BOOST_INTERPROCESS_SHARED_DIR_FUNC) && defined(BOOST_INTERPROCESS_SHARED_DIR_PATH) @@ -129,57 +155,75 @@ inline void get_shared_dir_root(std::string &dir_path) // get_shared_dir void get_shared_dir(std::string &shared_dir); + // When BOOST_INTERPROCESS_SHARED_DIR_FUNC is defined, users have to implement + // get_shared_dir + void get_shared_dir(std::wstring &shared_dir); + #else + +#if defined(BOOST_INTERPROCESS_SHARED_DIR_PATH) + inline void get_shared_dir(std::string &shared_dir) { - #if defined(BOOST_INTERPROCESS_SHARED_DIR_PATH) - shared_dir = BOOST_INTERPROCESS_SHARED_DIR_PATH; - #else + shared_dir = BOOST_INTERPROCESS_SHARED_DIR_PATH; +} + +#endif + +#if defined(BOOST_INTERPROCESS_SHARED_DIR_WPATH) + +inline void get_shared_dir(std::wstring &shared_dir) +{ + shared_dir = BOOST_INTERPROCESS_SHARED_DIR_WPATH; +} + +#endif + +template<class CharT> +inline void get_shared_dir(std::basic_string<CharT> &shared_dir) +{ get_shared_dir_root(shared_dir); #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) - shared_dir += "/"; + shared_dir += shared_dir_constants<CharT>::dir_separator(); get_bootstamp(shared_dir, true); #endif - #endif } #endif -inline void shared_filepath(const char *filename, std::string &filepath) +template<class CharT> +inline void shared_filepath(const CharT *filename, std::basic_string<CharT> &filepath) { get_shared_dir(filepath); - filepath += "/"; + filepath += shared_dir_constants<CharT>::dir_separator(); filepath += filename; } -inline void create_shared_dir_and_clean_old(std::string &shared_dir) +template<class CharT> +inline void create_shared_dir_and_clean_old(std::basic_string<CharT> &shared_dir) { #if defined(BOOST_INTERPROCESS_SHARED_DIR_PATH) || defined(BOOST_INTERPROCESS_SHARED_DIR_FUNC) get_shared_dir(shared_dir); #else //First get the temp directory - std::string root_shared_dir; + std::basic_string<CharT> root_shared_dir; get_shared_dir_root(root_shared_dir); //If fails, check that it's because already exists - if(!create_directory(root_shared_dir.c_str())){ + if(!open_or_create_shared_directory(root_shared_dir.c_str())){ error_info info(system_error_code()); - if(info.get_error_code() != already_exists_error){ - throw interprocess_exception(info); - } + throw interprocess_exception(info); } #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) get_shared_dir(shared_dir); //If fails, check that it's because already exists - if(!create_directory(shared_dir.c_str())){ + if(!open_or_create_shared_directory(shared_dir.c_str())){ error_info info(system_error_code()); - if(info.get_error_code() != already_exists_error){ - throw interprocess_exception(info); - } + throw interprocess_exception(info); } //Now erase all old directories created in the previous boot sessions - std::string subdir = shared_dir; + std::basic_string<CharT> subdir = shared_dir; subdir.erase(0, root_shared_dir.size()+1); delete_subdirectories(root_shared_dir, subdir.c_str()); #else @@ -188,17 +232,19 @@ inline void create_shared_dir_and_clean_old(std::string &shared_dir) #endif } -inline void create_shared_dir_cleaning_old_and_get_filepath(const char *filename, std::string &shared_dir) +template<class CharT> +inline void create_shared_dir_cleaning_old_and_get_filepath(const CharT *filename, std::basic_string<CharT> &shared_dir) { create_shared_dir_and_clean_old(shared_dir); - shared_dir += "/"; + shared_dir += shared_dir_constants<CharT>::dir_separator(); shared_dir += filename; } -inline void add_leading_slash(const char *name, std::string &new_name) +template<class CharT> +inline void add_leading_slash(const CharT *name, std::basic_string<CharT> &new_name) { - if(name[0] != '/'){ - new_name = '/'; + if(name[0] != shared_dir_constants<CharT>::dir_separator()){ + new_name = shared_dir_constants<CharT>::dir_separator(); } new_name += name; } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/timed_utils.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/timed_utils.hpp new file mode 100644 index 0000000000..89fbccd068 --- /dev/null +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/timed_utils.hpp @@ -0,0 +1,388 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2021-2021. +// +// Distributed under the 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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TIMED_UTILS_HPP +#define BOOST_INTERPROCESS_DETAIL_TIMED_UTILS_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/detail/mpl.hpp> +#include <boost/interprocess/detail/type_traits.hpp> +#include <boost/intrusive/detail/mpl.hpp> + +#include <ctime> +#include <boost/cstdint.hpp> + +//The following is used to support high precision time clocks +#ifdef BOOST_HAS_GETTIMEOFDAY +#include <sys/time.h> +#endif + +#ifdef BOOST_HAS_FTIME +#include <time.h> +#include <boost/winapi/time.hpp> +#endif + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(time_duration_type) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(clock) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(rep_type) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(rep) + +template<class T> +struct enable_if_ptime + : enable_if_c< BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, time_duration_type) > +{}; + +template<class T> +struct disable_if_ptime + : enable_if_c< ! BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, time_duration_type) > +{}; + +template<class T> +struct enable_if_ptime_duration + : enable_if_c< BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, rep_type) > +{}; + +template<class T> +struct enable_if_time_point + : enable_if_c< BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, clock) > +{}; + +template<class T> +struct enable_if_duration + : enable_if_c< BOOST_INTRUSIVE_HAS_TYPE(boost::interprocess::ipcdetail::, T, rep) > +{}; + +#if defined(BOOST_INTERPROCESS_HAS_REENTRANT_STD_FUNCTIONS) + + inline std::tm* interprocess_gmtime(const std::time_t* t, std::tm* result) + { + // gmtime_r() not in namespace std??? + #if defined(__VMS) && __INITIAL_POINTER_SIZE == 64 + std::tm tmp; + if(!gmtime_r(t,&tmp)) + result = 0; + else + *result = tmp; + #else + result = gmtime_r(t, result); + #endif + return result; + } + +#else // BOOST_DATE_TIME_HAS_REENTRANT_STD_FUNCTIONS + + #if defined(__clang__) // Clang has to be checked before MSVC + # pragma clang diagnostic push + # pragma clang diagnostic ignored "-Wdeprecated-declarations" + #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) + # pragma warning(push) // preserve warning settings + # pragma warning(disable : 4996) // disable depricated localtime/gmtime warning on vc8 + #endif + + inline std::tm* interprocess_gmtime(const std::time_t* t, std::tm* result) + { + result = std::gmtime(t); + return result; + } + + #if defined(__clang__) // Clang has to be checked before MSVC + # pragma clang diagnostic pop + #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) + # pragma warning(pop) // restore warnings to previous state + #endif + +#endif // BOOST_DATE_TIME_HAS_REENTRANT_STD_FUNCTIONS + +#if defined(BOOST_HAS_FTIME) +/*! +* The function converts file_time into number of microseconds elapsed since 1970-Jan-01 +* +* \note Only dates after 1970-Jan-01 are supported. Dates before will be wrapped. +*/ +inline boost::uint64_t file_time_to_microseconds(const boost::winapi::FILETIME_ & ft) +{ + // shift is difference between 1970-Jan-01 & 1601-Jan-01 + // in 100-nanosecond units + const boost::uint64_t shift = 116444736000000000ULL; // (27111902 << 32) + 3577643008 + + // 100-nanos since 1601-Jan-01 + boost::uint64_t ft_as_integer = (static_cast< boost::uint64_t >(ft.dwHighDateTime) << 32) | static_cast< boost::uint64_t >(ft.dwLowDateTime); + + ft_as_integer -= shift; // filetime is now 100-nanos since 1970-Jan-01 + return (ft_as_integer / 10U); // truncate to microseconds +} +#endif + +class ustime; + +class usduration +{ + public: + friend class ustime; + + explicit usduration(boost::uint64_t microsecs) + : m_microsecs(microsecs) + {} + + boost::uint64_t get_microsecs() const + { return m_microsecs; } + + bool operator < (const usduration &other) const + { return m_microsecs < other.m_microsecs; } + + bool operator > (const usduration &other) const + { return m_microsecs > other.m_microsecs; } + + bool operator <= (const usduration &other) const + { return m_microsecs <= other.m_microsecs; } + + bool operator >= (const usduration &other) const + { return m_microsecs >= other.m_microsecs; } + + private: + boost::uint64_t m_microsecs; +}; + +class ustime +{ + public: + explicit ustime(boost::uint64_t microsecs) + : m_microsecs(microsecs) + {} + + ustime &operator += (const usduration &other) + { m_microsecs += other.m_microsecs; return *this; } + + ustime operator + (const usduration &other) + { ustime r(*this); r += other; return r; } + + ustime &operator -= (const usduration &other) + { m_microsecs -= other.m_microsecs; return *this; } + + ustime operator - (const usduration &other) + { ustime r(*this); r -= other; return r; } + + friend usduration operator - (const ustime &l, const ustime &r) + { return usduration(l.m_microsecs - r.m_microsecs); } + + bool operator < (const ustime &other) const + { return m_microsecs < other.m_microsecs; } + + bool operator > (const ustime &other) const + { return m_microsecs > other.m_microsecs; } + + bool operator <= (const ustime &other) const + { return m_microsecs <= other.m_microsecs; } + + bool operator >= (const ustime &other) const + { return m_microsecs >= other.m_microsecs; } + + boost::uint64_t get_microsecs() const + { return m_microsecs; } + + private: + boost::uint64_t m_microsecs; +}; + +inline usduration usduration_milliseconds(boost::uint64_t millisec) +{ return usduration(millisec*1000u); } + +inline usduration usduration_seconds(boost::uint64_t sec) +{ return usduration(sec*uint64_t(1000000u)); } + +template<class TimeType, class Enable = void> +class microsec_clock; + +template<class TimeType> +class microsec_clock<TimeType, typename enable_if_ptime<TimeType>::type> +{ + private: + typedef typename TimeType::date_type date_type; + typedef typename TimeType::time_duration_type time_duration_type; + typedef typename time_duration_type::rep_type resolution_traits_type; + public: + + static TimeType universal_time() + { + #ifdef BOOST_HAS_GETTIMEOFDAY + timeval tv; + gettimeofday(&tv, 0); //gettimeofday does not support TZ adjust on Linux. + std::time_t t = tv.tv_sec; + boost::uint32_t sub_sec = static_cast<boost::uint32_t>(tv.tv_usec); + #elif defined(BOOST_HAS_FTIME) + boost::winapi::FILETIME_ ft; + boost::winapi::GetSystemTimeAsFileTime(&ft); + boost::uint64_t micros = file_time_to_microseconds(ft); // it will not wrap, since ft is the current time + // and cannot be before 1970-Jan-01 + std::time_t t = static_cast<std::time_t>(micros / 1000000UL); // seconds since epoch + // microseconds -- static casts suppress warnings + boost::uint32_t sub_sec = static_cast<boost::uint32_t>(micros % 1000000UL); + #else + #error "Unsupported date-time error: neither gettimeofday nor FILETIME support is detected" + #endif + + std::tm curr; + std::tm* curr_ptr = interprocess_gmtime(&t, &curr); + date_type d(static_cast< typename date_type::year_type::value_type >(curr_ptr->tm_year + 1900), + static_cast< typename date_type::month_type::value_type >(curr_ptr->tm_mon + 1), + static_cast< typename date_type::day_type::value_type >(curr_ptr->tm_mday)); + + //The following line will adjust the fractional second tick in terms + //of the current time system. For example, if the time system + //doesn't support fractional seconds then res_adjust returns 0 + //and all the fractional seconds return 0. + unsigned adjust = static_cast< unsigned >(resolution_traits_type::res_adjust() / 1000000); + + time_duration_type td(static_cast< typename time_duration_type::hour_type >(curr_ptr->tm_hour), + static_cast< typename time_duration_type::min_type >(curr_ptr->tm_min), + static_cast< typename time_duration_type::sec_type >(curr_ptr->tm_sec), + static_cast< typename time_duration_type::fractional_seconds_type >(sub_sec * adjust) + ); + return TimeType(d,td); + } +}; + +template<> +class microsec_clock<ustime> +{ + public: + static ustime universal_time() + { + #ifdef BOOST_HAS_GETTIMEOFDAY + timeval tv; + gettimeofday(&tv, 0); //gettimeofday does not support TZ adjust on Linux. + boost::uint64_t micros = boost::uint64_t(tv.tv_sec)*1000000; + micros += (boost::uint64_t)tv.tv_usec; + #elif defined(BOOST_HAS_FTIME) + boost::winapi::FILETIME_ ft; + boost::winapi::GetSystemTimeAsFileTime(&ft); + boost::uint64_t micros = file_time_to_microseconds(ft); // it will not wrap, since ft is the current time + // and cannot be before 1970-Jan-01 + #else + #error "Unsupported date-time error: neither gettimeofday nor FILETIME support is detected" + #endif + return ustime(micros); + } +}; + +template<class TimePoint> +class microsec_clock<TimePoint, typename enable_if_time_point<TimePoint>::type> +{ + public: + static TimePoint universal_time() + { return TimePoint::clock::now(); } +}; + + +template<class TimePoint> +inline TimePoint delay_ms(unsigned msecs, typename enable_if_ptime<TimePoint>::type* = 0) +{ + typedef typename TimePoint::time_duration_type time_duration_type; + typedef typename time_duration_type::rep_type resolution_traits_type; + + time_duration_type td(msecs*1000*resolution_traits_type::res_adjust()); + + TimePoint tp(microsec_clock<TimePoint>::universal_time()); + return (tp += td); +} + +template<class TimePoint> +inline bool is_pos_infinity(const TimePoint &abs_time, typename enable_if_ptime<TimePoint>::type* = 0) +{ + return abs_time.is_pos_infinity(); +} + +template<class TimePoint> +inline bool is_pos_infinity(const TimePoint &, typename disable_if_ptime<TimePoint>::type* = 0) +{ + return false; +} + +/* +template<class Duration> +inline ustime duration_to_timepoint(const Duration &dur, typename enable_if_ptime<Duration>::type* = 0) +{ + return dur.is_pos_infinity(); +} + +template<class Duration> +inline bool duration_to_timepoint(const Duration &, typename disable_if_ptime<Duration>::type* = 0) +{ + return false; +} +*/ + +// duration_to_milliseconds + +template<class Duration> +inline boost::uint64_t duration_to_milliseconds(const Duration &abs_time, typename enable_if_ptime_duration<Duration>::type* = 0) +{ + return static_cast<boost::uint64_t>(abs_time.total_milliseconds()); +} + +template<class Duration> +inline boost::uint64_t duration_to_milliseconds(const Duration &d, typename enable_if_duration<Duration>::type* = 0) +{ + const double factor = double(Duration::period::num)*1000.0/double(Duration::period::den); + return static_cast<boost::uint64_t>(double(d.count())*factor); +} + +inline boost::uint64_t duration_to_milliseconds(const usduration &d) +{ + return d.get_microsecs()/1000; +} + +// duration_to_usduration + +template<class Duration> +inline usduration duration_to_usduration(const Duration &d, typename enable_if_ptime_duration<Duration>::type* = 0) +{ + return usduration(static_cast<boost::uint64_t>(d.total_microseconds())); +} + +template<class Duration> +inline usduration duration_to_usduration(const Duration &d, typename enable_if_duration<Duration>::type* = 0) +{ + const double factor = double(Duration::period::num)*1000000.0/double(Duration::period::den); + return usduration(static_cast<boost::uint64_t>(double(d.count())*factor)); +} + +// duration_to_ustime + +template<class Duration> +inline ustime duration_to_ustime(const Duration &d) +{ + return microsec_clock<ustime>::universal_time() + (duration_to_usduration)(d); +} + + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include <boost/interprocess/detail/config_end.hpp> + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TIMED_UTILS_HPP + diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/utilities.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/utilities.hpp index c1b23423c2..247dff1e88 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/utilities.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/utilities.hpp @@ -87,7 +87,7 @@ struct ct_rounded_size }; // Gennaro Prota wrote this. Thanks! -template <int p, int n = 4> +template <std::size_t p, std::size_t n = 4> struct ct_max_pow2_less { static const std::size_t c = 2*n < p; @@ -163,8 +163,8 @@ template<class T, class OffsetType> class pointer_offset_caster<T*, OffsetType> { public: - BOOST_INTERPROCESS_FORCEINLINE explicit pointer_offset_caster(OffsetType offset) - : m_offset(offset) + BOOST_INTERPROCESS_FORCEINLINE explicit pointer_offset_caster(OffsetType off) + : m_offset(off) {} BOOST_INTERPROCESS_FORCEINLINE explicit pointer_offset_caster(const volatile T *p) diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/win32_api.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/win32_api.hpp index d12097f512..3967b0b299 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/win32_api.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/win32_api.hpp @@ -21,7 +21,7 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <boost/date_time/filetime_functions.hpp> +#include <boost/cstdint.hpp> #include <cstddef> #include <cstring> #include <cstdlib> @@ -31,51 +31,8 @@ #include <string> #include <vector> -//#define BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME -//#define BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED -//#define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED - -#ifdef BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME -# define BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME_VALUE 1 -#else -# define BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME_VALUE 0 -#endif - -#ifdef BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED -# define BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED_VALUE 1 -#else -# define BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED_VALUE 0 -#endif - -#ifdef BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED -# define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED_VALUE 1 -#else -# define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED_VALUE 0 -#endif - -#define BOOST_INTERPROCESS_BOOTSTAMP_VALUE_SUM \ - (BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED_VALUE + \ - BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED_VALUE + \ - BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME_VALUE) - -#if 1 < BOOST_INTERPROCESS_BOOTSTAMP_VALUE_SUM -# error "Only one of BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME, \ - BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED and \ - BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED can be defined" -#endif - -#if 0 == BOOST_INTERPROCESS_BOOTSTAMP_VALUE_SUM -# define BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED -#endif - #ifdef BOOST_USE_WINDOWS_H #include <windows.h> -# if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME) -# include <wbemidl.h> -# include <objbase.h> -# endif - -#include <shlobj.h> #endif #if defined(_MSC_VER) @@ -83,7 +40,6 @@ # pragma comment( lib, "Advapi32.lib" ) # pragma comment( lib, "oleaut32.lib" ) # pragma comment( lib, "Ole32.lib" ) -# pragma comment( lib, "Shell32.lib" ) //SHGetFolderPath #endif #if defined (BOOST_INTERPROCESS_WINDOWS) @@ -99,631 +55,63 @@ // ////////////////////////////////////////////////////////////////////////////// -//Ignore -pedantic errors here (anonymous structs, etc.) + #if defined(BOOST_GCC) +//Ignore -pedantic errors here (anonymous structs, etc.) # if (BOOST_GCC >= 40600) # pragma GCC diagnostic push -# if (BOOST_GCC >= 60000) +# if (BOOST_GCC >= 40800) # pragma GCC diagnostic ignored "-Wpedantic" # else # pragma GCC diagnostic ignored "-pedantic" # endif +# pragma GCC diagnostic ignored "-Wnon-virtual-dtor" # else # pragma GCC system_header # endif +//When loading DLLs we have no option but reinterpret casting function types +# if (BOOST_GCC >= 80000) +# pragma GCC diagnostic ignored "-Wcast-function-type" +# endif #endif -namespace boost { -namespace interprocess { -namespace winapi { - -//Own defines -static const unsigned long MaxPath = 260; - -#ifndef BOOST_USE_WINDOWS_H - -struct GUID_BIPC -{ - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8]; -}; - -#if defined(_MSC_VER) -#pragma warning (push) -#pragma warning (disable : 4201) // nonstandard extension used -#endif - -struct decimal -{ - unsigned short wReserved; - union { - struct { - unsigned char scale; - unsigned char sign; - }; - unsigned short signscale; - }; - unsigned long Hi32; - union { - struct { - unsigned long Lo32; - unsigned long Mid32; - }; - ::boost::ulong_long_type Lo64; - }; -}; - -typedef unsigned short *bstr; +//#define BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED +//#define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED -struct wchar_variant -{ - union - { - struct - { - unsigned short vt; - unsigned short wReserved1; - unsigned short wReserved2; - unsigned short wReserved3; - union - { - bstr bstrVal; - struct - { - void* pvRecord; - void* pRecInfo; - }; - }; - }; - decimal decVal; - }; -}; - -#if defined(_MSC_VER) -#pragma warning (pop) +#ifdef BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED +# define BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED_VALUE 1 +#else +# define BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED_VALUE 0 #endif -struct IUnknown_BIPC -{ - public: - virtual long __stdcall QueryInterface( - const GUID_BIPC &riid, // [in] - void **ppvObject) = 0; // [iid_is][out] - - virtual unsigned long __stdcall AddRef (void) = 0; - virtual unsigned long __stdcall Release(void) = 0; -}; - -struct IWbemClassObject_BIPC : public IUnknown_BIPC -{ - public: - virtual long __stdcall GetQualifierSet( - /* [out] */ void **ppQualSet) = 0; - - virtual long __stdcall Get( - /* [string][in] */ const bstr wszName, - /* [in] */ long lFlags, - /* [unique][in][out] */ wchar_variant *pVal, - /* [unique][in][out] */ long *pType, - /* [unique][in][out] */ long *plFlavor) = 0; - - virtual long __stdcall Put( - /* [string][in] */ const bstr wszName, - /* [in] */ long lFlags, - /* [in] */ wchar_variant *pVal, - /* [in] */ long Type) = 0; - - virtual long __stdcall Delete( - /* [string][in] */ const bstr wszName) = 0; - - virtual long __stdcall GetNames( - /* [string][in] */ const bstr wszQualifierName, - /* [in] */ long lFlags, - /* [in] */ wchar_variant *pQualifierVal, - /* [out] */ void * *pNames) = 0; - - virtual long __stdcall BeginEnumeration( - /* [in] */ long lEnumFlags) = 0; - - virtual long __stdcall Next( - /* [in] */ long lFlags, - /* [unique][in][out] */ bstr *strName, - /* [unique][in][out] */ wchar_variant *pVal, - /* [unique][in][out] */ long *pType, - /* [unique][in][out] */ long *plFlavor) = 0; - - virtual long __stdcall EndEnumeration( void) = 0; - - virtual long __stdcall GetPropertyQualifierSet( - /* [string][in] */ const bstr wszProperty, - /* [out] */ void **ppQualSet) = 0; - - virtual long __stdcall Clone( - /* [out] */ IWbemClassObject_BIPC **ppCopy) = 0; - - virtual long __stdcall GetObjectText( - /* [in] */ long lFlags, - /* [out] */ bstr *pstrObjectText) = 0; - - virtual long __stdcall SpawnDerivedClass( - /* [in] */ long lFlags, - /* [out] */ IWbemClassObject_BIPC **ppNewClass) = 0; - - virtual long __stdcall SpawnInstance( - /* [in] */ long lFlags, - /* [out] */ IWbemClassObject_BIPC **ppNewInstance) = 0; - - virtual long __stdcall CompareTo( - /* [in] */ long lFlags, - /* [in] */ IWbemClassObject_BIPC *pCompareTo) = 0; - - virtual long __stdcall GetPropertyOrigin( - /* [string][in] */ const bstr wszName, - /* [out] */ bstr *pstrClassName) = 0; - - virtual long __stdcall InheritsFrom( - /* [in] */ const bstr strAncestor) = 0; - - virtual long __stdcall GetMethod( - /* [string][in] */ const bstr wszName, - /* [in] */ long lFlags, - /* [out] */ IWbemClassObject_BIPC **ppInSignature, - /* [out] */ IWbemClassObject_BIPC **ppOutSignature) = 0; - - virtual long __stdcall PutMethod( - /* [string][in] */ const bstr wszName, - /* [in] */ long lFlags, - /* [in] */ IWbemClassObject_BIPC *pInSignature, - /* [in] */ IWbemClassObject_BIPC *pOutSignature) = 0; - - virtual long __stdcall DeleteMethod( - /* [string][in] */ const bstr wszName) = 0; - - virtual long __stdcall BeginMethodEnumeration( - /* [in] */ long lEnumFlags) = 0; - - virtual long __stdcall NextMethod( - /* [in] */ long lFlags, - /* [unique][in][out] */ bstr *pstrName, - /* [unique][in][out] */ IWbemClassObject_BIPC **ppInSignature, - /* [unique][in][out] */ IWbemClassObject_BIPC **ppOutSignature) = 0; - - virtual long __stdcall EndMethodEnumeration( void) = 0; - - virtual long __stdcall GetMethodQualifierSet( - /* [string][in] */ const bstr wszMethod, - /* [out] */ void **ppQualSet) = 0; - - virtual long __stdcall GetMethodOrigin( - /* [string][in] */ const bstr wszMethodName, - /* [out] */ bstr *pstrClassName) = 0; - -}; - -struct IWbemContext_BIPC : public IUnknown_BIPC -{ -public: - virtual long __stdcall Clone( - /* [out] */ IWbemContext_BIPC **ppNewCopy) = 0; - - virtual long __stdcall GetNames( - /* [in] */ long lFlags, - /* [out] */ void * *pNames) = 0; - - virtual long __stdcall BeginEnumeration( - /* [in] */ long lFlags) = 0; - - virtual long __stdcall Next( - /* [in] */ long lFlags, - /* [out] */ bstr *pstrName, - /* [out] */ wchar_variant *pValue) = 0; - - virtual long __stdcall EndEnumeration( void) = 0; - - virtual long __stdcall SetValue( - /* [string][in] */ const bstr wszName, - /* [in] */ long lFlags, - /* [in] */ wchar_variant *pValue) = 0; - - virtual long __stdcall GetValue( - /* [string][in] */ const bstr wszName, - /* [in] */ long lFlags, - /* [out] */ wchar_variant *pValue) = 0; - - virtual long __stdcall DeleteValue( - /* [string][in] */ const bstr wszName, - /* [in] */ long lFlags) = 0; - - virtual long __stdcall DeleteAll( void) = 0; - -}; - - -struct IEnumWbemClassObject_BIPC : public IUnknown_BIPC -{ -public: - virtual long __stdcall Reset( void) = 0; - - virtual long __stdcall Next( - /* [in] */ long lTimeout, - /* [in] */ unsigned long uCount, - /* [length_is][size_is][out] */ IWbemClassObject_BIPC **apObjects, - /* [out] */ unsigned long *puReturned) = 0; - - virtual long __stdcall NextAsync( - /* [in] */ unsigned long uCount, - /* [in] */ void *pSink) = 0; - - virtual long __stdcall Clone( - /* [out] */ void **ppEnum) = 0; - - virtual long __stdcall Skip( - /* [in] */ long lTimeout, - /* [in] */ unsigned long nCount) = 0; - -}; - -struct IWbemServices_BIPC : public IUnknown_BIPC -{ -public: - virtual long __stdcall OpenNamespace( - /* [in] */ const bstr strNamespace, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [unique][in][out] */ void **ppWorkingNamespace, - /* [unique][in][out] */ void **ppResult) = 0; - - virtual long __stdcall CancelAsyncCall( - /* [in] */ void *pSink) = 0; - - virtual long __stdcall QueryObjectSink( - /* [in] */ long lFlags, - /* [out] */ void **ppResponseHandler) = 0; - - virtual long __stdcall GetObject( - /* [in] */ const bstr strObjectPath, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [unique][in][out] */ void **ppObject, - /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall GetObjectAsync( - /* [in] */ const bstr strObjectPath, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall PutClass( - /* [in] */ IWbemClassObject_BIPC *pObject, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall PutClassAsync( - /* [in] */ IWbemClassObject_BIPC *pObject, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall DeleteClass( - /* [in] */ const bstr strClass, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall DeleteClassAsync( - /* [in] */ const bstr strClass, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall CreateClassEnum( - /* [in] */ const bstr strSuperclass, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [out] */ void **ppEnum) = 0; - - virtual long __stdcall CreateClassEnumAsync( - /* [in] */ const bstr strSuperclass, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall PutInstance( - /* [in] */ void *pInst, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall PutInstanceAsync( - /* [in] */ void *pInst, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall DeleteInstance( - /* [in] */ const bstr strObjectPath, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall DeleteInstanceAsync( - /* [in] */ const bstr strObjectPath, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall CreateInstanceEnum( - /* [in] */ const bstr strFilter, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [out] */ void **ppEnum) = 0; - - virtual long __stdcall CreateInstanceEnumAsync( - /* [in] */ const bstr strFilter, - /* [in] */ long lFlags, - /* [in] */ void *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall ExecQuery( - /* [in] */ const bstr strQueryLanguage, - /* [in] */ const bstr strQuery, - /* [in] */ long lFlags, - /* [in] */ IWbemContext_BIPC *pCtx, - /* [out] */ IEnumWbemClassObject_BIPC **ppEnum) = 0; - - virtual long __stdcall ExecQueryAsync( - /* [in] */ const bstr strQueryLanguage, - /* [in] */ const bstr strQuery, - /* [in] */ long lFlags, - /* [in] */ IWbemContext_BIPC *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall ExecNotificationQuery( - /* [in] */ const bstr strQueryLanguage, - /* [in] */ const bstr strQuery, - /* [in] */ long lFlags, - /* [in] */ IWbemContext_BIPC *pCtx, - /* [out] */ void **ppEnum) = 0; - - virtual long __stdcall ExecNotificationQueryAsync( - /* [in] */ const bstr strQueryLanguage, - /* [in] */ const bstr strQuery, - /* [in] */ long lFlags, - /* [in] */ IWbemContext_BIPC *pCtx, - /* [in] */ void *pResponseHandler) = 0; - - virtual long __stdcall ExecMethod( - /* [in] */ const bstr strObjectPath, - /* [in] */ const bstr strMethodName, - /* [in] */ long lFlags, - /* [in] */ IWbemContext_BIPC *pCtx, - /* [in] */ IWbemClassObject_BIPC *pInParams, - /* [unique][in][out] */ IWbemClassObject_BIPC **ppOutParams, - /* [unique][in][out] */ void **ppCallResult) = 0; - - virtual long __stdcall ExecMethodAsync( - /* [in] */ const bstr strObjectPath, - /* [in] */ const bstr strMethodName, - /* [in] */ long lFlags, - /* [in] */ IWbemContext_BIPC *pCtx, - /* [in] */ IWbemClassObject_BIPC *pInParams, - /* [in] */ void *pResponseHandler) = 0; - -}; - -struct IWbemLocator_BIPC : public IUnknown_BIPC -{ -public: - virtual long __stdcall ConnectServer( - /* [in] */ const bstr strNetworkResource, - /* [in] */ const bstr strUser, - /* [in] */ const bstr strPassword, - /* [in] */ const bstr strLocale, - /* [in] */ long lSecurityFlags, - /* [in] */ const bstr strAuthority, - /* [in] */ void *pCtx, - /* [out] */ IWbemServices_BIPC **ppNamespace) = 0; - -}; - -struct interprocess_overlapped -{ - unsigned long *internal; - unsigned long *internal_high; - union { - struct { - unsigned long offset; - unsigned long offset_high; - }dummy; - void *pointer; - }; - - void *h_event; -}; - - -struct interprocess_filetime -{ - unsigned long dwLowDateTime; - unsigned long dwHighDateTime; -}; - -struct win32_find_data -{ - unsigned long dwFileAttributes; - interprocess_filetime ftCreationTime; - interprocess_filetime ftLastAccessTime; - interprocess_filetime ftLastWriteTime; - unsigned long nFileSizeHigh; - unsigned long nFileSizeLow; - unsigned long dwReserved0; - unsigned long dwReserved1; - char cFileName[MaxPath]; - char cAlternateFileName[14]; -}; - -struct interprocess_security_attributes -{ - unsigned long nLength; - void *lpSecurityDescriptor; - int bInheritHandle; -}; - -struct system_info { - union { - unsigned long dwOemId; // Obsolete field...do not use - struct { - unsigned short wProcessorArchitecture; - unsigned short wReserved; - } dummy; - }; - unsigned long dwPageSize; - void * lpMinimumApplicationAddress; - void * lpMaximumApplicationAddress; - unsigned long * dwActiveProcessorMask; - unsigned long dwNumberOfProcessors; - unsigned long dwProcessorType; - unsigned long dwAllocationGranularity; - unsigned short wProcessorLevel; - unsigned short wProcessorRevision; -}; - -struct interprocess_acl -{ - unsigned char AclRevision; - unsigned char Sbz1; - unsigned short AclSize; - unsigned short AceCount; - unsigned short Sbz2; -}; - -struct interprocess_security_descriptor -{ - unsigned char Revision; - unsigned char Sbz1; - unsigned short Control; - void *Owner; - void *Group; - interprocess_acl *Sacl; - interprocess_acl *Dacl; -}; - -struct interprocess_by_handle_file_information -{ - unsigned long dwFileAttributes; - interprocess_filetime ftCreationTime; - interprocess_filetime ftLastAccessTime; - interprocess_filetime ftLastWriteTime; - unsigned long dwVolumeSerialNumber; - unsigned long nFileSizeHigh; - unsigned long nFileSizeLow; - unsigned long nNumberOfLinks; - unsigned long nFileIndexHigh; - unsigned long nFileIndexLow; -}; - -struct interprocess_eventlogrecord -{ - unsigned long Length; // Length of full record - unsigned long Reserved; // Used by the service - unsigned long RecordNumber; // Absolute record number - unsigned long TimeGenerated; // Seconds since 1-1-1970 - unsigned long TimeWritten; // Seconds since 1-1-1970 - unsigned long EventID; - unsigned short EventType; - unsigned short NumStrings; - unsigned short EventCategory; - unsigned short ReservedFlags; // For use with paired events (auditing) - unsigned long ClosingRecordNumber; // For use with paired events (auditing) - unsigned long StringOffset; // Offset from beginning of record - unsigned long UserSidLength; - unsigned long UserSidOffset; - unsigned long DataLength; - unsigned long DataOffset; // Offset from beginning of record - // - // Then follow: - // - // wchar_t SourceName[] - // wchar_t Computername[] - // SID UserSid - // wchar_t Strings[] - // BYTE Data[] - // CHAR Pad[] - // unsigned long Length; - // -}; - -union large_integer -{ - __int64 QuadPart; -}; - -struct hinstance_struct { int unused; }; -typedef hinstance_struct *hmodule; - -struct hkey_struct; -typedef hkey_struct *hkey; - -#ifdef _WIN64 -typedef __int64 (__stdcall *farproc_t)(); +#ifdef BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED +# define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED_VALUE 1 #else -typedef int (__stdcall *farproc_t)(); -#endif // _WIN64 - -#else //#ifndef BOOST_USE_WINDOWS_H - -typedef GUID GUID_BIPC; -typedef VARIANT wchar_variant; - -#if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME) - -typedef IUnknown IUnknown_BIPC; - -typedef IWbemClassObject IWbemClassObject_BIPC; - -typedef IWbemContext IWbemContext_BIPC; - -typedef IEnumWbemClassObject IEnumWbemClassObject_BIPC; - -typedef IWbemServices IWbemServices_BIPC; - -typedef IWbemLocator IWbemLocator_BIPC; - +# define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED_VALUE 0 #endif -typedef OVERLAPPED interprocess_overlapped; - -typedef FILETIME interprocess_filetime; - -typedef WIN32_FIND_DATAA win32_find_data; - -typedef SECURITY_ATTRIBUTES interprocess_security_attributes; - -typedef SYSTEM_INFO system_info; - -typedef ACL interprocess_acl; - -typedef SECURITY_DESCRIPTOR interprocess_security_descriptor; - -typedef BY_HANDLE_FILE_INFORMATION interprocess_by_handle_file_information; - -typedef EVENTLOGRECORD interprocess_eventlogrecord; - -typedef LARGE_INTEGER large_integer; +#define BOOST_INTERPROCESS_BOOTSTAMP_VALUE_SUM \ + (BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED_VALUE + \ + BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED_VALUE) -typedef HMODULE hmodule; +#if 1 < BOOST_INTERPROCESS_BOOTSTAMP_VALUE_SUM +# error "Only one of \ + BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED and \ + BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED can be defined" +#endif -typedef HKEY hkey; +#if 0 == BOOST_INTERPROCESS_BOOTSTAMP_VALUE_SUM +# define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED +#endif -typedef BSTR bstr; -typedef FARPROC farproc_t; +namespace boost { +namespace interprocess { +namespace winapi { -#endif //#ifndef BOOST_USE_WINDOWS_H +//Own defines +static const unsigned long MaxPath = 260; ////////////////////////////////////////////////////////////////////////////// // @@ -733,8 +121,8 @@ typedef FARPROC farproc_t; struct interprocess_semaphore_basic_information { - unsigned int count; // current semaphore count - unsigned int limit; // max semaphore count + unsigned long count; // current semaphore count + unsigned long limit; // max semaphore count }; struct interprocess_section_basic_information @@ -876,148 +264,212 @@ enum section_information_class section_image_information }; +} //namespace winapi { +} //namespace interprocess { +} //namespace boost { + + ////////////////////////////////////////////////////////////////////////////// // // Forward declaration of winapi // ////////////////////////////////////////////////////////////////////////////// +#include <boost/winapi/get_current_process_id.hpp> +#include <boost/winapi/get_current_thread_id.hpp> +#include <boost/winapi/get_current_process.hpp> +#include <boost/winapi/get_process_times.hpp> +#include <boost/winapi/error_codes.hpp> +#include <boost/winapi/thread.hpp> +#include <boost/winapi/system.hpp> +#include <boost/winapi/time.hpp> +#include <boost/winapi/timers.hpp> +#include <boost/winapi/get_last_error.hpp> +#include <boost/winapi/handles.hpp> +#include <boost/winapi/file_management.hpp> +#include <boost/winapi/mutex.hpp> +#include <boost/winapi/wait.hpp> +#include <boost/winapi/file_mapping.hpp> +#include <boost/winapi/semaphore.hpp> +#include <boost/winapi/system.hpp> +#include <boost/winapi/error_handling.hpp> +#include <boost/winapi/local_memory.hpp> +#include <boost/winapi/directory_management.hpp> +#include <boost/winapi/security.hpp> +#include <boost/winapi/dll.hpp> +#include <boost/winapi/basic_types.hpp> + +//This should go in winapi's basic_types.hpp +namespace boost { +namespace ipwinapiext { +typedef boost::winapi::LONG_ LSTATUS; + +typedef boost::winapi::DWORD_ (__stdcall *LPTHREAD_START_ROUTINE_) + (boost::winapi::LPVOID_ lpThreadParameter); + + +//#ifndef BOOST_USE_WINDOWS_H +//typedef boost::winapi::LARGE_INTEGER_ LARGE_INTEGER_EXT; +//#else +//typedef LARGE_INTEGER LARGE_INTEGER_EXT; +//#endif + +}} //namespace boost::ipwinapiext + #ifndef BOOST_USE_WINDOWS_H -//Kernel32.dll +extern "C" { -//Some windows API declarations -extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); -extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); -extern "C" __declspec(dllimport) int __stdcall GetProcessTimes - ( void *hProcess, interprocess_filetime* lpCreationTime - , interprocess_filetime *lpExitTime,interprocess_filetime *lpKernelTime - , interprocess_filetime *lpUserTime ); -extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long); -extern "C" __declspec(dllimport) unsigned long __stdcall GetTickCount(void); -extern "C" __declspec(dllimport) int __stdcall SwitchToThread(); -extern "C" __declspec(dllimport) unsigned long __stdcall GetLastError(); -extern "C" __declspec(dllimport) void __stdcall SetLastError(unsigned long); -extern "C" __declspec(dllimport) void * __stdcall GetCurrentProcess(); -extern "C" __declspec(dllimport) int __stdcall CloseHandle(void*); -extern "C" __declspec(dllimport) int __stdcall DuplicateHandle - ( void *hSourceProcessHandle, void *hSourceHandle - , void *hTargetProcessHandle, void **lpTargetHandle - , unsigned long dwDesiredAccess, int bInheritHandle - , unsigned long dwOptions); -extern "C" __declspec(dllimport) long __stdcall GetFileType(void *hFile); -extern "C" __declspec(dllimport) void *__stdcall FindFirstFileA(const char *lpFileName, win32_find_data *lpFindFileData); -extern "C" __declspec(dllimport) int __stdcall FindNextFileA(void *hFindFile, win32_find_data *lpFindFileData); -extern "C" __declspec(dllimport) int __stdcall FindClose(void *hFindFile); -//extern "C" __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(interprocess_filetime*); -//extern "C" __declspec(dllimport) int __stdcall FileTimeToLocalFileTime(const interprocess_filetime *in, const interprocess_filetime *out); -extern "C" __declspec(dllimport) void * __stdcall CreateMutexA(interprocess_security_attributes*, int, const char *); -extern "C" __declspec(dllimport) void * __stdcall OpenMutexA(unsigned long, int, const char *); -extern "C" __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void *, unsigned long); -extern "C" __declspec(dllimport) int __stdcall ReleaseMutex(void *); -extern "C" __declspec(dllimport) int __stdcall UnmapViewOfFile(void *); -extern "C" __declspec(dllimport) void * __stdcall CreateSemaphoreA(interprocess_security_attributes*, long, long, const char *); -extern "C" __declspec(dllimport) int __stdcall ReleaseSemaphore(void *, long, long *); -extern "C" __declspec(dllimport) void * __stdcall OpenSemaphoreA(unsigned long, int, const char *); -extern "C" __declspec(dllimport) void * __stdcall CreateFileMappingA (void *, interprocess_security_attributes*, unsigned long, unsigned long, unsigned long, const char *); -extern "C" __declspec(dllimport) void * __stdcall MapViewOfFileEx (void *, unsigned long, unsigned long, unsigned long, std::size_t, void*); -extern "C" __declspec(dllimport) void * __stdcall OpenFileMappingA (unsigned long, int, const char *); -extern "C" __declspec(dllimport) void * __stdcall CreateFileA (const char *, unsigned long, unsigned long, struct interprocess_security_attributes*, unsigned long, unsigned long, void *); -extern "C" __declspec(dllimport) void __stdcall GetSystemInfo (struct system_info *); -extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::size_t); -extern "C" __declspec(dllimport) int __stdcall VirtualUnlock (void *, std::size_t); -extern "C" __declspec(dllimport) int __stdcall VirtualProtect (void *, std::size_t, unsigned long, unsigned long *); -extern "C" __declspec(dllimport) int __stdcall FlushFileBuffers (void *); -extern "C" __declspec(dllimport) int __stdcall GetFileSizeEx (void *, large_integer *size); -extern "C" __declspec(dllimport) unsigned long __stdcall FormatMessageA - (unsigned long dwFlags, const void *lpSource, unsigned long dwMessageId, - unsigned long dwLanguageId, char *lpBuffer, unsigned long nSize, - std::va_list *Arguments); -extern "C" __declspec(dllimport) void *__stdcall LocalFree (void *); -extern "C" __declspec(dllimport) unsigned long __stdcall GetFileAttributesA(const char *); -extern "C" __declspec(dllimport) int __stdcall CreateDirectoryA(const char *, interprocess_security_attributes*); -extern "C" __declspec(dllimport) int __stdcall RemoveDirectoryA(const char *lpPathName); -extern "C" __declspec(dllimport) int __stdcall GetTempPathA(unsigned long length, char *buffer); -extern "C" __declspec(dllimport) int __stdcall CreateDirectory(const char *, interprocess_security_attributes*); -extern "C" __declspec(dllimport) int __stdcall SetFileValidData(void *, __int64 size); -extern "C" __declspec(dllimport) int __stdcall SetEndOfFile(void *); -extern "C" __declspec(dllimport) int __stdcall SetFilePointerEx(void *, large_integer distance, large_integer *new_file_pointer, unsigned long move_method); -extern "C" __declspec(dllimport) int __stdcall LockFile (void *hnd, unsigned long offset_low, unsigned long offset_high, unsigned long size_low, unsigned long size_high); -extern "C" __declspec(dllimport) int __stdcall UnlockFile(void *hnd, unsigned long offset_low, unsigned long offset_high, unsigned long size_low, unsigned long size_high); -extern "C" __declspec(dllimport) int __stdcall LockFileEx(void *hnd, unsigned long flags, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped* overlapped); -extern "C" __declspec(dllimport) int __stdcall UnlockFileEx(void *hnd, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped* overlapped); -extern "C" __declspec(dllimport) int __stdcall WriteFile(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped); -extern "C" __declspec(dllimport) int __stdcall ReadFile(void *hnd, void *buffer, unsigned long bytes_to_read, unsigned long *bytes_read, interprocess_overlapped* overlapped); -extern "C" __declspec(dllimport) int __stdcall InitializeSecurityDescriptor(interprocess_security_descriptor *pSecurityDescriptor, unsigned long dwRevision); -extern "C" __declspec(dllimport) int __stdcall SetSecurityDescriptorDacl(interprocess_security_descriptor *pSecurityDescriptor, int bDaclPresent, interprocess_acl *pDacl, int bDaclDefaulted); -extern "C" __declspec(dllimport) hmodule __stdcall LoadLibraryA(const char *); -extern "C" __declspec(dllimport) int __stdcall FreeLibrary(hmodule); -extern "C" __declspec(dllimport) farproc_t __stdcall GetProcAddress(void *, const char*); -extern "C" __declspec(dllimport) hmodule __stdcall GetModuleHandleA(const char*); -extern "C" __declspec(dllimport) void *__stdcall GetFileInformationByHandle(void *, interprocess_by_handle_file_information*); - -//Advapi32.dll -extern "C" __declspec(dllimport) long __stdcall RegOpenKeyExA(hkey, const char *, unsigned long, unsigned long, hkey*); -extern "C" __declspec(dllimport) long __stdcall RegQueryValueExA(hkey, const char *, unsigned long*, unsigned long*, unsigned char *, unsigned long*); -extern "C" __declspec(dllimport) long __stdcall RegCloseKey(hkey); - -//Ole32.dll -extern "C" __declspec(dllimport) long __stdcall CoInitializeEx(void *pvReserved, unsigned long dwCoInit); -extern "C" __declspec(dllimport) long __stdcall CoInitializeSecurity( - void* pSecDesc, - long cAuthSvc, - void * asAuthSvc, - void *pReserved1, - unsigned long dwAuthnLevel, - unsigned long dwImpLevel, - void *pAuthList, - unsigned long dwCapabilities, - void *pReserved3 ); - - extern "C" __declspec(dllimport) long __stdcall CoSetProxyBlanket( - IUnknown_BIPC *pProxy, - unsigned long dwAuthnSvc, - unsigned long dwAuthzSvc, - wchar_t *pServerPrincName, - unsigned long dwAuthnLevel, - unsigned long dwImpLevel, - void *pAuthInfo, - unsigned long dwCapabilities); -extern "C" __declspec(dllimport) long __stdcall CoCreateInstance(const GUID_BIPC & rclsid, IUnknown_BIPC *pUnkOuter, - unsigned long dwClsContext, const GUID_BIPC & riid, void** ppv); -extern "C" __declspec(dllimport) void __stdcall CoUninitialize(void); - -//OleAut32.dll -extern "C" __declspec(dllimport) long __stdcall VariantClear(wchar_variant * pvarg); - -//Shell32.dll -extern "C" __declspec(dllimport) int __stdcall SHGetSpecialFolderPathA - (void* hwnd, const char *pszPath, int csidl, int fCreate); - -extern "C" __declspec(dllimport) int __stdcall SHGetFolderPathA(void *hwnd, int csidl, void *hToken, unsigned long dwFlags, const char *pszPath); - -//EventLog access functions - -extern "C" __declspec(dllimport) void* __stdcall OpenEventLogA - (const char* lpUNCServerName, const char* lpSourceName); - -extern "C" __declspec(dllimport) int __stdcall CloseEventLog(void *hEventLog); - -extern "C" __declspec(dllimport) int __stdcall ReadEventLogA - (void *hEventLog, - unsigned long dwReadFlags, - unsigned long dwRecordOffset, - void *lpBuffer, - unsigned long nNumberOfBytesToRead, - unsigned long *pnBytesRead, - unsigned long *pnMinNumberOfBytesNeeded +//Error handling +BOOST_SYMBOL_IMPORT BOOST_WINAPI_DETAIL_VOID BOOST_WINAPI_WINAPI_CC SetLastError(boost::winapi::DWORD_ dwErrCode); + +//File management +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC GetFileType(boost::winapi::HANDLE_ hTemplateFile); +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC FlushFileBuffers(boost::winapi::HANDLE_ hFile); + +//threading + +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC CreateThread + ( ::_SECURITY_ATTRIBUTES* lpThreadAttributes + , boost::winapi::SIZE_T_ dwStackSize + , boost::ipwinapiext::LPTHREAD_START_ROUTINE_ lpStartAddress + , boost::winapi::LPVOID_ lpParameter + , boost::winapi::DWORD_ dwCreationFlags + , boost::winapi::LPDWORD_ lpThreadId ); +//Virtual Memory +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC VirtualLock(boost::winapi::LPVOID_ lpAddress, boost::winapi::SIZE_T_ dwSize); +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC VirtualUnlock(boost::winapi::LPVOID_ lpAddress, boost::winapi::SIZE_T_ dwSize); +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC VirtualProtect( boost::winapi::LPVOID_ lpAddress, boost::winapi::SIZE_T_ dwSize + , boost::winapi::DWORD_ flNewProtect, boost::winapi::PDWORD_ lpflOldProtect); +//registry.hpp +BOOST_WINAPI_DETAIL_DECLARE_HANDLE(HKEY); + + +BOOST_SYMBOL_IMPORT boost::ipwinapiext::LSTATUS BOOST_WINAPI_WINAPI_CC RegOpenKeyExA + (::HKEY hKey, const char *lpSubKey, boost::winapi::DWORD_ ulOptions, boost::winapi::DWORD_ samDesired, ::HKEY *phkResult); +BOOST_SYMBOL_IMPORT boost::ipwinapiext::LSTATUS BOOST_WINAPI_WINAPI_CC RegOpenKeyExW + (::HKEY hKey, const wchar_t *lpSubKey, boost::winapi::DWORD_ ulOptions, boost::winapi::DWORD_ samDesired, ::HKEY *phkResult); +BOOST_SYMBOL_IMPORT boost::ipwinapiext::LSTATUS BOOST_WINAPI_WINAPI_CC RegQueryValueExA + (::HKEY hKey, const char *lpValueName, boost::winapi::DWORD_ *lpReserved, boost::winapi::DWORD_ *lpType, boost::winapi::BYTE_ *lpData, boost::winapi::DWORD_ *lpcbData); +BOOST_SYMBOL_IMPORT boost::ipwinapiext::LSTATUS BOOST_WINAPI_WINAPI_CC RegQueryValueExW + (::HKEY hKey, const wchar_t *lpValueName, boost::winapi::DWORD_ *lpReserved, boost::winapi::DWORD_ *lpType, boost::winapi::BYTE_ *lpData, boost::winapi::DWORD_ *lpcbData); +BOOST_SYMBOL_IMPORT boost::ipwinapiext::LSTATUS BOOST_WINAPI_WINAPI_CC RegCloseKey(::HKEY hKey); + + +//Event Log +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC OpenEventLogA(const char* lpUNCServerName, const char* lpSourceName); +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC OpenEventLogW(const wchar_t* lpUNCServerName, const wchar_t* lpSourceName); +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC CloseEventLog(boost::winapi::HANDLE_ hEventLog); +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC ReadEventLogA + ( boost::winapi::HANDLE_ hEventLog, boost::winapi::DWORD_ dwReadFlags, boost::winapi::DWORD_ dwRecordOffset, void* lpBuffer + , boost::winapi::DWORD_ nNumberOfBytesToRead, boost::winapi::DWORD_ *pnBytesRead, boost::winapi::DWORD_ *pnMinNumberOfBytesNeeded); +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC ReadEventLogW + ( boost::winapi::HANDLE_ hEventLog, boost::winapi::DWORD_ dwReadFlags, boost::winapi::DWORD_ dwRecordOffset, void* lpBuffer + , boost::winapi::DWORD_ nNumberOfBytesToRead, boost::winapi::DWORD_ *pnBytesRead, boost::winapi::DWORD_ *pnMinNumberOfBytesNeeded); + +} //extern "C" { + #endif //#ifndef BOOST_USE_WINDOWS_H -//kernel32.dll -typedef int (__stdcall *QueryPerformanceCounter_t) (__int64 *lpPerformanceCount); -typedef int (__stdcall *QueryPerformanceFrequency_t)(__int64 *lpFrequency); +namespace boost { +namespace ipwinapiext { + +typedef ::HKEY HKEY_; + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM + +//Threads +BOOST_FORCEINLINE boost::winapi::HANDLE_ CreateThread + ( boost::winapi::SECURITY_ATTRIBUTES_* lpThreadAttributes + , boost::winapi::SIZE_T_ dwStackSize + , boost::ipwinapiext::LPTHREAD_START_ROUTINE_ lpStartAddress + , boost::winapi::LPVOID_ lpParameter + , boost::winapi::DWORD_ dwCreationFlags + , boost::winapi::LPDWORD_ lpThreadId +) +{ + return ::CreateThread( reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpThreadAttributes) + , dwStackSize, lpStartAddress + , lpParameter, dwCreationFlags, lpThreadId); +} + +//Error handling +BOOST_FORCEINLINE BOOST_WINAPI_DETAIL_VOID SetLastError(boost::winapi::DWORD_ dwErrCode) +{ ::SetLastError(dwErrCode); } + +//File management +BOOST_FORCEINLINE boost::winapi::DWORD_ GetFileType(boost::winapi::HANDLE_ hTemplateFile) +{ return ::GetFileType(hTemplateFile); } + +BOOST_FORCEINLINE boost::winapi::BOOL_ FlushFileBuffers(boost::winapi::HANDLE_ hFile) +{ return ::FlushFileBuffers(hFile); } + +//Virtual Memory +BOOST_FORCEINLINE boost::winapi::BOOL_ VirtualLock(boost::winapi::LPVOID_ lpAddress, boost::winapi::SIZE_T_ dwSize) +{ return ::VirtualLock(lpAddress, dwSize); } + +BOOST_FORCEINLINE boost::winapi::BOOL_ VirtualUnlock(boost::winapi::LPVOID_ lpAddress, boost::winapi::SIZE_T_ dwSize) +{ return ::VirtualUnlock(lpAddress, dwSize); } + +BOOST_FORCEINLINE boost::winapi::BOOL_ VirtualProtect( boost::winapi::LPVOID_ lpAddress, boost::winapi::SIZE_T_ dwSize + , boost::winapi::DWORD_ flNewProtect, boost::winapi::PDWORD_ lpflOldProtect) +{ return ::VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); } + +//registry.hpp +BOOST_FORCEINLINE boost::ipwinapiext::LSTATUS RegOpenKeyExA + (boost::ipwinapiext::HKEY_ hKey, const char *lpSubKey, boost::winapi::DWORD_ ulOptions, boost::winapi::DWORD_ samDesired, boost::ipwinapiext::HKEY_ *phkResult) +{ + return ::RegOpenKeyExA(reinterpret_cast< ::HKEY >(hKey), lpSubKey, ulOptions, samDesired, reinterpret_cast< ::HKEY* >(phkResult)); +} + +BOOST_FORCEINLINE boost::ipwinapiext::LSTATUS RegOpenKeyExW + (boost::ipwinapiext::HKEY_ hKey, const wchar_t *lpSubKey, boost::winapi::DWORD_ ulOptions, boost::winapi::DWORD_ samDesired, boost::ipwinapiext::HKEY_ *phkResult) +{ + return ::RegOpenKeyExW(reinterpret_cast< ::HKEY >(hKey), lpSubKey, ulOptions, samDesired, reinterpret_cast< ::HKEY* >(phkResult)); +} + +BOOST_FORCEINLINE boost::ipwinapiext::LSTATUS RegQueryValueExA + (boost::ipwinapiext::HKEY_ hKey, const char *lpValueName, boost::winapi::DWORD_ *lpReserved, boost::winapi::DWORD_ *lpType, boost::winapi::BYTE_ *lpData, boost::winapi::DWORD_ *lpcbData) +{ + return ::RegQueryValueExA(reinterpret_cast< ::HKEY >(hKey), lpValueName, lpReserved, lpType, lpData, lpcbData); +} + +BOOST_FORCEINLINE boost::ipwinapiext::LSTATUS RegQueryValueExW + (boost::ipwinapiext::HKEY_ hKey, const wchar_t *lpValueName, boost::winapi::DWORD_ *lpReserved, boost::winapi::DWORD_ *lpType, boost::winapi::BYTE_ *lpData, boost::winapi::DWORD_ *lpcbData) +{ + return ::RegQueryValueExW(reinterpret_cast< ::HKEY >(hKey), lpValueName, lpReserved, lpType, lpData, lpcbData); +} + +BOOST_FORCEINLINE boost::ipwinapiext::LSTATUS RegCloseKey(boost::ipwinapiext::HKEY_ hKey) +{ + return ::RegCloseKey(reinterpret_cast< ::HKEY >(hKey)); +} + +BOOST_FORCEINLINE void GetSystemInfo(boost::winapi::LPSYSTEM_INFO_ lpSystemInfo) +{ return ::GetSystemInfo(reinterpret_cast< ::_SYSTEM_INFO* >(lpSystemInfo)); } + +#endif //BOOST_WINAPI_PARTITION_APP_SYSTEM + +} //namespace ipwinapiext { +} //namespace boost { + +namespace boost { +namespace interprocess { +namespace winapi { + +typedef boost::winapi::SYSTEM_INFO_ interprocess_system_info; +typedef boost::winapi::OVERLAPPED_ interprocess_overlapped; +typedef boost::winapi::FILETIME_ interprocess_filetime; +typedef boost::winapi::WIN32_FIND_DATAA_ win32_find_data_a; +typedef boost::winapi::WIN32_FIND_DATAW_ win32_find_data_w; +typedef boost::winapi::SECURITY_ATTRIBUTES_ interprocess_security_attributes; +typedef boost::winapi::SECURITY_DESCRIPTOR_ interprocess_security_descriptor; +typedef boost::winapi::BY_HANDLE_FILE_INFORMATION_ interprocess_by_handle_file_information; +typedef boost::winapi::HMODULE_ hmodule; +typedef boost::ipwinapiext::HKEY_ hkey; +typedef boost::winapi::FARPROC_ farproc_t; //ntdll.dll typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes); @@ -1177,27 +629,6 @@ const unsigned long max_path = 260; static const hkey hkey_local_machine = (hkey)(unsigned long*)(long)(0x80000002); static unsigned long key_query_value = 0x0001; -//COM API -const unsigned long RPC_C_AUTHN_LEVEL_PKT_BIPC = 4; -const unsigned long RPC_C_AUTHN_DEFAULT_BIPC = 0xffffffffL; -const unsigned long RPC_C_AUTHZ_DEFAULT_BIPC = 0xffffffffL; -const unsigned long RPC_C_IMP_LEVEL_IMPERSONATE_BIPC = 3; -const signed long EOAC_NONE_BIPC = 0; -const signed long CLSCTX_INPROC_SERVER_BIPC = 0x1; -const signed long CLSCTX_LOCAL_SERVER_BIPC = 0x4; -const signed long WBEM_FLAG_RETURN_IMMEDIATELY_BIPC = 0x10; -const signed long WBEM_FLAG_RETURN_WHEN_COMPLETE_BIPC = 0x0; -const signed long WBEM_FLAG_FORWARD_ONLY_BIPC = 0x20; -const signed long WBEM_INFINITE_BIPC = 0xffffffffL; -const signed long RPC_E_TOO_LATE_BIPC = 0x80010119L; -const signed long S_OK_BIPC = 0L; -const signed long S_FALSE_BIPC = 1; -const signed long RPC_E_CHANGED_MODE_BIPC = 0x80010106L; -const unsigned long COINIT_APARTMENTTHREADED_BIPC = 0x2; -const unsigned long COINIT_MULTITHREADED_BIPC = 0x0; -const unsigned long COINIT_DISABLE_OLE1DDE_BIPC = 0x4; -const unsigned long COINIT_SPEED_OVER_MEMORY_BIPC = 0x4; - // Registry types #define reg_none ( 0 ) // No value type #define reg_sz ( 1 ) // Unicode nul terminated string @@ -1216,30 +647,6 @@ const unsigned long COINIT_SPEED_OVER_MEMORY_BIPC = 0x4; #define reg_qword_little_endian ( 11 ) // 64-bit number (same as reg_qword) -//If the user needs to change default COM initialization model, -//it can define BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL to one of these: -// -// COINIT_APARTMENTTHREADED_BIPC -// COINIT_MULTITHREADED_BIPC -// COINIT_DISABLE_OLE1DDE_BIPC -// COINIT_SPEED_OVER_MEMORY_BIPC -#if !defined(BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL) - #define BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL COINIT_APARTMENTTHREADED_BIPC -#elif (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_APARTMENTTHREADED_BIPC) &&\ - (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_MULTITHREADED_BIPC) &&\ - (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_DISABLE_OLE1DDE_BIPC) &&\ - (BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL != COINIT_SPEED_OVER_MEMORY_BIPC) - #error "Wrong value for BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL macro" -#endif - -const GUID_BIPC CLSID_WbemAdministrativeLocator = - { 0xcb8555cc, 0x9128, 0x11d1, {0xad, 0x9b, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff}}; - -const GUID_BIPC IID_IUnknown = { 0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; - -static const unsigned long eventlog_sequential_read = 0x0001; -static const unsigned long eventlog_backwards_read = 0x0008; - } //namespace winapi { } //namespace interprocess { } //namespace boost { @@ -1269,7 +676,11 @@ inline void * local_free(void *hmem) { return LocalFree(hmem); } inline unsigned long make_lang_id(unsigned long p, unsigned long s) -{ return ((((unsigned short)(s)) << 10) | (unsigned short)(p)); } +{ + const unsigned short s_us = (unsigned short)s; + const unsigned short p_us = (unsigned short)p; + return (unsigned long)((s_us << 10) | p_us); +} inline void sched_yield() { @@ -1296,15 +707,21 @@ inline bool get_process_times inline unsigned long get_current_process_id() { return GetCurrentProcessId(); } -inline unsigned int close_handle(void* handle) -{ return CloseHandle(handle); } +inline bool close_handle(void* handle) +{ return CloseHandle(handle) != 0; } -inline void * find_first_file(const char *lpFileName, win32_find_data *lpFindFileData) +inline void * find_first_file(const char *lpFileName, win32_find_data_a *lpFindFileData) { return FindFirstFileA(lpFileName, lpFindFileData); } -inline bool find_next_file(void *hFindFile, win32_find_data *lpFindFileData) +inline void * find_first_file(const wchar_t *lpFileName, win32_find_data_w *lpFindFileData) +{ return FindFirstFileW(lpFileName, lpFindFileData); } + +inline bool find_next_file(void *hFindFile, win32_find_data_a *lpFindFileData) { return FindNextFileA(hFindFile, lpFindFileData) != 0; } +inline bool find_next_file(void *hFindFile, win32_find_data_w *lpFindFileData) +{ return FindNextFileW(hFindFile, lpFindFileData) != 0; } + inline bool find_close(void *handle) { return FindClose(handle) != 0; } @@ -1333,6 +750,9 @@ inline bool file_time_to_local_file_time inline void *open_or_create_mutex(const char *name, bool initial_owner, interprocess_security_attributes *attr) { return CreateMutexA(attr, (int)initial_owner, name); } +inline void *open_or_create_mutex(const wchar_t *name, bool initial_owner, interprocess_security_attributes *attr) +{ return CreateMutexW(attr, (int)initial_owner, name); } + inline unsigned long wait_for_single_object(void *handle, unsigned long time) { return WaitForSingleObject(handle, time); } @@ -1345,9 +765,15 @@ inline int unmap_view_of_file(void *address) inline void *open_or_create_semaphore(const char *name, long initial_count, long maximum_count, interprocess_security_attributes *attr) { return CreateSemaphoreA(attr, initial_count, maximum_count, name); } +inline void *open_or_create_semaphore(const wchar_t *name, long initial_count, long maximum_count, interprocess_security_attributes *attr) +{ return CreateSemaphoreW(attr, initial_count, maximum_count, name); } + inline void *open_semaphore(const char *name) { return OpenSemaphoreA(semaphore_all_access, 0, name); } +inline void *open_semaphore(const wchar_t *name) +{ return OpenSemaphoreW(semaphore_all_access, 0, name); } + inline int release_semaphore(void *handle, long release_count, long *prev_count) { return ReleaseSemaphore(handle, release_count, prev_count); } @@ -1361,14 +787,14 @@ class interprocess_all_access_security interprocess_all_access_security() : initialized(false) { - if(!InitializeSecurityDescriptor(&sd, security_descriptor_revision)) + if(!boost::winapi::InitializeSecurityDescriptor(&sd, security_descriptor_revision)) return; - if(!SetSecurityDescriptorDacl(&sd, true, 0, false)) + if(!boost::winapi::SetSecurityDescriptorDacl(&sd, true, 0, false)) return; sa.lpSecurityDescriptor = &sd; sa.nLength = sizeof(interprocess_security_attributes); sa.bInheritHandle = false; - initialized = false; + initialized = true; } interprocess_security_attributes *get_attributes() @@ -1377,24 +803,36 @@ class interprocess_all_access_security inline void * create_file_mapping (void * handle, unsigned long access, ::boost::ulong_long_type file_offset, const char * name, interprocess_security_attributes *psec) { - const unsigned long high_size(file_offset >> 32), low_size((boost::uint32_t)file_offset); + const boost::winapi::DWORD_ high_size = boost::winapi::DWORD_(file_offset >> 32); + const boost::winapi::DWORD_ low_size = boost::winapi::DWORD_(file_offset); return CreateFileMappingA (handle, psec, access, high_size, low_size, name); } +inline void * create_file_mapping (void * handle, unsigned long access, ::boost::ulong_long_type file_offset, const wchar_t * name, interprocess_security_attributes *psec) +{ + const boost::winapi::DWORD_ high_size = boost::winapi::DWORD_(file_offset >> 32); + const boost::winapi::DWORD_ low_size = boost::winapi::DWORD_(file_offset); + return CreateFileMappingW (handle, psec, access, high_size, low_size, name); +} + inline void * open_file_mapping (unsigned long access, const char *name) { return OpenFileMappingA (access, 0, name); } +inline void * open_file_mapping (unsigned long access, const wchar_t *name) +{ return OpenFileMappingW (access, 0, name); } + inline void *map_view_of_file_ex(void *handle, unsigned long file_access, ::boost::ulong_long_type offset, std::size_t numbytes, void *base_addr) { - const unsigned long offset_low = (unsigned long)(offset & ((::boost::ulong_long_type)0xFFFFFFFF)); - const unsigned long offset_high = offset >> 32; + const boost::winapi::DWORD_ offset_low = boost::winapi::DWORD_(offset & ((::boost::ulong_long_type)0xFFFFFFFF)); + const boost::winapi::DWORD_ offset_high = boost::winapi::DWORD_(offset >> 32); return MapViewOfFileEx(handle, file_access, offset_high, offset_low, numbytes, base_addr); } -inline void *create_file(const char *name, unsigned long access, unsigned long creation_flags, unsigned long attributes, interprocess_security_attributes *psec) +template<class CharT> +inline void *create_file(const CharT *name, unsigned long access, unsigned long creation_flags, unsigned long attributes, interprocess_security_attributes *psec) { for (unsigned int attempt(0); attempt < error_sharing_violation_tries; ++attempt){ - void * const handle = CreateFileA(name, access, + void * const handle = boost::winapi::create_file(name, access, file_share_read | file_share_write | file_share_delete, psec, creation_flags, attributes, 0); bool const invalid(invalid_handle_value == handle); @@ -1409,59 +847,68 @@ inline void *create_file(const char *name, unsigned long access, unsigned long c return invalid_handle_value; } -inline void get_system_info(system_info *info) -{ GetSystemInfo(info); } +inline void get_system_info(interprocess_system_info *info) +{ boost::ipwinapiext::GetSystemInfo(info); } inline bool flush_view_of_file(void *base_addr, std::size_t numbytes) -{ return 0 != FlushViewOfFile(base_addr, numbytes); } +{ return 0 != boost::winapi::FlushViewOfFile(base_addr, numbytes); } inline bool virtual_unlock(void *base_addr, std::size_t numbytes) -{ return 0 != VirtualUnlock(base_addr, numbytes); } +{ return 0 != boost::ipwinapiext::VirtualUnlock(base_addr, numbytes); } inline bool virtual_protect(void *base_addr, std::size_t numbytes, unsigned long flNewProtect, unsigned long &lpflOldProtect) -{ return 0 != VirtualProtect(base_addr, numbytes, flNewProtect, &lpflOldProtect); } +{ return 0 != boost::ipwinapiext::VirtualProtect(base_addr, numbytes, flNewProtect, &lpflOldProtect); } inline bool flush_file_buffers(void *handle) -{ return 0 != FlushFileBuffers(handle); } +{ return 0 != boost::ipwinapiext::FlushFileBuffers(handle); } inline bool get_file_size(void *handle, __int64 &size) -{ return 0 != GetFileSizeEx(handle, (large_integer*)&size); } +{ return 0 != boost::winapi::GetFileSizeEx(handle, (boost::winapi::LARGE_INTEGER_*)&size); } -inline bool create_directory(const char *name) +template<class CharT> +inline bool create_directory(const CharT *name) { interprocess_all_access_security sec; - return 0 != CreateDirectoryA(name, sec.get_attributes()); + return 0 != boost::winapi::create_directory(name, sec.get_attributes()); } -inline bool remove_directory(const char *lpPathName) -{ return 0 != RemoveDirectoryA(lpPathName); } +template<class CharT> +inline bool remove_directory(const CharT *lpPathName) +{ return 0 != boost::winapi::remove_directory(lpPathName); } -inline unsigned long get_temp_path(unsigned long length, char *buffer) -{ return GetTempPathA(length, buffer); } +template<class CharT> +inline unsigned long get_temp_path(unsigned long length, CharT *buffer) +{ return boost::winapi::get_temp_path(length, buffer); } inline int set_end_of_file(void *handle) -{ return 0 != SetEndOfFile(handle); } +{ return 0 != boost::winapi::SetEndOfFile(handle); } -inline bool set_file_pointer_ex(void *handle, __int64 distance, __int64 *new_file_pointer, unsigned long move_method) +inline bool set_file_pointer(void *handle, __int64 distance, __int64 *new_file_pointer, unsigned long move_method) { - large_integer d; d.QuadPart = distance; - return 0 != SetFilePointerEx(handle, d, (large_integer*)new_file_pointer, move_method); + boost::winapi::LONG_ highPart = boost::winapi::LONG_(distance >> 32u); + boost::winapi::DWORD_ r = boost::winapi::SetFilePointer(handle, (long)distance, &highPart, move_method); + bool br = r != boost::winapi::INVALID_SET_FILE_POINTER_ || boost::winapi::GetLastError() != 0; + if (br && new_file_pointer){ + *new_file_pointer = (__int64)r + ((__int64)highPart << 32); + } + + return br; } inline bool lock_file_ex(void *hnd, unsigned long flags, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped *overlapped) -{ return 0 != LockFileEx(hnd, flags, reserved, size_low, size_high, overlapped); } +{ return 0 != boost::winapi::LockFileEx(hnd, flags, reserved, size_low, size_high, overlapped); } inline bool unlock_file_ex(void *hnd, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped *overlapped) -{ return 0 != UnlockFileEx(hnd, reserved, size_low, size_high, overlapped); } +{ return 0 != boost::winapi::UnlockFileEx(hnd, reserved, size_low, size_high, overlapped); } inline bool write_file(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped) -{ return 0 != WriteFile(hnd, buffer, bytes_to_write, bytes_written, overlapped); } +{ return 0 != boost::winapi::WriteFile(hnd, buffer, bytes_to_write, bytes_written, overlapped); } inline bool read_file(void *hnd, void *buffer, unsigned long bytes_to_read, unsigned long *bytes_read, interprocess_overlapped* overlapped) -{ return 0 != ReadFile(hnd, buffer, bytes_to_read, bytes_read, overlapped); } +{ return 0 != boost::winapi::ReadFile(hnd, buffer, bytes_to_read, bytes_read, overlapped); } inline bool get_file_information_by_handle(void *hnd, interprocess_by_handle_file_information *info) -{ return 0 != GetFileInformationByHandle(hnd, info); } +{ return 0 != boost::winapi::GetFileInformationByHandle(hnd, info); } inline long interlocked_increment(long volatile *addr) { return BOOST_INTERLOCKED_INCREMENT(const_cast<long*>(addr)); } @@ -1480,28 +927,35 @@ inline long interlocked_exchange(long volatile* addend, long value) //Forward functions inline hmodule load_library(const char *name) -{ return LoadLibraryA(name); } +{ return boost::winapi::LoadLibraryA(name); } inline bool free_library(hmodule module) -{ return 0 != FreeLibrary(module); } +{ return 0 != boost::winapi::FreeLibrary(module); } inline farproc_t get_proc_address(hmodule module, const char *name) -{ return GetProcAddress(module, name); } +{ return boost::winapi::GetProcAddress(module, name); } inline void *get_current_process() -{ return GetCurrentProcess(); } +{ return boost::winapi::GetCurrentProcess(); } inline hmodule get_module_handle(const char *name) -{ return GetModuleHandleA(name); } +{ return boost::winapi::GetModuleHandleA(name); } inline long reg_open_key_ex(hkey hKey, const char *lpSubKey, unsigned long ulOptions, unsigned long samDesired, hkey *phkResult) -{ return RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult); } +{ return boost::ipwinapiext::RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult); } + +inline long reg_open_key_ex(hkey hKey, const wchar_t *lpSubKey, unsigned long ulOptions, unsigned long samDesired, hkey *phkResult) +{ return boost::ipwinapiext::RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult); } + inline long reg_query_value_ex(hkey hKey, const char *lpValueName, unsigned long*lpReserved, unsigned long*lpType, unsigned char *lpData, unsigned long*lpcbData) -{ return RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } +{ return boost::ipwinapiext::RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } + +inline long reg_query_value_ex(hkey hKey, const wchar_t *lpValueName, unsigned long*lpReserved, unsigned long*lpType, unsigned char *lpData, unsigned long*lpcbData) +{ return boost::ipwinapiext::RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } inline long reg_close_key(hkey hKey) -{ return RegCloseKey(hKey); } +{ return boost::ipwinapiext::RegCloseKey(hKey); } inline void initialize_object_attributes ( object_attributes_t *pobject_attr, unicode_string_t *name @@ -1535,9 +989,6 @@ struct function_address_holder , NtOpenFile , NtClose , NtQueryTimerResolution - , NtSetTimerResolution - , QueryPerformanceCounter - , QueryPerformanceFrequency , NumFunction }; enum { NtDll_dll, Kernel32_dll, NumModule }; @@ -1618,9 +1069,6 @@ const char *function_address_holder<Dummy>::FunctionNames[function_address_holde "NtOpenFile", "NtClose", "NtQueryTimerResolution", - "NtSetTimerResolution", - "QueryPerformanceCounter", - "QueryPerformanceFrequency" }; template<int Dummy> @@ -1634,16 +1082,12 @@ unsigned int function_address_holder<Dummy>::FunctionModules[function_address_ho NtDll_dll, NtDll_dll, NtDll_dll, - NtDll_dll, - Kernel32_dll, - Kernel32_dll }; template<int Dummy> const char *function_address_holder<Dummy>::ModuleNames[function_address_holder<Dummy>::NumModule] = { - "ntdll.dll", - "kernel32.dll" + "ntdll.dll"//, "kernel32.dll" }; @@ -1675,8 +1119,8 @@ struct library_unloader inline bool get_system_time_of_day_information(system_timeofday_information &info) { - NtQuerySystemInformation_t pNtQuerySystemInformation = (NtQuerySystemInformation_t) - dll_func::get(dll_func::NtQuerySystemInformation); + NtQuerySystemInformation_t pNtQuerySystemInformation = reinterpret_cast<NtQuerySystemInformation_t> + (dll_func::get(dll_func::NtQuerySystemInformation)); unsigned long res; long status = pNtQuerySystemInformation(system_time_of_day_information, &info, sizeof(info), &res); if(status){ @@ -1780,17 +1224,6 @@ class handle_closer { close_handle(handle_); } }; -class eventlog_handle_closer -{ - void *handle_; - eventlog_handle_closer(const handle_closer &); - eventlog_handle_closer& operator=(const eventlog_handle_closer &); - public: - explicit eventlog_handle_closer(void *handle) : handle_(handle){} - ~eventlog_handle_closer() - { CloseEventLog(handle_); } -}; - union ntquery_mem_t { object_name_information_t name; @@ -1807,11 +1240,11 @@ class nt_query_mem_deleter offsetof(ntquery_mem_t, name.Name.Buffer); // Timestamp process id atomic count static const std::size_t rename_suffix = - (SystemTimeOfDayInfoLength + sizeof(unsigned long) + sizeof(boost::uint32_t))*2; + (SystemTimeOfDayInfoLength + sizeof(unsigned long) + sizeof(boost::winapi::DWORD_))*2; public: - explicit nt_query_mem_deleter(std::size_t object_name_information_size) - : m_size(object_name_information_size + rename_offset + rename_suffix) + explicit nt_query_mem_deleter(std::size_t object_name_info_size) + : m_size(object_name_info_size + rename_offset + rename_suffix) , m_buf(new char [m_size]) {} @@ -1859,10 +1292,10 @@ class c_heap_deleter void realloc_mem(std::size_t num_bytes) { - void *buf = ::realloc(m_buf, num_bytes); - if(!buf){ - free(m_buf); - m_buf = 0; + void *oldBuf = m_buf; + m_buf = ::realloc(m_buf, num_bytes); + if (!m_buf){ + free(oldBuf); } } @@ -1873,7 +1306,8 @@ class c_heap_deleter void *m_buf; }; -inline bool unlink_file(const char *filename) +template<class CharT> +inline bool unlink_file(const CharT *filename) { //Don't try to optimize doing a DeleteFile first //as there are interactions with permissions and @@ -1890,11 +1324,11 @@ inline bool unlink_file(const char *filename) //- Close the handle. If there are no file users, it will be deleted. // Otherwise it will be used by already connected handles but the // file name can't be used to open this file again - try{ + BOOST_TRY{ NtSetInformationFile_t pNtSetInformationFile = - (NtSetInformationFile_t)dll_func::get(dll_func::NtSetInformationFile); + reinterpret_cast<NtSetInformationFile_t>(dll_func::get(dll_func::NtSetInformationFile)); - NtQueryObject_t pNtQueryObject = (NtQueryObject_t)dll_func::get(dll_func::NtQueryObject); + NtQueryObject_t pNtQueryObject = reinterpret_cast<NtQueryObject_t>(dll_func::get(dll_func::NtQueryObject)); //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths void *fh = create_file(filename, generic_read | delete_access, open_existing, 0, 0); @@ -1920,7 +1354,7 @@ inline bool unlink_file(const char *filename) ntquery_mem_t *pmem = nt_query_mem.query_mem(); file_rename_information_t *pfri = &pmem->ren.info; const std::size_t RenMaxNumChars = - (((char*)(pmem) + nt_query_mem.file_rename_information_size()) - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); + std::size_t(((char*)(pmem) + nt_query_mem.file_rename_information_size()) - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); //Copy filename to the rename member std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); @@ -1966,8 +1400,8 @@ inline bool unlink_file(const char *filename) { //Don't use pNtSetInformationFile with file_disposition_information as it can return STATUS_CANNOT_DELETE //if the file is still mapped. Reopen it with NtOpenFile and file_delete_on_close - NtOpenFile_t pNtOpenFile = (NtOpenFile_t)dll_func::get(dll_func::NtOpenFile); - NtClose_t pNtClose = (NtClose_t)dll_func::get(dll_func::NtClose); + NtOpenFile_t pNtOpenFile = reinterpret_cast<NtOpenFile_t>(dll_func::get(dll_func::NtOpenFile)); + NtClose_t pNtClose = reinterpret_cast<NtClose_t>(dll_func::get(dll_func::NtClose)); const wchar_t empty_str [] = L""; unicode_string_t ustring = { sizeof(empty_str) - sizeof (wchar_t) //length in bytes without null , sizeof(empty_str) //total size in bytes of memory allocated for Buffer. @@ -1984,9 +1418,9 @@ inline bool unlink_file(const char *filename) return true; } } - catch(...){ + BOOST_CATCH(...){ return false; - } + } BOOST_CATCH_END return true; } @@ -1997,7 +1431,8 @@ struct reg_closer ~reg_closer(){ reg_close_key(key_); } }; -inline bool get_registry_value_buffer(hkey key_type, const char *subkey_name, const char *value_name, void *buf, std::size_t &buflen) +template <class CharT> +inline bool get_registry_value_buffer(hkey key_type, const CharT *subkey_name, const CharT *value_name, void *buf, std::size_t &buflen) { bool bret = false; hkey key; @@ -2019,7 +1454,8 @@ inline bool get_registry_value_buffer(hkey key_type, const char *subkey_name, co return bret; } -inline bool get_registry_value_string(hkey key_type, const char *subkey_name, const char *value_name, std::string &s) +template<class CharT> +inline bool get_registry_value_string(hkey key_type, const CharT *subkey_name, const CharT *value_name, std::basic_string<CharT> &s) { bool bret = false; s.clear(); @@ -2037,7 +1473,7 @@ inline bool get_registry_value_string(hkey key_type, const char *subkey_name, co long err = reg_query_value_ex( key, value_name, 0, &type, 0, &size); if((reg_sz == type || reg_expand_sz == type) && !err){ //Size includes terminating NULL - s.resize(size); + s.resize(size/sizeof(CharT)); err = reg_query_value_ex( key, value_name, 0, &type, (unsigned char*)(&s[0]), &size); if(!err){ s.erase(s.end()-1); @@ -2049,28 +1485,25 @@ inline bool get_registry_value_string(hkey key_type, const char *subkey_name, co return bret; } -inline void get_shared_documents_folder(std::string &s) +template<class CharT> +inline void get_shared_documents_folder(std::basic_string<CharT> &s) { - #if 1 //Original registry search code get_registry_value_string( hkey_local_machine , "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" , "Common AppData" , s); - #else //registry alternative: SHGetFolderPath - const int BIPC_CSIDL_COMMON_APPDATA = 0x0023; // All Users\Application Data - const int BIPC_CSIDL_FLAG_CREATE = 0x8000; // new for Win2K, or this in to force creation of folder - const int BIPC_SHGFP_TYPE_CURRENT = 0; // current value for user, verify it exists - - s.clear(); - char szPath[max_path]; - if(0 == SHGetFolderPathA(0, BIPC_CSIDL_COMMON_APPDATA | BIPC_CSIDL_FLAG_CREATE, 0, BIPC_SHGFP_TYPE_CURRENT, szPath)){ - s = szPath; - } +} - #endif +inline void get_shared_documents_folder(std::wstring &s) +{ + get_registry_value_string( hkey_local_machine + , L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" + , L"Common AppData" + , s); } -inline void get_registry_value(const char *folder, const char *value_key, std::vector<unsigned char> &s) +template<class CharT> +inline void get_registry_value(const CharT *folder, const CharT *value_key, std::vector<unsigned char> &s) { s.clear(); hkey key; @@ -2099,191 +1532,201 @@ inline void get_registry_value(const char *folder, const char *value_key, std::v } } -#if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME) +inline bool is_directory(const char *path) +{ + unsigned long attrib = GetFileAttributesA(path); -struct co_uninitializer + return (attrib != invalid_file_attributes && + (attrib & file_attribute_directory)); +} + +inline bool get_file_mapping_size(void *file_mapping_hnd, __int64 &size) { - co_uninitializer(bool b_uninitialize) - : m_b_uninitialize(b_uninitialize) - {} + NtQuerySection_t pNtQuerySection = + reinterpret_cast<NtQuerySection_t>(dll_func::get(dll_func::NtQuerySection)); + //Obtain file name + interprocess_section_basic_information info; + long ntstatus = + pNtQuerySection(file_mapping_hnd, section_basic_information, &info, sizeof(info), 0); + size = info.section_size; + return !ntstatus; +} - ~co_uninitializer() - { - if(m_b_uninitialize){ - CoUninitialize(); - } - } +inline bool get_semaphore_info(void *handle, long &count, long &limit) +{ + winapi::interprocess_semaphore_basic_information info; + winapi::NtQuerySemaphore_t pNtQuerySemaphore = + reinterpret_cast<winapi::NtQuerySemaphore_t>(dll_func::get(winapi::dll_func::NtQuerySemaphore)); + unsigned int ret_len; + long status = pNtQuerySemaphore(handle, winapi::semaphore_basic_information, &info, sizeof(info), &ret_len); + count = (long)info.count; + limit = (long)info.limit; + return !status; +} - private: - const bool m_b_uninitialize; -}; +inline bool query_timer_resolution(unsigned long *lowres, unsigned long *highres, unsigned long *curres) +{ + winapi::NtQueryTimerResolution_t pNtQueryTimerResolution = + reinterpret_cast<winapi::NtQueryTimerResolution_t>(dll_func::get(winapi::dll_func::NtQueryTimerResolution)); + return !pNtQueryTimerResolution(lowres, highres, curres); +} -template<class Object> -struct com_releaser +inline bool query_performance_counter(__int64 *lpPerformanceCount) { - Object *&object_; - com_releaser(Object *&object) : object_(object) {} - ~com_releaser() { object_->Release(); object_ = 0; } -}; + return 0 != boost::winapi::QueryPerformanceCounter(reinterpret_cast<boost::winapi::LARGE_INTEGER_*>(lpPerformanceCount)); +} -inline bool get_wmi_class_attribute( std::wstring& strValue, const wchar_t *wmi_class, const wchar_t *wmi_class_var) +inline bool query_performance_frequency(__int64 *lpFrequency) { - //See example http://msdn.microsoft.com/en-us/library/aa390423%28v=VS.85%29.aspx - // - //See BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL definition if you need to change the - //default value of this macro in your application - long co_init_ret = CoInitializeEx(0, BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL); - if(co_init_ret != S_OK_BIPC && co_init_ret != S_FALSE_BIPC && co_init_ret != RPC_E_CHANGED_MODE_BIPC) - return false; - co_uninitializer co_initialize_end(co_init_ret != RPC_E_CHANGED_MODE_BIPC); - (void)co_initialize_end; - - bool bRet = false; - long sec_init_ret = CoInitializeSecurity - ( 0 //pVoid - ,-1 //cAuthSvc - , 0 //asAuthSvc - , 0 //pReserved1 - , RPC_C_AUTHN_LEVEL_PKT_BIPC //dwAuthnLevel - , RPC_C_IMP_LEVEL_IMPERSONATE_BIPC //dwImpLevel - , 0 //pAuthList - , EOAC_NONE_BIPC //dwCapabilities - , 0 //pReserved3 - ); - if( 0 == sec_init_ret || RPC_E_TOO_LATE_BIPC == sec_init_ret) - { - IWbemLocator_BIPC * pIWbemLocator = 0; - const wchar_t * bstrNamespace = L"root\\cimv2"; - - if( 0 != CoCreateInstance( - CLSID_WbemAdministrativeLocator, - 0, - CLSCTX_INPROC_SERVER_BIPC | CLSCTX_LOCAL_SERVER_BIPC, - IID_IUnknown, (void **)&pIWbemLocator)){ - return false; - } + return 0 != boost::winapi::QueryPerformanceFrequency(reinterpret_cast<boost::winapi::LARGE_INTEGER_*>(lpFrequency)); +} - com_releaser<IWbemLocator_BIPC> IWbemLocator_releaser(pIWbemLocator); - - IWbemServices_BIPC *pWbemServices = 0; - - if( 0 != pIWbemLocator->ConnectServer( - (bstr)bstrNamespace, // Namespace - 0, // Userid - 0, // PW - 0, // Locale - 0, // flags - 0, // Authority - 0, // Context - &pWbemServices - ) - ){ - return false; - } +inline unsigned long get_tick_count() +{ return GetTickCount(); } - if( S_OK_BIPC != CoSetProxyBlanket( - pWbemServices, - RPC_C_AUTHN_DEFAULT_BIPC, - RPC_C_AUTHZ_DEFAULT_BIPC, - 0, - RPC_C_AUTHN_LEVEL_PKT_BIPC, - RPC_C_IMP_LEVEL_IMPERSONATE_BIPC, - 0, - EOAC_NONE_BIPC - ) - ){ - return false; - } - com_releaser<IWbemServices_BIPC> IWbemServices_releaser(pWbemServices); - - strValue.clear(); - strValue += L"Select "; - strValue += wmi_class_var; - strValue += L" from "; - strValue += wmi_class; - - IEnumWbemClassObject_BIPC * pEnumObject = 0; - - if ( 0 != pWbemServices->ExecQuery( - (bstr)L"WQL", - (bstr)strValue.c_str(), - //WBEM_FLAG_RETURN_IMMEDIATELY_BIPC, - WBEM_FLAG_RETURN_WHEN_COMPLETE_BIPC | WBEM_FLAG_FORWARD_ONLY_BIPC, - 0, - &pEnumObject - ) - ){ - return false; - } +template<class CharT> +struct winapi_traits; - com_releaser<IEnumWbemClassObject_BIPC> IEnumWbemClassObject_releaser(pEnumObject); +template<> +struct winapi_traits<char> +{ + static int cmp(const char *a, const char *b) + { return std::strcmp(a, b); } +}; + +template<> +struct winapi_traits<wchar_t> +{ + static int cmp(const wchar_t *a, const wchar_t *b) + { return std::wcscmp(a, b); } +}; + + +#if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED) - //WBEM_FLAG_FORWARD_ONLY_BIPC incompatible with Reset - //if ( 0 != pEnumObject->Reset() ){ - //return false; - //} - wchar_variant vwchar; - unsigned long uCount = 1, uReturned; - IWbemClassObject_BIPC * pClassObject = 0; - while( 0 == pEnumObject->Next( WBEM_INFINITE_BIPC, uCount, &pClassObject, &uReturned ) ) +inline bool get_last_bootup_time(std::string &stamp) +{ + unsigned dword_val = 0; + std::size_t dword_size = sizeof(dword_val); + bool b_ret = get_registry_value_buffer( hkey_local_machine + , "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters" + , "BootId", &dword_val, dword_size); + if (b_ret) + { + char dword_str[sizeof(dword_val)*2u+1]; + buffer_to_narrow_str(&dword_val, dword_size, dword_str); + dword_str[sizeof(dword_val)*2] = '\0'; + stamp = dword_str; + + b_ret = get_registry_value_buffer( hkey_local_machine + , "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power" + , "HybridBootAnimationTime", &dword_val, dword_size); + //Old Windows versions have no HybridBootAnimationTime + if(b_ret) { - com_releaser<IWbemClassObject_BIPC> IWbemClassObject_releaser(pClassObject); - if ( 0 == pClassObject->Get( (bstr)L"LastBootUpTime", 0, &vwchar, 0, 0 ) ){ - bRet = true; - strValue = (wchar_t*)vwchar.bstrVal; - VariantClear(&vwchar ); - break; - } + buffer_to_narrow_str(&dword_val, dword_size, dword_str); + dword_str[sizeof(dword_val)*2] = '\0'; + stamp += "_"; + stamp += dword_str; } + b_ret = true; } - return bRet; + return b_ret; } -//Obtains the bootup time from WMI LastBootUpTime. -//This time seems to change with hibernation and clock synchronization so avoid it. -inline bool get_last_bootup_time( std::wstring& strValue ) +inline bool get_last_bootup_time(std::wstring &stamp) { - bool ret = get_wmi_class_attribute(strValue, L"Win32_OperatingSystem", L"LastBootUpTime"); - std::size_t timezone = strValue.find(L'+'); - if(timezone != std::wstring::npos){ - strValue.erase(timezone); - } - timezone = strValue.find(L'-'); - if(timezone != std::wstring::npos){ - strValue.erase(timezone); - } - return ret; -} + unsigned dword_val = 0; + std::size_t dword_size = sizeof(dword_val); + bool b_ret = get_registry_value_buffer( hkey_local_machine + , L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters" + , L"BootId", &dword_val, dword_size); + if (b_ret) + { + wchar_t dword_str[sizeof(dword_val)*2u+1]; + buffer_to_wide_str(&dword_val, dword_size, dword_str); + dword_str[sizeof(dword_val)*2] = L'\0'; + stamp = dword_str; -inline bool get_last_bootup_time( std::string& str ) -{ - std::wstring wstr; - bool ret = get_last_bootup_time(wstr); - str.resize(wstr.size()); - for(std::size_t i = 0, max = str.size(); i != max; ++i){ - str[i] = '0' + (wstr[i]-L'0'); + b_ret = get_registry_value_buffer( hkey_local_machine + , L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power" + , L"HybridBootAnimationTime", &dword_val, dword_size); + //Old Windows versions have no HybridBootAnimationTime + if(b_ret) + { + buffer_to_wide_str(&dword_val, dword_size, dword_str); + dword_str[sizeof(dword_val)*2] = L'\0'; + stamp += L"_"; + stamp += dword_str; + } + b_ret = true; } - return ret; + return b_ret; } -#endif //BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME +#elif defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED) -#if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED) +static const unsigned long eventlog_sequential_read = 0x0001; +static const unsigned long eventlog_backwards_read = 0x0008; + +struct interprocess_eventlogrecord +{ + unsigned long Length; // Length of full record + unsigned long Reserved; // Used by the service + unsigned long RecordNumber; // Absolute record number + unsigned long TimeGenerated; // Seconds since 1-1-1970 + unsigned long TimeWritten; // Seconds since 1-1-1970 + unsigned long EventID; + unsigned short EventType; + unsigned short NumStrings; + unsigned short EventCategory; + unsigned short ReservedFlags; // For use with paired events (auditing) + unsigned long ClosingRecordNumber; // For use with paired events (auditing) + unsigned long StringOffset; // Offset from beginning of record + unsigned long UserSidLength; + unsigned long UserSidOffset; + unsigned long DataLength; + unsigned long DataOffset; // Offset from beginning of record + // + // Then follow: + // + // wchar_t SourceName[] + // wchar_t Computername[] + // SID UserSid + // wchar_t Strings[] + // BYTE Data[] + // CHAR Pad[] + // unsigned long Length; + // +}; + +class eventlog_handle_closer +{ + void *handle_; + eventlog_handle_closer(const handle_closer &); + eventlog_handle_closer& operator=(const eventlog_handle_closer &); + public: + explicit eventlog_handle_closer(void *handle) : handle_(handle){} + ~eventlog_handle_closer() + { CloseEventLog(handle_); } +}; // Loop through the buffer and obtain the contents of the // requested record in the buffer. -inline bool find_record_in_buffer( const void* pBuffer, unsigned long dwBytesRead, const char *provider_name +template<class CharT> +inline bool find_record_in_buffer( const void* pBuffer, unsigned long dwBytesRead, const CharT *provider_name , unsigned int id_to_find, interprocess_eventlogrecord *&pevent_log_record) { const unsigned char * pRecord = static_cast<const unsigned char*>(pBuffer); const unsigned char * pEndOfRecords = pRecord + dwBytesRead; while (pRecord < pEndOfRecords){ - interprocess_eventlogrecord *pTypedRecord = (interprocess_eventlogrecord*)pRecord; + interprocess_eventlogrecord *pTypedRecord = (interprocess_eventlogrecord*)(void*)pRecord; // Check provider, written at the end of the fixed-part of the record - if (0 == std::strcmp(provider_name, (char*)(pRecord + sizeof(interprocess_eventlogrecord)))) + + if (0 == winapi_traits<CharT>::cmp(provider_name, (CharT*)(void*)(pRecord + sizeof(interprocess_eventlogrecord)))) { // Check event id if(id_to_find == (pTypedRecord->EventID & 0xFFFF)){ @@ -2366,104 +1809,74 @@ inline bool get_last_bootup_time(std::string &stamp) return true; } -#endif //BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED - -#if defined(BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED) - -inline bool get_last_bootup_time(std::string &stamp) -{ - unsigned dword_val = 0; - std::size_t dword_size = sizeof(dword_val); - bool b_ret = get_registry_value_buffer( hkey_local_machine - , "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters" - , "BootId", &dword_val, dword_size); - if (b_ret) - { - char dword_str[sizeof(dword_val)*2u+1]; - buffer_to_narrow_str(&dword_val, dword_size, dword_str); - dword_str[sizeof(dword_val)*2] = '\0'; - stamp = dword_str; - - b_ret = get_registry_value_buffer( hkey_local_machine - , "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power" - , "HybridBootAnimationTime", &dword_val, dword_size); - //Old Windows versions have no HybridBootAnimationTime - if(b_ret) - { - buffer_to_narrow_str(&dword_val, dword_size, dword_str); - dword_str[sizeof(dword_val)*2] = '\0'; - stamp += "_"; - stamp += dword_str; - } - b_ret = true; - } - return b_ret; -} - -#endif //BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED - -inline bool is_directory(const char *path) -{ - unsigned long attrib = GetFileAttributesA(path); - - return (attrib != invalid_file_attributes && - (attrib & file_attribute_directory)); -} - -inline bool get_file_mapping_size(void *file_mapping_hnd, __int64 &size) -{ - NtQuerySection_t pNtQuerySection = - (NtQuerySection_t)dll_func::get(dll_func::NtQuerySection); - //Obtain file name - interprocess_section_basic_information info; - unsigned long ntstatus = - pNtQuerySection(file_mapping_hnd, section_basic_information, &info, sizeof(info), 0); - size = info.section_size; - return !ntstatus; -} -inline bool get_semaphore_info(void *handle, long &count, long &limit) +inline bool get_last_bootup_time(std::wstring &stamp) { - winapi::interprocess_semaphore_basic_information info; - winapi::NtQuerySemaphore_t pNtQuerySemaphore = - (winapi::NtQuerySemaphore_t)dll_func::get(winapi::dll_func::NtQuerySemaphore); - unsigned int ret_len; - long status = pNtQuerySemaphore(handle, winapi::semaphore_basic_information, &info, sizeof(info), &ret_len); - count = info.count; - limit = info.limit; - return !status; -} + const wchar_t *source_name = L"System"; + const wchar_t *provider_name = L"EventLog"; + const unsigned short event_id = 6005u; -inline bool query_timer_resolution(unsigned long *lowres, unsigned long *highres, unsigned long *curres) -{ - winapi::NtQueryTimerResolution_t pNtQueryTimerResolution = - (winapi::NtQueryTimerResolution_t)dll_func::get(winapi::dll_func::NtQueryTimerResolution); - return !pNtQueryTimerResolution(lowres, highres, curres); -} + unsigned long status = 0; + unsigned long dwBytesToRead = 0; + unsigned long dwBytesRead = 0; + unsigned long dwMinimumBytesToRead = 0; -inline bool set_timer_resolution(unsigned long RequestedResolution, int Set, unsigned long* ActualResolution) -{ - winapi::NtSetTimerResolution_t pNtSetTimerResolution = - (winapi::NtSetTimerResolution_t)dll_func::get(winapi::dll_func::NtSetTimerResolution); - return !pNtSetTimerResolution(RequestedResolution, Set, ActualResolution); -} + // The source name (provider) must exist as a subkey of Application. + void *hEventLog = OpenEventLogW(0, source_name); + if (hEventLog){ + eventlog_handle_closer hnd_closer(hEventLog); (void)hnd_closer; + // Allocate an initial block of memory used to read event records. The number + // of records read into the buffer will vary depending on the size of each event. + // The size of each event will vary based on the size of the user-defined + // data included with each event, the number and length of insertion + // strings, and other data appended to the end of the event record. + dwBytesToRead = max_record_buffer_size; + c_heap_deleter heap_deleter(dwBytesToRead); -inline bool query_performance_counter(__int64 *lpPerformanceCount) -{ - QueryPerformanceCounter_t pQueryPerformanceCounter = (QueryPerformanceCounter_t) - dll_func::get(dll_func::QueryPerformanceCounter); - return 0 != pQueryPerformanceCounter(lpPerformanceCount); + // Read blocks of records until you reach the end of the log or an + // error occurs. The records are read from newest to oldest. If the buffer + // is not big enough to hold a complete event record, reallocate the buffer. + if (heap_deleter.get() != 0){ + while (0 == status){ + if (!ReadEventLogW(hEventLog, + eventlog_sequential_read | eventlog_backwards_read, + 0, + heap_deleter.get(), + dwBytesToRead, + &dwBytesRead, + &dwMinimumBytesToRead)) { + status = get_last_error(); + if (error_insufficient_buffer == status) { + status = 0; + dwBytesToRead = dwMinimumBytesToRead; + heap_deleter.realloc_mem(dwMinimumBytesToRead); + if (!heap_deleter.get()){ + return false; + } + } + else{ //Not found or EOF + return false; + } + } + else + { + interprocess_eventlogrecord *pTypedRecord; + // Print the contents of each record in the buffer. + if(find_record_in_buffer(heap_deleter.get(), dwBytesRead, provider_name, event_id, pTypedRecord)){ + wchar_t stamp_str[sizeof(unsigned long)*3+1]; + std::swprintf(&stamp_str[0], L"%u", ((unsigned int)pTypedRecord->TimeGenerated)); + stamp = stamp_str; + break; + } + } + } + } + } + return true; } -inline bool query_performance_frequency(__int64 *lpFrequency) -{ - QueryPerformanceCounter_t pQueryPerformanceFrequency = (QueryPerformanceFrequency_t) - dll_func::get(dll_func::QueryPerformanceFrequency); - return 0 != pQueryPerformanceFrequency(lpFrequency); -} +#endif //BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED -inline unsigned long get_tick_count() -{ return GetTickCount(); } } //namespace winapi } //namespace interprocess diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/windows_intermodule_singleton.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/windows_intermodule_singleton.hpp index 12ad2015e3..67ce199b85 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/windows_intermodule_singleton.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/windows_intermodule_singleton.hpp @@ -138,7 +138,7 @@ class windows_semaphore_based_map name = "bipc_gmap_sem_map_"; name += pid_creation_time; success = success && m_sem_map.open_or_create - (name.c_str(), initial_count, max_count, perm, created); + (name.c_str(), (long)initial_count, (long)max_count, perm, created); if(!success){ delete m; //winapi_xxx wrappers do the cleanup... @@ -163,8 +163,8 @@ class windows_semaphore_based_map boost::uint32_t addr_uint32; } caster; caster.addr = 0; - caster.addr_uint32 = m_sem_map.limit(); - caster.addr_uint32 = caster.addr_uint32 << 2; + caster.addr_uint32 = boost::uint32_t(m_sem_map.limit()); + caster.addr_uint32 = caster.addr_uint32 << 2u; return *static_cast<map_type*>(caster.addr); } else{ @@ -173,11 +173,12 @@ class windows_semaphore_based_map void *addr; boost::uint64_t addr_uint64; } caster; - boost::uint32_t max_count(m_sem_map.limit()), initial_count(m_sem_map.value()); + boost::uint32_t max_count(boost::uint32_t(m_sem_map.limit())) + , initial_count(boost::uint32_t(m_sem_map.value())); //Clear quasi-top bit max_count &= boost::uint32_t(0xBFFFFFFF); caster.addr_uint64 = max_count; - caster.addr_uint64 = caster.addr_uint64 << 32; + caster.addr_uint64 = caster.addr_uint64 << 32u; caster.addr_uint64 |= boost::uint64_t(initial_count) << 2; return *static_cast<map_type*>(caster.addr); } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/workaround.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/workaround.hpp index 53cd3eb2c4..01b6c6eb05 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/workaround.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/detail/workaround.hpp @@ -19,12 +19,18 @@ # pragma once #endif +#if defined(BOOST_INTERPROCESS_FORCE_NATIVE_EMULATION) && defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) +#error "BOOST_INTERPROCESS_FORCE_NATIVE_EMULATION && BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION can't be defined at the same time" +#endif + +//#define BOOST_INTERPROCESS_FORCE_NATIVE_EMULATION + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) #define BOOST_INTERPROCESS_WINDOWS - #define BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION + #if !defined(BOOST_INTERPROCESS_FORCE_NATIVE_EMULATION) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) + #define BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION + #endif #define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME - //Define this to connect with shared memory created with versions < 1.54 - //#define BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME #else #include <unistd.h> @@ -49,17 +55,12 @@ //Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it. #if defined(__CYGWIN__) #define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED - //Mac Os X < Lion (10.7) might define _POSIX_THREAD_PROCESS_SHARED but there is no real support. #elif defined(__APPLE__) - #include "TargetConditionals.h" - //Check we're on Mac OS target - #if defined(TARGET_OS_MAC) - #include "AvailabilityMacros.h" - //If minimum target for this compilation is older than Mac Os Lion, then we are out of luck - #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 - #define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED - #endif - #endif + //The pthreads implementation of darwin stores a pointer to a mutex inside the condition + //structure so real sharing between processes is broken. See: + //https://opensource.apple.com/source/libpthread/libpthread-301.30.1/src/pthread_cond.c.auto.html + //in method pthread_cond_wait + #define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED #endif //If buggy _POSIX_THREAD_PROCESS_SHARED is detected avoid using it @@ -71,6 +72,13 @@ #endif ////////////////////////////////////////////////////// + // BOOST_INTERPROCESS_POSIX_ROBUST_MUTEXES + ////////////////////////////////////////////////////// + #if (_XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L) + #define BOOST_INTERPROCESS_POSIX_ROBUST_MUTEXES + #endif + + ////////////////////////////////////////////////////// // _POSIX_SHARED_MEMORY_OBJECTS (POSIX.1b/POSIX.4) ////////////////////////////////////////////////////// #if ( defined(_POSIX_SHARED_MEMORY_OBJECTS) && ((_POSIX_SHARED_MEMORY_OBJECTS + 0) > 0) ) ||\ @@ -154,6 +162,14 @@ (defined (_FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64)) #define BOOST_INTERPROCESS_UNIX_64_BIT_OR_BIGGER_OFF_T #endif + + ////////////////////////////////////////////////////// + //posix_fallocate + ////////////////////////////////////////////////////// + #if (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L) + #define BOOST_INTERPROCESS_POSIX_FALLOCATE + #endif + #endif //!defined(BOOST_INTERPROCESS_WINDOWS) #if defined(BOOST_INTERPROCESS_WINDOWS) || defined(BOOST_INTERPROCESS_POSIX_MAPPED_FILES) @@ -175,6 +191,18 @@ #define BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS 10000 #endif + +// Max open or create tries with managed memory segments +#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_INITIALIZE_MAX_TRIES + #define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_INITIALIZE_MAX_TRIES 20u +#endif + +// Maximum timeout in seconds with open or create tries with managed memory segments +// waiting the creator to initialize the shared memory +#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_INITIALIZE_TIMEOUT_SEC + #define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_INITIALIZE_TIMEOUT_SEC 300u +#endif + //Other switches //BOOST_INTERPROCESS_MSG_QUEUE_USES_CIRC_INDEX //message queue uses a circular queue as index instead of an array (better performance) @@ -195,14 +223,40 @@ #define BOOST_INTERPROCESS_FORCEINLINE inline #elif defined(BOOST_INTERPROCESS_FORCEINLINE_IS_BOOST_FORCELINE) #define BOOST_INTERPROCESS_FORCEINLINE BOOST_FORCEINLINE -#elif defined(BOOST_MSVC) && defined(_DEBUG) - //"__forceinline" and MSVC seems to have some bugs in debug mode +#elif defined(BOOST_MSVC) && (_MSC_VER < 1900 || defined(_DEBUG)) + //"__forceinline" and MSVC seems to have some bugs in old versions and in debug mode #define BOOST_INTERPROCESS_FORCEINLINE inline -#elif defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ < 5))) +#elif defined(BOOST_GCC) && (__GNUC__ <= 5) //Older GCCs have problems with forceinline #define BOOST_INTERPROCESS_FORCEINLINE inline #else #define BOOST_INTERPROCESS_FORCEINLINE BOOST_FORCEINLINE #endif +#ifdef BOOST_WINDOWS + +#define BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES + +#ifdef __clang__ + #define BOOST_INTERPROCESS_DISABLE_DEPRECATED_WARNING _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") + #define BOOST_INTERPROCESS_RESTORE_WARNING _Pragma("clang diagnostic pop") +#else // __clang__ + #define BOOST_INTERPROCESS_DISABLE_DEPRECATED_WARNING __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) + #define BOOST_INTERPROCESS_RESTORE_WARNING __pragma(warning(pop)) +#endif // __clang__ + +#endif + +#if defined(BOOST_HAS_THREADS) +# if defined(_MSC_VER) || defined(__MWERKS__) || defined(__MINGW32__) || defined(__BORLANDC__) + //no reentrant posix functions (eg: localtime_r) +# elif (!defined(__hpux) || (defined(__hpux) && defined(_REENTRANT))) +# define BOOST_INTERPROCESS_HAS_REENTRANT_STD_FUNCTIONS +# endif +#endif + +#include <boost/core/no_exceptions_support.hpp> + #endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/errors.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/errors.hpp index 46dc417a59..95bca55a17 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/errors.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/errors.hpp @@ -34,14 +34,13 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <stdarg.h> #include <string> #if defined (BOOST_INTERPROCESS_WINDOWS) # include <boost/interprocess/detail/win32_api.hpp> #else # ifdef BOOST_HAS_UNISTD_H -# include <errno.h> //Errors +# include <cerrno> //Errors # include <cstring> //strerror # else //ifdef BOOST_HAS_UNISTD_H # error Unknown platform @@ -57,7 +56,7 @@ namespace interprocess { inline int system_error_code() // artifact of POSIX and WINDOWS error reporting { #if defined (BOOST_INTERPROCESS_WINDOWS) - return winapi::get_last_error(); + return (int)winapi::get_last_error(); #else return errno; // GCC 3.1 won't accept ::errno #endif @@ -68,22 +67,27 @@ inline int system_error_code() // artifact of POSIX and WINDOWS error reporting inline void fill_system_message(int sys_err_code, std::string &str) { void *lpMsgBuf; - winapi::format_message( + unsigned long ret = winapi::format_message( winapi::format_message_allocate_buffer | winapi::format_message_from_system | winapi::format_message_ignore_inserts, 0, - sys_err_code, + (unsigned long)sys_err_code, winapi::make_lang_id(winapi::lang_neutral, winapi::sublang_default), // Default language reinterpret_cast<char *>(&lpMsgBuf), 0, 0 ); - str += static_cast<const char*>(lpMsgBuf); - winapi::local_free( lpMsgBuf ); // free the buffer - while ( str.size() - && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) - str.erase( str.size()-1 ); + if (ret != 0){ + str += static_cast<const char*>(lpMsgBuf); + winapi::local_free( lpMsgBuf ); // free the buffer + while ( str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) + str.erase( str.size()-1 ); + } + else{ + str += "WinApi FormatMessage returned error"; + } } # else inline void fill_system_message( int system_error, std::string &str) @@ -119,7 +123,8 @@ enum error_code_t invalid_argument, timeout_when_locking_error, timeout_when_waiting_error, - owner_dead_error + owner_dead_error, + not_recoverable }; typedef int native_error_t; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/exceptions.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/exceptions.hpp index eb4ddf2d67..3eeb9f6e0b 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/exceptions.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/exceptions.hpp @@ -36,17 +36,17 @@ namespace interprocess { class BOOST_SYMBOL_VISIBLE interprocess_exception : public std::exception { public: - interprocess_exception(const char *err) + interprocess_exception(const char *err) BOOST_NOEXCEPT : m_err(other_error) { - try { m_str = err; } - catch (...) {} + BOOST_TRY { m_str = err; } + BOOST_CATCH(...) {} BOOST_CATCH_END } interprocess_exception(const error_info &err_info, const char *str = 0) : m_err(err_info) { - try{ + BOOST_TRY{ if(m_err.get_native_error() != 0){ fill_system_message(m_err.get_native_error(), m_str); } @@ -57,18 +57,18 @@ class BOOST_SYMBOL_VISIBLE interprocess_exception : public std::exception m_str = "boost::interprocess_exception::library_error"; } } - catch(...){} + BOOST_CATCH(...){} BOOST_CATCH_END } - virtual ~interprocess_exception(){} + ~interprocess_exception() BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE {} - virtual const char * what() const noexcept + const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE { return m_str.c_str(); } - native_error_t get_native_error()const { return m_err.get_native_error(); } + native_error_t get_native_error() const BOOST_NOEXCEPT { return m_err.get_native_error(); } // Note: a value of other_error implies a library (rather than system) error - error_code_t get_error_code() const { return m_err.get_error_code(); } + error_code_t get_error_code() const BOOST_NOEXCEPT { return m_err.get_error_code(); } #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: @@ -82,11 +82,11 @@ class BOOST_SYMBOL_VISIBLE interprocess_exception : public std::exception class BOOST_SYMBOL_VISIBLE lock_exception : public interprocess_exception { public: - lock_exception() - : interprocess_exception(lock_error) + lock_exception(error_code_t err = lock_error) BOOST_NOEXCEPT + : interprocess_exception(err) {} - virtual const char* what() const noexcept + const char* what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE { return "boost::interprocess::lock_exception"; } }; @@ -96,9 +96,10 @@ class BOOST_SYMBOL_VISIBLE lock_exception : public interprocess_exception class BOOST_SYMBOL_VISIBLE bad_alloc : public interprocess_exception { public: - bad_alloc() : interprocess_exception("::boost::interprocess::bad_alloc"){} - virtual const char* what() const noexcept - { return "boost::interprocess::bad_alloc"; } + bad_alloc() : interprocess_exception("::boost::interprocess::bad_alloc") {} + + const char* what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE + { return "boost::interprocess::bad_alloc"; } }; } // namespace interprocess { diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/mapped_region.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/mapped_region.hpp index 1fb64086b5..1ef284522f 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/mapped_region.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/mapped_region.hpp @@ -47,7 +47,6 @@ #if defined (BOOST_INTERPROCESS_WINDOWS) # include <boost/interprocess/detail/win32_api.hpp> -# include <boost/interprocess/sync/windows/sync_utils.hpp> #else # ifdef BOOST_HAS_UNISTD_H # include <fcntl.h> @@ -136,11 +135,11 @@ class mapped_region //!Default constructor. Address will be 0 (nullptr). //!Size will be 0. //!Does not throw - mapped_region(); + mapped_region() BOOST_NOEXCEPT; //!Move constructor. *this will be constructed taking ownership of "other"'s //!region and "other" will be left in default constructor state. - mapped_region(BOOST_RV_REF(mapped_region) other) + mapped_region(BOOST_RV_REF(mapped_region) other) BOOST_NOEXCEPT #if defined (BOOST_INTERPROCESS_WINDOWS) : m_base(0), m_size(0) , m_page_offset(0) @@ -157,7 +156,7 @@ class mapped_region //!Move assignment. If *this owns a memory mapped region, it will be //!destroyed and it will take ownership of "other"'s memory mapped region. - mapped_region &operator=(BOOST_RV_REF(mapped_region) other) + mapped_region &operator=(BOOST_RV_REF(mapped_region) other) BOOST_NOEXCEPT { mapped_region tmp(boost::move(other)); this->swap(tmp); @@ -166,18 +165,18 @@ class mapped_region //!Swaps the mapped_region with another //!mapped region - void swap(mapped_region &other); + void swap(mapped_region &other) BOOST_NOEXCEPT; //!Returns the size of the mapping. Never throws. - std::size_t get_size() const; + std::size_t get_size() const BOOST_NOEXCEPT; //!Returns the base address of the mapping. //!Never throws. - void* get_address() const; + void* get_address() const BOOST_NOEXCEPT; //!Returns the mode of the mapping used to construct the mapped region. //!Never throws. - mode_t get_mode() const; + mode_t get_mode() const BOOST_NOEXCEPT; //!Flushes to the disk a byte range within the mapped memory. //!If 'async' is true, the function will return before flushing operation is completed @@ -190,7 +189,7 @@ class mapped_region //!mapped memory page, accessing that page can trigger a segmentation fault. //!Depending on the OS, this operation might fail (XSI shared memory), it can decommit storage //!and free a portion of the virtual address space (e.g.POSIX) or this - //!function can release some physical memory wihout freeing any virtual address space(Windows). + //!function can release some physical memory without freeing any virtual address space(Windows). //!Returns true on success. Never throws. bool shrink_by(std::size_t bytes, bool from_back = true); @@ -225,7 +224,7 @@ class mapped_region //!Returns the size of the page. This size is the minimum memory that //!will be used by the system when mapping a memory mappable source and //!will restrict the address and the offset to map. - static std::size_t get_page_size(); + static std::size_t get_page_size() BOOST_NOEXCEPT; #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: @@ -269,19 +268,19 @@ class mapped_region #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -inline void swap(mapped_region &x, mapped_region &y) +inline void swap(mapped_region &x, mapped_region &y) BOOST_NOEXCEPT { x.swap(y); } inline mapped_region::~mapped_region() { this->priv_close(); } -inline std::size_t mapped_region::get_size() const +inline std::size_t mapped_region::get_size() const BOOST_NOEXCEPT { return m_size; } -inline mode_t mapped_region::get_mode() const +inline mode_t mapped_region::get_mode() const BOOST_NOEXCEPT { return m_mode; } -inline void* mapped_region::get_address() const +inline void* mapped_region::get_address() const BOOST_NOEXCEPT { return m_base; } inline void* mapped_region::priv_map_address() const @@ -297,7 +296,7 @@ inline bool mapped_region::priv_flush_param_check if(m_base == 0) return false; - if(mapping_offset >= m_size || (mapping_offset + numbytes) > m_size){ + if(mapping_offset >= m_size || numbytes > (m_size - size_t(mapping_offset))){ return false; } @@ -346,14 +345,14 @@ inline void mapped_region::priv_size_from_mapping_size (offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size) { //Check if mapping size fits in the user address space - //as offset_t is the maximum file size and its signed. + //as offset_t is the maximum file size and it's signed. if(mapping_size < offset || boost::uintmax_t(mapping_size - (offset - page_offset)) > boost::uintmax_t(std::size_t(-1))){ error_info err(size_error); throw interprocess_exception(err); } - size = static_cast<std::size_t>(mapping_size - (offset - page_offset)); + size = static_cast<std::size_t>(mapping_size - offset); } inline offset_t mapped_region::priv_page_offset_addr_fixup(offset_t offset, const void *&address) @@ -365,17 +364,17 @@ inline offset_t mapped_region::priv_page_offset_addr_fixup(offset_t offset, cons //We calculate the difference between demanded and valid offset //(always less than a page in std::size_t, thus, representable by std::size_t) const std::size_t page_offset = - static_cast<std::size_t>(offset - (offset / page_size) * page_size); + static_cast<std::size_t>(offset - (offset / offset_t(page_size)) * offset_t(page_size)); //Update the mapping address if(address){ address = static_cast<const char*>(address) - page_offset; } - return page_offset; + return offset_t(page_offset); } #if defined (BOOST_INTERPROCESS_WINDOWS) -inline mapped_region::mapped_region() +inline mapped_region::mapped_region() BOOST_NOEXCEPT : m_base(0), m_size(0), m_page_offset(0), m_mode(read_only) , m_file_or_mapping_hnd(ipcdetail::invalid_file()) {} @@ -383,7 +382,7 @@ inline mapped_region::mapped_region() template<int dummy> inline std::size_t mapped_region::page_size_holder<dummy>::get_page_size() { - winapi::system_info info; + winapi::interprocess_system_info info; winapi::get_system_info(&info); return std::size_t(info.dwAllocationGranularity); } @@ -442,11 +441,11 @@ inline mapped_region::mapped_region //Create mapping handle native_mapping_handle = winapi::create_file_mapping ( ipcdetail::file_handle_from_mapping_handle(mapping.get_mapping_handle()) - , protection, 0, 0, 0); + , protection, 0, (char*)0, 0); //Check if all is correct if(!native_mapping_handle){ - error_info err = winapi::get_last_error(); + error_info err ((int)winapi::get_last_error()); throw interprocess_exception(err); } handle_to_close = native_mapping_handle; @@ -466,7 +465,7 @@ inline mapped_region::mapped_region if(size == 0){ offset_t mapping_size; if(!winapi::get_file_mapping_size(native_mapping_handle, mapping_size)){ - error_info err = winapi::get_last_error(); + error_info err((int)winapi::get_last_error()); throw interprocess_exception(err); } //This can throw @@ -477,18 +476,18 @@ inline mapped_region::mapped_region void *base = winapi::map_view_of_file_ex (native_mapping_handle, map_access, - offset - page_offset, + ::boost::ulong_long_type(offset - page_offset), static_cast<std::size_t>(page_offset + size), const_cast<void*>(address)); //Check error if(!base){ - error_info err = winapi::get_last_error(); + error_info err((int)winapi::get_last_error()); throw interprocess_exception(err); } //Calculate new base for the user m_base = static_cast<char*>(base) + page_offset; - m_page_offset = page_offset; + m_page_offset = static_cast<std::size_t>(page_offset); m_size = size; } //Windows shared memory needs the duplication of the handle if we want to @@ -496,7 +495,7 @@ inline mapped_region::mapped_region // //For mapped files, we duplicate the file handle to be able to FlushFileBuffers if(!winapi::duplicate_current_process_handle(mhandle.handle, &m_file_or_mapping_hnd)){ - error_info err = winapi::get_last_error(); + error_info err((int)winapi::get_last_error()); this->priv_close(); throw interprocess_exception(err); } @@ -573,7 +572,7 @@ inline void mapped_region::dont_close_on_destruction() #else //#if defined (BOOST_INTERPROCESS_WINDOWS) -inline mapped_region::mapped_region() +inline mapped_region::mapped_region() BOOST_NOEXCEPT : m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false) {} @@ -696,7 +695,7 @@ inline mapped_region::mapped_region //Map it to the address space void* base = mmap ( const_cast<void*>(address) - , static_cast<std::size_t>(page_offset + size) + , static_cast<std::size_t>(page_offset) + size , prot , flags , mapping.get_mapping_handle().handle @@ -710,7 +709,7 @@ inline mapped_region::mapped_region //Calculate new base for the user m_base = static_cast<char*>(base) + page_offset; - m_page_offset = page_offset; + m_page_offset = static_cast<std::size_t>(page_offset); m_size = size; //Check for fixed mapping error @@ -852,7 +851,7 @@ template<int dummy> const std::size_t mapped_region::page_size_holder<dummy>::PageSize = mapped_region::page_size_holder<dummy>::get_page_size(); -inline std::size_t mapped_region::get_page_size() +inline std::size_t mapped_region::get_page_size() BOOST_NOEXCEPT { if(!page_size_holder<0>::PageSize) return page_size_holder<0>::get_page_size(); @@ -860,7 +859,7 @@ inline std::size_t mapped_region::get_page_size() return page_size_holder<0>::PageSize; } -inline void mapped_region::swap(mapped_region &other) +inline void mapped_region::swap(mapped_region &other) BOOST_NOEXCEPT { ::boost::adl_move_swap(this->m_base, other.m_base); ::boost::adl_move_swap(this->m_size, other.m_size); diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index eda4cf1be3..c036ce9490 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -35,6 +35,8 @@ #include <boost/container/detail/placement_new.hpp> // move #include <boost/move/utility_core.hpp> +// move/detail +#include <boost/move/detail/force_ptr.hpp> // other boost #include <boost/static_assert.hpp> #include <boost/assert.hpp> @@ -289,10 +291,10 @@ class memory_algorithm_common max_value(ceil_units(nbytes) + AllocatedCtrlUnits, size_type(MinBlockUnits)); //We can create a new block in the end of the segment if(old_size >= (first_min_units + MinBlockUnits)){ - block_ctrl *second = reinterpret_cast<block_ctrl *> + block_ctrl *second = move_detail::force_ptr<block_ctrl*> (reinterpret_cast<char*>(first) + Alignment*first_min_units); - first->m_size = first_min_units; - second->m_size = old_size - first->m_size; + first->m_size = first_min_units & block_ctrl::size_mask; + second->m_size = (old_size - first->m_size) & block_ctrl::size_mask; BOOST_ASSERT(second->m_size >= MinBlockUnits); memory_algo->priv_mark_new_allocated_block(first); memory_algo->priv_mark_new_allocated_block(second); @@ -326,7 +328,8 @@ class memory_algorithm_common (reinterpret_cast<char*>(first) + first->m_size*Alignment)); //Set the new size of the first block size_type old_size = first->m_size; - first->m_size = (size_type)(reinterpret_cast<char*>(second) - reinterpret_cast<char*>(first))/Alignment; + first->m_size = size_type(size_type(reinterpret_cast<char*>(second) - reinterpret_cast<char*>(first))/Alignment + & block_ctrl::size_mask); memory_algo->priv_mark_new_allocated_block(first); //Now check if we can create a new buffer in the end @@ -346,15 +349,15 @@ class memory_algorithm_common if((old_size - first->m_size) >= (second_min_units + MinBlockUnits)){ //Now obtain the address of the end block block_ctrl *third = new (reinterpret_cast<char*>(second) + Alignment*second_min_units)block_ctrl; - second->m_size = second_min_units; - third->m_size = old_size - first->m_size - second->m_size; + second->m_size = second_min_units & block_ctrl::size_mask; + third->m_size = (old_size - first->m_size - second->m_size) & block_ctrl::size_mask; BOOST_ASSERT(third->m_size >= MinBlockUnits); memory_algo->priv_mark_new_allocated_block(second); memory_algo->priv_mark_new_allocated_block(third); memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(third)); } else{ - second->m_size = old_size - first->m_size; + second->m_size = (old_size - first->m_size) & block_ctrl::size_mask; BOOST_ASSERT(second->m_size >= MinBlockUnits); memory_algo->priv_mark_new_allocated_block(second); } @@ -437,15 +440,15 @@ class memory_algorithm_common return true; //Now we can just rewrite the size of the old buffer - block->m_size = (received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits; + block->m_size = ((received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits) & block_ctrl::size_mask; BOOST_ASSERT(block->m_size >= BlockCtrlUnits); //We create the new block - block_ctrl *new_block = reinterpret_cast<block_ctrl*> + block_ctrl *new_block = move_detail::force_ptr<block_ctrl*> (reinterpret_cast<char*>(block) + block->m_size*Alignment); //Write control data to simulate this new block was previously allocated //and deallocate it - new_block->m_size = old_block_units - block->m_size; + new_block->m_size = (old_block_units - block->m_size) & block_ctrl::size_mask; BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits); memory_algo->priv_mark_new_allocated_block(block); memory_algo->priv_mark_new_allocated_block(new_block); @@ -520,7 +523,7 @@ class memory_algorithm_common break; total_request_units -= elem_units; //This is the position where the new block must be created - block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address); + block_ctrl *new_block = move_detail::force_ptr<block_ctrl*>(block_address); assert_alignment(new_block); //The last block should take all the remaining space @@ -531,7 +534,7 @@ class memory_algorithm_common : max_value(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units)) > received_units)){ //By default, the new block will use the rest of the buffer - new_block->m_size = received_units - total_used_units; + new_block->m_size = (received_units - total_used_units) & block_ctrl::size_mask; memory_algo->priv_mark_new_allocated_block(new_block); //If the remaining units are bigger than needed and we can @@ -557,7 +560,7 @@ class memory_algorithm_common } } else{ - new_block->m_size = elem_units; + new_block->m_size = elem_units & block_ctrl::size_mask; memory_algo->priv_mark_new_allocated_block(new_block); } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/permissions.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/permissions.hpp index 87fea28be7..0b21a685aa 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/permissions.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/permissions.hpp @@ -29,6 +29,10 @@ #include <boost/interprocess/detail/win32_api.hpp> +#else + +#include <sys/stat.h> + #endif #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED @@ -70,7 +74,7 @@ class permissions #if defined(BOOST_INTERPROCESS_WINDOWS) typedef void* os_permissions_type; #else - typedef int os_permissions_type; + typedef ::mode_t os_permissions_type; #endif os_permissions_type m_perm; @@ -79,20 +83,20 @@ class permissions public: //!Constructs a permissions object from a user provided os-dependent //!permissions. - permissions(os_permissions_type type) + permissions(os_permissions_type type) BOOST_NOEXCEPT : m_perm(type) {} //!Constructs a default permissions object: //!A null security attributes pointer for windows or 0644 //!for UNIX. - permissions() + permissions() BOOST_NOEXCEPT { set_default(); } //!Sets permissions to default values: //!A null security attributes pointer for windows or 0644 //!for UNIX. - void set_default() + void set_default() BOOST_NOEXCEPT { #if defined (BOOST_INTERPROCESS_WINDOWS) m_perm = 0; @@ -103,7 +107,7 @@ class permissions //!Sets permissions to unrestricted access: //!A null DACL for windows or 0666 for UNIX. - void set_unrestricted() + void set_unrestricted() BOOST_NOEXCEPT { #if defined (BOOST_INTERPROCESS_WINDOWS) m_perm = &ipcdetail::unrestricted_permissions_holder<0>::unrestricted; @@ -114,12 +118,12 @@ class permissions //!Sets permissions from a user provided os-dependent //!permissions. - void set_permissions(os_permissions_type perm) + void set_permissions(os_permissions_type perm) BOOST_NOEXCEPT { m_perm = perm; } //!Returns stored os-dependent //!permissions - os_permissions_type get_permissions() const + os_permissions_type get_permissions() const BOOST_NOEXCEPT { return m_perm; } }; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/shared_memory_object.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/shared_memory_object.hpp index 34a695d461..2d429efcb1 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/shared_memory_object.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/shared_memory_object.hpp @@ -28,13 +28,14 @@ #include <boost/interprocess/exceptions.hpp> #include <boost/interprocess/detail/os_file_functions.hpp> #include <boost/interprocess/detail/shared_dir_helpers.hpp> +#include <boost/interprocess/detail/char_wchar_holder.hpp> #include <boost/interprocess/permissions.hpp> #include <boost/move/adl_move_swap.hpp> #include <cstddef> -#include <string> #if defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) -# include <fcntl.h> //O_CREAT, O_*... +# include <string> +# include <fcntl.h> //posix_fallocate, O_CREAT, O_*... # include <sys/mman.h> //shm_xxx # include <unistd.h> //ftruncate, close # include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, @@ -64,7 +65,7 @@ class shared_memory_object public: //!Default constructor. Represents an empty shared_memory_object. - shared_memory_object(); + shared_memory_object() BOOST_NOEXCEPT; //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode" //!If the file previously exists, throws an error.*/ @@ -82,10 +83,39 @@ class shared_memory_object shared_memory_object(open_only_t, const char *name, mode_t mode) { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); } + #if defined(BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode" + //!If the file previously exists, throws an error. + //! + //!Note: This function is only available on operating systems with + //! native wchar_t APIs (e.g. Windows). + shared_memory_object(create_only_t, const wchar_t*name, mode_t mode, const permissions &perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); } + + //!Tries to create a shared memory object with name "name" and mode "mode", with the + //!access mode "mode". If the file previously exists, it tries to open it with mode "mode". + //!Otherwise throws an error. + //! + //!Note: This function is only available on operating systems with + //! native wchar_t APIs (e.g. Windows). + shared_memory_object(open_or_create_t, const wchar_t*name, mode_t mode, const permissions &perm = permissions()) + { this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); } + + //!Tries to open a shared memory object with name "name", with the access mode "mode". + //!If the file does not previously exist, it throws an error. + //! + //!Note: This function is only available on operating systems with + //! native wchar_t APIs (e.g. Windows). + shared_memory_object(open_only_t, const wchar_t*name, mode_t mode) + { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); } + + #endif //defined(BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //!Moves the ownership of "moved"'s shared memory object to *this. //!After the call, "moved" does not represent any shared memory object. //!Does not throw - shared_memory_object(BOOST_RV_REF(shared_memory_object) moved) + shared_memory_object(BOOST_RV_REF(shared_memory_object) moved) BOOST_NOEXCEPT : m_handle(file_handle_t(ipcdetail::invalid_file())) , m_mode(read_only) { this->swap(moved); } @@ -93,7 +123,7 @@ class shared_memory_object //!Moves the ownership of "moved"'s shared memory to *this. //!After the call, "moved" does not represent any shared memory. //!Does not throw - shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved) + shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved) BOOST_NOEXCEPT { shared_memory_object tmp(boost::move(moved)); this->swap(tmp); @@ -101,12 +131,23 @@ class shared_memory_object } //!Swaps the shared_memory_objects. Does not throw - void swap(shared_memory_object &moved); + void swap(shared_memory_object &moved) BOOST_NOEXCEPT; //!Erases a shared memory object from the system. //!Returns false on error. Never throws static bool remove(const char *name); + #if defined(BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //!Erases a shared memory object from the system. + //!Returns false on error. Never throws + //! + //!Note: This function is only available on operating systems with + //! native wchar_t APIs (e.g. Windows). + static bool remove(const wchar_t *name); + + #endif //defined(BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + //!Sets the size of the shared memory mapping void truncate(offset_t length); @@ -120,17 +161,17 @@ class shared_memory_object ~shared_memory_object(); //!Returns the name of the shared memory object. - const char *get_name() const; + const char *get_name() const BOOST_NOEXCEPT; //!Returns true if the size of the shared memory object //!can be obtained and writes the size in the passed reference - bool get_size(offset_t &size) const; + bool get_size(offset_t &size) const BOOST_NOEXCEPT; //!Returns access mode - mode_t get_mode() const; + mode_t get_mode() const BOOST_NOEXCEPT; //!Returns mapping handle. Never throws. - mapping_handle_t get_mapping_handle() const; + mapping_handle_t get_mapping_handle() const BOOST_NOEXCEPT; #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: @@ -139,17 +180,18 @@ class shared_memory_object void priv_close(); //!Opens or creates a shared memory object. - bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm); + template<class CharT> + bool priv_open_or_create(ipcdetail::create_enum_t type, const CharT *filename, mode_t mode, const permissions &perm); - file_handle_t m_handle; - mode_t m_mode; - std::string m_filename; + file_handle_t m_handle; + mode_t m_mode; + char_wchar_holder m_filename; #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED }; #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -inline shared_memory_object::shared_memory_object() +inline shared_memory_object::shared_memory_object() BOOST_NOEXCEPT : m_handle(file_handle_t(ipcdetail::invalid_file())) , m_mode(read_only) {} @@ -158,34 +200,35 @@ inline shared_memory_object::~shared_memory_object() { this->priv_close(); } -inline const char *shared_memory_object::get_name() const -{ return m_filename.c_str(); } +inline const char *shared_memory_object::get_name() const BOOST_NOEXCEPT +{ return m_filename.getn(); } -inline bool shared_memory_object::get_size(offset_t &size) const +inline bool shared_memory_object::get_size(offset_t &size) const BOOST_NOEXCEPT { return ipcdetail::get_file_size((file_handle_t)m_handle, size); } -inline void shared_memory_object::swap(shared_memory_object &other) +inline void shared_memory_object::swap(shared_memory_object &other) BOOST_NOEXCEPT { boost::adl_move_swap(m_handle, other.m_handle); boost::adl_move_swap(m_mode, other.m_mode); m_filename.swap(other.m_filename); } -inline mapping_handle_t shared_memory_object::get_mapping_handle() const +inline mapping_handle_t shared_memory_object::get_mapping_handle() const BOOST_NOEXCEPT { return ipcdetail::mapping_handle_from_file_handle(m_handle); } -inline mode_t shared_memory_object::get_mode() const +inline mode_t shared_memory_object::get_mode() const BOOST_NOEXCEPT { return m_mode; } #if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) +template<class CharT> inline bool shared_memory_object::priv_open_or_create - (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm) + (ipcdetail::create_enum_t type, const CharT *filename, mode_t mode, const permissions &perm) { m_filename = filename; - std::string shmfile; + std::basic_string<CharT> shmfile; ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, shmfile); //Set accesses @@ -222,22 +265,39 @@ inline bool shared_memory_object::priv_open_or_create return true; } +#if defined(BOOST_INTERPROCESS_WCHAR_NAMED_RESOURCES) + +inline bool shared_memory_object::remove(const wchar_t *filename) +{ + BOOST_TRY{ + //Make sure a temporary path is created for shared memory + std::wstring shmfile; + ipcdetail::shared_filepath(filename, shmfile); + return ipcdetail::delete_file(shmfile.c_str()); + } + BOOST_CATCH(...){ + return false; + } BOOST_CATCH_END +} + +#endif + inline bool shared_memory_object::remove(const char *filename) { - try{ + BOOST_TRY{ //Make sure a temporary path is created for shared memory std::string shmfile; ipcdetail::shared_filepath(filename, shmfile); return ipcdetail::delete_file(shmfile.c_str()); } - catch(...){ + BOOST_CATCH(...){ return false; - } + } BOOST_CATCH_END } inline void shared_memory_object::truncate(offset_t length) { - if(!ipcdetail::truncate_file(m_handle, length)){ + if(!ipcdetail::truncate_file(m_handle, (std::size_t)length)){ error_info err = system_error_code(); throw interprocess_exception(err); } @@ -275,9 +335,10 @@ inline bool use_filesystem_based_posix() } //shared_memory_object_detail +template<class CharT> inline bool shared_memory_object::priv_open_or_create (ipcdetail::create_enum_t type, - const char *filename, + const CharT *filename, mode_t mode, const permissions &perm) { #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) @@ -287,11 +348,12 @@ inline bool shared_memory_object::priv_open_or_create #else const bool add_leading_slash = true; #endif + std::basic_string<CharT> fname; if(add_leading_slash){ - ipcdetail::add_leading_slash(filename, m_filename); + ipcdetail::add_leading_slash(filename, fname); } else{ - ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, m_filename); + ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, fname); } //Create new mapping @@ -306,19 +368,19 @@ inline bool shared_memory_object::priv_open_or_create error_info err(mode_error); throw interprocess_exception(err); } - int unix_perm = perm.get_permissions(); + ::mode_t unix_perm = perm.get_permissions(); switch(type){ case ipcdetail::DoOpen: { //No oflag addition - m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); + m_handle = shm_open(fname.c_str(), oflag, unix_perm); } break; case ipcdetail::DoCreate: { oflag |= (O_CREAT | O_EXCL); - m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); + m_handle = shm_open(fname.c_str(), oflag, unix_perm); if(m_handle >= 0){ ::fchmod(m_handle, unix_perm); } @@ -328,16 +390,16 @@ inline bool shared_memory_object::priv_open_or_create { //We need a create/open loop to change permissions correctly using fchmod, since //with "O_CREAT" only we don't know if we've created or opened the shm. - while(1){ + while(true){ //Try to create shared memory - m_handle = shm_open(m_filename.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm); + m_handle = shm_open(fname.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm); //If successful change real permissions if(m_handle >= 0){ ::fchmod(m_handle, unix_perm); } //If already exists, try to open else if(errno == EEXIST){ - m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); + m_handle = shm_open(fname.c_str(), oflag, unix_perm); //If open fails and errno tells the file does not exist //(shm was removed between creation and opening tries), just retry if(m_handle < 0 && errno == ENOENT){ @@ -370,7 +432,7 @@ inline bool shared_memory_object::priv_open_or_create inline bool shared_memory_object::remove(const char *filename) { - try{ + BOOST_TRY{ std::string filepath; #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) const bool add_leading_slash = false; @@ -387,14 +449,30 @@ inline bool shared_memory_object::remove(const char *filename) } return 0 == shm_unlink(filepath.c_str()); } - catch(...){ + BOOST_CATCH(...){ return false; - } + } BOOST_CATCH_END } inline void shared_memory_object::truncate(offset_t length) { - if(0 != ftruncate(m_handle, length)){ + #ifdef BOOST_INTERPROCESS_POSIX_FALLOCATE + int ret = EINTR; + while (EINTR == ret) { + ret = posix_fallocate(m_handle, 0, length); + } + + if (ret && ret != EOPNOTSUPP && ret != ENODEV){ + error_info err(ret); + throw interprocess_exception(err); + } + //ftruncate fallback + #endif //BOOST_INTERPROCESS_POSIX_FALLOCATE + + handle_eintr: + if (0 != ftruncate(m_handle, length)){ + if (errno == EINTR) + goto handle_eintr; error_info err(system_error_code()); throw interprocess_exception(err); } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/deleter.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/deleter.hpp index 3cd469df8b..bc0f8c8aaf 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/deleter.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/deleter.hpp @@ -52,7 +52,7 @@ class deleter segment_manager_pointer mp_mngr; public: - deleter(segment_manager_pointer pmngr) + deleter(segment_manager_pointer pmngr) BOOST_NOEXCEPT : mp_mngr(pmngr) {} diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp index 30866adefe..e2ce9a78d8 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp @@ -36,7 +36,7 @@ class bad_weak_ptr { public: - virtual char const * what() const noexcept + virtual char const * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE { return "boost::interprocess::bad_weak_ptr"; } }; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/shared_count.hpp index 61cf9ea198..9b0244e423 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/shared_count.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -25,7 +25,6 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <boost/checked_delete.hpp> #include <boost/intrusive/pointer_traits.hpp> #include <boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp> #include <boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp> @@ -47,18 +46,21 @@ template<class T, class VoidAllocator, class Deleter> class shared_count { public: + + typedef typename boost::container:: + allocator_traits<VoidAllocator>::pointer void_ptr; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template - rebind_pointer<T>::type pointer; + pointer_traits<void_ptr>::template + rebind_pointer<T>::type pointer; private: typedef sp_counted_impl_pd<VoidAllocator, Deleter> counted_impl; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<counted_impl>::type counted_impl_ptr; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<sp_counted_base>::type counted_base_ptr; typedef boost::container::allocator_traits<VoidAllocator> vallocator_traits; @@ -67,11 +69,11 @@ class shared_count portable_rebind_alloc<counted_impl>::type counted_impl_allocator; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<const Deleter>::type const_deleter_pointer; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<const VoidAllocator>::type const_allocator_pointer; pointer m_px; @@ -229,8 +231,10 @@ template<class T, class VoidAllocator, class Deleter> class weak_count { public: + typedef typename boost::container:: + allocator_traits<VoidAllocator>::pointer void_ptr; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<T>::type pointer; private: @@ -238,10 +242,10 @@ class weak_count typedef sp_counted_impl_pd<VoidAllocator, Deleter> counted_impl; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<counted_impl>::type counted_impl_ptr; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<sp_counted_base>::type counted_base_ptr; pointer m_px; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp index a025309bd5..ed1d72706f 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp @@ -43,17 +43,19 @@ namespace ipcdetail { template <class Allocator> struct scoped_ptr_dealloc_functor { - typedef typename Allocator::pointer pointer; + typedef typename boost::container:: + allocator_traits<Allocator>::pointer pointer; + typedef ipcdetail::integral_constant<unsigned, boost::interprocess::version<Allocator>::value> alloc_version; typedef ipcdetail::integral_constant<unsigned, 1> allocator_v1; typedef ipcdetail::integral_constant<unsigned, 2> allocator_v2; private: - void priv_deallocate(const typename Allocator::pointer &p, allocator_v1) + void priv_deallocate(const pointer &p, allocator_v1) { m_alloc.deallocate(p, 1); } - void priv_deallocate(const typename Allocator::pointer &p, allocator_v2) + void priv_deallocate(const pointer &p, allocator_v2) { m_alloc.deallocate_one(p); } public: @@ -85,7 +87,11 @@ class sp_counted_impl_pd allocator_traits<A>::template portable_rebind_alloc < const this_type >::type const_this_allocator; - typedef typename this_allocator::pointer this_pointer; + typedef typename boost::container:: + allocator_traits<this_allocator> + ::pointer this_pointer; + typedef typename boost::container:: + allocator_traits<A>::pointer a_pointer; typedef typename boost::intrusive:: pointer_traits<this_pointer> this_pointer_traits; @@ -93,10 +99,10 @@ class sp_counted_impl_pd sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & ); typedef typename boost::intrusive:: - pointer_traits<typename A::pointer>::template + pointer_traits<a_pointer>::template rebind_pointer<const D>::type const_deleter_pointer; typedef typename boost::intrusive:: - pointer_traits<typename A::pointer>::template + pointer_traits<a_pointer>::template rebind_pointer<const A>::type const_allocator_pointer; typedef typename D::pointer pointer; @@ -127,8 +133,7 @@ class sp_counted_impl_pd //Do it now! scoped_ptr< this_type, scoped_ptr_dealloc_functor<this_allocator> > deleter_ptr(this_ptr, a_copy); - typedef typename this_allocator::value_type value_type; - ipcdetail::to_raw_pointer(this_ptr)->~value_type(); + ipcdetail::to_raw_pointer(this_ptr)->~this_type(); } void release() // nothrow diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/scoped_ptr.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/scoped_ptr.hpp index 5506040b63..f480428ca8 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/scoped_ptr.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/scoped_ptr.hpp @@ -91,49 +91,49 @@ class scoped_ptr //!Assigns internal pointer as 0 and returns previous pointer. This will //!avoid deletion on destructor - pointer release() + pointer release() BOOST_NOEXCEPT { pointer tmp(m_ptr); m_ptr = 0; return tmp; } //!Returns a reference to the object pointed to by the stored pointer. //!Never throws. - reference operator*() const + reference operator*() const BOOST_NOEXCEPT { BOOST_ASSERT(m_ptr != 0); return *m_ptr; } //!Returns the internal stored pointer. //!Never throws. - pointer &operator->() + pointer &operator->() BOOST_NOEXCEPT { BOOST_ASSERT(m_ptr != 0); return m_ptr; } //!Returns the internal stored pointer. //!Never throws. - const pointer &operator->() const + const pointer &operator->() const BOOST_NOEXCEPT { BOOST_ASSERT(m_ptr != 0); return m_ptr; } //!Returns the stored pointer. //!Never throws. - pointer & get() + pointer & get() BOOST_NOEXCEPT { return m_ptr; } //!Returns the stored pointer. //!Never throws. - const pointer & get() const + const pointer & get() const BOOST_NOEXCEPT { return m_ptr; } typedef pointer this_type::*unspecified_bool_type; //!Conversion to bool //!Never throws - operator unspecified_bool_type() const + operator unspecified_bool_type() const BOOST_NOEXCEPT { return m_ptr == 0? 0: &this_type::m_ptr; } //!Returns true if the stored pointer is 0. //!Never throws. - bool operator! () const // never throws + bool operator! () const BOOST_NOEXCEPT // never throws { return m_ptr == 0; } //!Exchanges the internal pointer and deleter with other scoped_ptr //!Never throws. - void swap(scoped_ptr & b) // never throws + void swap(scoped_ptr & b) BOOST_NOEXCEPT // never throws { ::boost::adl_move_swap(static_cast<Deleter&>(*this), static_cast<Deleter&>(b)); ::boost::adl_move_swap(m_ptr, b.m_ptr); @@ -148,7 +148,7 @@ class scoped_ptr //!Exchanges the internal pointer and deleter with other scoped_ptr //!Never throws. template<class T, class D> inline -void swap(scoped_ptr<T, D> & a, scoped_ptr<T, D> & b) +void swap(scoped_ptr<T, D> & a, scoped_ptr<T, D> & b) BOOST_NOEXCEPT { a.swap(b); } //!Returns a copy of the stored pointer diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/shared_ptr.hpp index 67aa597c4d..c50f2cbf7e 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/shared_ptr.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -103,18 +103,20 @@ class shared_ptr typedef T element_type; typedef T value_type; + typedef typename boost::container:: + allocator_traits<VoidAllocator>::pointer void_ptr; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<T>::type pointer; typedef typename ipcdetail::add_reference <value_type>::type reference; typedef typename ipcdetail::add_reference <const value_type>::type const_reference; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<const Deleter>::type const_deleter_pointer; typedef typename boost::intrusive:: - pointer_traits<typename VoidAllocator::pointer>::template + pointer_traits<void_ptr>::template rebind_pointer<const VoidAllocator>::type const_allocator_pointer; BOOST_COPYABLE_AND_MOVABLE(shared_ptr) @@ -395,16 +397,16 @@ template<class T, class ManagedMemory> inline typename managed_shared_ptr<T, ManagedMemory>::type make_managed_shared_ptr(T *constructed_object, ManagedMemory &managed_memory, const std::nothrow_t &) { - try{ + BOOST_TRY{ return typename managed_shared_ptr<T, ManagedMemory>::type ( constructed_object , managed_memory.template get_allocator<void>() , managed_memory.template get_deleter<T>() ); } - catch(...){ + BOOST_CATCH(...){ return typename managed_shared_ptr<T, ManagedMemory>::type(); - } + } BOOST_CATCH_END } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/weak_ptr.hpp index c6e52ddabe..e4873122d8 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/weak_ptr.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -63,8 +63,10 @@ class weak_ptr private: // Borland 5.5.1 specific workarounds typedef weak_ptr<T, A, D> this_type; + typedef typename boost::container:: + allocator_traits<A>::pointer alloc_ptr; typedef typename boost::intrusive:: - pointer_traits<typename A::pointer>::template + pointer_traits<alloc_ptr>::template rebind_pointer<T>::type pointer; typedef typename ipcdetail::add_reference <T>::type reference; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/streams/bufferstream.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/streams/bufferstream.hpp index 51f52b09e0..51987233c4 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/streams/bufferstream.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/streams/bufferstream.hpp @@ -88,7 +88,7 @@ class basic_bufferbuf : basic_streambuf_t(), m_mode(mode), m_buffer(buf), m_length(length) { this->set_pointers(); } - virtual ~basic_bufferbuf(){} + virtual ~basic_bufferbuf() BOOST_OVERRIDE {} public: //!Returns the pointer and size of the internal buffer. @@ -115,14 +115,14 @@ class basic_bufferbuf } protected: - virtual int_type underflow() + virtual int_type underflow() BOOST_OVERRIDE { // Precondition: gptr() >= egptr(). Returns a character, if available. return this->gptr() != this->egptr() ? CharTraits::to_int_type(*this->gptr()) : CharTraits::eof(); } - virtual int_type pbackfail(int_type c = CharTraits::eof()) + virtual int_type pbackfail(int_type c = CharTraits::eof()) BOOST_OVERRIDE { if(this->gptr() != this->eback()) { if(!CharTraits::eq_int_type(c, CharTraits::eof())) { @@ -132,7 +132,7 @@ class basic_bufferbuf } else if(m_mode & std::ios_base::out) { this->gbump(-1); - *this->gptr() = c; + *this->gptr() = CharTraits::to_char_type(c); return c; } else @@ -147,7 +147,7 @@ class basic_bufferbuf return CharTraits::eof(); } - virtual int_type overflow(int_type c = CharTraits::eof()) + virtual int_type overflow(int_type c = CharTraits::eof()) BOOST_OVERRIDE { if(m_mode & std::ios_base::out) { if(!CharTraits::eq_int_type(c, CharTraits::eof())) { @@ -181,7 +181,7 @@ class basic_bufferbuf virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode - = std::ios_base::in | std::ios_base::out) + = std::ios_base::in | std::ios_base::out) BOOST_OVERRIDE { bool in = false; bool out = false; @@ -238,7 +238,7 @@ class basic_bufferbuf return pos_type(off_type(-1)); else { this->setp(this->pbase(), this->pbase() + n); - this->pbump(off); + this->pbump(static_cast<int>(off)); } } @@ -246,7 +246,7 @@ class basic_bufferbuf } virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode - = std::ios_base::in | std::ios_base::out) + = std::ios_base::in | std::ios_base::out) BOOST_OVERRIDE { return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); } private: @@ -308,7 +308,7 @@ class basic_ibufferstream : , basic_streambuf_t(this) {} - ~basic_ibufferstream(){}; + ~basic_ibufferstream(){} public: //!Returns the address of the stored diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/cv_status.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/cv_status.hpp new file mode 100644 index 0000000000..afbcdf6fd7 --- /dev/null +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/cv_status.hpp @@ -0,0 +1,29 @@ +// cv_status.hpp +// +// Copyright (C) 2011 Vicente J. Botet Escriba +// Copyright (C) 2021 Ion Gaztanaga +// +// Distributed under the 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_INTERPROCESS_CV_STATUS_HPP +#define BOOST_INTERPROCESS_CV_STATUS_HPP + +#include <boost/core/scoped_enum.hpp> + +namespace boost { +namespace interprocess { + + // enum class cv_status; + BOOST_SCOPED_ENUM_DECLARE_BEGIN(cv_status) + { + no_timeout, + timeout + } + BOOST_SCOPED_ENUM_DECLARE_END(cv_status) + +} //namespace interprocess +} //namespace boost + +#endif // header diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/common_algorithms.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/common_algorithms.hpp index 87739b8121..3cb1d1a17d 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/common_algorithms.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/common_algorithms.hpp @@ -23,16 +23,17 @@ #include <boost/interprocess/detail/workaround.hpp> #include <boost/interprocess/sync/spin/wait.hpp> +#include <boost/interprocess/detail/timed_utils.hpp> namespace boost { namespace interprocess { namespace ipcdetail { -template<class MutexType> -bool try_based_timed_lock(MutexType &m, const boost::posix_time::ptime &abs_time) +template<class MutexType, class TimePoint> +bool try_based_timed_lock(MutexType &m, const TimePoint &abs_time) { //Same as lock() - if(abs_time == boost::posix_time::pos_infin){ + if(is_pos_infinity(abs_time)){ m.lock(); return true; } @@ -45,7 +46,7 @@ bool try_based_timed_lock(MutexType &m, const boost::posix_time::ptime &abs_time } else{ spin_wait swait; - while(microsec_clock::universal_time() < abs_time){ + while(microsec_clock<TimePoint>::universal_time() < abs_time){ if(m.try_lock()){ return true; } @@ -73,46 +74,19 @@ void try_based_lock(MutexType &m) } template<class MutexType> -void timed_based_lock(MutexType &m, unsigned const uCheckPeriodSec) -{ - const boost::posix_time::time_duration dur(0, 0, uCheckPeriodSec); - boost::posix_time::ptime deadline(microsec_clock::universal_time()+dur); - if(!m.timed_lock(deadline)){ - spin_wait swait; - do{ - deadline = microsec_clock::universal_time()+dur; - if(m.timed_lock(deadline)){ - break; - } - else{ - swait.yield(); - } - } - while(1); - } -} - -template<class MutexType> -void timed_based_timed_lock(MutexType &m, const boost::posix_time::ptime &abs_time, unsigned const uCheckPeriodSec) +void timeout_when_locking_aware_lock(MutexType &m) { - const boost::posix_time::time_duration dur(0, 0, uCheckPeriodSec); - boost::posix_time::ptime deadline(microsec_clock::universal_time()+dur); - if(abs_time <= deadline){ - m.timed_lock(abs_time); - } - else if(!m.timed_lock(deadline)){ - spin_wait swait; - do{ - deadline = microsec_clock::universal_time()+dur; - if(m.timed_lock(deadline)){ - break; - } - else{ - swait.yield(); - } + #ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING + if (!m.timed_lock(microsec_clock<ustime>::universal_time() + + usduration_milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS))) + { + throw interprocess_exception(timeout_when_locking_error + , "Interprocess mutex timeout when locking. Possible deadlock: " + "owner died without unlocking?"); } - while(1); - } + #else + m.lock(); + #endif } } //namespace ipcdetail diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/condition_algorithm_8a.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/condition_algorithm_8a.hpp index 9978309b96..a4cce7ba7e 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/condition_algorithm_8a.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/condition_algorithm_8a.hpp @@ -193,130 +193,124 @@ class condition_algorithm_8a typedef typename ConditionMembers::integer_type integer_type; public: - template<class Lock> - static bool wait ( ConditionMembers &data, Lock &lock - , bool timeout_enabled, const boost::posix_time::ptime &abs_time); - static void signal(ConditionMembers &data, bool broadcast); -}; - -template<class ConditionMembers> -inline void condition_algorithm_8a<ConditionMembers>::signal(ConditionMembers &data, bool broadcast) -{ - integer_type nsignals_to_issue; - + template<bool TimeoutEnabled, class Lock, class TimePoint> + static bool wait ( ConditionMembers &data, Lock &lock, const TimePoint &abs_time) { - scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock()); - - if ( 0 != data.get_nwaiters_to_unblock() ) { // the gate is closed!!! - if ( 0 == data.get_nwaiters_blocked() ) { // NO-OP - //locker's destructor triggers data.get_mtx_unblock_lock().unlock() - return; - } - if (broadcast) { - data.get_nwaiters_to_unblock() += nsignals_to_issue = data.get_nwaiters_blocked(); - data.get_nwaiters_blocked() = 0; - } - else { - nsignals_to_issue = 1; - data.get_nwaiters_to_unblock()++; - data.get_nwaiters_blocked()--; + //Initialize to avoid warnings + integer_type nsignals_was_left = 0; + integer_type nwaiters_was_gone = 0; + + data.get_sem_block_lock().wait(); + ++data.get_nwaiters_blocked(); + data.get_sem_block_lock().post(); + + //Unlock external lock and program for relock + lock_inverter<Lock> inverted_lock(lock); + scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock); + + bool bTimedOut = !do_sem_timed_wait(data.get_sem_block_queue(), abs_time, bool_<TimeoutEnabled>()); + + { + scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock()); + if ( 0 != (nsignals_was_left = data.get_nwaiters_to_unblock()) ) { + if ( bTimedOut ) { // timeout (or canceled) + if ( 0 != data.get_nwaiters_blocked() ) { + data.get_nwaiters_blocked()--; + } + else { + data.get_nwaiters_gone()++; // count spurious wakeups. + } + } + if ( 0 == --data.get_nwaiters_to_unblock() ) { + if ( 0 != data.get_nwaiters_blocked() ) { + data.get_sem_block_lock().post(); // open the gate. + nsignals_was_left = 0; // do not open the gate below again. + } + else if ( 0 != (nwaiters_was_gone = data.get_nwaiters_gone()) ) { + data.get_nwaiters_gone() = 0; + } + } } - } - else if ( data.get_nwaiters_blocked() > data.get_nwaiters_gone() ) { // HARMLESS RACE CONDITION! - data.get_sem_block_lock().wait(); // close the gate - if ( 0 != data.get_nwaiters_gone() ) { - data.get_nwaiters_blocked() -= data.get_nwaiters_gone(); + else if ( (std::numeric_limits<integer_type>::max)()/2 + == ++data.get_nwaiters_gone() ) { // timeout/canceled or spurious semaphore :-) + data.get_sem_block_lock().wait(); + data.get_nwaiters_blocked() -= data.get_nwaiters_gone(); // something is going on here - test of timeouts? :-) + data.get_sem_block_lock().post(); data.get_nwaiters_gone() = 0; } - if (broadcast) { - nsignals_to_issue = data.get_nwaiters_to_unblock() = data.get_nwaiters_blocked(); - data.get_nwaiters_blocked() = 0; - } - else { - nsignals_to_issue = data.get_nwaiters_to_unblock() = 1; - data.get_nwaiters_blocked()--; - } - } - else { // NO-OP //locker's destructor triggers data.get_mtx_unblock_lock().unlock() - return; } - //locker's destructor triggers data.get_mtx_unblock_lock().unlock() - } - data.get_sem_block_queue().post(nsignals_to_issue); -} -template<class ConditionMembers> -template<class Lock> -inline bool condition_algorithm_8a<ConditionMembers>::wait - ( ConditionMembers &data - , Lock &lock - , bool tout_enabled - , const boost::posix_time::ptime &abs_time - ) -{ - //Initialize to avoid warnings - integer_type nsignals_was_left = 0; - integer_type nwaiters_was_gone = 0; - - data.get_sem_block_lock().wait(); - ++data.get_nwaiters_blocked(); - data.get_sem_block_lock().post(); + if ( 1 == nsignals_was_left ) { + if ( 0 != nwaiters_was_gone ) { + // sem_adjust( data.get_sem_block_queue(),-nwaiters_was_gone ); + while ( nwaiters_was_gone-- ) { + data.get_sem_block_queue().wait(); // better now than spurious later + } + } + data.get_sem_block_lock().post(); // open the gate + } - //Unlock external lock and program for relock - lock_inverter<Lock> inverted_lock(lock); - scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock); + //lock.lock(); called from unlocker destructor - bool bTimedOut = tout_enabled - ? !data.get_sem_block_queue().timed_wait(abs_time) - : (data.get_sem_block_queue().wait(), false); + return ( bTimedOut ) ? false : true; + } + static void signal(ConditionMembers &data, bool broadcast) { - scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock()); - if ( 0 != (nsignals_was_left = data.get_nwaiters_to_unblock()) ) { - if ( bTimedOut ) { // timeout (or canceled) - if ( 0 != data.get_nwaiters_blocked() ) { - data.get_nwaiters_blocked()--; + integer_type nsignals_to_issue; + + { + scoped_lock<mutex_type> locker(data.get_mtx_unblock_lock()); + + if ( 0 != data.get_nwaiters_to_unblock() ) { // the gate is closed!!! + if ( 0 == data.get_nwaiters_blocked() ) { // NO-OP + //locker's destructor triggers data.get_mtx_unblock_lock().unlock() + return; + } + if (broadcast) { + data.get_nwaiters_to_unblock() += nsignals_to_issue = data.get_nwaiters_blocked(); + data.get_nwaiters_blocked() = 0; } else { - data.get_nwaiters_gone()++; // count spurious wakeups. + nsignals_to_issue = 1; + data.get_nwaiters_to_unblock()++; + data.get_nwaiters_blocked()--; } } - if ( 0 == --data.get_nwaiters_to_unblock() ) { - if ( 0 != data.get_nwaiters_blocked() ) { - data.get_sem_block_lock().post(); // open the gate. - nsignals_was_left = 0; // do not open the gate below again. - } - else if ( 0 != (nwaiters_was_gone = data.get_nwaiters_gone()) ) { + else if ( data.get_nwaiters_blocked() > data.get_nwaiters_gone() ) { // HARMLESS RACE CONDITION! + data.get_sem_block_lock().wait(); // close the gate + if ( 0 != data.get_nwaiters_gone() ) { + data.get_nwaiters_blocked() -= data.get_nwaiters_gone(); data.get_nwaiters_gone() = 0; } + if (broadcast) { + nsignals_to_issue = data.get_nwaiters_to_unblock() = data.get_nwaiters_blocked(); + data.get_nwaiters_blocked() = 0; + } + else { + nsignals_to_issue = data.get_nwaiters_to_unblock() = 1; + data.get_nwaiters_blocked()--; + } } - } - else if ( (std::numeric_limits<integer_type>::max)()/2 - == ++data.get_nwaiters_gone() ) { // timeout/canceled or spurious semaphore :-) - data.get_sem_block_lock().wait(); - data.get_nwaiters_blocked() -= data.get_nwaiters_gone(); // something is going on here - test of timeouts? :-) - data.get_sem_block_lock().post(); - data.get_nwaiters_gone() = 0; - } - //locker's destructor triggers data.get_mtx_unblock_lock().unlock() - } - - if ( 1 == nsignals_was_left ) { - if ( 0 != nwaiters_was_gone ) { - // sem_adjust( data.get_sem_block_queue(),-nwaiters_was_gone ); - while ( nwaiters_was_gone-- ) { - data.get_sem_block_queue().wait(); // better now than spurious later + else { // NO-OP + //locker's destructor triggers data.get_mtx_unblock_lock().unlock() + return; } + //locker's destructor triggers data.get_mtx_unblock_lock().unlock() } - data.get_sem_block_lock().post(); // open the gate + data.get_sem_block_queue().post(nsignals_to_issue); } - //lock.lock(); called from unlocker destructor - - return ( bTimedOut ) ? false : true; -} + private: + template<class TimePoint> + static bool do_sem_timed_wait(semaphore_type &sem, const TimePoint &abs_time, bool_<true>) + { return sem.timed_wait(abs_time); } + template<class TimePoint> + static bool do_sem_timed_wait(semaphore_type &sem, const TimePoint &, bool_<false>) + { sem.wait(); return true; } +}; template<class ConditionMembers> class condition_8a_wrapper @@ -326,7 +320,7 @@ class condition_8a_wrapper condition_8a_wrapper &operator=(const condition_8a_wrapper &); ConditionMembers m_data; - typedef ipcdetail::condition_algorithm_8a<ConditionMembers> algo_type; + typedef condition_algorithm_8a<ConditionMembers> algo_type; public: @@ -352,7 +346,7 @@ class condition_8a_wrapper { if (!lock) throw lock_exception(); - algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + algo_type::template wait<false>(m_data, lock, 0); } template <typename L, typename Pr> @@ -362,24 +356,24 @@ class condition_8a_wrapper throw lock_exception(); while (!pred()) - algo_type::wait(m_data, lock, false, boost::posix_time::ptime()); + algo_type::template wait<false>(m_data, lock, 0); } - template <typename L> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + template <typename L, class TimePoint> + bool timed_wait(L& lock, const TimePoint &abs_time) { if (!lock) throw lock_exception(); - return algo_type::wait(m_data, lock, true, abs_time); + return algo_type::template wait<true>(m_data, lock, abs_time); } - template <typename L, typename Pr> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + template <typename L, class TimePoint, typename Pr> + bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) { if (!lock) throw lock_exception(); while (!pred()){ - if (!algo_type::wait(m_data, lock, true, abs_time)) + if (!algo_type::template wait<true>(m_data, lock, abs_time)) return pred(); } return true; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/locks.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/locks.hpp index 88d9c0cb48..a2beb8917c 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/locks.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/detail/locks.hpp @@ -35,18 +35,18 @@ class internal_mutex_lock typedef typename Lock::mutex_type::internal_mutex_type mutex_type; - internal_mutex_lock(Lock &l) + BOOST_INTERPROCESS_FORCEINLINE internal_mutex_lock(Lock &l) : l_(l) {} - mutex_type* mutex() const + BOOST_INTERPROCESS_FORCEINLINE mutex_type* mutex() const { return l_ ? &l_.mutex()->internal_mutex() : 0; } - void lock() { l_.lock(); } + BOOST_INTERPROCESS_FORCEINLINE void lock() { l_.lock(); } - void unlock() { l_.unlock(); } + BOOST_INTERPROCESS_FORCEINLINE void unlock() { l_.unlock(); } - operator unspecified_bool_type() const + BOOST_INTERPROCESS_FORCEINLINE operator unspecified_bool_type() const { return l_ ? &internal_mutex_lock::lock : 0; } private: @@ -58,11 +58,13 @@ class lock_inverter { Lock &l_; public: - lock_inverter(Lock &l) + BOOST_INTERPROCESS_FORCEINLINE lock_inverter(Lock &l) : l_(l) {} - void lock() { l_.unlock(); } - void unlock() { l_.lock(); } + + BOOST_INTERPROCESS_FORCEINLINE void lock() { l_.unlock(); } + + BOOST_INTERPROCESS_FORCEINLINE void unlock() { l_.lock(); } }; template <class Lock> @@ -71,12 +73,15 @@ class lock_to_sharable Lock &l_; public: - explicit lock_to_sharable(Lock &l) + BOOST_INTERPROCESS_FORCEINLINE explicit lock_to_sharable(Lock &l) : l_(l) {} - void lock() { l_.lock_sharable(); } - bool try_lock(){ return l_.try_lock_sharable(); } - void unlock() { l_.unlock_sharable(); } + + BOOST_INTERPROCESS_FORCEINLINE void lock() { l_.lock_sharable(); } + + BOOST_INTERPROCESS_FORCEINLINE bool try_lock(){ return l_.try_lock_sharable(); } + + BOOST_INTERPROCESS_FORCEINLINE void unlock() { l_.unlock_sharable(); } }; template <class Lock> @@ -85,11 +90,16 @@ class lock_to_wait Lock &l_; public: - explicit lock_to_wait(Lock &l) + BOOST_INTERPROCESS_FORCEINLINE explicit lock_to_wait(Lock &l) : l_(l) {} - void lock() { l_.wait(); } - bool try_lock(){ return l_.try_wait(); } + BOOST_INTERPROCESS_FORCEINLINE void lock() { l_.wait(); } + + BOOST_INTERPROCESS_FORCEINLINE bool try_lock() { return l_.try_wait(); } + + template<class TimePoint> + BOOST_INTERPROCESS_FORCEINLINE bool timed_lock(const TimePoint &abs_time) + { return l_.timed_wait(abs_time); } }; } //namespace ipcdetail diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/interprocess_condition.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/interprocess_condition.hpp index c98ece8821..24ca5b5f0f 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/interprocess_condition.hpp @@ -24,23 +24,23 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> +#include <boost/interprocess/sync/cv_status.hpp> #include <boost/interprocess/sync/interprocess_mutex.hpp> #include <boost/interprocess/sync/detail/locks.hpp> #include <boost/interprocess/exceptions.hpp> #include <boost/limits.hpp> #include <boost/assert.hpp> -#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) #include <boost/interprocess/sync/posix/condition.hpp> - #define BOOST_INTERPROCESS_USE_POSIX + #define BOOST_INTERPROCESS_CONDITION_USE_POSIX //Experimental... #elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) #include <boost/interprocess/sync/windows/condition.hpp> - #define BOOST_INTERPROCESS_USE_WINDOWS -#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + #define BOOST_INTERPROCESS_CONDITION_USE_WINAPI +#else + //spin_condition is used #include <boost/interprocess/sync/spin/condition.hpp> - #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED @@ -49,14 +49,6 @@ //!Describes process-shared variables interprocess_condition class namespace boost { - -#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - -namespace posix_time -{ class ptime; } - -#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - namespace interprocess { class named_condition; @@ -121,8 +113,8 @@ class interprocess_condition //!this->notify_one() or this->notify_all(), or until time abs_time is reached, //!and then reacquires the lock. //!Returns: false if time abs_time is reached, otherwise true. - template <typename L> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + template <typename L, class TimePoint> + bool timed_wait(L& lock, const TimePoint &abs_time) { ipcdetail::internal_mutex_lock<L> internal_lock(lock); return m_condition.timed_wait(internal_lock, abs_time); @@ -131,28 +123,48 @@ class interprocess_condition //!The same as: while (!pred()) { //! if (!timed_wait(lock, abs_time)) return pred(); //! } return true; - template <typename L, typename Pr> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + template <typename L, class TimePoint, typename Pr> + bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) { ipcdetail::internal_mutex_lock<L> internal_lock(lock); return m_condition.timed_wait(internal_lock, abs_time, pred); } + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template <typename L, class TimePoint> + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template <typename L, class TimePoint, typename Pr> + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts. + template <typename L, class Duration> + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur)); } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface and uses relative timeouts + template <typename L, class Duration, typename Pr> + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, ipcdetail::duration_to_ustime(dur), pred); } + #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: - #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) - #undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION - ipcdetail::spin_condition m_condition; - #elif defined(BOOST_INTERPROCESS_USE_POSIX) - #undef BOOST_INTERPROCESS_USE_POSIX + #if defined(BOOST_INTERPROCESS_CONDITION_USE_POSIX) ipcdetail::posix_condition m_condition; - #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) - #undef BOOST_INTERPROCESS_USE_WINDOWS - ipcdetail::windows_condition m_condition; + #elif defined(BOOST_INTERPROCESS_CONDITION_USE_WINAPI) + ipcdetail::winapi_condition m_condition; #else - #error "Unknown platform for interprocess_mutex" + ipcdetail::spin_condition m_condition; #endif + #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED }; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/interprocess_mutex.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/interprocess_mutex.hpp index 8bfc02c15d..4eb1f592c8 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/interprocess_mutex.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -28,30 +28,28 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/exceptions.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/assert.hpp> +#include <boost/interprocess/sync/detail/common_algorithms.hpp> #if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) #include <boost/interprocess/sync/posix/mutex.hpp> - #define BOOST_INTERPROCESS_USE_POSIX -//Experimental... + #define BOOST_INTERPROCESS_MUTEX_USE_POSIX #elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + //Experimental... + #define BOOST_INTERPROCESS_MUTEX_USE_WINAPI #include <boost/interprocess/sync/windows/mutex.hpp> - #define BOOST_INTERPROCESS_USE_WINDOWS -#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +#else + //spin_mutex is used #include <boost/interprocess/sync/spin/mutex.hpp> - #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION + namespace boost { + namespace interprocess { + namespace ipcdetail{ + namespace robust_emulation_helpers { -namespace boost { -namespace interprocess { -namespace ipcdetail{ -namespace robust_emulation_helpers { - -template<class T> -class mutex_traits; - -}}}} + template<class T> + class mutex_traits; + }}}} #endif #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED @@ -76,21 +74,16 @@ class interprocess_mutex friend class interprocess_condition; public: - #if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION) - #undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION + #if defined(BOOST_INTERPROCESS_MUTEX_USE_POSIX) + typedef ipcdetail::posix_mutex internal_mutex_type; + #elif defined(BOOST_INTERPROCESS_MUTEX_USE_WINAPI) + typedef ipcdetail::winapi_mutex internal_mutex_type; + #else typedef ipcdetail::spin_mutex internal_mutex_type; private: friend class ipcdetail::robust_emulation_helpers::mutex_traits<interprocess_mutex>; void take_ownership(){ m_mutex.take_ownership(); } public: - #elif defined(BOOST_INTERPROCESS_USE_POSIX) - #undef BOOST_INTERPROCESS_USE_POSIX - typedef ipcdetail::posix_mutex internal_mutex_type; - #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) - #undef BOOST_INTERPROCESS_USE_WINDOWS - typedef ipcdetail::windows_mutex internal_mutex_type; - #else - #error "Unknown platform for interprocess_mutex" #endif #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED @@ -104,20 +97,34 @@ class interprocess_mutex //!the result is undefined. Does not throw. ~interprocess_mutex(); + //!Requires: The calling thread does not own the mutex. + //! //!Effects: The calling thread tries to obtain ownership of the mutex, and //! if another thread has ownership of the mutex, it waits until it can //! obtain the ownership. If a thread takes ownership of the mutex the //! mutex must be unlocked by the same mutex. //!Throws: interprocess_exception on error. + //! + //!Note: A program may deadlock if the thread that has ownership calls + //! this function. If the implementation can detect the deadlock, + //! an exception could be thrown. void lock(); + //!Requires: The calling thread does not own the mutex. + //! //!Effects: The calling thread tries to obtain ownership of the mutex, and //! if another thread has ownership of the mutex returns immediately. //!Returns: If the thread acquires ownership of the mutex, returns true, if //! the another thread has ownership of the mutex, returns false. //!Throws: interprocess_exception on error. + //! + //!Note: A program may deadlock if the thread that has ownership calls + //! this function. If the implementation can detect the deadlock, + //! an exception could be thrown. bool try_lock(); + //!Requires: The calling thread does not own the mutex. + //! //!Effects: The calling thread will try to obtain exclusive ownership of the //! mutex if it can do so in until the specified time is reached. If the //! mutex supports recursive locking, the mutex must be unlocked the same @@ -125,7 +132,22 @@ class interprocess_mutex //!Returns: If the thread acquires ownership of the mutex, returns true, if //! the timeout expires returns false. //!Throws: interprocess_exception on error. - bool timed_lock(const boost::posix_time::ptime &abs_time); + //! + //!Note: A program may deadlock if the thread that has ownership calls + //! this function. If the implementation can detect the deadlock, + //! an exception could be thrown. + template<class TimePoint> + bool timed_lock(const TimePoint &abs_time); + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template<class TimePoint> bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + //!Same as `timed_lock`, but this function is modeled after the + //!standard library interface. + template<class Duration> bool try_lock_for(const Duration &dur) + { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); } //!Effects: The calling thread releases the exclusive ownership of the mutex. //!Throws: interprocess_exception on error. @@ -155,26 +177,13 @@ inline interprocess_mutex::interprocess_mutex(){} inline interprocess_mutex::~interprocess_mutex(){} inline void interprocess_mutex::lock() -{ - #ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING - boost::posix_time::ptime wait_time - = microsec_clock::universal_time() - + boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS); - if (!m_mutex.timed_lock(wait_time)) - { - throw interprocess_exception(timeout_when_locking_error - , "Interprocess mutex timeout when locking. Possible deadlock: " - "owner died without unlocking?"); - } - #else - m_mutex.lock(); - #endif -} +{ ipcdetail::timeout_when_locking_aware_lock(m_mutex); } inline bool interprocess_mutex::try_lock() { return m_mutex.try_lock(); } -inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +template <class TimePoint> +inline bool interprocess_mutex::timed_lock(const TimePoint &abs_time) { return m_mutex.timed_lock(abs_time); } inline void interprocess_mutex::unlock() diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/lock_options.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/lock_options.hpp index 981ff5b6d3..a79159a480 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/lock_options.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/lock_options.hpp @@ -26,14 +26,6 @@ //!Describes the lock options with associated with interprocess_mutex lock constructors. namespace boost { - -#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - -namespace posix_time -{ class ptime; } - -#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - namespace interprocess { //!Type to indicate to a mutex lock constructor that must not lock the mutex. diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/condition.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/condition.hpp index 5372d96891..f151a5b98c 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/condition.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/condition.hpp @@ -22,11 +22,12 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/sync/cv_status.hpp> #include <pthread.h> #include <errno.h> #include <boost/interprocess/sync/posix/pthread_helpers.hpp> -#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> +#include <boost/interprocess/sync/posix/timepoint_to_timespec.hpp> +#include <boost/interprocess/detail/timed_utils.hpp> #include <boost/interprocess/sync/posix/mutex.hpp> #include <boost/assert.hpp> @@ -84,13 +85,13 @@ class posix_condition //!this->notify_one() or this->notify_all(), or until time abs_time is reached, //!and then reacquires the lock. //!Returns: false if time abs_time is reached, otherwise true. - template <typename L> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + template <typename L, typename TimePoint> + bool timed_wait(L& lock, const TimePoint &abs_time) { if (!lock) throw lock_exception(); //Posix does not support infinity absolute time so handle it here - if(abs_time == boost::posix_time::pos_infin){ + if(ipcdetail::is_pos_infinity(abs_time)){ this->wait(lock); return true; } @@ -100,13 +101,13 @@ class posix_condition //!The same as: while (!pred()) { //! if (!timed_wait(lock, abs_time)) return pred(); //! } return true; - template <typename L, typename Pr> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + template <typename L, typename TimePoint, typename Pr> + bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) { if (!lock) throw lock_exception(); //Posix does not support infinity absolute time so handle it here - if(abs_time == boost::posix_time::pos_infin){ + if(ipcdetail::is_pos_infinity(abs_time)){ this->wait(lock, pred); return true; } @@ -117,10 +118,30 @@ class posix_condition return true; } + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template <typename L, class TimePoint> + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + //!Same as `timed_wait`, but this function is modeled after the + //!standard library interface. + template <typename L, class TimePoint, typename Pr> + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + template <typename L, class Duration> + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, duration_to_ustime(dur)) ? cv_status::no_timeout : cv_status::timeout; } + + template <typename L, class Duration, typename Pr> + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, duration_to_ustime(dur), pred); } void do_wait(posix_mutex &mut); - bool do_timed_wait(const boost::posix_time::ptime &abs_time, posix_mutex &mut); + template<class TimePoint> + bool do_timed_wait(const TimePoint &abs_time, posix_mutex &mut); private: pthread_cond_t m_condition; @@ -175,10 +196,11 @@ inline void posix_condition::do_wait(posix_mutex &mut) BOOST_ASSERT(res == 0); (void)res; } +template<class TimePoint> inline bool posix_condition::do_timed_wait - (const boost::posix_time::ptime &abs_time, posix_mutex &mut) + (const TimePoint &abs_time, posix_mutex &mut) { - timespec ts = ptime_to_timespec(abs_time); + timespec ts = timepoint_to_timespec(abs_time); pthread_mutex_t* pmutex = &mut.m_mut; int res = 0; res = pthread_cond_timedwait(&m_condition, pmutex, &ts); diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/mutex.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/mutex.hpp index 70adc23c96..69cc1626ea 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/mutex.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/mutex.hpp @@ -41,10 +41,11 @@ #include <pthread.h> #include <errno.h> #include <boost/interprocess/exceptions.hpp> -#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> +#include <boost/interprocess/sync/posix/timepoint_to_timespec.hpp> #include <boost/interprocess/exceptions.hpp> #include <boost/interprocess/sync/posix/pthread_helpers.hpp> +#include <boost/interprocess/detail/timed_utils.hpp> + #ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS # include <boost/interprocess/detail/os_thread_functions.hpp> @@ -69,7 +70,14 @@ class posix_mutex void lock(); bool try_lock(); - bool timed_lock(const boost::posix_time::ptime &abs_time); + template<class TimePoint> bool timed_lock(const TimePoint &abs_time); + + template<class TimePoint> bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template<class Duration> bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + void unlock(); friend class posix_condition; @@ -93,28 +101,66 @@ inline posix_mutex::~posix_mutex() inline void posix_mutex::lock() { - if (pthread_mutex_lock(&m_mut) != 0) + int res = pthread_mutex_lock(&m_mut); + #ifdef BOOST_INTERPROCESS_POSIX_ROBUST_MUTEXES + if (res == EOWNERDEAD) + { + //We can't inform the application and data might + //corrupted, so be safe and mark the mutex as not recoverable + //so applications can act accordingly. + pthread_mutex_unlock(&m_mut); + throw lock_exception(not_recoverable); + } + else if (res == ENOTRECOVERABLE) + throw lock_exception(not_recoverable); + #endif + if (res != 0) throw lock_exception(); } inline bool posix_mutex::try_lock() { int res = pthread_mutex_trylock(&m_mut); + #ifdef BOOST_INTERPROCESS_POSIX_ROBUST_MUTEXES + if (res == EOWNERDEAD) + { + //We can't inform the application and data might + //corrupted, so be safe and mark the mutex as not recoverable + //so applications can act accordingly. + pthread_mutex_unlock(&m_mut); + throw lock_exception(not_recoverable); + } + else if (res == ENOTRECOVERABLE) + throw lock_exception(not_recoverable); + #endif if (!(res == 0 || res == EBUSY)) throw lock_exception(); return res == 0; } -inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +template<class TimePoint> +inline bool posix_mutex::timed_lock(const TimePoint &abs_time) { #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS //Posix does not support infinity absolute time so handle it here - if(abs_time == boost::posix_time::pos_infin){ + if(ipcdetail::is_pos_infinity(abs_time)){ this->lock(); return true; } - timespec ts = ptime_to_timespec(abs_time); + timespec ts = timepoint_to_timespec(abs_time); int res = pthread_mutex_timedlock(&m_mut, &ts); + #ifdef BOOST_INTERPROCESS_POSIX_ROBUST_MUTEXES + if (res == EOWNERDEAD) + { + //We can't inform the application and data might + //corrupted, so be safe and mark the mutex as not recoverable + //so applications can act accordingly. + pthread_mutex_unlock(&m_mut); + throw lock_exception(not_recoverable); + } + else if (res == ENOTRECOVERABLE) + throw lock_exception(not_recoverable); + #endif if (res != 0 && res != ETIMEDOUT) throw lock_exception(); return res == 0; @@ -128,8 +174,7 @@ inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time) inline void posix_mutex::unlock() { - int res = 0; - res = pthread_mutex_unlock(&m_mut); + int res = pthread_mutex_unlock(&m_mut); (void)res; BOOST_ASSERT(res == 0); } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/pthread_helpers.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/pthread_helpers.hpp index c615c851eb..f247d5e596 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/pthread_helpers.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/pthread_helpers.hpp @@ -41,8 +41,12 @@ namespace ipcdetail{ if(pthread_mutexattr_init(&m_attr)!=0 || pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0 || (recursive && - pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE)!= 0 )) - throw interprocess_exception("pthread_mutexattr_xxxx failed"); + pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE) != 0 ) + #ifdef BOOST_INTERPROCESS_POSIX_ROBUST_MUTEXES + || pthread_mutexattr_setrobust(&m_attr, PTHREAD_MUTEX_ROBUST) != 0 + #endif + ) + throw interprocess_exception("pthread_mutexattr_xxxx failed"); } //!Destructor @@ -144,7 +148,7 @@ namespace ipcdetail{ //!Constructor. Takes barrier attributes to initialize the barrier barrier_initializer(pthread_barrier_t &mut, pthread_barrierattr_t &mut_attr, - int count) + unsigned int count) : mp_barrier(&mut) { if(pthread_barrier_init(mp_barrier, &mut_attr, count) != 0) diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp deleted file mode 100644 index 5aa09e0c19..0000000000 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp +++ /dev/null @@ -1,48 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/interprocess for documentation. -// -////////////////////////////////////////////////////////////////////////////// - -#ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP -#define BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP - -#ifndef BOOST_CONFIG_HPP -# include <boost/config.hpp> -#endif -# -#if defined(BOOST_HAS_PRAGMA_ONCE) -# pragma once -#endif - -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> - -namespace boost { - -namespace interprocess { - -namespace ipcdetail { - -inline timespec ptime_to_timespec (const boost::posix_time::ptime &tm) -{ - const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); - //Avoid negative absolute times - boost::posix_time::time_duration duration = (tm <= epoch) ? boost::posix_time::time_duration(epoch - epoch) - : boost::posix_time::time_duration(tm - epoch); - timespec ts; - ts.tv_sec = duration.total_seconds(); - ts.tv_nsec = duration.total_nanoseconds() % 1000000000; - return ts; -} - -} //namespace ipcdetail { - -} //namespace interprocess { - -} //namespace boost { - -#endif //ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/timepoint_to_timespec.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/timepoint_to_timespec.hpp new file mode 100644 index 0000000000..297fe8adf7 --- /dev/null +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/posix/timepoint_to_timespec.hpp @@ -0,0 +1,87 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TIMEPOINT_TO_TIMESPEC_HPP +#define BOOST_INTERPROCESS_DETAIL_TIMEPOINT_TO_TIMESPEC_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include <boost/interprocess/detail/mpl.hpp> +#include <boost/interprocess/detail/type_traits.hpp> +#include <boost/interprocess/detail/timed_utils.hpp> + +namespace boost { + +namespace interprocess { + +namespace ipcdetail { + +template<class TimePoint> +inline timespec timepoint_to_timespec ( const TimePoint &tm + , typename enable_if_ptime<TimePoint>::type * = 0) +{ + typedef typename TimePoint::date_type date_type; + typedef typename TimePoint::time_duration_type time_duration_type; + + const TimePoint epoch(date_type(1970,1,1)); + + //Avoid negative absolute times + time_duration_type duration = (tm <= epoch) ? time_duration_type(epoch - epoch) + : time_duration_type(tm - epoch); + timespec ts; + ts.tv_sec = static_cast<time_t>(duration.total_seconds()); + ts.tv_nsec = static_cast<long>(duration.total_nanoseconds() % 1000000000); + return ts; +} + +inline timespec timepoint_to_timespec (const ustime &tm) +{ + timespec ts; + ts.tv_sec = static_cast<time_t>(tm.get_microsecs()/1000000u); + ts.tv_nsec = static_cast<long>((tm.get_microsecs()%1000000u)*1000u); + return ts; +} + +template<class TimePoint> +inline timespec timepoint_to_timespec ( const TimePoint &tm + , typename enable_if_time_point<TimePoint>::type * = 0) +{ + typedef typename TimePoint::duration duration_t; + duration_t d(tm.time_since_epoch()); + + timespec ts; + BOOST_IF_CONSTEXPR(duration_t::period::num == 1 && duration_t::period::den == 1000000000) + { + ts.tv_sec = static_cast<time_t>(d.count()/duration_t::period::den); + ts.tv_nsec = static_cast<long>(d.count()%duration_t::period::den); + } + else + { + const double factor = double(duration_t::period::num)/double(duration_t::period::den); + const double res = d.count()*factor; + ts.tv_sec = static_cast<time_t>(res); + ts.tv_nsec = static_cast<long>(res - double(ts.tv_sec)); + } + return ts; +} + +} //namespace ipcdetail { + +} //namespace interprocess { + +} //namespace boost { + +#endif //ifndef BOOST_INTERPROCESS_DETAIL_TIMEPOINT_TO_TIMESPEC_HPP diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/scoped_lock.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/scoped_lock.hpp index 97986f0361..35e1cc4cf7 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/scoped_lock.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/scoped_lock.hpp @@ -32,7 +32,6 @@ #include <boost/interprocess/detail/mpl.hpp> #include <boost/interprocess/detail/type_traits.hpp> #include <boost/move/utility_core.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/interprocess/detail/simple_swap.hpp> //!\file @@ -67,7 +66,7 @@ class scoped_lock //!Effects: Default constructs a scoped_lock. //!Postconditions: owns() == false and mutex() == 0. - scoped_lock() + scoped_lock() BOOST_NOEXCEPT : mp_mutex(0), m_locked(false) {} @@ -114,7 +113,8 @@ class scoped_lock //! handles recursive locking depends upon the mutex. If the mutex_type //! does not support try_lock, this constructor will fail at compile //! time if instantiated, but otherwise have no effect. - scoped_lock(mutex_type& m, const boost::posix_time::ptime& abs_time) + template<class TimePoint> + scoped_lock(mutex_type& m, const TimePoint& abs_time) : mp_mutex(&m), m_locked(mp_mutex->timed_lock(abs_time)) {} @@ -128,7 +128,7 @@ class scoped_lock //! can be moved with the expression: "boost::move(lock);". This //! constructor does not alter the state of the mutex, only potentially //! who owns it. - scoped_lock(BOOST_RV_REF(scoped_lock) scop) + scoped_lock(BOOST_RV_REF(scoped_lock) scop) BOOST_NOEXCEPT : mp_mutex(0), m_locked(scop.owns()) { mp_mutex = scop.release(); } @@ -202,8 +202,8 @@ class scoped_lock //! "write lock". If the "read lock" isn't held in the first place, the mutex //! merely changes type to an unlocked "write lock". If the "read lock" is held, //! then mutex transfer occurs only if it can do so in a non-blocking manner. - template<class T> - scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr, boost::posix_time::ptime &abs_time + template<class T, class TimePoint> + scoped_lock(BOOST_RV_REF(upgradable_lock<T>) upgr, const TimePoint &abs_time , typename ipcdetail::enable_if< ipcdetail::is_same<T, Mutex> >::type * = 0) : mp_mutex(0), m_locked(false) { @@ -253,8 +253,8 @@ class scoped_lock //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/ ~scoped_lock() { - try{ if(m_locked && mp_mutex) mp_mutex->unlock(); } - catch(...){} + BOOST_TRY{ if(m_locked && mp_mutex) mp_mutex->unlock(); } + BOOST_CATCH(...){} BOOST_CATCH_END } //!Effects: If owns() before the call, then unlock() is called on mutex(). @@ -307,7 +307,8 @@ class scoped_lock //! owning the mutex, but only if it can obtain ownership by the specified //! time. If the mutex_type does not support timed_lock (), this function //! will fail at compile time if instantiated, but otherwise have no effect.*/ - bool timed_lock(const boost::posix_time::ptime& abs_time) + template<class TimePoint> + bool timed_lock(const TimePoint& abs_time) { if(!mp_mutex || m_locked) throw lock_exception(); @@ -315,6 +316,38 @@ class scoped_lock return m_locked; } + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls try_lock_until(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time). + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, but only if it can obtain ownership by the specified + //! time. If the mutex_type does not support timed_lock (), this function + //! will fail at compile time if instantiated, but otherwise have no effect.*/ + template<class TimePoint> + bool try_lock_until(const TimePoint& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_until(abs_time); + return m_locked; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls try_lock_until(abs_time) on the referenced mutex. + //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time). + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, but only if it can obtain ownership by the specified + //! time. If the mutex_type does not support timed_lock (), this function + //! will fail at compile time if instantiated, but otherwise have no effect.*/ + template<class Duration> + bool try_lock_for(const Duration& dur) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_for(dur); + return m_locked; + } + //!Effects: If mutex() == 0 or if not locked, throws a lock_exception() //! exception. Calls unlock() on the referenced mutex. //!Postconditions: owns() == false. @@ -330,23 +363,23 @@ class scoped_lock //!Effects: Returns true if this scoped_lock has acquired //!the referenced mutex. - bool owns() const + bool owns() const BOOST_NOEXCEPT { return m_locked && mp_mutex; } //!Conversion to bool. //!Returns owns(). - operator unspecified_bool_type() const + operator unspecified_bool_type() const BOOST_NOEXCEPT { return m_locked? &this_type::m_locked : 0; } //!Effects: Returns a pointer to the referenced mutex, or 0 if //!there is no mutex to reference. - mutex_type* mutex() const + mutex_type* mutex() const BOOST_NOEXCEPT { return mp_mutex; } //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no //! mutex to reference. //!Postconditions: mutex() == 0 and owns() == false. - mutex_type* release() + mutex_type* release() BOOST_NOEXCEPT { mutex_type *mut = mp_mutex; mp_mutex = 0; @@ -356,7 +389,7 @@ class scoped_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - void swap( scoped_lock<mutex_type> &other) + void swap( scoped_lock<mutex_type> &other) BOOST_NOEXCEPT { (simple_swap)(mp_mutex, other.mp_mutex); (simple_swap)(m_locked, other.m_locked); diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/spin/condition.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/spin/condition.hpp index 1a1878b8ac..cf3a15970f 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/spin/condition.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/spin/condition.hpp @@ -21,12 +21,14 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> + +#include <boost/interprocess/sync/cv_status.hpp> #include <boost/interprocess/sync/spin/mutex.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/interprocess/detail/atomic.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> #include <boost/interprocess/exceptions.hpp> #include <boost/interprocess/detail/os_thread_functions.hpp> +#include <boost/interprocess/detail/timed_utils.hpp> #include <boost/interprocess/sync/spin/wait.hpp> #include <boost/move/utility_core.hpp> #include <boost/cstdint.hpp> @@ -39,261 +41,253 @@ class spin_condition { spin_condition(const spin_condition &); spin_condition &operator=(const spin_condition &); + public: - spin_condition(); - ~spin_condition(); + spin_condition() + { + //Note that this class is initialized to zero. + //So zeroed memory can be interpreted as an initialized + //condition variable + m_command = SLEEP; + m_num_waiters = 0; + } + + ~spin_condition() + { + //Notify all waiting threads + //to allow POSIX semantics on condition destruction + this->notify_all(); + } - void notify_one(); - void notify_all(); + void notify_one() + { this->notify(NOTIFY_ONE); } + + void notify_all() + { this->notify(NOTIFY_ALL); } template <typename L> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + this->do_timed_wait_impl<false>(0, *lock.mutex()); + } + + template <typename L, typename Pr> + void wait(L& lock, Pr pred) + { + if (!lock) + throw lock_exception(); + + while (!pred()) + this->do_timed_wait_impl<false>(0, *lock.mutex()); + } + + template <typename L, typename TimePoint> + bool timed_wait(L& lock, const TimePoint &abs_time) { if (!lock) throw lock_exception(); //Handle infinity absolute time here to avoid complications in do_timed_wait - if(abs_time == boost::posix_time::pos_infin){ + if(is_pos_infinity(abs_time)){ this->wait(lock); return true; } - return this->do_timed_wait(abs_time, *lock.mutex()); + return this->do_timed_wait_impl<true>(abs_time, *lock.mutex()); } - template <typename L, typename Pr> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) + template <typename L, typename TimePoint, typename Pr> + bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) { if (!lock) throw lock_exception(); //Handle infinity absolute time here to avoid complications in do_timed_wait - if(abs_time == boost::posix_time::pos_infin){ + if(is_pos_infinity(abs_time)){ this->wait(lock, pred); return true; } while (!pred()){ - if (!this->do_timed_wait(abs_time, *lock.mutex())) + if (!this->do_timed_wait_impl<true>(abs_time, *lock.mutex())) return pred(); } return true; } - template <typename L> - void wait(L& lock) - { - if (!lock) - throw lock_exception(); - do_wait(*lock.mutex()); - } - - template <typename L, typename Pr> - void wait(L& lock, Pr pred) - { - if (!lock) - throw lock_exception(); + template <typename L, class TimePoint> + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } - while (!pred()) - do_wait(*lock.mutex()); - } + template <typename L, class TimePoint, typename Pr> + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } - template<class InterprocessMutex> - void do_wait(InterprocessMutex &mut); + template <typename L, class Duration> + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, duration_to_ustime(dur)); } - template<class InterprocessMutex> - bool do_timed_wait(const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); + template <typename L, class Duration, typename Pr> + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, duration_to_ustime(dur), pred); } private: - template<class InterprocessMutex> - bool do_timed_wait(bool tout_enabled, const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); - - enum { SLEEP = 0, NOTIFY_ONE, NOTIFY_ALL }; - spin_mutex m_enter_mut; - volatile boost::uint32_t m_command; - volatile boost::uint32_t m_num_waiters; - void notify(boost::uint32_t command); -}; -inline spin_condition::spin_condition() -{ - //Note that this class is initialized to zero. - //So zeroed memory can be interpreted as an initialized - //condition variable - m_command = SLEEP; - m_num_waiters = 0; -} - -inline spin_condition::~spin_condition() -{ - //Notify all waiting threads - //to allow POSIX semantics on condition destruction - this->notify_all(); -} + template<bool TimeoutEnabled, class InterprocessMutex, class TimePoint> + bool do_timed_wait_impl(const TimePoint &abs_time, InterprocessMutex &mut) + { + typedef boost::interprocess::scoped_lock<spin_mutex> InternalLock; + //The enter mutex guarantees that while executing a notification, + //no other thread can execute the do_timed_wait method. + { + //--------------------------------------------------------------- + InternalLock lock; + get_lock(bool_<TimeoutEnabled>(), m_enter_mut, lock, abs_time); + + if(!lock) + return false; + //--------------------------------------------------------------- + //We increment the waiting thread count protected so that it will be + //always constant when another thread enters the notification logic. + //The increment marks this thread as "waiting on spin_condition" + atomic_inc32(const_cast<boost::uint32_t*>(&m_num_waiters)); + + //We unlock the external mutex atomically with the increment + mut.unlock(); + } -inline void spin_condition::notify_one() -{ - this->notify(NOTIFY_ONE); -} + //By default, we suppose that no timeout has happened + bool timed_out = false, unlock_enter_mut= false; + + //Loop until a notification indicates that the thread should + //exit or timeout occurs + while(1){ + //The thread sleeps/spins until a spin_condition commands a notification + //Notification occurred, we will lock the checking mutex so that + spin_wait swait; + while(atomic_read32(&m_command) == SLEEP){ + swait.yield(); + + //Check for timeout + if(TimeoutEnabled){ + TimePoint now = get_now<TimePoint>(bool_<TimeoutEnabled>()); + + if(now >= abs_time){ + //If we can lock the mutex it means that no notification + //is being executed in this spin_condition variable + timed_out = m_enter_mut.try_lock(); + + //If locking fails, indicates that another thread is executing + //notification, so we play the notification game + if(!timed_out){ + //There is an ongoing notification, we will try again later + continue; + } + //No notification in execution, since enter mutex is locked. + //We will execute time-out logic, so we will decrement count, + //release the enter mutex and return false. + break; + } + } + } -inline void spin_condition::notify_all() -{ - this->notify(NOTIFY_ALL); -} + //If a timeout occurred, the mutex will not execute checking logic + if(TimeoutEnabled && timed_out){ + //Decrement wait count + atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); + unlock_enter_mut = true; + break; + } + else{ + boost::uint32_t result = atomic_cas32 + (const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ONE); + if(result == SLEEP){ + //Other thread has been notified and since it was a NOTIFY one + //command, this thread must sleep again + continue; + } + else if(result == NOTIFY_ONE){ + //If it was a NOTIFY_ONE command, only this thread should + //exit. This thread has atomically marked command as sleep before + //so no other thread will exit. + //Decrement wait count. + unlock_enter_mut = true; + atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); + break; + } + else{ + //If it is a NOTIFY_ALL command, all threads should return + //from do_timed_wait function. Decrement wait count. + unlock_enter_mut = 1 == atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); + //Check if this is the last thread of notify_all waiters + //Only the last thread will release the mutex + if(unlock_enter_mut){ + atomic_cas32(const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ALL); + } + break; + } + } + } -inline void spin_condition::notify(boost::uint32_t command) -{ - //This mutex guarantees that no other thread can enter to the - //do_timed_wait method logic, so that thread count will be - //constant until the function writes a NOTIFY_ALL command. - //It also guarantees that no other notification can be signaled - //on this spin_condition before this one ends - m_enter_mut.lock(); - - //Return if there are no waiters - if(!atomic_read32(&m_num_waiters)) { - m_enter_mut.unlock(); - return; - } + //Unlock the enter mutex if it is a single notification, if this is + //the last notified thread in a notify_all or a timeout has occurred + if(unlock_enter_mut){ + m_enter_mut.unlock(); + } - //Notify that all threads should execute wait logic - spin_wait swait; - while(SLEEP != atomic_cas32(const_cast<boost::uint32_t*>(&m_command), command, SLEEP)){ - swait.yield(); + //Lock external again before returning from the method + mut.lock(); + return !timed_out; } - //The enter mutex will rest locked until the last waiting thread unlocks it -} -template<class InterprocessMutex> -inline void spin_condition::do_wait(InterprocessMutex &mut) -{ - this->do_timed_wait(false, boost::posix_time::ptime(), mut); -} + template <class TimePoint> + static TimePoint get_now(bool_<true>) + { return microsec_clock<TimePoint>::universal_time(); } -template<class InterprocessMutex> -inline bool spin_condition::do_timed_wait - (const boost::posix_time::ptime &abs_time, InterprocessMutex &mut) -{ - return this->do_timed_wait(true, abs_time, mut); -} + template <class TimePoint> + static TimePoint get_now(bool_<false>) + { return TimePoint(); } -template<class InterprocessMutex> -inline bool spin_condition::do_timed_wait(bool tout_enabled, - const boost::posix_time::ptime &abs_time, - InterprocessMutex &mut) -{ - boost::posix_time::ptime now = microsec_clock::universal_time(); + template <class Mutex, class Lock, class TimePoint> + static void get_lock(bool_<true>, Mutex &m, Lock &lck, const TimePoint &abs_time) + { + Lock dummy(m, abs_time); + lck = boost::move(dummy); + } - if(tout_enabled){ - if(now >= abs_time) return false; + template <class Mutex, class Lock, class TimePoint> + static void get_lock(bool_<false>, Mutex &m, Lock &lck, const TimePoint &) + { + Lock dummy(m); + lck = boost::move(dummy); } - typedef boost::interprocess::scoped_lock<spin_mutex> InternalLock; - //The enter mutex guarantees that while executing a notification, - //no other thread can execute the do_timed_wait method. + void notify(boost::uint32_t command) { - //--------------------------------------------------------------- - InternalLock lock; - if(tout_enabled){ - InternalLock dummy(m_enter_mut, abs_time); - lock = boost::move(dummy); - } - else{ - InternalLock dummy(m_enter_mut); - lock = boost::move(dummy); + //This mutex guarantees that no other thread can enter to the + //do_timed_wait method logic, so that thread count will be + //constant until the function writes a NOTIFY_ALL command. + //It also guarantees that no other notification can be signaled + //on this spin_condition before this one ends + m_enter_mut.lock(); + + //Return if there are no waiters + if(!atomic_read32(&m_num_waiters)) { + m_enter_mut.unlock(); + return; } - if(!lock) - return false; - //--------------------------------------------------------------- - //We increment the waiting thread count protected so that it will be - //always constant when another thread enters the notification logic. - //The increment marks this thread as "waiting on spin_condition" - atomic_inc32(const_cast<boost::uint32_t*>(&m_num_waiters)); - - //We unlock the external mutex atomically with the increment - mut.unlock(); - } - - //By default, we suppose that no timeout has happened - bool timed_out = false, unlock_enter_mut= false; - - //Loop until a notification indicates that the thread should - //exit or timeout occurs - while(1){ - //The thread sleeps/spins until a spin_condition commands a notification - //Notification occurred, we will lock the checking mutex so that + //Notify that all threads should execute wait logic spin_wait swait; - while(atomic_read32(&m_command) == SLEEP){ + while(SLEEP != atomic_cas32(const_cast<boost::uint32_t*>(&m_command), command, SLEEP)){ swait.yield(); - - //Check for timeout - if(tout_enabled){ - now = microsec_clock::universal_time(); - - if(now >= abs_time){ - //If we can lock the mutex it means that no notification - //is being executed in this spin_condition variable - timed_out = m_enter_mut.try_lock(); - - //If locking fails, indicates that another thread is executing - //notification, so we play the notification game - if(!timed_out){ - //There is an ongoing notification, we will try again later - continue; - } - //No notification in execution, since enter mutex is locked. - //We will execute time-out logic, so we will decrement count, - //release the enter mutex and return false. - break; - } - } - } - - //If a timeout occurred, the mutex will not execute checking logic - if(tout_enabled && timed_out){ - //Decrement wait count - atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); - unlock_enter_mut = true; - break; - } - else{ - boost::uint32_t result = atomic_cas32 - (const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ONE); - if(result == SLEEP){ - //Other thread has been notified and since it was a NOTIFY one - //command, this thread must sleep again - continue; - } - else if(result == NOTIFY_ONE){ - //If it was a NOTIFY_ONE command, only this thread should - //exit. This thread has atomically marked command as sleep before - //so no other thread will exit. - //Decrement wait count. - unlock_enter_mut = true; - atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); - break; - } - else{ - //If it is a NOTIFY_ALL command, all threads should return - //from do_timed_wait function. Decrement wait count. - unlock_enter_mut = 1 == atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); - //Check if this is the last thread of notify_all waiters - //Only the last thread will release the mutex - if(unlock_enter_mut){ - atomic_cas32(const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ALL); - } - break; - } } + //The enter mutex will rest locked until the last waiting thread unlocks it } - //Unlock the enter mutex if it is a single notification, if this is - //the last notified thread in a notify_all or a timeout has occurred - if(unlock_enter_mut){ - m_enter_mut.unlock(); - } - - //Lock external again before returning from the method - mut.lock(); - return !timed_out; -} + enum { SLEEP = 0, NOTIFY_ONE, NOTIFY_ALL }; + spin_mutex m_enter_mut; + volatile boost::uint32_t m_command; + volatile boost::uint32_t m_num_waiters; +}; } //namespace ipcdetail } //namespace interprocess diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/spin/mutex.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/spin/mutex.hpp index 7663673433..ce9f87fe79 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/spin/mutex.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/spin/mutex.hpp @@ -21,7 +21,6 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/assert.hpp> #include <boost/interprocess/detail/atomic.hpp> #include <boost/cstdint.hpp> @@ -43,11 +42,37 @@ class spin_mutex void lock(); bool try_lock(); - bool timed_lock(const boost::posix_time::ptime &abs_time); + template<class TimePoint> + bool timed_lock(const TimePoint &abs_time); + + template<class TimePoint> bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template<class Duration> bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + void unlock(); - void take_ownership(){}; + void take_ownership(){} private: volatile boost::uint32_t m_s; + + struct common_lock_wrapper + { + common_lock_wrapper(spin_mutex &sp) + : m_sp(sp) + {} + + void lock() + { + ipcdetail::try_based_lock(m_sp); + } + + template<class TimePoint> + bool timed_lock(const TimePoint &abs_time) + { return m_sp.timed_lock(abs_time); } + + spin_mutex &m_sp; + }; }; inline spin_mutex::spin_mutex() @@ -64,7 +89,10 @@ inline spin_mutex::~spin_mutex() } inline void spin_mutex::lock(void) -{ return ipcdetail::try_based_lock(*this); } +{ + common_lock_wrapper clw(*this); + ipcdetail::timeout_when_locking_aware_lock(clw); +} inline bool spin_mutex::try_lock(void) { @@ -72,7 +100,8 @@ inline bool spin_mutex::try_lock(void) return m_s == 1 && prev_s == 0; } -inline bool spin_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +template<class TimePoint> +inline bool spin_mutex::timed_lock(const TimePoint &abs_time) { return ipcdetail::try_based_timed_lock(*this, abs_time); } inline void spin_mutex::unlock(void) diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/condition.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/condition.hpp index 58a43e25a5..255cb69c16 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/condition.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/condition.hpp @@ -21,8 +21,8 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> +#include <boost/interprocess/sync/cv_status.hpp> #include <boost/interprocess/sync/interprocess_mutex.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> #include <boost/interprocess/exceptions.hpp> @@ -35,17 +35,17 @@ namespace boost { namespace interprocess { namespace ipcdetail { -class windows_condition +class winapi_condition { - windows_condition(const windows_condition &); - windows_condition &operator=(const windows_condition &); + winapi_condition(const winapi_condition &); + winapi_condition &operator=(const winapi_condition &); public: - windows_condition() + winapi_condition() : m_condition_data() {} - ~windows_condition() + ~winapi_condition() { //Notify all waiting threads //to allow POSIX semantics on condition destruction @@ -59,14 +59,6 @@ class windows_condition { m_condition_data.notify_all(); } template <typename L> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) - { return m_condition_data.timed_wait(lock, abs_time); } - - template <typename L, typename Pr> - bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) - { return m_condition_data.timed_wait(lock, abs_time, pred); } - - template <typename L> void wait(L& lock) { m_condition_data.wait(lock); } @@ -74,13 +66,38 @@ class windows_condition void wait(L& lock, Pr pred) { m_condition_data.wait(lock, pred); } + + template <typename L, typename TimePoint> + bool timed_wait(L& lock, const TimePoint &abs_time) + { return m_condition_data.timed_wait(lock, abs_time); } + + template <typename L, typename TimePoint, typename Pr> + bool timed_wait(L& lock, const TimePoint &abs_time, Pr pred) + { return m_condition_data.timed_wait(lock, abs_time, pred); } + + template <typename L, class TimePoint> + cv_status wait_until(L& lock, const TimePoint &abs_time) + { return this->timed_wait(lock, abs_time) ? cv_status::no_timeout : cv_status::timeout; } + + template <typename L, class TimePoint, typename Pr> + bool wait_until(L& lock, const TimePoint &abs_time, Pr pred) + { return this->timed_wait(lock, abs_time, pred); } + + template <typename L, class Duration> + cv_status wait_for(L& lock, const Duration &dur) + { return this->wait_until(lock, duration_to_ustime(dur)); } + + template <typename L, class Duration, typename Pr> + bool wait_for(L& lock, const Duration &dur, Pr pred) + { return this->wait_until(lock, duration_to_ustime(dur), pred); } + private: struct condition_data { - typedef boost::int32_t integer_type; - typedef windows_semaphore semaphore_type; - typedef windows_mutex mutex_type; + typedef unsigned int integer_type; + typedef winapi_semaphore semaphore_type; + typedef winapi_mutex mutex_type; condition_data() : m_nwaiters_blocked(0) @@ -109,12 +126,12 @@ class windows_condition mutex_type &get_mtx_unblock_lock() { return m_mtx_unblock_lock; } - boost::int32_t m_nwaiters_blocked; - boost::int32_t m_nwaiters_gone; - boost::int32_t m_nwaiters_to_unblock; - windows_semaphore m_sem_block_queue; - windows_semaphore m_sem_block_lock; - windows_mutex m_mtx_unblock_lock; + integer_type m_nwaiters_blocked; + integer_type m_nwaiters_gone; + integer_type m_nwaiters_to_unblock; + semaphore_type m_sem_block_queue; + semaphore_type m_sem_block_lock; + mutex_type m_mtx_unblock_lock; }; ipcdetail::condition_8a_wrapper<condition_data> m_condition_data; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/mutex.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/mutex.hpp index 4747d0cc66..e1bd190803 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/mutex.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/mutex.hpp @@ -21,7 +21,6 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/interprocess/detail/win32_api.hpp> #include <boost/interprocess/detail/windows_intermodule_singleton.hpp> #include <boost/interprocess/sync/windows/sync_utils.hpp> @@ -33,18 +32,25 @@ namespace boost { namespace interprocess { namespace ipcdetail { -class windows_mutex +class winapi_mutex { - windows_mutex(const windows_mutex &); - windows_mutex &operator=(const windows_mutex &); + winapi_mutex(const winapi_mutex &); + winapi_mutex &operator=(const winapi_mutex &); public: - windows_mutex(); - ~windows_mutex(); + winapi_mutex(); + ~winapi_mutex(); void lock(); bool try_lock(); - bool timed_lock(const boost::posix_time::ptime &abs_time); + template<class TimePoint> bool timed_lock(const TimePoint &abs_time); + + template<class TimePoint> bool try_lock_until(const TimePoint &abs_time) + { return this->timed_lock(abs_time); } + + template<class Duration> bool try_lock_for(const Duration &dur) + { return this->timed_lock(duration_to_ustime(dur)); } + void unlock(); void take_ownership(){}; @@ -52,60 +58,61 @@ class windows_mutex const sync_id id_; }; -inline windows_mutex::windows_mutex() - : id_(this) +inline winapi_mutex::winapi_mutex() + : id_() { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //Create mutex with the initial count bool open_or_created; - (void)handles.obtain_mutex(this->id_, &open_or_created); + (void)handles.obtain_mutex(this->id_, this, &open_or_created); //The mutex must be created, never opened BOOST_ASSERT(open_or_created); BOOST_ASSERT(open_or_created && winapi::get_last_error() != winapi::error_already_exists); (void)open_or_created; } -inline windows_mutex::~windows_mutex() +inline winapi_mutex::~winapi_mutex() { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); - handles.destroy_handle(this->id_); + handles.destroy_handle(this->id_, this); } -inline void windows_mutex::lock(void) +inline void winapi_mutex::lock(void) { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //This can throw - winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + winapi_mutex_functions mut(handles.obtain_mutex(this->id_, this)); mut.lock(); } -inline bool windows_mutex::try_lock(void) +inline bool winapi_mutex::try_lock(void) { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //This can throw - winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + winapi_mutex_functions mut(handles.obtain_mutex(this->id_, this)); return mut.try_lock(); } -inline bool windows_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +template<class TimePoint> +inline bool winapi_mutex::timed_lock(const TimePoint &abs_time) { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //This can throw - winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + winapi_mutex_functions mut(handles.obtain_mutex(this->id_, this)); return mut.timed_lock(abs_time); } -inline void windows_mutex::unlock(void) +inline void winapi_mutex::unlock(void) { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //This can throw - winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + winapi_mutex_functions mut(handles.obtain_mutex(this->id_, this)); return mut.unlock(); } diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/semaphore.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/semaphore.hpp index 7a29d962e5..888ab71a0c 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/semaphore.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/semaphore.hpp @@ -21,7 +21,6 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/interprocess/detail/win32_api.hpp> #include <boost/interprocess/detail/windows_intermodule_singleton.hpp> #include <boost/interprocess/sync/windows/sync_utils.hpp> @@ -34,80 +33,83 @@ namespace boost { namespace interprocess { namespace ipcdetail { -class windows_semaphore +class winapi_semaphore { - windows_semaphore(const windows_semaphore &); - windows_semaphore &operator=(const windows_semaphore &); + winapi_semaphore(const winapi_semaphore &); + winapi_semaphore &operator=(const winapi_semaphore &); public: - windows_semaphore(unsigned int initialCount); - ~windows_semaphore(); + winapi_semaphore(unsigned int initialCount); + ~winapi_semaphore(); - void post(long release_count = 1); + void post(unsigned int release_count = 1); void wait(); bool try_wait(); - bool timed_wait(const boost::posix_time::ptime &abs_time); + template<class TimePoint> bool timed_wait(const TimePoint &abs_time); private: const sync_id id_; + const unsigned initial_count_; }; -inline windows_semaphore::windows_semaphore(unsigned int initialCount) - : id_(this) +inline winapi_semaphore::winapi_semaphore(unsigned int initialCount) + : id_(), initial_count_(initialCount) { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //Force smeaphore creation with the initial count bool open_or_created; - handles.obtain_semaphore(this->id_, initialCount, &open_or_created); + handles.obtain_semaphore(this->id_, this, initialCount, &open_or_created); //The semaphore must be created, never opened BOOST_ASSERT(open_or_created); BOOST_ASSERT(open_or_created && winapi::get_last_error() != winapi::error_already_exists); (void)open_or_created; } -inline windows_semaphore::~windows_semaphore() +inline winapi_semaphore::~winapi_semaphore() { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); - handles.destroy_handle(this->id_); + handles.destroy_handle(this->id_, this); } -inline void windows_semaphore::wait(void) +inline void winapi_semaphore::wait() { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //This can throw - winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, 0)); + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, this, initial_count_)); sem.wait(); } -inline bool windows_semaphore::try_wait(void) +inline bool winapi_semaphore::try_wait() { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //This can throw - winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, 0)); + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, this, initial_count_)); return sem.try_wait(); } -inline bool windows_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +template<class TimePoint> +inline bool winapi_semaphore::timed_wait(const TimePoint &abs_time) { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); //This can throw - winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, 0)); + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, this, initial_count_)); return sem.timed_wait(abs_time); } -inline void windows_semaphore::post(long release_count) +inline void winapi_semaphore::post(unsigned release_count) { sync_handles &handles = windows_intermodule_singleton<sync_handles>::get(); - winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, 0)); - sem.post(release_count); + winapi_semaphore_functions sem(handles.obtain_semaphore(this->id_, this, initial_count_)); + sem.post(static_cast<long>(release_count)); } + } //namespace ipcdetail { } //namespace interprocess { } //namespace boost { diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/sync_utils.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/sync_utils.hpp index 8e054660ca..04106318cf 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/sync_utils.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/sync_utils.hpp @@ -30,11 +30,10 @@ //Shield against external warnings #include <boost/interprocess/detail/config_external_begin.hpp> - #include <boost/unordered/unordered_map.hpp> +#include <boost/unordered/unordered_map.hpp> #include <boost/interprocess/detail/config_external_end.hpp> +#include <boost/container/flat_map.hpp> - -#include <boost/container/map.hpp> #include <cstddef> namespace boost { @@ -63,16 +62,36 @@ inline bool bytes_to_str(const void *mem, const std::size_t mem_length, char *ou return true; } +inline bool bytes_to_str(const void *mem, const std::size_t mem_length, wchar_t *out_str, std::size_t &out_length) +{ + const std::size_t need_mem = mem_length*2+1; + if(out_length < need_mem){ + out_length = need_mem; + return false; + } + + const wchar_t Characters [] = + { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7' + , L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' }; + + std::size_t char_counter = 0; + const char *buf = (const char *)mem; + for(std::size_t i = 0; i != mem_length; ++i){ + out_str[char_counter++] = Characters[(buf[i]&0xF0)>>4]; + out_str[char_counter++] = Characters[(buf[i]&0x0F)]; + } + out_str[char_counter] = 0; + return true; +} + class sync_id { public: typedef __int64 internal_type; - sync_id(const void *map_addr) - : map_addr_(map_addr) + sync_id() { winapi::query_performance_counter(&rand_); } - explicit sync_id(internal_type val, const void *map_addr) - : map_addr_(map_addr) + explicit sync_id(internal_type val) { rand_ = val; } const internal_type &internal_pod() const @@ -81,18 +100,14 @@ class sync_id internal_type &internal_pod() { return rand_; } - const void *map_address() const - { return map_addr_; } - friend std::size_t hash_value(const sync_id &m) { return boost::hash_value(m.rand_); } friend bool operator==(const sync_id &l, const sync_id &r) - { return l.rand_ == r.rand_ && l.map_addr_ == r.map_addr_; } + { return l.rand_ == r.rand_; } private: internal_type rand_; - const void * const map_addr_; }; class sync_handles @@ -101,19 +116,15 @@ class sync_handles enum type { MUTEX, SEMAPHORE }; private: - struct address_less - { - bool operator()(sync_id const * const l, sync_id const * const r) const - { return l->map_address() < r->map_address(); } - }; + //key: id -> mapped: HANDLE. Hash map to allow efficient sync operations typedef boost::unordered_map<sync_id, void*> umap_type; - typedef boost::container::map<const sync_id*, umap_type::iterator, address_less> map_type; + //key: ordered address of the sync type -> iterator from umap_type. Ordered map to allow closing handles when unmapping + typedef boost::container::flat_map<const void*, umap_type::iterator> map_type; static const std::size_t LengthOfGlobal = sizeof("Global\\boost.ipc")-1; static const std::size_t StrSize = LengthOfGlobal + (sizeof(sync_id)*2+1); typedef char NameBuf[StrSize]; - void fill_name(NameBuf &name, const sync_id &id) { const char *n = "Global\\boost.ipc"; @@ -129,7 +140,7 @@ class sync_handles void throw_if_error(void *hnd_val) { if(!hnd_val){ - error_info err(winapi::get_last_error()); + error_info err(static_cast<int>(winapi::get_last_error())); throw interprocess_exception(err); } } @@ -161,41 +172,57 @@ class sync_handles } public: - void *obtain_mutex(const sync_id &id, bool *popen_created = 0) + sync_handles() + : num_handles_() + {} + + ~sync_handles() + { + BOOST_ASSERT(num_handles_ == 0); //Sanity check that handle we don't leak handles + } + + void *obtain_mutex(const sync_id &id, const void *mapping_address, bool *popen_created = 0) { umap_type::value_type v(id, (void*)0); scoped_lock<spin_mutex> lock(mtx_); umap_type::iterator it = umap_.insert(v).first; void *&hnd_val = it->second; if(!hnd_val){ - map_[&it->first] = it; + BOOST_ASSERT(map_.find(mapping_address) == map_.end()); + map_[mapping_address] = it; hnd_val = open_or_create_mutex(id); if(popen_created) *popen_created = true; + ++num_handles_; } else if(popen_created){ + BOOST_ASSERT(map_.find(mapping_address) != map_.end()); *popen_created = false; } + return hnd_val; } - void *obtain_semaphore(const sync_id &id, unsigned int initial_count, bool *popen_created = 0) + void *obtain_semaphore(const sync_id &id, const void *mapping_address, unsigned int initial_count, bool *popen_created = 0) { umap_type::value_type v(id, (void*)0); scoped_lock<spin_mutex> lock(mtx_); umap_type::iterator it = umap_.insert(v).first; void *&hnd_val = it->second; if(!hnd_val){ - map_[&it->first] = it; + BOOST_ASSERT(map_.find(mapping_address) == map_.end()); + map_[mapping_address] = it; hnd_val = open_or_create_semaphore(id, initial_count); if(popen_created) *popen_created = true; + ++num_handles_; } else if(popen_created){ + BOOST_ASSERT(map_.find(mapping_address) != map_.end()); *popen_created = false; } return hnd_val; } - void destroy_handle(const sync_id &id) + void destroy_handle(const sync_id &id, const void *mapping_address) { scoped_lock<spin_mutex> lock(mtx_); umap_type::iterator it = umap_.find(id); @@ -203,31 +230,39 @@ class sync_handles if(it != itend){ winapi::close_handle(it->second); - const map_type::key_type &k = &it->first; - map_.erase(k); + --num_handles_; + std::size_t i = map_.erase(mapping_address); + (void)i; + BOOST_ASSERT(i == 1); //The entry should be there umap_.erase(it); } } void destroy_syncs_in_range(const void *addr, std::size_t size) { - const sync_id low_id(addr); - const sync_id hig_id(static_cast<const char*>(addr)+size); + const void *low_id(addr); + const void *hig_id(static_cast<const char*>(addr)+size); scoped_lock<spin_mutex> lock(mtx_); - map_type::iterator itlow(map_.lower_bound(&low_id)), - ithig(map_.lower_bound(&hig_id)); - while(itlow != ithig){ - void * const hnd = umap_[*itlow->first]; - winapi::close_handle(hnd); - umap_.erase(*itlow->first); - itlow = map_.erase(itlow); + map_type::iterator itlow(map_.lower_bound(low_id)), + ithig(map_.lower_bound(hig_id)), + it(itlow); + for (; it != ithig; ++it){ + umap_type::iterator uit = it->second; + void * const hnd = uit->second; + umap_.erase(uit); + int ret = winapi::close_handle(hnd); + --num_handles_; + BOOST_ASSERT(ret != 0); (void)ret; //Sanity check that handle was ok } + + map_.erase(itlow, ithig); } private: spin_mutex mtx_; umap_type umap_; map_type map_; + std::size_t num_handles_; }; diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp index 983e33571d..487571a50b 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp @@ -24,7 +24,6 @@ #include <boost/interprocess/creation_tags.hpp> #include <boost/interprocess/permissions.hpp> #include <boost/interprocess/detail/win32_api.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/interprocess/sync/windows/winapi_wrapper_common.hpp> #include <boost/interprocess/errors.hpp> #include <boost/interprocess/exceptions.hpp> @@ -57,7 +56,8 @@ class winapi_mutex_functions bool try_lock() { return winapi_wrapper_try_wait_for_single_object(m_mtx_hnd); } - bool timed_lock(const boost::posix_time::ptime &abs_time) + template<class TimePoint> + bool timed_lock(const TimePoint &abs_time) { return winapi_wrapper_timed_wait_for_single_object(m_mtx_hnd, abs_time); } #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) @@ -98,7 +98,8 @@ class winapi_mutex_wrapper void *handle() const { return m_mtx_hnd; } - bool open_or_create(const char *name, const permissions &perm) + template<class CharT> + bool open_or_create(const CharT *name, const permissions &perm) { if(m_mtx_hnd == 0){ m_mtx_hnd = winapi::open_or_create_mutex diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp index c98224f15d..b8580486af 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp @@ -24,7 +24,6 @@ #include <boost/interprocess/creation_tags.hpp> #include <boost/interprocess/permissions.hpp> #include <boost/interprocess/detail/win32_api.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/interprocess/sync/windows/winapi_wrapper_common.hpp> #include <boost/interprocess/errors.hpp> #include <boost/interprocess/exceptions.hpp> @@ -60,7 +59,8 @@ class winapi_semaphore_functions bool try_wait() { return winapi_wrapper_try_wait_for_single_object(m_sem_hnd); } - bool timed_wait(const boost::posix_time::ptime &abs_time) + template<class TimePoint> + bool timed_wait(const TimePoint &abs_time) { return winapi_wrapper_timed_wait_for_single_object(m_sem_hnd, abs_time); } long value() const @@ -115,7 +115,8 @@ class winapi_semaphore_wrapper void *handle() const { return m_sem_hnd; } - bool open_or_create( const char *name + template <class CharT> + bool open_or_create( const CharT *name , long sem_count , long max_count , const permissions &perm diff --git a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_wrapper_common.hpp b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_wrapper_common.hpp index 428a26eb66..60794903de 100644 --- a/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_wrapper_common.hpp +++ b/contrib/restricted/boost/interprocess/include/boost/interprocess/sync/windows/winapi_wrapper_common.hpp @@ -22,70 +22,60 @@ #include <boost/interprocess/detail/config_begin.hpp> #include <boost/interprocess/detail/workaround.hpp> #include <boost/interprocess/detail/win32_api.hpp> -#include <boost/interprocess/detail/posix_time_types_wrk.hpp> #include <boost/interprocess/errors.hpp> #include <boost/interprocess/exceptions.hpp> +#include <boost/interprocess/detail/timed_utils.hpp> #include <limits> namespace boost { namespace interprocess { namespace ipcdetail { -inline void winapi_wrapper_wait_for_single_object(void *handle) -{ - unsigned long ret = winapi::wait_for_single_object(handle, winapi::infinite_time); - if(ret != winapi::wait_object_0){ - if(ret != winapi::wait_abandoned){ - error_info err = system_error_code(); - throw interprocess_exception(err); - } - else{ //Special case for orphaned mutexes - winapi::release_mutex(handle); - throw interprocess_exception(owner_dead_error); - } - } -} - -inline bool winapi_wrapper_try_wait_for_single_object(void *handle) +inline bool do_winapi_wait(void *handle, unsigned long dwMilliseconds) { - unsigned long ret = winapi::wait_for_single_object(handle, 0); + unsigned long ret = winapi::wait_for_single_object(handle, dwMilliseconds); if(ret == winapi::wait_object_0){ return true; } else if(ret == winapi::wait_timeout){ return false; } + else if(ret == winapi::wait_abandoned){ //Special case for orphaned mutexes + winapi::release_mutex(handle); + throw interprocess_exception(owner_dead_error); + } else{ error_info err = system_error_code(); throw interprocess_exception(err); } } -inline bool winapi_wrapper_timed_wait_for_single_object(void *handle, const boost::posix_time::ptime &abs_time) +template<class TimePoint> +inline bool winapi_wrapper_timed_wait_for_single_object(void *handle, const TimePoint &abs_time) { - //Windows does not support infinity abs_time so check it - if(abs_time == boost::posix_time::pos_infin){ - winapi_wrapper_wait_for_single_object(handle); - return true; - } - const boost::posix_time::ptime cur_time = microsec_clock::universal_time(); //Windows uses relative wait times so check for negative waits //and implement as 0 wait to allow try-semantics as POSIX mandates. - unsigned long ret = winapi::wait_for_single_object - ( handle - , (abs_time <= cur_time) ? 0u - : (abs_time - cur_time).total_milliseconds() - ); - if(ret == winapi::wait_object_0){ - return true; - } - else if(ret == winapi::wait_timeout){ - return false; + unsigned long time_ms = 0u; + if (ipcdetail::is_pos_infinity(abs_time)){ + time_ms = winapi::infinite_time; } - else{ - error_info err = system_error_code(); - throw interprocess_exception(err); + else { + const TimePoint cur_time = microsec_clock<TimePoint>::universal_time(); + if(abs_time > cur_time){ + time_ms = static_cast<unsigned long>(duration_to_milliseconds(abs_time - cur_time)); + } } + return do_winapi_wait(handle, time_ms); +} + +inline void winapi_wrapper_wait_for_single_object(void *handle) +{ + (void)do_winapi_wait(handle, winapi::infinite_time); +} + +inline bool winapi_wrapper_try_wait_for_single_object(void *handle) +{ + return do_winapi_wait(handle, 0u); } } //namespace ipcdetail { @@ -94,4 +84,4 @@ inline bool winapi_wrapper_timed_wait_for_single_object(void *handle, const boos #include <boost/interprocess/detail/config_end.hpp> -#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP +#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_WRAPPER_COMMON_HPP diff --git a/contrib/restricted/boost/move/include/boost/move/algo/adaptive_sort.hpp b/contrib/restricted/boost/move/include/boost/move/algo/adaptive_sort.hpp new file mode 100644 index 0000000000..d1aa883cb1 --- /dev/null +++ b/contrib/restricted/boost/move/include/boost/move/algo/adaptive_sort.hpp @@ -0,0 +1,654 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_ADAPTIVE_SORT_HPP +#define BOOST_MOVE_ADAPTIVE_SORT_HPP + +#include <boost/move/detail/config_begin.hpp> + +#include <boost/move/algo/detail/adaptive_sort_merge.hpp> +#include <boost/core/ignore_unused.hpp> + +#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +namespace boost { +namespace movelib { + +///@cond +namespace detail_adaptive { + +template<class RandIt> +void move_data_backward( RandIt cur_pos + , typename iter_size<RandIt>::type const l_data + , RandIt new_pos + , bool const xbuf_used) +{ + //Move buffer to the total combination right + if(xbuf_used){ + boost::move_backward(cur_pos, cur_pos+l_data, new_pos+l_data); + } + else{ + boost::adl_move_swap_ranges_backward(cur_pos, cur_pos+l_data, new_pos+l_data); + //Rotate does less moves but it seems slower due to cache issues + //rotate_gcd(first-l_block, first+len-l_block, first+len); + } +} + +template<class RandIt> +void move_data_forward( RandIt cur_pos + , typename iter_size<RandIt>::type const l_data + , RandIt new_pos + , bool const xbuf_used) +{ + //Move buffer to the total combination right + if(xbuf_used){ + boost::move(cur_pos, cur_pos+l_data, new_pos); + } + else{ + boost::adl_move_swap_ranges(cur_pos, cur_pos+l_data, new_pos); + //Rotate does less moves but it seems slower due to cache issues + //rotate_gcd(first-l_block, first+len-l_block, first+len); + } +} + +// build blocks of length 2*l_build_buf. l_build_buf is power of two +// input: [0, l_build_buf) elements are buffer, rest unsorted elements +// output: [0, l_build_buf) elements are buffer, blocks 2*l_build_buf and last subblock sorted +// +// First elements are merged from right to left until elements start +// at first. All old elements [first, first + l_build_buf) are placed at the end +// [first+len-l_build_buf, first+len). To achieve this: +// - If we have external memory to merge, we save elements from the buffer +// so that a non-swapping merge is used. Buffer elements are restored +// at the end of the buffer from the external memory. +// +// - When the external memory is not available or it is insufficient +// for a merge operation, left swap merging is used. +// +// Once elements are merged left to right in blocks of l_build_buf, then a single left +// to right merge step is performed to achieve merged blocks of size 2K. +// If external memory is available, usual merge is used, swap merging otherwise. +// +// As a last step, if auxiliary memory is available in-place merge is performed. +// until all is merged or auxiliary memory is not large enough. +template<class RandIt, class Compare, class XBuf> +typename iter_size<RandIt>::type + adaptive_sort_build_blocks + ( RandIt const first + , typename iter_size<RandIt>::type const len + , typename iter_size<RandIt>::type const l_base + , typename iter_size<RandIt>::type const l_build_buf + , XBuf & xbuf + , Compare comp) +{ + typedef typename iter_size<RandIt>::type size_type; + BOOST_ASSERT(l_build_buf <= len); + BOOST_ASSERT(0 == ((l_build_buf / l_base)&(l_build_buf/l_base-1))); + + //Place the start pointer after the buffer + RandIt first_block = first + l_build_buf; + size_type const elements_in_blocks = size_type(len - l_build_buf); + + ////////////////////////////////// + // Start of merge to left step + ////////////////////////////////// + size_type l_merged = 0u; + + BOOST_ASSERT(l_build_buf); + //If there is no enough buffer for the insertion sort step, just avoid the external buffer + size_type kbuf = min_value<size_type>(l_build_buf, size_type(xbuf.capacity())); + kbuf = kbuf < l_base ? 0 : kbuf; + + if(kbuf){ + //Backup internal buffer values in external buffer so they can be overwritten + xbuf.move_assign(first+l_build_buf-kbuf, kbuf); + l_merged = op_insertion_sort_step_left(first_block, elements_in_blocks, l_base, comp, move_op()); + + //Now combine them using the buffer. Elements from buffer can be + //overwritten since they've been saved to xbuf + l_merged = op_merge_left_step_multiple + ( first_block - l_merged, elements_in_blocks, l_merged, l_build_buf, size_type(kbuf - l_merged), comp, move_op()); + + //Restore internal buffer from external buffer unless kbuf was l_build_buf, + //in that case restoration will happen later + if(kbuf != l_build_buf){ + boost::move(xbuf.data()+kbuf-l_merged, xbuf.data() + kbuf, first_block-l_merged+elements_in_blocks); + } + } + else{ + l_merged = insertion_sort_step(first_block, elements_in_blocks, l_base, comp); + rotate_gcd(first_block-l_merged, first_block, first_block+elements_in_blocks); + } + + //Now combine elements using the buffer. Elements from buffer can't be + //overwritten since xbuf was not big enough, so merge swapping elements. + l_merged = op_merge_left_step_multiple + (first_block-l_merged, elements_in_blocks, l_merged, l_build_buf, size_type(l_build_buf - l_merged), comp, swap_op()); + + BOOST_ASSERT(l_merged == l_build_buf); + + ////////////////////////////////// + // Start of merge to right step + ////////////////////////////////// + + //If kbuf is l_build_buf then we can merge right without swapping + //Saved data is still in xbuf + if(kbuf && kbuf == l_build_buf){ + op_merge_right_step_once(first, elements_in_blocks, l_build_buf, comp, move_op()); + //Restore internal buffer from external buffer if kbuf was l_build_buf. + //as this operation was previously delayed. + boost::move(xbuf.data(), xbuf.data() + kbuf, first); + } + else{ + op_merge_right_step_once(first, elements_in_blocks, l_build_buf, comp, swap_op()); + } + xbuf.clear(); + //2*l_build_buf or total already merged + return min_value<size_type>(elements_in_blocks, size_type(2u*l_build_buf)); +} + +template<class RandItKeys, class KeyCompare, class RandIt, class Compare, class XBuf> +void adaptive_sort_combine_blocks + ( RandItKeys const keys + , KeyCompare key_comp + , RandIt const first + , typename iter_size<RandIt>::type const len + , typename iter_size<RandIt>::type const l_prev_merged + , typename iter_size<RandIt>::type const l_block + , bool const use_buf + , bool const xbuf_used + , XBuf & xbuf + , Compare comp + , bool merge_left) +{ + boost::ignore_unused(xbuf); + typedef typename iter_size<RandIt>::type size_type; + + size_type const l_reg_combined = size_type(2u*l_prev_merged); + size_type l_irreg_combined = 0; + size_type const l_total_combined = calculate_total_combined(len, l_prev_merged, &l_irreg_combined); + size_type const n_reg_combined = len/l_reg_combined; + RandIt combined_first = first; + + boost::ignore_unused(l_total_combined); + BOOST_ASSERT(l_total_combined <= len); + + size_type const max_i = size_type(n_reg_combined + (l_irreg_combined != 0)); + + if(merge_left || !use_buf) { + for( size_type combined_i = 0; combined_i != max_i; ) { + //Now merge blocks + bool const is_last = combined_i==n_reg_combined; + size_type const l_cur_combined = is_last ? l_irreg_combined : l_reg_combined; + + range_xbuf<RandIt, size_type, move_op> rbuf( (use_buf && xbuf_used) ? (combined_first-l_block) : combined_first, combined_first); + size_type n_block_a, n_block_b, l_irreg1, l_irreg2; + combine_params( keys, key_comp, l_cur_combined + , l_prev_merged, l_block, rbuf + , n_block_a, n_block_b, l_irreg1, l_irreg2); //Outputs + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" A combpar: ", len + l_block); + BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(combined_first, combined_first + n_block_a*l_block+l_irreg1, comp)); + BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(combined_first + n_block_a*l_block+l_irreg1, combined_first + n_block_a*l_block+l_irreg1+n_block_b*l_block+l_irreg2, comp)); + if(!use_buf){ + merge_blocks_bufferless + (keys, key_comp, combined_first, l_block, 0u, n_block_a, n_block_b, l_irreg2, comp); + } + else{ + merge_blocks_left + (keys, key_comp, combined_first, l_block, 0u, n_block_a, n_block_b, l_irreg2, comp, xbuf_used); + } + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" After merge_blocks_L: ", len + l_block); + ++combined_i; + if(combined_i != max_i) + combined_first += l_reg_combined; + } + } + else{ + combined_first += size_type(l_reg_combined*(max_i-1u)); + for( size_type combined_i = max_i; combined_i; ) { + --combined_i; + bool const is_last = combined_i==n_reg_combined; + size_type const l_cur_combined = is_last ? l_irreg_combined : l_reg_combined; + + RandIt const combined_last(combined_first+l_cur_combined); + range_xbuf<RandIt, size_type, move_op> rbuf(combined_last, xbuf_used ? (combined_last+l_block) : combined_last); + size_type n_block_a, n_block_b, l_irreg1, l_irreg2; + combine_params( keys, key_comp, l_cur_combined + , l_prev_merged, l_block, rbuf + , n_block_a, n_block_b, l_irreg1, l_irreg2); //Outputs + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" A combpar: ", len + l_block); + BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(combined_first, combined_first + n_block_a*l_block+l_irreg1, comp)); + BOOST_MOVE_ADAPTIVE_SORT_INVARIANT(boost::movelib::is_sorted(combined_first + n_block_a*l_block+l_irreg1, combined_first + n_block_a*l_block+l_irreg1+n_block_b*l_block+l_irreg2, comp)); + merge_blocks_right + (keys, key_comp, combined_first, l_block, n_block_a, n_block_b, l_irreg2, comp, xbuf_used); + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" After merge_blocks_R: ", len + l_block); + if(combined_i) + combined_first -= l_reg_combined; + } + } +} + +//Returns true if buffer is placed in +//[buffer+len-l_intbuf, buffer+len). Otherwise, buffer is +//[buffer,buffer+l_intbuf) +template<class RandIt, class Compare, class XBuf> +bool adaptive_sort_combine_all_blocks + ( RandIt keys + , typename iter_size<RandIt>::type &n_keys + , RandIt const buffer + , typename iter_size<RandIt>::type const l_buf_plus_data + , typename iter_size<RandIt>::type l_merged + , typename iter_size<RandIt>::type &l_intbuf + , XBuf & xbuf + , Compare comp) +{ + typedef typename iter_size<RandIt>::type size_type; + + RandIt const first = buffer + l_intbuf; + size_type const l_data = size_type(l_buf_plus_data - l_intbuf); + size_type const l_unique = size_type(l_intbuf + n_keys); + //Backup data to external buffer once if possible + bool const common_xbuf = l_data > l_merged && l_intbuf && l_intbuf <= xbuf.capacity(); + if(common_xbuf){ + xbuf.move_assign(buffer, l_intbuf); + } + + bool prev_merge_left = true; + size_type l_prev_total_combined = l_merged, l_prev_block = 0; + bool prev_use_internal_buf = true; + + for( size_type n = 0; l_data > l_merged + ; l_merged = size_type(2u*l_merged) + , ++n){ + //If l_intbuf is non-zero, use that internal buffer. + // Implies l_block == l_intbuf && use_internal_buf == true + //If l_intbuf is zero, see if half keys can be reused as a reduced emergency buffer, + // Implies l_block == n_keys/2 && use_internal_buf == true + //Otherwise, just give up and and use all keys to merge using rotations (use_internal_buf = false) + bool use_internal_buf = false; + size_type const l_block = lblock_for_combine(l_intbuf, n_keys, size_type(2*l_merged), use_internal_buf); + BOOST_ASSERT(!l_intbuf || (l_block == l_intbuf)); + BOOST_ASSERT(n == 0 || (!use_internal_buf || prev_use_internal_buf) ); + BOOST_ASSERT(n == 0 || (!use_internal_buf || l_prev_block == l_block) ); + + bool const is_merge_left = (n&1) == 0; + size_type const l_total_combined = calculate_total_combined(l_data, l_merged); + if(n && prev_use_internal_buf && prev_merge_left){ + if(is_merge_left || !use_internal_buf){ + move_data_backward(first-l_prev_block, l_prev_total_combined, first, common_xbuf); + } + else{ + //Put the buffer just after l_total_combined + RandIt const buf_end = first+l_prev_total_combined; + RandIt const buf_beg = buf_end-l_block; + if(l_prev_total_combined > l_total_combined){ + size_type const l_diff = size_type(l_prev_total_combined - l_total_combined); + move_data_backward(buf_beg-l_diff, l_diff, buf_end-l_diff, common_xbuf); + } + else if(l_prev_total_combined < l_total_combined){ + size_type const l_diff = size_type(l_total_combined - l_prev_total_combined); + move_data_forward(buf_end, l_diff, buf_beg, common_xbuf); + } + } + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" After move_data : ", l_data + l_intbuf); + } + + //Combine to form l_merged*2 segments + if(n_keys){ + size_type upper_n_keys_this_iter = size_type(2u*l_merged/l_block); + if(upper_n_keys_this_iter > 256){ + adaptive_sort_combine_blocks + ( keys, comp, !use_internal_buf || is_merge_left ? first : first-l_block + , l_data, l_merged, l_block, use_internal_buf, common_xbuf, xbuf, comp, is_merge_left); + } + else{ + unsigned char uint_keys[256]; + adaptive_sort_combine_blocks + ( uint_keys, less(), !use_internal_buf || is_merge_left ? first : first-l_block + , l_data, l_merged, l_block, use_internal_buf, common_xbuf, xbuf, comp, is_merge_left); + } + } + else{ + size_type *const uint_keys = xbuf.template aligned_trailing<size_type>(); + adaptive_sort_combine_blocks + ( uint_keys, less(), !use_internal_buf || is_merge_left ? first : first-l_block + , l_data, l_merged, l_block, use_internal_buf, common_xbuf, xbuf, comp, is_merge_left); + } + + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(is_merge_left ? " After comb blocks L: " : " After comb blocks R: ", l_data + l_intbuf); + prev_merge_left = is_merge_left; + l_prev_total_combined = l_total_combined; + l_prev_block = l_block; + prev_use_internal_buf = use_internal_buf; + } + BOOST_ASSERT(l_prev_total_combined == l_data); + bool const buffer_right = prev_use_internal_buf && prev_merge_left; + + l_intbuf = prev_use_internal_buf ? l_prev_block : 0u; + n_keys = size_type(l_unique - l_intbuf); + //Restore data from to external common buffer if used + if(common_xbuf){ + if(buffer_right){ + boost::move(xbuf.data(), xbuf.data() + l_intbuf, buffer+l_data); + } + else{ + boost::move(xbuf.data(), xbuf.data() + l_intbuf, buffer); + } + } + return buffer_right; +} + + +template<class RandIt, class Compare, class XBuf> +void adaptive_sort_final_merge( bool buffer_right + , RandIt const first + , typename iter_size<RandIt>::type const l_intbuf + , typename iter_size<RandIt>::type const n_keys + , typename iter_size<RandIt>::type const len + , XBuf & xbuf + , Compare comp) +{ + //BOOST_ASSERT(n_keys || xbuf.size() == l_intbuf); + xbuf.clear(); + + typedef typename iter_size<RandIt>::type size_type; + + size_type const n_key_plus_buf = size_type(l_intbuf+n_keys); + if(buffer_right){ + //Use stable sort as some buffer elements might not be unique (see non_unique_buf) + stable_sort(first+len-l_intbuf, first+len, comp, xbuf); + stable_merge( first+n_keys, first+len-l_intbuf, first+len, antistable<Compare>(comp), xbuf); + unstable_sort(first, first+n_keys, comp, xbuf); + stable_merge(first, first+n_keys, first+len, comp, xbuf); + } + else{ + //Use stable sort as some buffer elements might not be unique (see non_unique_buf) + stable_sort(first, first+n_key_plus_buf, comp, xbuf); + if(xbuf.capacity() >= n_key_plus_buf){ + buffered_merge(first, first+n_key_plus_buf, first+len, comp, xbuf); + } + else if(xbuf.capacity() >= min_value<size_type>(l_intbuf, n_keys)){ + stable_merge( first+n_keys, first+n_key_plus_buf + , first+len, comp, xbuf); + stable_merge(first, first+n_keys, first+len, comp, xbuf); + } + else{ + stable_merge(first, first+n_key_plus_buf, first+len, comp, xbuf); + } + } + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(" After final_merge : ", len); +} + +template<class RandIt, class Compare, class Unsigned, class XBuf> +bool adaptive_sort_build_params + (RandIt first, Unsigned const len, Compare comp + , Unsigned &n_keys, Unsigned &l_intbuf, Unsigned &l_base, Unsigned &l_build_buf + , XBuf & xbuf + ) +{ + typedef typename iter_size<RandIt>::type size_type; + + //Calculate ideal parameters and try to collect needed unique keys + l_base = 0u; + + //Try to find a value near sqrt(len) that is 2^N*l_base where + //l_base <= AdaptiveSortInsertionSortThreshold. This property is important + //as build_blocks merges to the left iteratively duplicating the + //merged size and all the buffer must be used just before the final + //merge to right step. This guarantees "build_blocks" produces + //segments of size l_build_buf*2, maximizing the classic merge phase. + l_intbuf = size_type(ceil_sqrt_multiple(len, &l_base)); + + //The internal buffer can be expanded if there is enough external memory + while(xbuf.capacity() >= l_intbuf*2){ + l_intbuf = size_type(2u*l_intbuf); + } + + //This is the minimum number of keys to implement the ideal algorithm + // + //l_intbuf is used as buffer plus the key count + size_type n_min_ideal_keys = size_type(l_intbuf-1u); + while(n_min_ideal_keys >= (len-l_intbuf-n_min_ideal_keys)/l_intbuf){ + --n_min_ideal_keys; + } + ++n_min_ideal_keys; + BOOST_ASSERT(n_min_ideal_keys <= l_intbuf); + + if(xbuf.template supports_aligned_trailing<size_type> + (l_intbuf, size_type((size_type(len-l_intbuf)-1u)/l_intbuf+1u))){ + n_keys = 0u; + l_build_buf = l_intbuf; + } + else{ + //Try to achieve a l_build_buf of length l_intbuf*2, so that we can merge with that + //l_intbuf*2 buffer in "build_blocks" and use half of them as buffer and the other half + //as keys in combine_all_blocks. In that case n_keys >= n_min_ideal_keys but by a small margin. + // + //If available memory is 2*sqrt(l), then only sqrt(l) unique keys are needed, + //(to be used for keys in combine_all_blocks) as the whole l_build_buf + //will be backuped in the buffer during build_blocks. + bool const non_unique_buf = xbuf.capacity() >= l_intbuf; + size_type const to_collect = non_unique_buf ? n_min_ideal_keys : size_type(l_intbuf*2u); + size_type collected = collect_unique(first, first+len, to_collect, comp, xbuf); + + //If available memory is 2*sqrt(l), then for "build_params" + //the situation is the same as if 2*l_intbuf were collected. + if(non_unique_buf && collected == n_min_ideal_keys){ + l_build_buf = l_intbuf; + n_keys = n_min_ideal_keys; + } + else if(collected == 2*l_intbuf){ + //l_intbuf*2 elements found. Use all of them in the build phase + l_build_buf = size_type(l_intbuf*2); + n_keys = l_intbuf; + } + else if(collected >= (n_min_ideal_keys+l_intbuf)){ + l_build_buf = l_intbuf; + n_keys = size_type(collected - l_intbuf); + } + //If collected keys are not enough, try to fix n_keys and l_intbuf. If no fix + //is possible (due to very low unique keys), then go to a slow sort based on rotations. + else{ + BOOST_ASSERT(collected < (n_min_ideal_keys+l_intbuf)); + if(collected < 4){ //No combination possible with less that 4 keys + return false; + } + n_keys = l_intbuf; + while(n_keys & (n_keys-1u)){ + n_keys &= size_type(n_keys-1u); // make it power or 2 + } + while(n_keys > collected){ + n_keys/=2; + } + //AdaptiveSortInsertionSortThreshold is always power of two so the minimum is power of two + l_base = min_value<Unsigned>(n_keys, AdaptiveSortInsertionSortThreshold); + l_intbuf = 0; + l_build_buf = n_keys; + } + BOOST_ASSERT((n_keys+l_intbuf) >= l_build_buf); + } + + return true; +} + +// Main explanation of the sort algorithm. +// +// csqrtlen = ceil(sqrt(len)); +// +// * First, 2*csqrtlen unique elements elements are extracted from elements to be +// sorted and placed in the beginning of the range. +// +// * Step "build_blocks": In this nearly-classic merge step, 2*csqrtlen unique elements +// will be used as auxiliary memory, so trailing len-2*csqrtlen elements are +// are grouped in blocks of sorted 4*csqrtlen elements. At the end of the step +// 2*csqrtlen unique elements are again the leading elements of the whole range. +// +// * Step "combine_blocks": pairs of previously formed blocks are merged with a different +// ("smart") algorithm to form blocks of 8*csqrtlen elements. This step is slower than the +// "build_blocks" step and repeated iteratively (forming blocks of 16*csqrtlen, 32*csqrtlen +// elements, etc) of until all trailing (len-2*csqrtlen) elements are merged. +// +// In "combine_blocks" len/csqrtlen elements used are as "keys" (markers) to +// know if elements belong to the first or second block to be merged and another +// leading csqrtlen elements are used as buffer. Explanation of the "combine_blocks" step: +// +// Iteratively until all trailing (len-2*csqrtlen) elements are merged: +// Iteratively for each pair of previously merged block: +// * Blocks are divided groups of csqrtlen elements and +// 2*merged_block/csqrtlen keys are sorted to be used as markers +// * Groups are selection-sorted by first or last element (depending whether they are going +// to be merged to left or right) and keys are reordered accordingly as an imitation-buffer. +// * Elements of each block pair are merged using the csqrtlen buffer taking into account +// if they belong to the first half or second half (marked by the key). +// +// * In the final merge step leading elements (2*csqrtlen) are sorted and merged with +// rotations with the rest of sorted elements in the "combine_blocks" step. +// +// Corner cases: +// +// * If no 2*csqrtlen elements can be extracted: +// +// * If csqrtlen+len/csqrtlen are extracted, then only csqrtlen elements are used +// as buffer in the "build_blocks" step forming blocks of 2*csqrtlen elements. This +// means that an additional "combine_blocks" step will be needed to merge all elements. +// +// * If no csqrtlen+len/csqrtlen elements can be extracted, but still more than a minimum, +// then reduces the number of elements used as buffer and keys in the "build_blocks" +// and "combine_blocks" steps. If "combine_blocks" has no enough keys due to this reduction +// then uses a rotation based smart merge. +// +// * If the minimum number of keys can't be extracted, a rotation-based sorting is performed. +// +// * If auxiliary memory is more or equal than ceil(len/2), half-copying mergesort is used. +// +// * If auxiliary memory is more than csqrtlen+n_keys*sizeof(std::size_t), +// then only csqrtlen elements need to be extracted and "combine_blocks" will use integral +// keys to combine blocks. +// +// * If auxiliary memory is available, the "build_blocks" will be extended to build bigger blocks +// using classic merge and "combine_blocks" will use bigger blocks when merging. +template<class RandIt, class Compare, class XBuf> +void adaptive_sort_impl + ( RandIt first + , typename iter_size<RandIt>::type const len + , Compare comp + , XBuf & xbuf + ) +{ + typedef typename iter_size<RandIt>::type size_type; + + //Small sorts go directly to insertion sort + if(len <= size_type(AdaptiveSortInsertionSortThreshold)){ + insertion_sort(first, first + len, comp); + } + else if((len-len/2) <= xbuf.capacity()){ + merge_sort(first, first+len, comp, xbuf.data()); + } + else{ + //Make sure it is at least four + BOOST_STATIC_ASSERT(AdaptiveSortInsertionSortThreshold >= 4); + + size_type l_base = 0; + size_type l_intbuf = 0; + size_type n_keys = 0; + size_type l_build_buf = 0; + + //Calculate and extract needed unique elements. If a minimum is not achieved + //fallback to a slow stable sort + if(!adaptive_sort_build_params(first, len, comp, n_keys, l_intbuf, l_base, l_build_buf, xbuf)){ + stable_sort(first, first+len, comp, xbuf); + } + else{ + BOOST_ASSERT(l_build_buf); + //Otherwise, continue the adaptive_sort + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1("\n After collect_unique: ", len); + size_type const n_key_plus_buf = size_type(l_intbuf+n_keys); + //l_build_buf is always power of two if l_intbuf is zero + BOOST_ASSERT(l_intbuf || (0 == (l_build_buf & (l_build_buf-1)))); + + //Classic merge sort until internal buffer and xbuf are exhausted + size_type const l_merged = adaptive_sort_build_blocks + ( first + n_key_plus_buf-l_build_buf + , size_type(len-n_key_plus_buf+l_build_buf) + , l_base, l_build_buf, xbuf, comp); + BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(" After build_blocks: ", len); + + //Non-trivial merge + bool const buffer_right = adaptive_sort_combine_all_blocks + (first, n_keys, first+n_keys, size_type(len-n_keys), l_merged, l_intbuf, xbuf, comp); + + //Sort keys and buffer and merge the whole sequence + adaptive_sort_final_merge(buffer_right, first, l_intbuf, n_keys, len, xbuf, comp); + } + } +} + +} //namespace detail_adaptive { + +///@endcond + +//! <b>Effects</b>: Sorts the elements in the range [first, last) in ascending order according +//! to comparison functor "comp". The sort is stable (order of equal elements +//! is guaranteed to be preserved). Performance is improved if additional raw storage is +//! provided. +//! +//! <b>Requires</b>: +//! - RandIt must meet the requirements of ValueSwappable and RandomAccessIterator. +//! - The type of dereferenced RandIt must meet the requirements of MoveAssignable and MoveConstructible. +//! +//! <b>Parameters</b>: +//! - first, last: the range of elements to sort +//! - comp: comparison function object which returns true if the first argument is is ordered before the second. +//! - uninitialized, uninitialized_len: raw storage starting on "uninitialized", able to hold "uninitialized_len" +//! elements of type iterator_traits<RandIt>::value_type. Maximum performance is achieved when uninitialized_len +//! is ceil(std::distance(first, last)/2). +//! +//! <b>Throws</b>: If comp throws or the move constructor, move assignment or swap of the type +//! of dereferenced RandIt throws. +//! +//! <b>Complexity</b>: Always K x O(Nxlog(N)) comparisons and move assignments/constructors/swaps. +//! Comparisons are close to minimum even with no additional memory. Constant factor for data movement is minimized +//! when uninitialized_len is ceil(std::distance(first, last)/2). Pretty good enough performance is achieved when +//! ceil(sqrt(std::distance(first, last)))*2. +//! +//! <b>Caution</b>: Experimental implementation, not production-ready. +template<class RandIt, class RandRawIt, class Compare> +void adaptive_sort( RandIt first, RandIt last, Compare comp + , RandRawIt uninitialized + , typename iter_size<RandIt>::type uninitialized_len) +{ + typedef typename iter_size<RandIt>::type size_type; + typedef typename iterator_traits<RandIt>::value_type value_type; + + ::boost::movelib::adaptive_xbuf<value_type, RandRawIt, size_type> xbuf(uninitialized, uninitialized_len); + ::boost::movelib::detail_adaptive::adaptive_sort_impl(first, size_type(last - first), comp, xbuf); +} + +template<class RandIt, class Compare> +void adaptive_sort( RandIt first, RandIt last, Compare comp) +{ + typedef typename iterator_traits<RandIt>::value_type value_type; + adaptive_sort(first, last, comp, (value_type*)0, 0u); +} + +} //namespace movelib { +} //namespace boost { + +#include <boost/move/detail/config_end.hpp> + +#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600)) +#pragma GCC diagnostic pop +#endif + +#endif //#define BOOST_MOVE_ADAPTIVE_SORT_HPP diff --git a/contrib/restricted/boost/move/include/boost/move/algo/detail/pdqsort.hpp b/contrib/restricted/boost/move/include/boost/move/algo/detail/pdqsort.hpp new file mode 100644 index 0000000000..640f8a3d1b --- /dev/null +++ b/contrib/restricted/boost/move/include/boost/move/algo/detail/pdqsort.hpp @@ -0,0 +1,344 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Orson Peters 2017. +// (C) Copyright Ion Gaztanaga 2017-2018. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This implementation of Pattern-defeating quicksort (pdqsort) was written +// by Orson Peters, and discussed in the Boost mailing list: +// http://boost.2283326.n4.nabble.com/sort-pdqsort-td4691031.html +// +// This implementation is the adaptation by Ion Gaztanaga of code originally in GitHub +// with permission from the author to relicense it under the Boost Software License +// (see the Boost mailing list for details). +// +// The original copyright statement is pasted here for completeness: +// +// pdqsort.h - Pattern-defeating quicksort. +// Copyright (c) 2015 Orson Peters +// This software is provided 'as-is', without any express or implied warranty. In no event will the +// authors be held liable for any damages arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, including commercial +// applications, and to alter it and redistribute it freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the +// original software. If you use this software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as +// being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_ALGO_PDQSORT_HPP +#define BOOST_MOVE_ALGO_PDQSORT_HPP + +#ifndef BOOST_CONFIG_HPP +# include <boost/config.hpp> +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include <boost/move/detail/config_begin.hpp> + +#include <boost/move/detail/workaround.hpp> +#include <boost/move/utility_core.hpp> +#include <boost/move/algo/detail/insertion_sort.hpp> +#include <boost/move/algo/detail/heap_sort.hpp> +#include <boost/move/detail/iterator_traits.hpp> + +#include <boost/move/adl_move_swap.hpp> +#include <cstddef> + +#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +namespace boost { +namespace movelib { + +namespace pdqsort_detail { + + //A simple pair implementation to avoid including <utility> + template<class T1, class T2> + struct pair + { + pair() + {} + + pair(const T1 &t1, const T2 &t2) + : first(t1), second(t2) + {} + + T1 first; + T2 second; + }; + + enum { + // Partitions below this size are sorted using insertion sort. + insertion_sort_threshold = 24, + + // Partitions above this size use Tukey's ninther to select the pivot. + ninther_threshold = 128, + + // When we detect an already sorted partition, attempt an insertion sort that allows this + // amount of element moves before giving up. + partial_insertion_sort_limit = 8, + + // Must be multiple of 8 due to loop unrolling, and < 256 to fit in unsigned char. + block_size = 64, + + // Cacheline size, assumes power of two. + cacheline_size = 64 + + }; + + // Returns floor(log2(n)), assumes n > 0. + template<class Unsigned> + Unsigned log2(Unsigned n) { + Unsigned log = 0; + while (n >>= 1) ++log; + return log; + } + + // Attempts to use insertion sort on [begin, end). Will return false if more than + // partial_insertion_sort_limit elements were moved, and abort sorting. Otherwise it will + // successfully sort and return true. + template<class Iter, class Compare> + inline bool partial_insertion_sort(Iter begin, Iter end, Compare comp) { + typedef typename boost::movelib::iterator_traits<Iter>::value_type T; + typedef typename boost::movelib:: iter_size<Iter>::type size_type; + if (begin == end) return true; + + size_type limit = 0; + for (Iter cur = begin + 1; cur != end; ++cur) { + if (limit > partial_insertion_sort_limit) return false; + + Iter sift = cur; + Iter sift_1 = cur - 1; + + // Compare first so we can avoid 2 moves for an element already positioned correctly. + if (comp(*sift, *sift_1)) { + T tmp = boost::move(*sift); + + do { *sift-- = boost::move(*sift_1); } + while (sift != begin && comp(tmp, *--sift_1)); + + *sift = boost::move(tmp); + limit += size_type(cur - sift); + } + } + + return true; + } + + template<class Iter, class Compare> + inline void sort2(Iter a, Iter b, Compare comp) { + if (comp(*b, *a)) boost::adl_move_iter_swap(a, b); + } + + // Sorts the elements *a, *b and *c using comparison function comp. + template<class Iter, class Compare> + inline void sort3(Iter a, Iter b, Iter c, Compare comp) { + sort2(a, b, comp); + sort2(b, c, comp); + sort2(a, b, comp); + } + + // Partitions [begin, end) around pivot *begin using comparison function comp. Elements equal + // to the pivot are put in the right-hand partition. Returns the position of the pivot after + // partitioning and whether the passed sequence already was correctly partitioned. Assumes the + // pivot is a median of at least 3 elements and that [begin, end) is at least + // insertion_sort_threshold long. + template<class Iter, class Compare> + pdqsort_detail::pair<Iter, bool> partition_right(Iter begin, Iter end, Compare comp) { + typedef typename boost::movelib::iterator_traits<Iter>::value_type T; + + // Move pivot into local for speed. + T pivot(boost::move(*begin)); + + Iter first = begin; + Iter last = end; + + // Find the first element greater than or equal than the pivot (the median of 3 guarantees + // this exists). + while (comp(*++first, pivot)); + + // Find the first element strictly smaller than the pivot. We have to guard this search if + // there was no element before *first. + if (first - 1 == begin) while (first < last && !comp(*--last, pivot)); + else while ( !comp(*--last, pivot)); + + // If the first pair of elements that should be swapped to partition are the same element, + // the passed in sequence already was correctly partitioned. + bool already_partitioned = first >= last; + + // Keep swapping pairs of elements that are on the wrong side of the pivot. Previously + // swapped pairs guard the searches, which is why the first iteration is special-cased + // above. + while (first < last) { + boost::adl_move_iter_swap(first, last); + while (comp(*++first, pivot)); + while (!comp(*--last, pivot)); + } + + // Put the pivot in the right place. + Iter pivot_pos = first - 1; + *begin = boost::move(*pivot_pos); + *pivot_pos = boost::move(pivot); + + return pdqsort_detail::pair<Iter, bool>(pivot_pos, already_partitioned); + } + + // Similar function to the one above, except elements equal to the pivot are put to the left of + // the pivot and it doesn't check or return if the passed sequence already was partitioned. + // Since this is rarely used (the many equal case), and in that case pdqsort already has O(n) + // performance, no block quicksort is applied here for simplicity. + template<class Iter, class Compare> + inline Iter partition_left(Iter begin, Iter end, Compare comp) { + typedef typename boost::movelib::iterator_traits<Iter>::value_type T; + + T pivot(boost::move(*begin)); + Iter first = begin; + Iter last = end; + + while (comp(pivot, *--last)); + + if (last + 1 == end) while (first < last && !comp(pivot, *++first)); + else while ( !comp(pivot, *++first)); + + while (first < last) { + boost::adl_move_iter_swap(first, last); + while (comp(pivot, *--last)); + while (!comp(pivot, *++first)); + } + + Iter pivot_pos = last; + *begin = boost::move(*pivot_pos); + *pivot_pos = boost::move(pivot); + + return pivot_pos; + } + + + template<class Iter, class Compare> + void pdqsort_loop( Iter begin, Iter end, Compare comp + , typename boost::movelib:: iter_size<Iter>::type bad_allowed + , bool leftmost = true) + { + typedef typename boost::movelib:: iter_size<Iter>::type size_type; + + // Use a while loop for tail recursion elimination. + while (true) { + size_type size = size_type(end - begin); + + // Insertion sort is faster for small arrays. + if (size < insertion_sort_threshold) { + insertion_sort(begin, end, comp); + return; + } + + // Choose pivot as median of 3 or pseudomedian of 9. + size_type s2 = size / 2; + if (size > ninther_threshold) { + sort3(begin, begin + s2, end - 1, comp); + sort3(begin + 1, begin + (s2 - 1), end - 2, comp); + sort3(begin + 2, begin + (s2 + 1), end - 3, comp); + sort3(begin + (s2 - 1), begin + s2, begin + (s2 + 1), comp); + boost::adl_move_iter_swap(begin, begin + s2); + } else sort3(begin + s2, begin, end - 1, comp); + + // If *(begin - 1) is the end of the right partition of a previous partition operation + // there is no element in [begin, end) that is smaller than *(begin - 1). Then if our + // pivot compares equal to *(begin - 1) we change strategy, putting equal elements in + // the left partition, greater elements in the right partition. We do not have to + // recurse on the left partition, since it's sorted (all equal). + if (!leftmost && !comp(*(begin - 1), *begin)) { + begin = partition_left(begin, end, comp) + 1; + continue; + } + + // Partition and get results. + pdqsort_detail::pair<Iter, bool> part_result = partition_right(begin, end, comp); + Iter pivot_pos = part_result.first; + bool already_partitioned = part_result.second; + + // Check for a highly unbalanced partition. + size_type l_size = size_type(pivot_pos - begin); + size_type r_size = size_type(end - (pivot_pos + 1)); + bool highly_unbalanced = l_size < size / 8 || r_size < size / 8; + + // If we got a highly unbalanced partition we shuffle elements to break many patterns. + if (highly_unbalanced) { + // If we had too many bad partitions, switch to heapsort to guarantee O(n log n). + if (--bad_allowed == 0) { + boost::movelib::heap_sort(begin, end, comp); + return; + } + + if (l_size >= insertion_sort_threshold) { + boost::adl_move_iter_swap(begin, begin + l_size / 4); + boost::adl_move_iter_swap(pivot_pos - 1, pivot_pos - l_size / 4); + + if (l_size > ninther_threshold) { + boost::adl_move_iter_swap(begin + 1, begin + (l_size / 4 + 1)); + boost::adl_move_iter_swap(begin + 2, begin + (l_size / 4 + 2)); + boost::adl_move_iter_swap(pivot_pos - 2, pivot_pos - (l_size / 4 + 1)); + boost::adl_move_iter_swap(pivot_pos - 3, pivot_pos - (l_size / 4 + 2)); + } + } + + if (r_size >= insertion_sort_threshold) { + boost::adl_move_iter_swap(pivot_pos + 1, pivot_pos + (1 + r_size / 4)); + boost::adl_move_iter_swap(end - 1, end - r_size / 4); + + if (r_size > ninther_threshold) { + boost::adl_move_iter_swap(pivot_pos + 2, pivot_pos + (2 + r_size / 4)); + boost::adl_move_iter_swap(pivot_pos + 3, pivot_pos + (3 + r_size / 4)); + boost::adl_move_iter_swap(end - 2, end - (1 + r_size / 4)); + boost::adl_move_iter_swap(end - 3, end - (2 + r_size / 4)); + } + } + } else { + // If we were decently balanced and we tried to sort an already partitioned + // sequence try to use insertion sort. + if (already_partitioned && partial_insertion_sort(begin, pivot_pos, comp) + && partial_insertion_sort(pivot_pos + 1, end, comp)) return; + } + + // Sort the left partition first using recursion and do tail recursion elimination for + // the right-hand partition. + pdqsort_loop<Iter, Compare>(begin, pivot_pos, comp, bad_allowed, leftmost); + begin = pivot_pos + 1; + leftmost = false; + } + } +} + + +template<class Iter, class Compare> +void pdqsort(Iter begin, Iter end, Compare comp) +{ + if (begin == end) return; + typedef typename boost::movelib:: iter_size<Iter>::type size_type; + pdqsort_detail::pdqsort_loop<Iter, Compare>(begin, end, comp, pdqsort_detail::log2(size_type(end - begin))); +} + +} //namespace movelib { +} //namespace boost { + +#if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600)) +#pragma GCC diagnostic pop +#endif + +#include <boost/move/detail/config_end.hpp> + +#endif //BOOST_MOVE_ALGO_PDQSORT_HPP diff --git a/contrib/restricted/boost/python/README.md b/contrib/restricted/boost/python/README.md index c692bb8a66..f57b97505a 100644 --- a/contrib/restricted/boost/python/README.md +++ b/contrib/restricted/boost/python/README.md @@ -2,6 +2,8 @@ # Synopsis +[![Join the chat at https://gitter.im/boostorg/python](https://badges.gitter.im/boostorg/python.svg)](https://gitter.im/boostorg/python?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Welcome to Boost.Python, a C++ library which enables seamless interoperability between C++ and the Python programming language. The library includes support for: * References and Pointers @@ -19,7 +21,7 @@ See the [Boost.Python](http://boostorg.github.io/python) documentation for detai **Hint :** Check out the [development version](http://boostorg.github.io/python/develop) of the documentation to see work in progress. -# Building ![Build Status](https://travis-ci.org/boostorg/python.svg?branch=develop) +# Building ![Test Ubuntu](https://github.com/boostorg/python/workflows/Test%20Ubuntu/badge.svg) ![Test OSX](https://github.com/boostorg/python/workflows/Test%20OSX/badge.svg) ![Test Windows](https://github.com/boostorg/python/workflows/Test%20Windows/badge.svg) While Boost.Python is part of the Boost C++ Libraries super-project, and thus can be compiled as part of Boost, it can also be compiled and installed stand-alone, i.e. against a pre-installed Boost package. diff --git a/contrib/restricted/boost/python/include/boost/python/call.hpp b/contrib/restricted/boost/python/include/boost/python/call.hpp index 5d2d7d2341..c057ee9a12 100644 --- a/contrib/restricted/boost/python/include/boost/python/call.hpp +++ b/contrib/restricted/boost/python/include/boost/python/call.hpp @@ -60,7 +60,7 @@ call(PyObject* callable ) { PyObject* const result = - PyEval_CallFunction( + PyObject_CallFunction( callable , const_cast<char*>("(" BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_FIXED, "O") ")") BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_FAST_ARG_TO_PYTHON_GET, nil) @@ -69,7 +69,7 @@ call(PyObject* callable // This conversion *must not* be done in the same expression as // the call, because, in the special case where the result is a // reference a Python object which was created by converting a C++ - // argument for passing to PyEval_CallFunction, its reference + // argument for passing to PyObject_CallFunction, its reference // count will be 2 until the end of the full expression containing // the conversion, and that interferes with dangling // pointer/reference detection. diff --git a/contrib/restricted/boost/python/include/boost/python/call_method.hpp b/contrib/restricted/boost/python/include/boost/python/call_method.hpp index 410f66820e..424077eab4 100644 --- a/contrib/restricted/boost/python/include/boost/python/call_method.hpp +++ b/contrib/restricted/boost/python/include/boost/python/call_method.hpp @@ -69,7 +69,7 @@ call_method(PyObject* self, char const* name // This conversion *must not* be done in the same expression as // the call, because, in the special case where the result is a // reference a Python object which was created by converting a C++ - // argument for passing to PyEval_CallFunction, its reference + // argument for passing to PyObject_CallFunction, its reference // count will be 2 until the end of the full expression containing // the conversion, and that interferes with dangling // pointer/reference detection. diff --git a/contrib/restricted/boost/python/include/boost/python/def_visitor.hpp b/contrib/restricted/boost/python/include/boost/python/def_visitor.hpp index 9c8907cd6f..18dd928684 100644 --- a/contrib/restricted/boost/python/include/boost/python/def_visitor.hpp +++ b/contrib/restricted/boost/python/include/boost/python/def_visitor.hpp @@ -16,7 +16,7 @@ template <class T, class X1, class X2, class X3> class class_; class def_visitor_access { # if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) \ - || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) + || BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x551)) // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. public: @@ -52,7 +52,7 @@ class def_visitor friend class def_visitor_access; # if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) \ - || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) + || BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x551)) // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. public: diff --git a/contrib/restricted/boost/python/include/boost/python/detail/caller.hpp b/contrib/restricted/boost/python/include/boost/python/detail/caller.hpp index 1bd30bfb5a..2834d6da99 100644 --- a/contrib/restricted/boost/python/include/boost/python/detail/caller.hpp +++ b/contrib/restricted/boost/python/include/boost/python/detail/caller.hpp @@ -109,6 +109,23 @@ struct converter_target_type <void_result_to_python > return 0; } }; + +// Generation of ret moved from caller_arity<N>::impl::signature to here due to "feature" in MSVC 15.7.2 with /O2 +// which left the ret uninitialized and caused segfaults in Python interpreter. +template<class Policies, class Sig> const signature_element* get_ret() +{ + typedef BOOST_DEDUCED_TYPENAME Policies::template extract_return_type<Sig>::type rtype; + typedef typename select_result_converter<Policies, rtype>::type result_converter; + + static const signature_element ret = { + (is_void<rtype>::value ? "void" : type_id<rtype>().name()) + , &detail::converter_target_type<result_converter>::get_pytype + , boost::detail::indirect_traits::is_reference_to_non_const<rtype>::value + }; + + return &ret; +} + #endif @@ -229,16 +246,12 @@ struct caller_arity<N> { const signature_element * sig = detail::signature<Sig>::elements(); #ifndef BOOST_PYTHON_NO_PY_SIGNATURES + // MSVC 15.7.2, when compiling to /O2 left the static const signature_element ret, + // originally defined here, uninitialized. This in turn led to SegFault in Python interpreter. + // Issue is resolved by moving the generation of ret to separate function in detail namespace (see above). + const signature_element * ret = detail::get_ret<Policies, Sig>(); - typedef BOOST_DEDUCED_TYPENAME Policies::template extract_return_type<Sig>::type rtype; - typedef typename select_result_converter<Policies, rtype>::type result_converter; - - static const signature_element ret = { - (is_void<rtype>::value ? "void" : type_id<rtype>().name()) - , &detail::converter_target_type<result_converter>::get_pytype - , boost::detail::indirect_traits::is_reference_to_non_const<rtype>::value - }; - py_func_sig_info res = {sig, &ret }; + py_func_sig_info res = {sig, ret }; #else py_func_sig_info res = {sig, sig }; #endif diff --git a/contrib/restricted/boost/python/include/boost/python/detail/config.hpp b/contrib/restricted/boost/python/include/boost/python/detail/config.hpp index acf588311f..8dce9b742e 100644 --- a/contrib/restricted/boost/python/include/boost/python/detail/config.hpp +++ b/contrib/restricted/boost/python/include/boost/python/detail/config.hpp @@ -105,7 +105,9 @@ // Set the name of our library, this will get undef'ed by auto_link.hpp // once it's done with it: // -#define BOOST_LIB_NAME boost_python##PY_MAJOR_VERSION##PY_MINOR_VERSION +#define _BOOST_PYTHON_CONCAT(N, M, m) N ## M ## m +#define BOOST_PYTHON_CONCAT(N, M, m) _BOOST_PYTHON_CONCAT(N, M, m) +#define BOOST_LIB_NAME BOOST_PYTHON_CONCAT(boost_python, PY_MAJOR_VERSION, PY_MINOR_VERSION) // // If we're importing code from a dll, then tell auto_link.hpp about it: // @@ -118,6 +120,9 @@ #include <boost/config/auto_link.hpp> #endif // auto-linking disabled +#undef BOOST_PYTHON_CONCAT +#undef _BOOST_PYTHON_CONCAT + #ifndef BOOST_PYTHON_NO_PY_SIGNATURES #define BOOST_PYTHON_SUPPORTS_PY_SIGNATURES // enables smooth transition #endif diff --git a/contrib/restricted/boost/python/include/boost/python/detail/wrap_python.hpp b/contrib/restricted/boost/python/include/boost/python/detail/wrap_python.hpp index 9fdb222c68..037e4bf2ec 100644 --- a/contrib/restricted/boost/python/include/boost/python/detail/wrap_python.hpp +++ b/contrib/restricted/boost/python/include/boost/python/detail/wrap_python.hpp @@ -47,6 +47,13 @@ # endif #endif +// pyconfig.h defines a macro with hypot name, what breaks libstdc++ math headers +// that Python.h tries to include afterwards. +#if defined(__MINGW32__) +# include <cmath> +# include <math.h> +#endif + # include <pyconfig.h> # if defined(_SGI_COMPILER_VERSION) && _SGI_COMPILER_VERSION >= 740 # undef _POSIX_C_SOURCE @@ -83,6 +90,7 @@ // than MSVC on Win32 // #if defined(_WIN32) || defined(__CYGWIN__) + # if defined(__GNUC__) && defined(__CYGWIN__) # if defined(__LP64__) @@ -138,19 +146,45 @@ typedef int pid_t; # undef hypot // undo the evil #define left by Python. -# elif defined(__BORLANDC__) +# elif defined(__BORLANDC__) && !defined(__clang__) # undef HAVE_HYPOT # define HAVE_HYPOT 1 # endif #endif // _WIN32 +#if defined(__GNUC__) +# if defined(__has_warning) +# define BOOST_PYTHON_GCC_HAS_WREGISTER __has_warning("-Wregister") +# else +# define BOOST_PYTHON_GCC_HAS_WREGISTER __GNUC__ >= 7 +# endif +#else +# define BOOST_PYTHON_GCC_HAS_WREGISTER 0 +#endif + +// Python.h header uses `register` keyword until Python 3.4 +#if BOOST_PYTHON_GCC_HAS_WREGISTER +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wregister" +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 5033) // 'register' is no longer a supported storage class +#endif + #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION == 2 && PY_MICRO_VERSION < 2 # include <boost/python/detail/python22_fixed.h> #else # include <Python.h> #endif +#if BOOST_PYTHON_GCC_HAS_WREGISTER +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif +#undef BOOST_PYTHON_GCC_HAS_WREGISTER + #ifdef BOOST_PYTHON_ULONG_MAX_UNDEFINED # undef ULONG_MAX # undef BOOST_PYTHON_ULONG_MAX_UNDEFINED @@ -193,7 +227,11 @@ typedef int pid_t; # define PyVarObject_HEAD_INIT(type, size) \ PyObject_HEAD_INIT(type) size, +#endif +#if PY_VERSION_HEX < 0x030900A4 +# define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0) +# define Py_SET_SIZE(obj, size) ((Py_SIZE(obj) = (size)), (void)0) #endif diff --git a/contrib/restricted/boost/python/include/boost/python/list.hpp b/contrib/restricted/boost/python/include/boost/python/list.hpp index 10fd40fda5..0d5e2c8fd9 100644 --- a/contrib/restricted/boost/python/include/boost/python/list.hpp +++ b/contrib/restricted/boost/python/include/boost/python/list.hpp @@ -73,7 +73,7 @@ class list : public detail::list_base } template <class T> - long count(T const& value) const + ssize_t count(T const& value) const { return base::count(object(value)); } diff --git a/contrib/restricted/boost/python/include/boost/python/long.hpp b/contrib/restricted/boost/python/include/boost/python/long.hpp index 129c61f9e4..c15604c91c 100644 --- a/contrib/restricted/boost/python/include/boost/python/long.hpp +++ b/contrib/restricted/boost/python/include/boost/python/long.hpp @@ -24,8 +24,8 @@ namespace detail BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(long_base, object) private: - static detail::new_non_null_reference call(object const&); - static detail::new_non_null_reference call(object const&, object const&); + static detail::new_reference call(object const&); + static detail::new_reference call(object const&, object const&); }; } diff --git a/contrib/restricted/boost/python/include/boost/python/object/iterator.hpp b/contrib/restricted/boost/python/include/boost/python/object/iterator.hpp index e2f65721fb..874950365d 100644 --- a/contrib/restricted/boost/python/include/boost/python/object/iterator.hpp +++ b/contrib/restricted/boost/python/include/boost/python/object/iterator.hpp @@ -25,7 +25,7 @@ # include <boost/type.hpp> -# include <boost/detail/iterator.hpp> +# include <iterator> namespace boost { namespace python { namespace objects { @@ -42,7 +42,7 @@ struct iterator_range { iterator_range(object sequence, Iterator start, Iterator finish); - typedef boost::detail::iterator_traits<Iterator> traits_t; + typedef std::iterator_traits<Iterator> traits_t; struct next { diff --git a/contrib/restricted/boost/python/include/boost/python/object/make_instance.hpp b/contrib/restricted/boost/python/include/boost/python/object/make_instance.hpp index 31ec08f7c3..5eb3aa9d9c 100644 --- a/contrib/restricted/boost/python/include/boost/python/object/make_instance.hpp +++ b/contrib/restricted/boost/python/include/boost/python/object/make_instance.hpp @@ -47,7 +47,7 @@ struct make_instance_impl // Note the position of the internally-stored Holder, // for the sake of destruction - Py_SIZE(instance) = offsetof(instance_t, storage); + Py_SET_SIZE(instance, offsetof(instance_t, storage)); // Release ownership of the python object protect.cancel(); diff --git a/contrib/restricted/boost/python/include/boost/python/other.hpp b/contrib/restricted/boost/python/include/boost/python/other.hpp index 24a24ad8d1..26ebb426ba 100644 --- a/contrib/restricted/boost/python/include/boost/python/other.hpp +++ b/contrib/restricted/boost/python/include/boost/python/other.hpp @@ -1,5 +1,5 @@ -#ifndef OTHER_DWA20020601_HPP -# define OTHER_DWA20020601_HPP +#ifndef BOOST_PYTHON_OTHER_HPP +# define BOOST_PYTHON_OTHER_HPP # include <boost/python/detail/prefix.hpp> // Copyright David Abrahams 2002. @@ -7,8 +7,6 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -# pragma once - # include <boost/config.hpp> namespace boost { namespace python { @@ -51,4 +49,4 @@ namespace detail }} // namespace boost::python -#endif // #ifndef OTHER_DWA20020601_HPP +#endif diff --git a/contrib/restricted/boost/python/include/boost/python/override.hpp b/contrib/restricted/boost/python/include/boost/python/override.hpp index 39714257f9..b631226fd6 100644 --- a/contrib/restricted/boost/python/include/boost/python/override.hpp +++ b/contrib/restricted/boost/python/include/boost/python/override.hpp @@ -97,7 +97,7 @@ class override : public object operator()() const { detail::method_result x( - PyEval_CallFunction( + PyObject_CallFunction( this->ptr() , const_cast<char*>("()") )); @@ -132,7 +132,7 @@ detail::method_result operator()( BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, A, const& a) ) const { detail::method_result x( - PyEval_CallFunction( + PyObject_CallFunction( this->ptr() , const_cast<char*>("(" BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_FIXED, "O") ")") BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_fast_arg_to_python_get, nil) diff --git a/contrib/restricted/boost/python/include/boost/python/ptr.hpp b/contrib/restricted/boost/python/include/boost/python/ptr.hpp index 287daba458..8e97aa4064 100644 --- a/contrib/restricted/boost/python/include/boost/python/ptr.hpp +++ b/contrib/restricted/boost/python/include/boost/python/ptr.hpp @@ -1,5 +1,5 @@ -#ifndef PTR_DWA20020601_HPP -# define PTR_DWA20020601_HPP +#ifndef BOOST_PYTHON_PTR_HPP +# define BOOST_PYTHON_PTR_HPP # include <boost/python/detail/prefix.hpp> // Copyright David Abrahams 2002. @@ -11,8 +11,6 @@ // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) // Copyright (C) 2001 Peter Dimov -# pragma once - # include <boost/config.hpp> # include <boost/mpl/bool.hpp> @@ -64,4 +62,4 @@ class unwrap_pointer<pointer_wrapper<T> > }} // namespace boost::python -#endif // #ifndef PTR_DWA20020601_HPP +#endif diff --git a/contrib/restricted/boost/python/src/exec.cpp b/contrib/restricted/boost/python/src/exec.cpp index 5193b04745..8bc8be996b 100644 --- a/contrib/restricted/boost/python/src/exec.cpp +++ b/contrib/restricted/boost/python/src/exec.cpp @@ -116,7 +116,7 @@ object BOOST_PYTHON_DECL exec_file(char const *filename, object global, object l #elif PY_VERSION_HEX >= 0x03000000 // Let python open the file to avoid potential binary incompatibilities. PyObject *fo = Py_BuildValue("s", f); - FILE *fs = _Py_fopen(fo, "r"); // Private CPython API + FILE *fs = fopen(fo, "r"); Py_DECREF(fo); #else // Let python open the file to avoid potential binary incompatibilities. @@ -128,7 +128,7 @@ object BOOST_PYTHON_DECL exec_file(char const *filename, object global, object l PyObject* result = PyRun_File(fs, f, Py_file_input, - global.ptr(), local.ptr()); + global.ptr(), local.ptr()); if (!result) throw_error_already_set(); return object(detail::new_reference(result)); } diff --git a/contrib/restricted/boost/python/src/long.cpp b/contrib/restricted/boost/python/src/long.cpp index 1ec8ebc011..6aa2965e83 100644 --- a/contrib/restricted/boost/python/src/long.cpp +++ b/contrib/restricted/boost/python/src/long.cpp @@ -6,16 +6,16 @@ namespace boost { namespace python { namespace detail { -new_non_null_reference long_base::call(object const& arg_) +new_reference long_base::call(object const& arg_) { - return (detail::new_non_null_reference)PyObject_CallFunction( + return (detail::new_reference)PyObject_CallFunction( (PyObject*)&PyLong_Type, const_cast<char*>("(O)"), arg_.ptr()); } -new_non_null_reference long_base::call(object const& arg_, object const& base) +new_reference long_base::call(object const& arg_, object const& base) { - return (detail::new_non_null_reference)PyObject_CallFunction( + return (detail::new_reference)PyObject_CallFunction( (PyObject*)&PyLong_Type, const_cast<char*>("(OO)"), arg_.ptr(), base.ptr()); } diff --git a/contrib/restricted/boost/python/src/module.cpp b/contrib/restricted/boost/python/src/module.cpp index 9628481996..57675fa2df 100644 --- a/contrib/restricted/boost/python/src/module.cpp +++ b/contrib/restricted/boost/python/src/module.cpp @@ -21,7 +21,7 @@ namespace object m_obj(((borrowed_reference_t*)m)); scope current_module(m_obj); - handle_exception(init_function); + if (handle_exception(init_function)) return NULL; } return m; diff --git a/contrib/restricted/boost/python/src/object/class.cpp b/contrib/restricted/boost/python/src/object/class.cpp index 8d0daf63d7..9f8dc61ad1 100644 --- a/contrib/restricted/boost/python/src/object/class.cpp +++ b/contrib/restricted/boost/python/src/object/class.cpp @@ -208,7 +208,7 @@ namespace objects { if (static_data_object.tp_dict == 0) { - Py_TYPE(&static_data_object) = &PyType_Type; + Py_SET_TYPE(&static_data_object, &PyType_Type); static_data_object.tp_base = &PyProperty_Type; if (PyType_Ready(&static_data_object)) return 0; @@ -316,7 +316,7 @@ namespace objects { if (class_metatype_object.tp_dict == 0) { - Py_TYPE(&class_metatype_object) = &PyType_Type; + Py_SET_TYPE(&class_metatype_object, &PyType_Type); class_metatype_object.tp_base = &PyType_Type; if (PyType_Ready(&class_metatype_object)) return type_handle(); @@ -374,12 +374,7 @@ namespace objects // like, so we'll store the total size of the object // there. A negative number indicates that the extra // instance memory is not yet allocated to any holders. -#if PY_VERSION_HEX >= 0x02060000 - Py_SIZE(result) = -#else - result->ob_size = -#endif - -(static_cast<int>(offsetof(instance<>,storage) + instance_size)); + Py_SET_SIZE(result,-static_cast<int>(offsetof(instance<>,storage) + instance_size)); } return (PyObject*)result; } @@ -470,7 +465,7 @@ namespace objects { if (class_type_object.tp_dict == 0) { - Py_TYPE(&class_type_object) = incref(class_metatype().get()); + Py_SET_TYPE(&class_type_object, incref(class_metatype().get())); class_type_object.tp_base = &PyBaseObject_Type; if (PyType_Ready(&class_type_object)) return type_handle(); @@ -618,7 +613,7 @@ namespace objects { object property( (python::detail::new_reference) - PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("Osss"), fget.ptr(), 0, 0, docstr)); + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("Osss"), fget.ptr(), (char*)NULL, (char*)NULL, docstr)); this->setattr(name, property); } @@ -628,7 +623,7 @@ namespace objects { object property( (python::detail::new_reference) - PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("OOss"), fget.ptr(), fset.ptr(), 0, docstr)); + PyObject_CallFunction((PyObject*)&PyProperty_Type, const_cast<char*>("OOss"), fget.ptr(), fset.ptr(), (char*)NULL, docstr)); this->setattr(name, property); } @@ -739,7 +734,7 @@ void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std: assert(holder_offset >= offsetof(objects::instance<>,storage)); // Record the fact that the storage is occupied, noting where it starts - Py_SIZE(self) = holder_offset; + Py_SET_SIZE(self, holder_offset); return (char*)self + holder_offset; } else diff --git a/contrib/restricted/boost/python/src/object/enum.cpp b/contrib/restricted/boost/python/src/object/enum.cpp index 10122ad1da..293e705899 100644 --- a/contrib/restricted/boost/python/src/object/enum.cpp +++ b/contrib/restricted/boost/python/src/object/enum.cpp @@ -153,7 +153,7 @@ namespace { if (enum_type_object.tp_dict == 0) { - Py_TYPE(&enum_type_object) = incref(&PyType_Type); + Py_SET_TYPE(&enum_type_object, incref(&PyType_Type)); #if PY_VERSION_HEX >= 0x03000000 enum_type_object.tp_base = &PyLong_Type; #else diff --git a/contrib/restricted/boost/python/src/object/function.cpp b/contrib/restricted/boost/python/src/object/function.cpp index e15eb3ffc0..787679e138 100644 --- a/contrib/restricted/boost/python/src/object/function.cpp +++ b/contrib/restricted/boost/python/src/object/function.cpp @@ -107,7 +107,7 @@ function::function( PyObject* p = this; if (Py_TYPE(&function_type) == 0) { - Py_TYPE(&function_type) = &PyType_Type; + Py_SET_TYPE(&function_type, &PyType_Type); ::PyType_Ready(&function_type); } @@ -158,11 +158,6 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const { // no argument preprocessing } - else if (n_actual > max_arity) - { - // too many arguments - inner_args = handle<>(); - } else { // build a new arg tuple, will adjust its size later diff --git a/contrib/restricted/boost/python/src/object/life_support.cpp b/contrib/restricted/boost/python/src/object/life_support.cpp index b7e9aa861e..281c3bffc5 100644 --- a/contrib/restricted/boost/python/src/object/life_support.cpp +++ b/contrib/restricted/boost/python/src/object/life_support.cpp @@ -93,7 +93,7 @@ PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient) if (Py_TYPE(&life_support_type) == 0) { - Py_TYPE(&life_support_type) = &PyType_Type; + Py_SET_TYPE(&life_support_type, &PyType_Type); PyType_Ready(&life_support_type); } diff --git a/contrib/restricted/boost/python/src/wrapper.cpp b/contrib/restricted/boost/python/src/wrapper.cpp index f8feaef947..8b1b884769 100644 --- a/contrib/restricted/boost/python/src/wrapper.cpp +++ b/contrib/restricted/boost/python/src/wrapper.cpp @@ -25,7 +25,7 @@ namespace detail if ( PyMethod_Check(m.get()) - && ((PyMethodObject*)m.get())->im_self == this->m_self + && PyMethod_GET_SELF(m.get()) == this->m_self && class_object->tp_dict != 0 ) { @@ -34,7 +34,7 @@ namespace detail } - if (borrowed_f != ((PyMethodObject*)m.get())->im_func) + if (borrowed_f != PyMethod_GET_FUNCTION(m.get())) return override(m); } } diff --git a/contrib/restricted/boost/winapi/include/boost/winapi/directory_management.hpp b/contrib/restricted/boost/winapi/include/boost/winapi/directory_management.hpp new file mode 100644 index 0000000000..b219010d6d --- /dev/null +++ b/contrib/restricted/boost/winapi/include/boost/winapi/directory_management.hpp @@ -0,0 +1,106 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_DIRECTORY_MANAGEMENT_HPP_INCLUDED_ +#define BOOST_WINAPI_DIRECTORY_MANAGEMENT_HPP_INCLUDED_ + +#include <boost/winapi/basic_types.hpp> +#include <boost/winapi/get_system_directory.hpp> +#include <boost/winapi/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_WINAPI_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC + CreateDirectoryA(boost::winapi::LPCSTR_, ::_SECURITY_ATTRIBUTES*); +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_WINAPI_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC + GetTempPathA(boost::winapi::DWORD_ length, boost::winapi::LPSTR_ buffer); +#endif +BOOST_WINAPI_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC + RemoveDirectoryA(boost::winapi::LPCSTR_); +#endif +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC + CreateDirectoryW(boost::winapi::LPCWSTR_, ::_SECURITY_ATTRIBUTES*); +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC + GetTempPathW(boost::winapi::DWORD_ length, boost::winapi::LPWSTR_ buffer); +#endif +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC + RemoveDirectoryW(boost::winapi::LPCWSTR_); +} // extern "C" +#endif + +namespace boost { +namespace winapi { + +#if !defined( BOOST_NO_ANSI_APIS ) +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +using ::GetTempPathA; +#endif +using ::RemoveDirectoryA; +#endif +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +using ::GetTempPathW; +#endif +using ::RemoveDirectoryW; + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE BOOL_ CreateDirectoryA(LPCSTR_ pPathName, PSECURITY_ATTRIBUTES_ pSecurityAttributes) +{ + return ::CreateDirectoryA(pPathName, reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(pSecurityAttributes)); +} +#endif + +BOOST_FORCEINLINE BOOL_ CreateDirectoryW(LPCWSTR_ pPathName, PSECURITY_ATTRIBUTES_ pSecurityAttributes) +{ + return ::CreateDirectoryW(pPathName, reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(pSecurityAttributes)); +} + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE BOOL_ create_directory(LPCSTR_ pPathName, PSECURITY_ATTRIBUTES_ pSecurityAttributes) +{ + return ::CreateDirectoryA(pPathName, reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(pSecurityAttributes)); +} +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_FORCEINLINE DWORD_ get_temp_path(DWORD_ length, LPSTR_ buffer) +{ + return ::GetTempPathA(length, buffer); +} +#endif +BOOST_FORCEINLINE BOOL_ remove_directory(LPCSTR_ pPathName) +{ + return ::RemoveDirectoryA(pPathName); +} +#endif + +BOOST_FORCEINLINE BOOL_ create_directory(LPCWSTR_ pPathName, PSECURITY_ATTRIBUTES_ pSecurityAttributes) +{ + return ::CreateDirectoryW(pPathName, reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(pSecurityAttributes)); +} +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_FORCEINLINE DWORD_ get_temp_path(DWORD_ length, LPWSTR_ buffer) +{ + return ::GetTempPathW(length, buffer); +} +#endif +BOOST_FORCEINLINE BOOL_ remove_directory(LPCWSTR_ pPathName) +{ + return ::RemoveDirectoryW(pPathName); +} + +} // namespace winapi +} // namespace boost + +#include <boost/winapi/detail/footer.hpp> + +#endif // BOOST_WINAPI_DIRECTORY_MANAGEMENT_HPP_INCLUDED_ diff --git a/contrib/restricted/boost/winapi/include/boost/winapi/file_mapping.hpp b/contrib/restricted/boost/winapi/include/boost/winapi/file_mapping.hpp new file mode 100644 index 0000000000..9a5e23803a --- /dev/null +++ b/contrib/restricted/boost/winapi/include/boost/winapi/file_mapping.hpp @@ -0,0 +1,262 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * Copyright 2016 Jorge Lodos + * Copyright 2017 James E. King, III + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_FILE_MAPPING_HPP_INCLUDED_ +#define BOOST_WINAPI_FILE_MAPPING_HPP_INCLUDED_ + +#include <boost/winapi/basic_types.hpp> +#include <boost/winapi/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* + * UWP: + * API SDK 8 SDK 10 + * CreateFileMapping DESKTOP - DESKTOP | SYSTEM + * FlushViewOfFile APP - APP | SYSTEM + * MapViewOfFile DESKTOP - DESKTOP | SYSTEM + * MapViewOfFileEx DESKTOP - DESKTOP | SYSTEM + * OpenFileMapping DESKTOP - DESKTOP | SYSTEM + * UnmapViewOfFile APP - APP | SYSTEM + */ + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { + +#if BOOST_WINAPI_PARTITION_DESKTOP +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_WINAPI_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateFileMappingA( + boost::winapi::HANDLE_ hFile, + ::_SECURITY_ATTRIBUTES* lpFileMappingAttributes, + boost::winapi::DWORD_ flProtect, + boost::winapi::DWORD_ dwMaximumSizeHigh, + boost::winapi::DWORD_ dwMaximumSizeLow, + boost::winapi::LPCSTR_ lpName); + +BOOST_WINAPI_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +OpenFileMappingA( + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::LPCSTR_ lpName); +#endif // !defined( BOOST_NO_ANSI_APIS ) +#endif // BOOST_WINAPI_PARTITION_DESKTOP + +#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateFileMappingW( + boost::winapi::HANDLE_ hFile, + ::_SECURITY_ATTRIBUTES* lpFileMappingAttributes, + boost::winapi::DWORD_ flProtect, + boost::winapi::DWORD_ dwMaximumSizeHigh, + boost::winapi::DWORD_ dwMaximumSizeLow, + boost::winapi::LPCWSTR_ lpName); + +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::LPVOID_ BOOST_WINAPI_WINAPI_CC +MapViewOfFile( + boost::winapi::HANDLE_ hFileMappingObject, + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::DWORD_ dwFileOffsetHigh, + boost::winapi::DWORD_ dwFileOffsetLow, + boost::winapi::SIZE_T_ dwNumberOfBytesToMap); + +BOOST_WINAPI_IMPORT boost::winapi::LPVOID_ BOOST_WINAPI_WINAPI_CC +MapViewOfFileEx( + boost::winapi::HANDLE_ hFileMappingObject, + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::DWORD_ dwFileOffsetHigh, + boost::winapi::DWORD_ dwFileOffsetLow, + boost::winapi::SIZE_T_ dwNumberOfBytesToMap, + boost::winapi::LPVOID_ lpBaseAddress); + +BOOST_WINAPI_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +OpenFileMappingW( + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::LPCWSTR_ lpName); +#endif // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM + +#if BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +FlushViewOfFile( + boost::winapi::LPCVOID_ lpBaseAddress, + boost::winapi::SIZE_T_ dwNumberOfBytesToFlush); + +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +UnmapViewOfFile(boost::winapi::LPCVOID_ lpBaseAddress); +#endif // BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM + +} // extern "C" +#endif // !defined( BOOST_USE_WINDOWS_H ) + +namespace boost { +namespace winapi { + +#if defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_FILE_ = SEC_FILE; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_IMAGE_ = SEC_IMAGE; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_RESERVE_ = SEC_RESERVE; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_COMMIT_ = SEC_COMMIT; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_NOCACHE_ = SEC_NOCACHE; + +// These permission flags are undocumented and some of them are equivalent to the FILE_MAP_* flags. +// SECTION_QUERY enables NtQuerySection. +// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FSection%2FNtQuerySection.html +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_QUERY_ = SECTION_QUERY; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_MAP_WRITE_ = SECTION_MAP_WRITE; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_MAP_READ_ = SECTION_MAP_READ; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_MAP_EXECUTE_ = SECTION_MAP_EXECUTE; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_EXTEND_SIZE_ = SECTION_EXTEND_SIZE; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_ALL_ACCESS_ = SECTION_ALL_ACCESS; + +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_COPY_ = FILE_MAP_COPY; +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_WRITE_ = FILE_MAP_WRITE; +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_READ_ = FILE_MAP_READ; +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_ALL_ACCESS_ = FILE_MAP_ALL_ACCESS; + +#else // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_FILE_ = 0x800000; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_IMAGE_ = 0x1000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_RESERVE_ = 0x4000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_COMMIT_ = 0x8000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_NOCACHE_ = 0x10000000; + +// These permission flags are undocumented and some of them are equivalent to the FILE_MAP_* flags. +// SECTION_QUERY enables NtQuerySection. +// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FSection%2FNtQuerySection.html +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_QUERY_ = 0x00000001; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_MAP_WRITE_ = 0x00000002; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_MAP_READ_ = 0x00000004; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_MAP_EXECUTE_ = 0x00000008; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_EXTEND_SIZE_ = 0x00000010; +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_ALL_ACCESS_ = 0x000F001F; // STANDARD_RIGHTS_REQUIRED | SECTION_* + +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_COPY_ = SECTION_QUERY_; +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_WRITE_ = SECTION_MAP_WRITE_; +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_READ_ = SECTION_MAP_READ_; +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_ALL_ACCESS_ = SECTION_ALL_ACCESS_; + +#endif // defined( BOOST_USE_WINDOWS_H ) + +// These constants are not defined in Windows SDK up until the one shipped with MSVC 8 and MinGW (as of 2016-02-14) +BOOST_CONSTEXPR_OR_CONST DWORD_ SECTION_MAP_EXECUTE_EXPLICIT_ = 0x00000020; // not included in SECTION_ALL_ACCESS +BOOST_CONSTEXPR_OR_CONST DWORD_ FILE_MAP_EXECUTE_ = SECTION_MAP_EXECUTE_EXPLICIT_; // not included in FILE_MAP_ALL_ACCESS + +// These constants are not defined in Windows SDK up until 6.0A and MinGW (as of 2016-02-14) +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_PROTECTED_IMAGE_ = 0x2000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_WRITECOMBINE_ = 0x40000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_LARGE_PAGES_ = 0x80000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEC_IMAGE_NO_EXECUTE_ = (SEC_IMAGE_ | SEC_NOCACHE_); + +#if BOOST_WINAPI_PARTITION_DESKTOP +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE HANDLE_ CreateFileMappingA( + HANDLE_ hFile, + SECURITY_ATTRIBUTES_* lpFileMappingAttributes, + DWORD_ flProtect, + DWORD_ dwMaximumSizeHigh, + DWORD_ dwMaximumSizeLow, + LPCSTR_ lpName) +{ + return ::CreateFileMappingA( + hFile, + reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpFileMappingAttributes), + flProtect, + dwMaximumSizeHigh, + dwMaximumSizeLow, + lpName); +} + +BOOST_FORCEINLINE HANDLE_ create_file_mapping( + HANDLE_ hFile, + SECURITY_ATTRIBUTES_* lpFileMappingAttributes, + DWORD_ flProtect, + DWORD_ dwMaximumSizeHigh, + DWORD_ dwMaximumSizeLow, + LPCSTR_ lpName) +{ + return ::CreateFileMappingA( + hFile, + reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpFileMappingAttributes), + flProtect, + dwMaximumSizeHigh, + dwMaximumSizeLow, + lpName); +} + +using ::OpenFileMappingA; + +BOOST_FORCEINLINE HANDLE_ open_file_mapping(DWORD_ dwDesiredAccess, BOOL_ bInheritHandle, LPCSTR_ lpName) +{ + return ::OpenFileMappingA(dwDesiredAccess, bInheritHandle, lpName); +} +#endif +#endif // BOOST_WINAPI_PARTITION_DESKTOP + +#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM +BOOST_FORCEINLINE HANDLE_ CreateFileMappingW( + HANDLE_ hFile, + SECURITY_ATTRIBUTES_* lpFileMappingAttributes, + DWORD_ flProtect, + DWORD_ dwMaximumSizeHigh, + DWORD_ dwMaximumSizeLow, + LPCWSTR_ lpName) +{ + return ::CreateFileMappingW( + hFile, + reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpFileMappingAttributes), + flProtect, + dwMaximumSizeHigh, + dwMaximumSizeLow, + lpName); +} + +BOOST_FORCEINLINE HANDLE_ create_file_mapping( + HANDLE_ hFile, + SECURITY_ATTRIBUTES_* lpFileMappingAttributes, + DWORD_ flProtect, + DWORD_ dwMaximumSizeHigh, + DWORD_ dwMaximumSizeLow, + LPCWSTR_ lpName) +{ + return ::CreateFileMappingW( + hFile, + reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpFileMappingAttributes), + flProtect, + dwMaximumSizeHigh, + dwMaximumSizeLow, + lpName); +} + +using ::MapViewOfFile; +using ::MapViewOfFileEx; +using ::OpenFileMappingW; + +BOOST_FORCEINLINE HANDLE_ open_file_mapping(DWORD_ dwDesiredAccess, BOOL_ bInheritHandle, LPCWSTR_ lpName) +{ + return ::OpenFileMappingW(dwDesiredAccess, bInheritHandle, lpName); +} +#endif // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM + +#if BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM +using ::FlushViewOfFile; +using ::UnmapViewOfFile; +#endif // BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM + +} +} + +#include <boost/winapi/detail/footer.hpp> + +#endif // BOOST_WINAPI_FILE_MAPPING_HPP_INCLUDED_ diff --git a/contrib/restricted/boost/winapi/include/boost/winapi/get_system_directory.hpp b/contrib/restricted/boost/winapi/include/boost/winapi/get_system_directory.hpp new file mode 100644 index 0000000000..636808a915 --- /dev/null +++ b/contrib/restricted/boost/winapi/include/boost/winapi/get_system_directory.hpp @@ -0,0 +1,64 @@ +/* + * Copyright 2016 Klemens D. Morgenstern + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_GET_SYSTEM_DIRECTORY_HPP_INCLUDED_ +#define BOOST_WINAPI_GET_SYSTEM_DIRECTORY_HPP_INCLUDED_ + +#include <boost/winapi/basic_types.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if BOOST_WINAPI_PARTITION_DESKTOP + +#include <boost/winapi/detail/header.hpp> + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_WINAPI_IMPORT boost::winapi::UINT_ BOOST_WINAPI_WINAPI_CC +GetSystemDirectoryA( + boost::winapi::LPSTR_ lpBuffer, + boost::winapi::UINT_ uSize); +#endif + +BOOST_WINAPI_IMPORT boost::winapi::UINT_ BOOST_WINAPI_WINAPI_CC +GetSystemDirectoryW( + boost::winapi::LPWSTR_ lpBuffer, + boost::winapi::UINT_ uSize); +} // extern "C" +#endif + +namespace boost { +namespace winapi { + +#if !defined( BOOST_NO_ANSI_APIS ) +using ::GetSystemDirectoryA; +#endif +using ::GetSystemDirectoryW; + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE UINT_ get_system_directory(LPSTR_ lpBuffer, UINT_ uSize) +{ + return ::GetSystemDirectoryA(lpBuffer, uSize); +} +#endif + +BOOST_FORCEINLINE UINT_ get_system_directory(LPWSTR_ lpBuffer, UINT_ uSize) +{ + return ::GetSystemDirectoryW(lpBuffer, uSize); +} + +} +} + +#include <boost/winapi/detail/footer.hpp> + +#endif // BOOST_WINAPI_PARTITION_DESKTOP + +#endif // BOOST_WINAPI_GET_SYSTEM_DIRECTORY_HPP_INCLUDED_ diff --git a/contrib/restricted/boost/winapi/include/boost/winapi/mutex.hpp b/contrib/restricted/boost/winapi/include/boost/winapi/mutex.hpp new file mode 100644 index 0000000000..c708c54376 --- /dev/null +++ b/contrib/restricted/boost/winapi/include/boost/winapi/mutex.hpp @@ -0,0 +1,185 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015, 2017 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_MUTEX_HPP_INCLUDED_ +#define BOOST_WINAPI_MUTEX_HPP_INCLUDED_ + +#include <boost/winapi/basic_types.hpp> +#include <boost/winapi/detail/header.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) && BOOST_WINAPI_PARTITION_APP_SYSTEM +extern "C" { +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_WINAPI_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateMutexA( + ::_SECURITY_ATTRIBUTES* lpMutexAttributes, + boost::winapi::BOOL_ bInitialOwner, + boost::winapi::LPCSTR_ lpName); +#endif + +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateMutexW( + ::_SECURITY_ATTRIBUTES* lpMutexAttributes, + boost::winapi::BOOL_ bInitialOwner, + boost::winapi::LPCWSTR_ lpName); +} // extern "C" +#endif // !defined( BOOST_USE_WINDOWS_H ) && BOOST_WINAPI_PARTITION_APP_SYSTEM + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +#if !defined( BOOST_NO_ANSI_APIS ) +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_WINAPI_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateMutexExA( + ::_SECURITY_ATTRIBUTES* lpMutexAttributes, + boost::winapi::LPCSTR_ lpName, + boost::winapi::DWORD_ dwFlags, + boost::winapi::DWORD_ dwDesiredAccess); +#endif + +BOOST_WINAPI_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +OpenMutexA( + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::LPCSTR_ lpName); +#endif // !defined( BOOST_NO_ANSI_APIS ) + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_WINAPI_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateMutexExW( + ::_SECURITY_ATTRIBUTES* lpMutexAttributes, + boost::winapi::LPCWSTR_ lpName, + boost::winapi::DWORD_ dwFlags, + boost::winapi::DWORD_ dwDesiredAccess); +#endif + +BOOST_WINAPI_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +OpenMutexW( + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::LPCWSTR_ lpName); + +BOOST_WINAPI_IMPORT_EXCEPT_WM boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +ReleaseMutex(boost::winapi::HANDLE_ hMutex); +} // extern "C" +#endif + +namespace boost { +namespace winapi { + +#if !defined( BOOST_NO_ANSI_APIS ) +using ::OpenMutexA; +#endif +using ::OpenMutexW; +using ::ReleaseMutex; + +#if defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ MUTEX_ALL_ACCESS_ = MUTEX_ALL_ACCESS; +BOOST_CONSTEXPR_OR_CONST DWORD_ MUTEX_MODIFY_STATE_ = MUTEX_MODIFY_STATE; +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_CONSTEXPR_OR_CONST DWORD_ CREATE_MUTEX_INITIAL_OWNER_ = CREATE_MUTEX_INITIAL_OWNER; +#endif + +#else // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ MUTEX_ALL_ACCESS_ = 0x001F0001; +BOOST_CONSTEXPR_OR_CONST DWORD_ MUTEX_MODIFY_STATE_ = 0x00000001; +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_CONSTEXPR_OR_CONST DWORD_ CREATE_MUTEX_INITIAL_OWNER_ = 0x00000001; +#endif + +#endif // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ mutex_all_access = MUTEX_ALL_ACCESS_; +BOOST_CONSTEXPR_OR_CONST DWORD_ mutex_modify_state = MUTEX_MODIFY_STATE_; +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_CONSTEXPR_OR_CONST DWORD_ create_mutex_initial_owner = CREATE_MUTEX_INITIAL_OWNER_; +#endif + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE HANDLE_ CreateMutexA(SECURITY_ATTRIBUTES_* lpMutexAttributes, BOOL_ bInitialOwner, LPCSTR_ lpName) +{ +#if !BOOST_WINAPI_PARTITION_APP_SYSTEM && BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 + const DWORD_ flags = bInitialOwner ? create_mutex_initial_owner : 0u; + return ::CreateMutexExA(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpMutexAttributes), lpName, flags, mutex_all_access); +#else + return ::CreateMutexA(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpMutexAttributes), bInitialOwner, lpName); +#endif +} + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_FORCEINLINE HANDLE_ CreateMutexExA( + SECURITY_ATTRIBUTES_* lpMutexAttributes, + LPCSTR_ lpName, + DWORD_ dwFlags, + DWORD_ dwDesiredAccess) +{ + return ::CreateMutexExA(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpMutexAttributes), lpName, dwFlags, dwDesiredAccess); +} +#endif +#endif + +BOOST_FORCEINLINE HANDLE_ CreateMutexW(SECURITY_ATTRIBUTES_* lpMutexAttributes, BOOL_ bInitialOwner, LPCWSTR_ lpName) +{ +#if !BOOST_WINAPI_PARTITION_APP_SYSTEM && BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 + const DWORD_ flags = bInitialOwner ? create_mutex_initial_owner : 0u; + return ::CreateMutexExW(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpMutexAttributes), lpName, flags, mutex_all_access); +#else + return ::CreateMutexW(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpMutexAttributes), bInitialOwner, lpName); +#endif +} + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_FORCEINLINE HANDLE_ CreateMutexExW( + SECURITY_ATTRIBUTES_* lpMutexAttributes, + LPCWSTR_ lpName, + DWORD_ dwFlags, + DWORD_ dwDesiredAccess) +{ + return ::CreateMutexExW(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpMutexAttributes), lpName, dwFlags, dwDesiredAccess); +} +#endif + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE HANDLE_ create_mutex(SECURITY_ATTRIBUTES_* lpAttributes, BOOL_ bInitialOwner, LPCSTR_ lpName) +{ + return winapi::CreateMutexA(lpAttributes, bInitialOwner, lpName); +} + +BOOST_FORCEINLINE HANDLE_ open_mutex(DWORD_ dwDesiredAccess, BOOL_ bInheritHandle, LPCSTR_ lpName) +{ + return ::OpenMutexA(dwDesiredAccess, bInheritHandle, lpName); +} +#endif + +BOOST_FORCEINLINE HANDLE_ create_mutex(SECURITY_ATTRIBUTES_* lpAttributes, BOOL_ bInitialOwner, LPCWSTR_ lpName) +{ + return winapi::CreateMutexW(lpAttributes, bInitialOwner, lpName); +} + +BOOST_FORCEINLINE HANDLE_ open_mutex(DWORD_ dwDesiredAccess, BOOL_ bInheritHandle, LPCWSTR_ lpName) +{ + return ::OpenMutexW(dwDesiredAccess, bInheritHandle, lpName); +} + +BOOST_FORCEINLINE HANDLE_ create_anonymous_mutex(SECURITY_ATTRIBUTES_* lpAttributes, BOOL_ bInitialOwner) +{ + return winapi::CreateMutexW(lpAttributes, bInitialOwner, 0); +} + +} +} + +#include <boost/winapi/detail/footer.hpp> + +#endif // BOOST_WINAPI_MUTEX_HPP_INCLUDED_ diff --git a/contrib/restricted/boost/winapi/include/boost/winapi/security.hpp b/contrib/restricted/boost/winapi/include/boost/winapi/security.hpp new file mode 100644 index 0000000000..80a2d952e3 --- /dev/null +++ b/contrib/restricted/boost/winapi/include/boost/winapi/security.hpp @@ -0,0 +1,89 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_SECURITY_HPP_INCLUDED_ +#define BOOST_WINAPI_SECURITY_HPP_INCLUDED_ + +#include <boost/winapi/basic_types.hpp> + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM + +#include <boost/winapi/detail/header.hpp> + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +struct _ACL; +struct _SECURITY_DESCRIPTOR; +#if defined( BOOST_WINAPI_IS_MINGW ) +typedef _SECURITY_DESCRIPTOR *PSECURITY_DESCRIPTOR; +#else +typedef boost::winapi::PVOID_ PSECURITY_DESCRIPTOR; +#endif + +BOOST_WINAPI_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +InitializeSecurityDescriptor( + PSECURITY_DESCRIPTOR pSecurityDescriptor, + boost::winapi::DWORD_ dwRevision); +BOOST_WINAPI_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +SetSecurityDescriptorDacl( + PSECURITY_DESCRIPTOR pSecurityDescriptor, + boost::winapi::BOOL_ bDaclPresent, + ::_ACL* pDacl, + boost::winapi::BOOL_ bDaclDefaulted); +} +#endif + +namespace boost { +namespace winapi { + +typedef PVOID_ PSID_; +typedef WORD_ SECURITY_DESCRIPTOR_CONTROL_, *PSECURITY_DESCRIPTOR_CONTROL_; + +typedef struct BOOST_MAY_ALIAS _ACL { + BYTE_ AclRevision; + BYTE_ Sbz1; + WORD_ AclSize; + WORD_ AceCount; + WORD_ Sbz2; +} ACL_, *PACL_; + +typedef struct BOOST_MAY_ALIAS _SECURITY_DESCRIPTOR { + BYTE_ Revision; + BYTE_ Sbz1; + SECURITY_DESCRIPTOR_CONTROL_ Control; + PSID_ Owner; + PSID_ Group; + PACL_ Sacl; + PACL_ Dacl; +} SECURITY_DESCRIPTOR_, *PISECURITY_DESCRIPTOR_; + +// To abstract away the different ::PSECURITY_DESCRIPTOR on MinGW, we use PVOID_ universally here +// and cast the pointers to ::PSECURITY_DESCRIPTOR in wrapper functions. +typedef PVOID_ PSECURITY_DESCRIPTOR_; + +BOOST_FORCEINLINE BOOL_ InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR_ pSecurityDescriptor, DWORD_ dwRevision) +{ + return ::InitializeSecurityDescriptor(reinterpret_cast< ::PSECURITY_DESCRIPTOR >(pSecurityDescriptor), dwRevision); +} + +BOOST_FORCEINLINE BOOL_ SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR_ pSecurityDescriptor, BOOL_ bDaclPresent, PACL_ pDacl, BOOL_ bDaclDefaulted) +{ + return ::SetSecurityDescriptorDacl(reinterpret_cast< ::PSECURITY_DESCRIPTOR >(pSecurityDescriptor), bDaclPresent, reinterpret_cast< ::_ACL* >(pDacl), bDaclDefaulted); +} + +} +} + +#include <boost/winapi/detail/footer.hpp> + +#endif // BOOST_WINAPI_PARTITION_APP_SYSTEM +#endif // BOOST_WINAPI_SECURITY_HPP_INCLUDED_ |