diff --git a/cpp/BoostParts/CMakeLists.txt b/cpp/BoostParts/CMakeLists.txt index 8d153d01..a9f22e09 100644 --- a/cpp/BoostParts/CMakeLists.txt +++ b/cpp/BoostParts/CMakeLists.txt @@ -19,7 +19,7 @@ # the BCP tool: # http://www.boost.org/doc/libs/1_52_0/tools/bcp/doc/html/index.html # -# bcp call: bcp boost/utility.hpp boost/python.hpp boost/bind.hpp boost/lambda/lambda.hpp boost/exception/all.hpp boost/tuple/tuple_io.hpp boost/tuple/tuple_comparison.hpp boost/regex.hpp boost/foreach.hpp boost/smart_ptr.hpp boost/algorithm/string_regex.hpp boost/thread.hpp boost/unordered_map.hpp boost/unordered_set.hpp boost/format.hpp boost/ptr_container/ptr_container.hpp boost/filesystem.hpp boost/filesystem/fstream.hpp boost/utility.hpp boost/algorithm/cxx11/any_of.hpp ../BoostParts +# bcp call: bcp boost/utility.hpp boost/python.hpp boost/bind.hpp boost/lambda/lambda.hpp boost/exception/all.hpp boost/tuple/tuple_io.hpp boost/tuple/tuple_comparison.hpp boost/regex.hpp boost/foreach.hpp boost/smart_ptr.hpp boost/algorithm/string_regex.hpp boost/thread.hpp boost/unordered_map.hpp boost/unordered_set.hpp boost/format.hpp boost/ptr_container/ptr_container.hpp boost/filesystem.hpp boost/filesystem/fstream.hpp boost/utility.hpp boost/algorithm/cxx11/any_of.hpp atomic lockfree ../BoostParts cmake_minimum_required( VERSION 2.8 ) diff --git a/cpp/BoostParts/boost/atomic.hpp b/cpp/BoostParts/boost/atomic.hpp new file mode 100644 index 00000000..0f5883c3 --- /dev/null +++ b/cpp/BoostParts/boost/atomic.hpp @@ -0,0 +1,18 @@ +#ifndef BOOST_ATOMIC_HPP +#define BOOST_ATOMIC_HPP + +// Copyright (c) 2011 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This header includes all Boost.Atomic public headers + +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif diff --git a/cpp/BoostParts/boost/atomic/atomic.hpp b/cpp/BoostParts/boost/atomic/atomic.hpp new file mode 100644 index 00000000..f47bdb16 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/atomic.hpp @@ -0,0 +1,205 @@ +#ifndef BOOST_ATOMIC_ATOMIC_HPP +#define BOOST_ATOMIC_ATOMIC_HPP + +// Copyright (c) 2011 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include + +#include +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +#ifndef BOOST_ATOMIC_CHAR_LOCK_FREE +#define BOOST_ATOMIC_CHAR_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_CHAR16_T_LOCK_FREE +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_CHAR32_T_LOCK_FREE +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_WCHAR_T_LOCK_FREE +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_SHORT_LOCK_FREE +#define BOOST_ATOMIC_SHORT_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT_LOCK_FREE +#define BOOST_ATOMIC_INT_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_LONG_LOCK_FREE +#define BOOST_ATOMIC_LONG_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_LLONG_LOCK_FREE +#define BOOST_ATOMIC_LLONG_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_POINTER_LOCK_FREE +#define BOOST_ATOMIC_POINTER_LOCK_FREE 0 +#endif + +#define BOOST_ATOMIC_ADDRESS_LOCK_FREE BOOST_ATOMIC_POINTER_LOCK_FREE + +#ifndef BOOST_ATOMIC_BOOL_LOCK_FREE +#define BOOST_ATOMIC_BOOL_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_THREAD_FENCE +#define BOOST_ATOMIC_THREAD_FENCE 0 +inline void atomic_thread_fence(memory_order) +{ +} +#endif + +#ifndef BOOST_ATOMIC_SIGNAL_FENCE +#define BOOST_ATOMIC_SIGNAL_FENCE 0 +inline void atomic_signal_fence(memory_order order) +{ + atomic_thread_fence(order); +} +#endif + +template +class atomic : + public atomics::detail::base_atomic::type, atomics::detail::storage_size_of::value, boost::is_signed::value > +{ +private: + typedef T value_type; + typedef atomics::detail::base_atomic::type, atomics::detail::storage_size_of::value, boost::is_signed::value > super; +public: + atomic(void) : super() {} + explicit atomic(const value_type & v) : super(v) {} + + atomic & operator=(value_type v) volatile + { + super::operator=(v); + return *const_cast(this); + } +private: + atomic(const atomic &) /* =delete */ ; + atomic & operator=(const atomic &) /* =delete */ ; +}; + +typedef atomic atomic_char; +typedef atomic atomic_uchar; +typedef atomic atomic_schar; +typedef atomic atomic_uint8_t; +typedef atomic atomic_int8_t; +typedef atomic atomic_ushort; +typedef atomic atomic_short; +typedef atomic atomic_uint16_t; +typedef atomic atomic_int16_t; +typedef atomic atomic_uint; +typedef atomic atomic_int; +typedef atomic atomic_uint32_t; +typedef atomic atomic_int32_t; +typedef atomic atomic_ulong; +typedef atomic atomic_long; +typedef atomic atomic_uint64_t; +typedef atomic atomic_int64_t; +#ifdef BOOST_HAS_LONG_LONG +typedef atomic atomic_ullong; +typedef atomic atomic_llong; +#endif +typedef atomic atomic_address; +typedef atomic atomic_bool; +typedef atomic atomic_wchar_t; +#if !defined(BOOST_NO_CXX11_CHAR16_T) +typedef atomic atomic_char16_t; +#endif +#if !defined(BOOST_NO_CXX11_CHAR32_T) +typedef atomic atomic_char32_t; +#endif + +typedef atomic atomic_int_least8_t; +typedef atomic atomic_uint_least8_t; +typedef atomic atomic_int_least16_t; +typedef atomic atomic_uint_least16_t; +typedef atomic atomic_int_least32_t; +typedef atomic atomic_uint_least32_t; +typedef atomic atomic_int_least64_t; +typedef atomic atomic_uint_least64_t; +typedef atomic atomic_int_fast8_t; +typedef atomic atomic_uint_fast8_t; +typedef atomic atomic_int_fast16_t; +typedef atomic atomic_uint_fast16_t; +typedef atomic atomic_int_fast32_t; +typedef atomic atomic_uint_fast32_t; +typedef atomic atomic_int_fast64_t; +typedef atomic atomic_uint_fast64_t; +typedef atomic atomic_intmax_t; +typedef atomic atomic_uintmax_t; + +typedef atomic atomic_size_t; +typedef atomic atomic_ptrdiff_t; + +// PGI seems to not support intptr_t/uintptr_t properly. BOOST_HAS_STDINT_H is not defined for this compiler by Boost.Config. +#if !defined(__PGIC__) + +#if (defined(BOOST_WINDOWS) && !defined(_WIN32_WCE)) \ + || (defined(_XOPEN_UNIX) && (_XOPEN_UNIX+0 > 0)) \ + || defined(__CYGWIN__) \ + || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ + || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +typedef atomic atomic_intptr_t; +typedef atomic atomic_uintptr_t; +#elif defined(__GNUC__) || defined(__clang__) +#if defined(__INTPTR_TYPE__) +typedef atomic< __INTPTR_TYPE__ > atomic_intptr_t; +#endif +#if defined(__UINTPTR_TYPE__) +typedef atomic< __UINTPTR_TYPE__ > atomic_uintptr_t; +#endif +#endif + +#endif + +#ifndef BOOST_ATOMIC_FLAG_LOCK_FREE +#define BOOST_ATOMIC_FLAG_LOCK_FREE 0 +class atomic_flag +{ +public: + atomic_flag(void) : v_(false) {} + + bool + test_and_set(memory_order order = memory_order_seq_cst) + { + return v_.exchange(true, order); + } + + void + clear(memory_order order = memory_order_seq_cst) volatile + { + v_.store(false, order); + } +private: + atomic_flag(const atomic_flag &) /* = delete */ ; + atomic_flag & operator=(const atomic_flag &) /* = delete */ ; + atomic v_; +}; +#endif + +} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/base.hpp b/cpp/BoostParts/boost/atomic/detail/base.hpp new file mode 100644 index 00000000..b0354543 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/base.hpp @@ -0,0 +1,519 @@ +#ifndef BOOST_ATOMIC_DETAIL_BASE_HPP +#define BOOST_ATOMIC_DETAIL_BASE_HPP + +// Copyright (c) 2009 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Base class definition and fallback implementation. +// To be overridden (through partial specialization) by +// platform implementations. + +#include + +#include +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_DECLARE_BASE_OPERATORS \ + operator value_type(void) volatile const \ + { \ + return load(memory_order_seq_cst); \ + } \ + \ + this_type & \ + operator=(value_type v) volatile \ + { \ + store(v, memory_order_seq_cst); \ + return *const_cast(this); \ + } \ + \ + bool \ + compare_exchange_strong( \ + value_type & expected, \ + value_type desired, \ + memory_order order = memory_order_seq_cst) volatile \ + { \ + return compare_exchange_strong(expected, desired, order, calculate_failure_order(order)); \ + } \ + \ + bool \ + compare_exchange_weak( \ + value_type & expected, \ + value_type desired, \ + memory_order order = memory_order_seq_cst) volatile \ + { \ + return compare_exchange_weak(expected, desired, order, calculate_failure_order(order)); \ + } \ + \ + +#define BOOST_ATOMIC_DECLARE_ADDITIVE_OPERATORS \ + value_type \ + operator++(int) volatile \ + { \ + return fetch_add(1); \ + } \ + \ + value_type \ + operator++(void) volatile \ + { \ + return fetch_add(1) + 1; \ + } \ + \ + value_type \ + operator--(int) volatile \ + { \ + return fetch_sub(1); \ + } \ + \ + value_type \ + operator--(void) volatile \ + { \ + return fetch_sub(1) - 1; \ + } \ + \ + value_type \ + operator+=(difference_type v) volatile \ + { \ + return fetch_add(v) + v; \ + } \ + \ + value_type \ + operator-=(difference_type v) volatile \ + { \ + return fetch_sub(v) - v; \ + } \ + +#define BOOST_ATOMIC_DECLARE_BIT_OPERATORS \ + value_type \ + operator&=(difference_type v) volatile \ + { \ + return fetch_and(v) & v; \ + } \ + \ + value_type \ + operator|=(difference_type v) volatile \ + { \ + return fetch_or(v) | v; \ + } \ + \ + value_type \ + operator^=(difference_type v) volatile \ + { \ + return fetch_xor(v) ^ v; \ + } \ + +#define BOOST_ATOMIC_DECLARE_POINTER_OPERATORS \ + BOOST_ATOMIC_DECLARE_BASE_OPERATORS \ + BOOST_ATOMIC_DECLARE_ADDITIVE_OPERATORS \ + +#define BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS \ + BOOST_ATOMIC_DECLARE_BASE_OPERATORS \ + BOOST_ATOMIC_DECLARE_ADDITIVE_OPERATORS \ + BOOST_ATOMIC_DECLARE_BIT_OPERATORS \ + +namespace boost { +namespace atomics { +namespace detail { + +inline memory_order +calculate_failure_order(memory_order order) +{ + switch(order) { + case memory_order_acq_rel: + return memory_order_acquire; + case memory_order_release: + return memory_order_relaxed; + default: + return order; + } +} + +template +class base_atomic { +private: + typedef base_atomic this_type; + typedef T value_type; + typedef lockpool::scoped_lock guard_type; +public: + base_atomic(void) {} + + explicit base_atomic(const value_type & v) + { + memcpy(&v_, &v, sizeof(value_type)); + } + + void + store(value_type const& v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(v_)); + + memcpy(const_cast(v_), &v, sizeof(value_type)); + } + + value_type + load(memory_order /*order*/ = memory_order_seq_cst) volatile const + { + guard_type guard(const_cast(v_)); + + value_type v; + memcpy(&v, const_cast(v_), sizeof(value_type)); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order /*success_order*/, + memory_order /*failure_order*/) volatile + { + guard_type guard(const_cast(v_)); + + if (memcmp(const_cast(v_), &expected, sizeof(value_type)) == 0) { + memcpy(const_cast(v_), &desired, sizeof(value_type)); + return true; + } else { + memcpy(&expected, const_cast(v_), sizeof(value_type)); + return false; + } + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + exchange(value_type const& v, memory_order /*order*/=memory_order_seq_cst) volatile + { + guard_type guard(const_cast(v_)); + + value_type tmp; + memcpy(&tmp, const_cast(v_), sizeof(value_type)); + + memcpy(const_cast(v_), &v, sizeof(value_type)); + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return false; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + + char v_[sizeof(value_type)]; +}; + +template +class base_atomic { +private: + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef lockpool::scoped_lock guard_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + v_ = v; + } + + value_type + load(memory_order /*order*/ = memory_order_seq_cst) const volatile + { + guard_type guard(const_cast(&v_)); + + value_type v = const_cast(v_); + return v; + } + + value_type + exchange(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ = v; + return old; + } + + bool + compare_exchange_strong(value_type & expected, value_type desired, + memory_order /*success_order*/, + memory_order /*failure_order*/) volatile + { + guard_type guard(const_cast(&v_)); + + if (v_ == expected) { + v_ = desired; + return true; + } else { + expected = v_; + return false; + } + } + + bool + compare_exchange_weak(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_add(difference_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ += v; + return old; + } + + value_type + fetch_sub(difference_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ -= v; + return old; + } + + value_type + fetch_and(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ &= v; + return old; + } + + value_type + fetch_or(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ |= v; + return old; + } + + value_type + fetch_xor(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ ^= v; + return old; + } + + bool + is_lock_free(void) const volatile + { + return false; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { +private: + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; + typedef lockpool::scoped_lock guard_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + v_ = v; + } + + value_type + load(memory_order /*order*/ = memory_order_seq_cst) const volatile + { + guard_type guard(const_cast(&v_)); + + value_type v = const_cast(v_); + return v; + } + + value_type + exchange(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ = v; + return old; + } + + bool + compare_exchange_strong(value_type & expected, value_type desired, + memory_order /*success_order*/, + memory_order /*failure_order*/) volatile + { + guard_type guard(const_cast(&v_)); + + if (v_ == expected) { + v_ = desired; + return true; + } else { + expected = v_; + return false; + } + } + + bool + compare_exchange_weak(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type fetch_add(difference_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ += v; + return old; + } + + value_type fetch_sub(difference_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ -= v; + return old; + } + + bool + is_lock_free(void) const volatile + { + return false; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { +private: + typedef base_atomic this_type; + typedef void * value_type; + typedef lockpool::scoped_lock guard_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + v_ = v; + } + + value_type + load(memory_order /*order*/ = memory_order_seq_cst) const volatile + { + guard_type guard(const_cast(&v_)); + + value_type v = const_cast(v_); + return v; + } + + value_type + exchange(value_type v, memory_order /*order*/ = memory_order_seq_cst) volatile + { + guard_type guard(const_cast(&v_)); + + value_type old = v_; + v_ = v; + return old; + } + + bool + compare_exchange_strong(value_type & expected, value_type desired, + memory_order /*success_order*/, + memory_order /*failure_order*/) volatile + { + guard_type guard(const_cast(&v_)); + + if (v_ == expected) { + v_ = desired; + return true; + } else { + expected = v_; + return false; + } + } + + bool + compare_exchange_weak(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return false; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +} +} +} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/cas32strong.hpp b/cpp/BoostParts/boost/atomic/detail/cas32strong.hpp new file mode 100644 index 00000000..2cbfaab8 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/cas32strong.hpp @@ -0,0 +1,872 @@ +#ifndef BOOST_ATOMIC_DETAIL_CAS32STRONG_HPP +#define BOOST_ATOMIC_DETAIL_CAS32STRONG_HPP + +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Copyright (c) 2011 Helge Bahmann + +// Build 8-, 16- and 32-bit atomic operations from +// a platform_cmpxchg32_strong primitive. + +#include +#include +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/* integral types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + storage_type expected_s = (storage_type) expected; + storage_type desired_s = (storage_type) desired; + + bool success = platform_cmpxchg32_strong(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + expected = (value_type) expected_s; + } + + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original & v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original | v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original ^ v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + storage_type expected_s = (storage_type) expected; + storage_type desired_s = (storage_type) desired; + + bool success = platform_cmpxchg32_strong(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + expected = (value_type) expected_s; + } + + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original & v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original | v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original ^ v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg32_strong(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original & v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original | v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original ^ v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +/* pointer types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef void * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg32_strong(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg32_strong(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +/* generic types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before_store(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + platform_fence_before(success_order); + bool success = platform_cmpxchg32_strong(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + } + + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before_store(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + platform_fence_before(success_order); + bool success = platform_cmpxchg32_strong(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + } + + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before_store(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + platform_fence_before(success_order); + bool success = platform_cmpxchg32_strong(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + } + + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +} +} +} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/cas32weak.hpp b/cpp/BoostParts/boost/atomic/detail/cas32weak.hpp new file mode 100644 index 00000000..f4d9f7f2 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/cas32weak.hpp @@ -0,0 +1,916 @@ +#ifndef BOOST_ATOMIC_DETAIL_CAS32WEAK_HPP +#define BOOST_ATOMIC_DETAIL_CAS32WEAK_HPP + +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Copyright (c) 2011 Helge Bahmann + +#include +#include +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/* integral types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + storage_type expected_s = (storage_type) expected; + storage_type desired_s = (storage_type) desired; + + bool success = platform_cmpxchg32(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + expected = (value_type) expected_s; + } + + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + for(;;) { + value_type tmp = expected; + if (compare_exchange_weak(tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) { + expected = tmp; + return false; + } + } + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original & v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original | v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original ^ v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + storage_type expected_s = (storage_type) expected; + storage_type desired_s = (storage_type) desired; + + bool success = platform_cmpxchg32(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + expected = (value_type) expected_s; + } + + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + for(;;) { + value_type tmp = expected; + if (compare_exchange_weak(tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) { + expected = tmp; + return false; + } + } + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original & v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original | v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original ^ v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg32(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + for(;;) { + value_type tmp = expected; + if (compare_exchange_weak(tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) { + expected = tmp; + return false; + } + } + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original & v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original | v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original ^ v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +/* pointer types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef void * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg32(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + for(;;) { + value_type tmp = expected; + if (compare_exchange_weak(tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) { + expected = tmp; + return false; + } + } + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg32(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + for(;;) { + value_type tmp = expected; + if (compare_exchange_weak(tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) { + expected = tmp; + return false; + } + } + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +/* generic types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before_store(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + platform_fence_before(success_order); + + bool success = platform_cmpxchg32(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + } + + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + for(;;) { + value_type tmp = expected; + if (compare_exchange_weak(tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) { + expected = tmp; + return false; + } + } + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before_store(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + platform_fence_before(success_order); + + bool success = platform_cmpxchg32(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + } + + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + for(;;) { + value_type tmp = expected; + if (compare_exchange_weak(tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) { + expected = tmp; + return false; + } + } + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before_store(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + platform_fence_before(success_order); + + bool success = platform_cmpxchg32(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + } + + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + for(;;) { + value_type tmp = expected; + if (compare_exchange_weak(tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) { + expected = tmp; + return false; + } + } + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +} +} +} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/cas64strong.hpp b/cpp/BoostParts/boost/atomic/detail/cas64strong.hpp new file mode 100644 index 00000000..ca7f41f3 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/cas64strong.hpp @@ -0,0 +1,438 @@ +#ifndef BOOST_ATOMIC_DETAIL_CAS64STRONG_HPP +#define BOOST_ATOMIC_DETAIL_CAS64STRONG_HPP + +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Copyright (c) 2011 Helge Bahmann + +// Build 64-bit atomic operation from platform_cmpxchg64_strong +// primitive. It is assumed that 64-bit loads/stores are not +// atomic, so they are funnelled through cmpxchg as well. + +#include +#include +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/* integral types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + platform_store64(v, &v_); + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = platform_load64(&v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg64_strong(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original & v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original | v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original ^ v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +/* pointer types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef void * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + platform_store64(v, &v_); + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = platform_load64(&v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg64_strong(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before_store(order); + platform_store64(v, &v_); + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = platform_load64(&v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + + bool success = platform_cmpxchg64_strong(expected, desired, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + } + + return success; + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original + v, order, memory_order_relaxed)); + return original; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, original - v, order, memory_order_relaxed)); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +/* generic types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint64_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& value, memory_order order = memory_order_seq_cst) volatile + { + storage_type value_s = 0; + memcpy(&value_s, &value, sizeof(value_s)); + platform_fence_before_store(order); + platform_store64(value_s, &v_); + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type value_s = platform_load64(&v_); + platform_fence_after_load(order); + value_type value; + memcpy(&value, &value_s, sizeof(value_s)); + return value; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type original = load(memory_order_relaxed); + do { + } while (!compare_exchange_weak(original, v, order, memory_order_relaxed)); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + platform_fence_before(success_order); + bool success = platform_cmpxchg64_strong(expected_s, desired_s, &v_); + + if (success) { + platform_fence_after(success_order); + } else { + platform_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + } + + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +} +} +} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/config.hpp b/cpp/BoostParts/boost/atomic/detail/config.hpp new file mode 100644 index 00000000..979bdd8f --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/config.hpp @@ -0,0 +1,54 @@ +#ifndef BOOST_ATOMIC_DETAIL_CONFIG_HPP +#define BOOST_ATOMIC_DETAIL_CONFIG_HPP + +// Copyright (c) 2012 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if (defined(_MSC_VER) && (_MSC_VER >= 1020)) || defined(__GNUC__) || defined(BOOST_CLANG) || defined(BOOST_INTEL) || defined(__COMO__) || defined(__DMC__) +#define BOOST_ATOMIC_HAS_PRAGMA_ONCE +#endif + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Set up dll import/export options +#if (defined(BOOST_ATOMIC_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && \ + !defined(BOOST_ATOMIC_STATIC_LINK) + +#if defined(BOOST_ATOMIC_SOURCE) +#define BOOST_ATOMIC_DECL BOOST_SYMBOL_EXPORT +#define BOOST_ATOMIC_BUILD_DLL +#else +#define BOOST_ATOMIC_DECL BOOST_SYMBOL_IMPORT +#endif + +#endif // building a shared library + +#ifndef BOOST_ATOMIC_DECL +#define BOOST_ATOMIC_DECL +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Auto library naming +#if !defined(BOOST_ATOMIC_SOURCE) && !defined(BOOST_ALL_NO_LIB) && \ + !defined(BOOST_ATOMIC_NO_LIB) + +#define BOOST_LIB_NAME boost_atomic + +// tell the auto-link code to select a dll when required: +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_ATOMIC_DYN_LINK) +#define BOOST_DYN_LINK +#endif + +#include + +#endif // auto-linking disabled + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/gcc-alpha.hpp b/cpp/BoostParts/boost/atomic/detail/gcc-alpha.hpp new file mode 100644 index 00000000..0748fc38 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/gcc-alpha.hpp @@ -0,0 +1,359 @@ +#ifndef BOOST_ATOMIC_DETAIL_GCC_ALPHA_HPP +#define BOOST_ATOMIC_DETAIL_GCC_ALPHA_HPP + +// Copyright (c) 2009 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* + Refer to http://h71000.www7.hp.com/doc/82final/5601/5601pro_004.html + (HP OpenVMS systems documentation) and the alpha reference manual. + */ + +/* + NB: The most natural thing would be to write the increment/decrement + operators along the following lines: + + __asm__ __volatile__( + "1: ldl_l %0,%1 \n" + "addl %0,1,%0 \n" + "stl_c %0,%1 \n" + "beq %0,1b\n" + : "=&b" (tmp) + : "m" (value) + : "cc" + ); + + However according to the comments on the HP website and matching + comments in the Linux kernel sources this defies branch prediction, + as the cpu assumes that backward branches are always taken; so + instead copy the trick from the Linux kernel, introduce a forward + branch and back again. + + I have, however, had a hard time measuring the difference between + the two versions in microbenchmarks -- I am leaving it in nevertheless + as it apparently does not hurt either. +*/ + +namespace boost { +namespace atomics { +namespace detail { + +inline void fence_before(memory_order order) +{ + switch(order) { + case memory_order_consume: + case memory_order_release: + case memory_order_acq_rel: + case memory_order_seq_cst: + __asm__ __volatile__ ("mb" ::: "memory"); + default:; + } +} + +inline void fence_after(memory_order order) +{ + switch(order) { + case memory_order_acquire: + case memory_order_acq_rel: + case memory_order_seq_cst: + __asm__ __volatile__ ("mb" ::: "memory"); + default:; + } +} + +template<> +inline void platform_atomic_thread_fence(memory_order order) +{ + switch(order) { + case memory_order_acquire: + case memory_order_consume: + case memory_order_release: + case memory_order_acq_rel: + case memory_order_seq_cst: + __asm__ __volatile__ ("mb" ::: "memory"); + default:; + } +} + +template +class atomic_alpha_32 { +public: + typedef T integral_type; + explicit atomic_alpha_32(T v) : i(v) {} + atomic_alpha_32() {} + T load(memory_order order=memory_order_seq_cst) const volatile + { + T v=*reinterpret_cast(&i); + fence_after(order); + return v; + } + void store(T v, memory_order order=memory_order_seq_cst) volatile + { + fence_before(order); + *reinterpret_cast(&i)=(int)v; + } + bool compare_exchange_weak( + T &expected, + T desired, + memory_order success_order, + memory_order failure_order) volatile + { + fence_before(success_order); + int current, success; + __asm__ __volatile__( + "1: ldl_l %2, %4\n" + "cmpeq %2, %0, %3\n" + "mov %2, %0\n" + "beq %3, 3f\n" + "stl_c %1, %4\n" + "2:\n" + + ".subsection 2\n" + "3: mov %3, %1\n" + "br 2b\n" + ".previous\n" + + : "+&r" (expected), "+&r" (desired), "=&r"(current), "=&r"(success) + : "m" (i) + : + ); + if (desired) fence_after(success_order); + else fence_after(failure_order); + return desired; + } + + bool is_lock_free(void) const volatile {return true;} +protected: + inline T fetch_add_var(T c, memory_order order) volatile + { + fence_before(order); + T original, modified; + __asm__ __volatile__( + "1: ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), "=&r" (modified) + : "m" (i), "r" (c) + : + ); + fence_after(order); + return original; + } + inline T fetch_inc(memory_order order) volatile + { + fence_before(order); + int original, modified; + __asm__ __volatile__( + "1: ldl_l %0, %2\n" + "addl %0, 1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), "=&r" (modified) + : "m" (i) + : + ); + fence_after(order); + return original; + } + inline T fetch_dec(memory_order order) volatile + { + fence_before(order); + int original, modified; + __asm__ __volatile__( + "1: ldl_l %0, %2\n" + "subl %0, 1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), "=&r" (modified) + : "m" (i) + : + ); + fence_after(order); + return original; + } +private: + T i; +}; + +template +class atomic_alpha_64 { +public: + typedef T integral_type; + explicit atomic_alpha_64(T v) : i(v) {} + atomic_alpha_64() {} + T load(memory_order order=memory_order_seq_cst) const volatile + { + T v=*reinterpret_cast(&i); + fence_after(order); + return v; + } + void store(T v, memory_order order=memory_order_seq_cst) volatile + { + fence_before(order); + *reinterpret_cast(&i)=v; + } + bool compare_exchange_weak( + T &expected, + T desired, + memory_order success_order, + memory_order failure_order) volatile + { + fence_before(success_order); + int current, success; + __asm__ __volatile__( + "1: ldq_l %2, %4\n" + "cmpeq %2, %0, %3\n" + "mov %2, %0\n" + "beq %3, 3f\n" + "stq_c %1, %4\n" + "2:\n" + + ".subsection 2\n" + "3: mov %3, %1\n" + "br 2b\n" + ".previous\n" + + : "+&r" (expected), "+&r" (desired), "=&r"(current), "=&r"(success) + : "m" (i) + : + ); + if (desired) fence_after(success_order); + else fence_after(failure_order); + return desired; + } + + bool is_lock_free(void) const volatile {return true;} +protected: + inline T fetch_add_var(T c, memory_order order) volatile + { + fence_before(order); + T original, modified; + __asm__ __volatile__( + "1: ldq_l %0, %2\n" + "addq %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), "=&r" (modified) + : "m" (i), "r" (c) + : + ); + fence_after(order); + return original; + } + inline T fetch_inc(memory_order order) volatile + { + fence_before(order); + T original, modified; + __asm__ __volatile__( + "1: ldq_l %0, %2\n" + "addq %0, 1, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), "=&r" (modified) + : "m" (i) + : + ); + fence_after(order); + return original; + } + inline T fetch_dec(memory_order order) volatile + { + fence_before(order); + T original, modified; + __asm__ __volatile__( + "1: ldq_l %0, %2\n" + "subq %0, 1, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), "=&r" (modified) + : "m" (i) + : + ); + fence_after(order); + return original; + } +private: + T i; +}; + +template +class platform_atomic_integral : public build_atomic_from_typical > > { +public: + typedef build_atomic_from_typical > > super; + explicit platform_atomic_integral(T v) : super(v) {} + platform_atomic_integral(void) {} +}; + +template +class platform_atomic_integral : public build_atomic_from_typical > > { +public: + typedef build_atomic_from_typical > > super; + explicit platform_atomic_integral(T v) : super(v) {} + platform_atomic_integral(void) {} +}; + +template +class platform_atomic_integral: public build_atomic_from_larger_type, T> { +public: + typedef build_atomic_from_larger_type, T> super; + + explicit platform_atomic_integral(T v) : super(v) {} + platform_atomic_integral(void) {} +}; + +template +class platform_atomic_integral: public build_atomic_from_larger_type, T> { +public: + typedef build_atomic_from_larger_type, T> super; + + explicit platform_atomic_integral(T v) : super(v) {} + platform_atomic_integral(void) {} +}; + +} +} +} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/gcc-armv6plus.hpp b/cpp/BoostParts/boost/atomic/detail/gcc-armv6plus.hpp new file mode 100644 index 00000000..5d02cde8 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/gcc-armv6plus.hpp @@ -0,0 +1,250 @@ +#ifndef BOOST_ATOMIC_DETAIL_GCC_ARMV6PLUS_HPP +#define BOOST_ATOMIC_DETAIL_GCC_ARMV6PLUS_HPP + +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Copyright (c) 2009 Helge Bahmann +// Copyright (c) 2009 Phil Endecott +// ARM Code by Phil Endecott, based on other architectures. + +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +// From the ARM Architecture Reference Manual for architecture v6: +// +// LDREX{} , [] +// Specifies the destination register for the memory word addressed by +// Specifies the register containing the address. +// +// STREX{} , , [] +// Specifies the destination register for the returned status value. +// 0 if the operation updates memory +// 1 if the operation fails to update memory +// Specifies the register containing the word to be stored to memory. +// Specifies the register containing the address. +// Rd must not be the same register as Rm or Rn. +// +// ARM v7 is like ARM v6 plus: +// There are half-word and byte versions of the LDREX and STREX instructions, +// LDREXH, LDREXB, STREXH and STREXB. +// There are also double-word versions, LDREXD and STREXD. +// (Actually it looks like these are available from version 6k onwards.) +// FIXME these are not yet used; should be mostly a matter of copy-and-paste. +// I think you can supply an immediate offset to the address. +// +// A memory barrier is effected using a "co-processor 15" instruction, +// though a separate assembler mnemonic is available for it in v7. + +namespace boost { +namespace atomics { +namespace detail { + +// "Thumb 1" is a subset of the ARM instruction set that uses a 16-bit encoding. It +// doesn't include all instructions and in particular it doesn't include the co-processor +// instruction used for the memory barrier or the load-locked/store-conditional +// instructions. So, if we're compiling in "Thumb 1" mode, we need to wrap all of our +// asm blocks with code to temporarily change to ARM mode. +// +// You can only change between ARM and Thumb modes when branching using the bx instruction. +// bx takes an address specified in a register. The least significant bit of the address +// indicates the mode, so 1 is added to indicate that the destination code is Thumb. +// A temporary register is needed for the address and is passed as an argument to these +// macros. It must be one of the "low" registers accessible to Thumb code, specified +// using the "l" attribute in the asm statement. +// +// Architecture v7 introduces "Thumb 2", which does include (almost?) all of the ARM +// instruction set. So in v7 we don't need to change to ARM mode; we can write "universal +// assembler" which will assemble to Thumb 2 or ARM code as appropriate. The only thing +// we need to do to make this "universal" assembler mode work is to insert "IT" instructions +// to annotate the conditional instructions. These are ignored in other modes (e.g. v6), +// so they can always be present. + +#if defined(__thumb__) && !defined(__ARM_ARCH_7A__) +// FIXME also other v7 variants. +#define BOOST_ATOMIC_ARM_ASM_START(TMPREG) "adr " #TMPREG ", 1f\n" "bx " #TMPREG "\n" ".arm\n" ".align 4\n" "1: " +#define BOOST_ATOMIC_ARM_ASM_END(TMPREG) "adr " #TMPREG ", 1f + 1\n" "bx " #TMPREG "\n" ".thumb\n" ".align 2\n" "1: " + +#else +// The tmpreg is wasted in this case, which is non-optimal. +#define BOOST_ATOMIC_ARM_ASM_START(TMPREG) +#define BOOST_ATOMIC_ARM_ASM_END(TMPREG) +#endif + +#if defined(__ARM_ARCH_7A__) +// FIXME ditto. +#define BOOST_ATOMIC_ARM_DMB "dmb\n" +#else +#define BOOST_ATOMIC_ARM_DMB "mcr\tp15, 0, r0, c7, c10, 5\n" +#endif + +inline void +arm_barrier(void) +{ + int brtmp; + __asm__ __volatile__ ( + BOOST_ATOMIC_ARM_ASM_START(%0) + BOOST_ATOMIC_ARM_DMB + BOOST_ATOMIC_ARM_ASM_END(%0) + : "=&l" (brtmp) :: "memory" + ); +} + +inline void +platform_fence_before(memory_order order) +{ + switch(order) { + case memory_order_release: + case memory_order_acq_rel: + case memory_order_seq_cst: + arm_barrier(); + case memory_order_consume: + default:; + } +} + +inline void +platform_fence_after(memory_order order) +{ + switch(order) { + case memory_order_acquire: + case memory_order_acq_rel: + case memory_order_seq_cst: + arm_barrier(); + default:; + } +} + +inline void +platform_fence_before_store(memory_order order) +{ + platform_fence_before(order); +} + +inline void +platform_fence_after_store(memory_order order) +{ + if (order == memory_order_seq_cst) + arm_barrier(); +} + +inline void +platform_fence_after_load(memory_order order) +{ + platform_fence_after(order); +} + +template +inline bool +platform_cmpxchg32(T & expected, T desired, volatile T * ptr) +{ + int success; + int tmp; + __asm__ ( + BOOST_ATOMIC_ARM_ASM_START(%2) + "mov %1, #0\n" // success = 0 + "ldrex %0, %3\n" // expected' = *(&i) + "teq %0, %4\n" // flags = expected'==expected + "ittt eq\n" + "strexeq %2, %5, %3\n" // if (flags.equal) *(&i) = desired, tmp = !OK + "teqeq %2, #0\n" // if (flags.equal) flags = tmp==0 + "moveq %1, #1\n" // if (flags.equal) success = 1 + BOOST_ATOMIC_ARM_ASM_END(%2) + : "=&r" (expected), // %0 + "=&r" (success), // %1 + "=&l" (tmp), // %2 + "+Q" (*ptr) // %3 + : "r" (expected), // %4 + "r" (desired) // %5 + : "cc" + ); + return success; +} + +} +} + +#define BOOST_ATOMIC_THREAD_FENCE 2 +inline void +atomic_thread_fence(memory_order order) +{ + switch(order) { + case memory_order_acquire: + case memory_order_release: + case memory_order_acq_rel: + case memory_order_seq_cst: + atomics::detail::arm_barrier(); + default:; + } +} + +#define BOOST_ATOMIC_SIGNAL_FENCE 2 +inline void +atomic_signal_fence(memory_order) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +class atomic_flag { +private: + atomic_flag(const atomic_flag &) /* = delete */ ; + atomic_flag & operator=(const atomic_flag &) /* = delete */ ; + uint32_t v_; +public: + atomic_flag(void) : v_(false) {} + + void + clear(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before_store(order); + const_cast(v_) = 0; + atomics::detail::platform_fence_after_store(order); + } + + bool + test_and_set(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before(order); + uint32_t expected = v_; + do { + if (expected == 1) + break; + } while (!atomics::detail::platform_cmpxchg32(expected, (uint32_t)1, &v_)); + atomics::detail::platform_fence_after(order); + return expected; + } +}; +#define BOOST_ATOMIC_FLAG_LOCK_FREE 2 + +} + +#undef BOOST_ATOMIC_ARM_ASM_START +#undef BOOST_ATOMIC_ARM_ASM_END + +#include + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE 2 +#define BOOST_ATOMIC_LLONG_LOCK_FREE 0 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 +#define BOOST_ATOMIC_BOOL_LOCK_FREE 2 + +#include + +#endif /* !defined(BOOST_ATOMIC_FORCE_FALLBACK) */ + +#endif + diff --git a/cpp/BoostParts/boost/atomic/detail/gcc-cas.hpp b/cpp/BoostParts/boost/atomic/detail/gcc-cas.hpp new file mode 100644 index 00000000..781e935f --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/gcc-cas.hpp @@ -0,0 +1,155 @@ +// Copyright (c) 2011 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Use the gnu builtin __sync_val_compare_and_swap to build +// atomic operations for 32 bit and smaller. + +#ifndef BOOST_ATOMIC_DETAIL_GENERIC_CAS_HPP +#define BOOST_ATOMIC_DETAIL_GENERIC_CAS_HPP + +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +#define BOOST_ATOMIC_THREAD_FENCE 2 +inline void +atomic_thread_fence(memory_order order) +{ + switch(order) { + case memory_order_relaxed: + break; + case memory_order_release: + case memory_order_consume: + case memory_order_acquire: + case memory_order_acq_rel: + case memory_order_seq_cst: + __sync_synchronize(); + break; + } +} + +namespace atomics { +namespace detail { + +inline void +platform_fence_before(memory_order) +{ + /* empty, as compare_and_swap is synchronizing already */ +} + +inline void +platform_fence_after(memory_order) +{ + /* empty, as compare_and_swap is synchronizing already */ +} + +inline void +platform_fence_before_store(memory_order order) +{ + switch(order) { + case memory_order_relaxed: + case memory_order_acquire: + case memory_order_consume: + break; + case memory_order_release: + case memory_order_acq_rel: + case memory_order_seq_cst: + __sync_synchronize(); + break; + } +} + +inline void +platform_fence_after_store(memory_order order) +{ + if (order == memory_order_seq_cst) + __sync_synchronize(); +} + +inline void +platform_fence_after_load(memory_order order) +{ + switch(order) { + case memory_order_relaxed: + case memory_order_release: + break; + case memory_order_consume: + case memory_order_acquire: + case memory_order_acq_rel: + case memory_order_seq_cst: + __sync_synchronize(); + break; + } +} + +template +inline bool +platform_cmpxchg32_strong(T & expected, T desired, volatile T * ptr) +{ + T found = __sync_val_compare_and_swap(ptr, expected, desired); + bool success = (found == expected); + expected = found; + return success; +} + +class atomic_flag { +private: + atomic_flag(const atomic_flag &) /* = delete */ ; + atomic_flag & operator=(const atomic_flag &) /* = delete */ ; + uint32_t v_; +public: + atomic_flag(void) : v_(false) {} + + void + clear(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before_store(order); + const_cast(v_) = 0; + atomics::detail::platform_fence_after_store(order); + } + + bool + test_and_set(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before(order); + uint32_t expected = v_; + do { + if (expected == 1) + break; + } while (!atomics::detail::platform_cmpxchg32(expected, (uint32_t)1, &v_)); + atomics::detail::platform_fence_after(order); + return expected; + } +}; +#define BOOST_ATOMIC_FLAG_LOCK_FREE 2 + +} +} +} + +#include + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE (sizeof(long) <= 4 ? 2 : 0) +#define BOOST_ATOMIC_LLONG_LOCK_FREE (sizeof(long long) <= 4 ? 2 : 0) +#define BOOST_ATOMIC_POINTER_LOCK_FREE (sizeof(void *) <= 4 ? 2 : 0) +#define BOOST_ATOMIC_BOOL_LOCK_FREE 2 + +#include + +#endif /* !defined(BOOST_ATOMIC_FORCE_FALLBACK) */ + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/gcc-ppc.hpp b/cpp/BoostParts/boost/atomic/detail/gcc-ppc.hpp new file mode 100644 index 00000000..dd58aaf3 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/gcc-ppc.hpp @@ -0,0 +1,2757 @@ +#ifndef BOOST_ATOMIC_DETAIL_GCC_PPC_HPP +#define BOOST_ATOMIC_DETAIL_GCC_PPC_HPP + +// Copyright (c) 2009 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* + Refer to: Motorola: "Programming Environments Manual for 32-Bit + Implementations of the PowerPC Architecture", Appendix E: + "Synchronization Programming Examples" for an explanation of what is + going on here (can be found on the web at various places by the + name "MPCFPE32B.pdf", Google is your friend...) + + Most of the atomic operations map to instructions in a relatively + straight-forward fashion, but "load"s may at first glance appear + a bit strange as they map to: + + lwz %rX, addr + cmpw %rX, %rX + bne- 1f + 1: + + That is, the CPU is forced to perform a branch that "formally" depends + on the value retrieved from memory. This scheme has an overhead of + about 1-2 clock cycles per load, but it allows to map "acquire" to + the "isync" instruction instead of "sync" uniformly and for all type + of atomic operations. Since "isync" has a cost of about 15 clock + cycles, while "sync" hast a cost of about 50 clock cycles, the small + penalty to atomic loads more than compensates for this. + + Byte- and halfword-sized atomic values are realized by encoding the + value to be represented into a word, performing sign/zero extension + as appropriate. This means that after add/sub operations the value + needs fixing up to accurately preserve the wrap-around semantic of + the smaller type. (Nothing special needs to be done for the bit-wise + and the "exchange type" operators as the compiler already sees to + it that values carried in registers are extended appropriately and + everything falls into place naturally). + + The register constraint "b" instructs gcc to use any register + except r0; this is sometimes required because the encoding for + r0 is used to signify "constant zero" in a number of instructions, + making r0 unusable in this place. For simplicity this constraint + is used everywhere since I am to lazy to look this up on a + per-instruction basis, and ppc has enough registers for this not + to pose a problem. +*/ + +namespace boost { +namespace atomics { +namespace detail { + +inline void +ppc_fence_before(memory_order order) +{ + switch(order) { + case memory_order_release: + case memory_order_acq_rel: +#if defined(__powerpc64__) + __asm__ __volatile__ ("lwsync" ::: "memory"); + break; +#endif + case memory_order_seq_cst: + __asm__ __volatile__ ("sync" ::: "memory"); + default:; + } +} + +inline void +ppc_fence_after(memory_order order) +{ + switch(order) { + case memory_order_acquire: + case memory_order_acq_rel: + case memory_order_seq_cst: + __asm__ __volatile__ ("isync"); + case memory_order_consume: + __asm__ __volatile__ ("" ::: "memory"); + default:; + } +} + +inline void +ppc_fence_after_store(memory_order order) +{ + switch(order) { + case memory_order_seq_cst: + __asm__ __volatile__ ("sync"); + default:; + } +} + +} +} + +class atomic_flag { +private: + atomic_flag(const atomic_flag &) /* = delete */ ; + atomic_flag & operator=(const atomic_flag &) /* = delete */ ; + uint32_t v_; +public: + atomic_flag(void) : v_(false) {} + + void + clear(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::ppc_fence_before(order); + const_cast(v_) = 0; + atomics::detail::ppc_fence_after_store(order); + } + + bool + test_and_set(memory_order order = memory_order_seq_cst) volatile + { + uint32_t original; + atomics::detail::ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (1) + : "cr0" + ); + atomics::detail::ppc_fence_after(order); + return original; + } +}; + +} /* namespace boost */ + +#define BOOST_ATOMIC_FLAG_LOCK_FREE 2 + +#include + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 +#if defined(__powerpc64__) +#define BOOST_ATOMIC_LLONG_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_LLONG_LOCK_FREE 0 +#endif +#define BOOST_ATOMIC_BOOL_LOCK_FREE 2 + +/* Would like to move the slow-path of failed compare_exchange +(that clears the "success" bit) out-of-line. gcc can in +principle do that using ".subsection"/".previous", but Apple's +binutils seemingly does not understand that. Therefore wrap +the "clear" of the flag in a macro and let it remain +in-line for Apple +*/ + +#if !defined(__APPLE__) + +#define BOOST_ATOMIC_ASM_SLOWPATH_CLEAR \ + "9:\n" \ + ".subsection 2\n" \ + "2: addi %1,0,0\n" \ + "b 9b\n" \ + ".previous\n" \ + +#else + +#define BOOST_ATOMIC_ASM_SLOWPATH_CLEAR \ + "b 9f\n" \ + "2: addi %1,0,0\n" \ + "9:\n" \ + +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/* integral types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef int32_t storage_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m"(v_) + : "r" (v) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v; + __asm__ __volatile__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=&r" (v) + : "m" (v_) + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "add %1,%0,%3\n" + "extsb %1, %1\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "sub %1,%0,%3\n" + "extsb %1, %1\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "and %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "or %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "xor %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m"(v_) + : "r" (v) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v; + __asm__ __volatile__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=&r" (v) + : "m" (v_) + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "add %1,%0,%3\n" + "rlwinm %1, %1, 0, 0xff\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "sub %1,%0,%3\n" + "rlwinm %1, %1, 0, 0xff\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "and %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "or %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "xor %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef int32_t storage_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m"(v_) + : "r" (v) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v; + __asm__ __volatile__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=&r" (v) + : "m" (v_) + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "add %1,%0,%3\n" + "extsh %1, %1\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "sub %1,%0,%3\n" + "extsh %1, %1\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "and %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "or %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "xor %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m"(v_) + : "r" (v) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v; + __asm__ __volatile__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=&r" (v) + : "m" (v_) + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "add %1,%0,%3\n" + "rlwinm %1, %1, 0, 0xffff\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "sub %1,%0,%3\n" + "rlwinm %1, %1, 0, 0xffff\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "and %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "or %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "xor %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + const_cast(v_) = v; + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + __asm__ __volatile__ ( + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "+b"(v) + : + : "cr0" + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "add %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "sub %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "and %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "or %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "xor %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +#if defined(__powerpc64__) + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + const_cast(v_) = v; + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + __asm__ __volatile__ ( + "cmpd %0, %0\n" + "bne- 1f\n" + "1:\n" + : "+b"(v) + : + : "cr0" + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y1\n" + "stdcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "ldarx %0,%y2\n" + "cmpd %0, %3\n" + "bne- 2f\n" + "stdcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: ldarx %0,%y2\n" + "cmpd %0, %3\n" + "bne- 2f\n" + "stdcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y2\n" + "add %1,%0,%3\n" + "stdcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y2\n" + "sub %1,%0,%3\n" + "stdcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y2\n" + "and %1,%0,%3\n" + "stdcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y2\n" + "or %1,%0,%3\n" + "stdcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y2\n" + "xor %1,%0,%3\n" + "stdcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +#endif + +/* pointer types */ + +#if !defined(__powerpc64__) + +template +class base_atomic { + typedef base_atomic this_type; + typedef void * value_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m" (v_) + : "r" (v) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v; + __asm__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=r"(v) + : "m"(v_) + : "cr0" + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m" (v_) + : "r" (v) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v; + __asm__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=r"(v) + : "m"(v_) + : "cr0" + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + v = v * sizeof(*v_); + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "add %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + v = v * sizeof(*v_); + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y2\n" + "sub %1,%0,%3\n" + "stwcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +#else + +template +class base_atomic { + typedef base_atomic this_type; + typedef void * value_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + __asm__ ( + "std %1, %0\n" + : "+m" (v_) + : "r" (v) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v; + __asm__ ( + "ld %0, %1\n" + "cmpd %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=r"(v) + : "m"(v_) + : "cr0" + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y1\n" + "stdcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "ldarx %0,%y2\n" + "cmpd %0, %3\n" + "bne- 2f\n" + "stdcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: ldarx %0,%y2\n" + "cmpd %0, %3\n" + "bne- 2f\n" + "stdcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + ppc_fence_before(order); + __asm__ ( + "std %1, %0\n" + : "+m" (v_) + : "r" (v) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v; + __asm__ ( + "ld %0, %1\n" + "cmpd %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=r"(v) + : "m"(v_) + : "cr0" + ); + ppc_fence_after(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type original; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y1\n" + "stdcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (v) + : "cr0" + ); + ppc_fence_after(order); + return original; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "ldarx %0,%y2\n" + "cmpd %0, %3\n" + "bne- 2f\n" + "stdcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + int success; + ppc_fence_before(success_order); + __asm__( + "0: ldarx %0,%y2\n" + "cmpd %0, %3\n" + "bne- 2f\n" + "stdcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected), "=&b" (success), "+Z"(v_) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + return success; + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + v = v * sizeof(*v_); + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y2\n" + "add %1,%0,%3\n" + "stdcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + v = v * sizeof(*v_); + value_type original, tmp; + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y2\n" + "sub %1,%0,%3\n" + "stdcx. %1,%y2\n" + "bne- 1b\n" + : "=&b" (original), "=&b" (tmp), "+Z"(v_) + : "b" (v) + : "cc"); + ppc_fence_after(order); + return original; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +#endif + +/* generic */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m" (v_) + : "r" (tmp) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp; + __asm__ __volatile__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=r"(tmp) + : "m"(v_) + : "cr0" + ); + ppc_fence_after(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0, original; + memcpy(&tmp, &v, sizeof(value_type)); + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (tmp) + : "cr0" + ); + ppc_fence_after(order); + value_type res; + memcpy(&res, &original, sizeof(value_type)); + return res; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected_s), "=&b" (success), "+Z"(v_) + : "b" (expected_s), "b" (desired_s) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected_s), "=&b" (success), "+Z"(v_) + : "b" (expected_s), "b" (desired_s) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m" (v_) + : "r" (tmp) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp; + __asm__ __volatile__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=r"(tmp) + : "m"(v_) + : "cr0" + ); + ppc_fence_after(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0, original; + memcpy(&tmp, &v, sizeof(value_type)); + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (tmp) + : "cr0" + ); + ppc_fence_after(order); + value_type res; + memcpy(&res, &original, sizeof(value_type)); + return res; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected_s), "=&b" (success), "+Z"(v_) + : "b" (expected_s), "b" (desired_s) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected_s), "=&b" (success), "+Z"(v_) + : "b" (expected_s), "b" (desired_s) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + ppc_fence_before(order); + __asm__ ( + "stw %1, %0\n" + : "+m" (v_) + : "r" (tmp) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp; + __asm__ __volatile__ ( + "lwz %0, %1\n" + "cmpw %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=r"(tmp) + : "m"(v_) + : "cr0" + ); + ppc_fence_after(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0, original; + memcpy(&tmp, &v, sizeof(value_type)); + ppc_fence_before(order); + __asm__ ( + "1:\n" + "lwarx %0,%y1\n" + "stwcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (tmp) + : "cr0" + ); + ppc_fence_after(order); + value_type res; + memcpy(&res, &original, sizeof(value_type)); + return res; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + int success; + ppc_fence_before(success_order); + __asm__( + "lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected_s), "=&b" (success), "+Z"(v_) + : "b" (expected_s), "b" (desired_s) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + int success; + ppc_fence_before(success_order); + __asm__( + "0: lwarx %0,%y2\n" + "cmpw %0, %3\n" + "bne- 2f\n" + "stwcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected_s), "=&b" (success), "+Z"(v_) + : "b" (expected_s), "b" (desired_s) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +#if defined(__powerpc64__) + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint64_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp; + memcpy(&tmp, &v, sizeof(value_type)); + ppc_fence_before(order); + __asm__ ( + "std %1, %0\n" + : "+m" (v_) + : "r" (tmp) + ); + ppc_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp; + __asm__ __volatile__ ( + "ld %0, %1\n" + "cmpd %0, %0\n" + "bne- 1f\n" + "1:\n" + : "=r"(tmp) + : "m"(v_) + : "cr0" + ); + ppc_fence_after(order); + + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0, original; + memcpy(&tmp, &v, sizeof(value_type)); + ppc_fence_before(order); + __asm__ ( + "1:\n" + "ldarx %0,%y1\n" + "stdcx. %2,%y1\n" + "bne- 1b\n" + : "=&b" (original), "+Z"(v_) + : "b" (tmp) + : "cr0" + ); + ppc_fence_after(order); + value_type res; + memcpy(&res, &original, sizeof(value_type)); + return res; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s, desired_s; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + int success; + ppc_fence_before(success_order); + __asm__( + "ldarx %0,%y2\n" + "cmpd %0, %3\n" + "bne- 2f\n" + "stdcx. %4,%y2\n" + "bne- 2f\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected_s), "=&b" (success), "+Z"(v_) + : "b" (expected_s), "b" (desired_s) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s, desired_s; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + + int success; + ppc_fence_before(success_order); + __asm__( + "0: ldarx %0,%y2\n" + "cmpd %0, %3\n" + "bne- 2f\n" + "stdcx. %4,%y2\n" + "bne- 0b\n" + "addi %1,0,1\n" + "1:" + + BOOST_ATOMIC_ASM_SLOWPATH_CLEAR + : "=&b" (expected_s), "=&b" (success), "+Z"(v_) + : "b" (expected_s), "b" (desired_s) + : "cr0" + ); + if (success) + ppc_fence_after(success_order); + else + ppc_fence_after(failure_order); + memcpy(&expected, &expected_s, sizeof(value_type)); + return success; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; +#endif + +} +} + +#define BOOST_ATOMIC_THREAD_FENCE 2 +inline void +atomic_thread_fence(memory_order order) +{ + switch(order) { + case memory_order_acquire: + __asm__ __volatile__ ("isync" ::: "memory"); + break; + case memory_order_release: +#if defined(__powerpc64__) + __asm__ __volatile__ ("lwsync" ::: "memory"); + break; +#endif + case memory_order_acq_rel: + case memory_order_seq_cst: + __asm__ __volatile__ ("sync" ::: "memory"); + default:; + } +} + +#define BOOST_ATOMIC_SIGNAL_FENCE 2 +inline void +atomic_signal_fence(memory_order order) +{ + switch(order) { + case memory_order_acquire: + case memory_order_release: + case memory_order_acq_rel: + case memory_order_seq_cst: + __asm__ __volatile__ ("" ::: "memory"); + break; + default:; + } +} + +} + +#endif /* !defined(BOOST_ATOMIC_FORCE_FALLBACK) */ + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/gcc-sparcv9.hpp b/cpp/BoostParts/boost/atomic/detail/gcc-sparcv9.hpp new file mode 100644 index 00000000..ae256d13 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/gcc-sparcv9.hpp @@ -0,0 +1,1229 @@ +#ifndef BOOST_ATOMIC_DETAIL_GCC_SPARC_HPP +#define BOOST_ATOMIC_DETAIL_GCC_SPARC_HPP + +// Copyright (c) 2010 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +inline void +platform_fence_before(memory_order order) +{ + switch(order) { + case memory_order_relaxed: + case memory_order_acquire: + case memory_order_consume: + break; + case memory_order_release: + case memory_order_acq_rel: + __asm__ __volatile__ ("membar #StoreStore | #LoadStore" ::: "memory"); + /* release */ + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + /* seq */ + break; + } +} + +inline void +platform_fence_after(memory_order order) +{ + switch(order) { + case memory_order_relaxed: + case memory_order_release: + break; + case memory_order_acquire: + case memory_order_acq_rel: + __asm__ __volatile__ ("membar #LoadLoad | #LoadStore" ::: "memory"); + /* acquire */ + break; + case memory_order_consume: + /* consume */ + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + /* seq */ + break; + default:; + } +} + +inline void +platform_fence_after_store(memory_order order) +{ + switch(order) { + case memory_order_seq_cst: + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + default:; + } +} + + +inline void +platform_fence_after_load(memory_order order) +{ + platform_fence_after(order); +} + +} +} + +class atomic_flag { +private: + atomic_flag(const atomic_flag &) /* = delete */ ; + atomic_flag & operator=(const atomic_flag &) /* = delete */ ; + uint32_t v_; +public: + atomic_flag(void) : v_(false) {} + + void + clear(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before(order); + const_cast(v_) = 0; + atomics::detail::platform_fence_after_store(order); + } + + bool + test_and_set(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before(order); + uint32_t tmp = 1; + __asm__ ( + "cas [%1], %2, %0" + : "+r" (tmp) + : "r" (&v_), "r" (0) + : "memory" + ); + atomics::detail::platform_fence_after(order); + return tmp; + } +}; + +} /* namespace boost */ + +#define BOOST_ATOMIC_FLAG_LOCK_FREE 2 + +#include + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE 2 +#define BOOST_ATOMIC_LLONG_LOCK_FREE 0 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 +#define BOOST_ATOMIC_BOOL_LOCK_FREE 2 + +namespace boost { + +#define BOOST_ATOMIC_THREAD_FENCE 2 +inline void +atomic_thread_fence(memory_order order) +{ + switch(order) { + case memory_order_relaxed: + break; + case memory_order_release: + __asm__ __volatile__ ("membar #StoreStore | #LoadStore" ::: "memory"); + break; + case memory_order_acquire: + __asm__ __volatile__ ("membar #LoadLoad | #LoadStore" ::: "memory"); + break; + case memory_order_acq_rel: + __asm__ __volatile__ ("membar #LoadLoad | #LoadStore | #StoreStore" ::: "memory"); + break; + case memory_order_consume: + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + break; + default:; + } +} + +#define BOOST_ATOMIC_SIGNAL_FENCE 2 +inline void +atomic_signal_fence(memory_order) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +namespace atomics { +namespace detail { + +/* integral types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef int32_t storage_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp + v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp - v, order, memory_order_relaxed)); + return tmp; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + storage_type desired_s = desired; + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired_s) + : "r" (&v_), "r" ((storage_type)expected) + : "memory" + ); + desired = desired_s; + bool success = (desired == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = desired; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed)); + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp + v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp - v, order, memory_order_relaxed)); + return tmp; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + storage_type desired_s = desired; + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired_s) + : "r" (&v_), "r" ((storage_type)expected) + : "memory" + ); + desired = desired_s; + bool success = (desired == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = desired; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed)); + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef int32_t storage_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp + v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp - v, order, memory_order_relaxed)); + return tmp; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + storage_type desired_s = desired; + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired_s) + : "r" (&v_), "r" ((storage_type)expected) + : "memory" + ); + desired = desired_s; + bool success = (desired == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = desired; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed)); + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp + v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp - v, order, memory_order_relaxed)); + return tmp; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + storage_type desired_s = desired; + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired_s) + : "r" (&v_), "r" ((storage_type)expected) + : "memory" + ); + desired = desired_s; + bool success = (desired == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = desired; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed)); + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp + v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp - v, order, memory_order_relaxed)); + return tmp; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired) + : "r" (&v_), "r" (expected) + : "memory" + ); + bool success = (desired == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = desired; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed)); + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +/* pointer types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef void * value_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired) + : "r" (&v_), "r" (expected) + : "memory" + ); + bool success = (desired == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = desired; + return success; + } + + + bool compare_exchange_weak(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + const_cast(v_) = v; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + platform_fence_before(success_order); + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired) + : "r" (&v_), "r" (expected) + : "memory" + ); + bool success = (desired == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = desired; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp + v, order, memory_order_relaxed)); + return tmp; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, tmp - v, order, memory_order_relaxed)); + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +/* generic types */ + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + platform_fence_before(success_order); + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired_s) + : "r" (&v_), "r" (expected_s) + : "memory" + ); + bool success = (desired_s == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &desired_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + platform_fence_before(success_order); + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired_s) + : "r" (&v_), "r" (expected_s) + : "memory" + ); + bool success = (desired_s == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &desired_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + platform_fence_after_store(order); + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + do {} while(!compare_exchange_weak(tmp, v, order, memory_order_relaxed)); + return tmp; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + platform_fence_before(success_order); + __asm__ ( + "cas [%1], %2, %0" + : "+r" (desired_s) + : "r" (&v_), "r" (expected_s) + : "memory" + ); + bool success = (desired_s == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &desired_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +#endif /* !defined(BOOST_ATOMIC_FORCE_FALLBACK) */ + +} +} +} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/gcc-x86.hpp b/cpp/BoostParts/boost/atomic/detail/gcc-x86.hpp new file mode 100644 index 00000000..0b06e47b --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/gcc-x86.hpp @@ -0,0 +1,1651 @@ +#ifndef BOOST_ATOMIC_DETAIL_GCC_X86_HPP +#define BOOST_ATOMIC_DETAIL_GCC_X86_HPP + +// Copyright (c) 2009 Helge Bahmann +// Copyright (c) 2012 Tim Blechmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if defined(__x86_64__) || defined(__SSE2__) +# define BOOST_ATOMIC_X86_FENCE_INSTR "mfence\n" +#else +# define BOOST_ATOMIC_X86_FENCE_INSTR "lock ; addl $0, (%%esp)\n" +#endif + +#define BOOST_ATOMIC_X86_PAUSE() __asm__ __volatile__ ("pause\n") + +inline void +platform_fence_before(memory_order order) +{ + switch(order) + { + case memory_order_relaxed: + case memory_order_acquire: + case memory_order_consume: + break; + case memory_order_release: + case memory_order_acq_rel: + __asm__ __volatile__ ("" ::: "memory"); + /* release */ + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("" ::: "memory"); + /* seq */ + break; + default:; + } +} + +inline void +platform_fence_after(memory_order order) +{ + switch(order) + { + case memory_order_relaxed: + case memory_order_release: + break; + case memory_order_acquire: + case memory_order_acq_rel: + __asm__ __volatile__ ("" ::: "memory"); + /* acquire */ + break; + case memory_order_consume: + /* consume */ + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("" ::: "memory"); + /* seq */ + break; + default:; + } +} + +inline void +platform_fence_after_load(memory_order order) +{ + switch(order) + { + case memory_order_relaxed: + case memory_order_release: + break; + case memory_order_acquire: + case memory_order_acq_rel: + __asm__ __volatile__ ("" ::: "memory"); + break; + case memory_order_consume: + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("" ::: "memory"); + break; + default:; + } +} + +inline void +platform_fence_before_store(memory_order order) +{ + switch(order) + { + case memory_order_relaxed: + case memory_order_acquire: + case memory_order_consume: + break; + case memory_order_release: + case memory_order_acq_rel: + __asm__ __volatile__ ("" ::: "memory"); + /* release */ + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("" ::: "memory"); + /* seq */ + break; + default:; + } +} + +inline void +platform_fence_after_store(memory_order order) +{ + switch(order) + { + case memory_order_relaxed: + case memory_order_release: + break; + case memory_order_acquire: + case memory_order_acq_rel: + __asm__ __volatile__ ("" ::: "memory"); + /* acquire */ + break; + case memory_order_consume: + /* consume */ + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("" ::: "memory"); + /* seq */ + break; + default:; + } +} + +} +} + +class atomic_flag +{ +private: + atomic_flag(const atomic_flag &) /* = delete */ ; + atomic_flag & operator=(const atomic_flag &) /* = delete */ ; + uint32_t v_; +public: + atomic_flag(void) : v_(0) {} + + bool + test_and_set(memory_order order = memory_order_seq_cst) volatile + { + uint32_t v = 1; + atomics::detail::platform_fence_before(order); + __asm__ __volatile__ ( + "xchgl %0, %1" + : "+r" (v), "+m" (v_) + ); + atomics::detail::platform_fence_after(order); + return v; + } + + void + clear(memory_order order = memory_order_seq_cst) volatile + { + if (order == memory_order_seq_cst) { + uint32_t v = 0; + __asm__ __volatile__ ( + "xchgl %0, %1" + : "+r" (v), "+m" (v_) + ); + } else { + atomics::detail::platform_fence_before(order); + v_ = 0; + } + } +}; + +} /* namespace boost */ + +#define BOOST_ATOMIC_FLAG_LOCK_FREE 2 + +#include + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE 2 + +#if defined(__x86_64__) +#define BOOST_ATOMIC_LLONG_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_LLONG_LOCK_FREE 1 +#endif + +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 +#define BOOST_ATOMIC_BOOL_LOCK_FREE 2 + +namespace boost { + +#define BOOST_ATOMIC_THREAD_FENCE 2 +inline void +atomic_thread_fence(memory_order order) +{ + switch(order) + { + case memory_order_relaxed: + break; + case memory_order_release: + __asm__ __volatile__ ("" ::: "memory"); + break; + case memory_order_acquire: + __asm__ __volatile__ ("" ::: "memory"); + break; + case memory_order_acq_rel: + __asm__ __volatile__ ("" ::: "memory"); + break; + case memory_order_consume: + break; + case memory_order_seq_cst: + __asm__ __volatile__ (BOOST_ATOMIC_X86_FENCE_INSTR ::: "memory"); + break; + default:; + } +} + +#define BOOST_ATOMIC_SIGNAL_FENCE 2 +inline void +atomic_signal_fence(memory_order) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +namespace atomics { +namespace detail { + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "lock ; xaddb %0, %1" + : "+q" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + return fetch_add(-v, order); + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "xchgb %0, %1" + : "+q" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgb %2, %1" + : "+a" (previous), "+m" (v_) + : "q" (desired) + ); + bool success = (previous == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = previous; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for(; !compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "lock ; xaddw %0, %1" + : "+q" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + return fetch_add(-v, order); + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "xchgw %0, %1" + : "+q" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgw %2, %1" + : "+a" (previous), "+m" (v_) + : "q" (desired) + ); + bool success = (previous == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = previous; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "lock ; xaddl %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + return fetch_add(-v, order); + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "xchgl %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgl %2, %1" + : "+a" (previous), "+m" (v_) + : "r" (desired) + ); + bool success = (previous == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = previous; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +#if defined(__x86_64__) +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "lock ; xaddq %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + return fetch_add(-v, order); + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "xchgq %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgq %2, %1" + : "+a" (previous), "+m" (v_) + : "r" (desired) + ); + bool success = (previous == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = previous; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +#endif + +/* pointers */ + +#if !defined(__x86_64__) + +template +class base_atomic { + typedef base_atomic this_type; + typedef void * value_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "xchgl %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + bool compare_exchange_strong(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgl %2, %1" + : "+a" (previous), "+m" (v_) + : "r" (desired) + ); + bool success = (previous == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = previous; + return success; + } + + bool compare_exchange_weak(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "xchgl %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgl %2, %1" + : "+a" (previous), "+m" (v_) + : "r" (desired) + ); + bool success = (previous == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = previous; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + v = v * sizeof(*v_); + platform_fence_before(order); + __asm__ ( + "lock ; xaddl %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return reinterpret_cast(v); + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + return fetch_add(-v, order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +#else + +template +class base_atomic { + typedef base_atomic this_type; + typedef void * value_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "xchgq %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + bool compare_exchange_strong(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgq %2, %1" + : "+a" (previous), "+m" (v_) + : "r" (desired) + ); + bool success = (previous == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = previous; + return success; + } + + bool compare_exchange_weak(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T * value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + __asm__ ( + "xchgq %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgq %2, %1" + : "+a" (previous), "+m" (v_) + : "r" (desired) + ); + bool success = (previous == expected); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = previous; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + v = v * sizeof(*v_); + platform_fence_before(order); + __asm__ ( + "lock ; xaddq %0, %1" + : "+r" (v), "+m" (v_) + ); + platform_fence_after(order); + return reinterpret_cast(v); + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + return fetch_add(-v, order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +#endif + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint8_t storage_type; +public: + explicit base_atomic(value_type const& v) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + storage_type tmp; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + __asm__ ( + "xchgb %0, %1" + : "+q" (tmp), "+m" (v_) + ); + platform_fence_after(order); + value_type res; + memcpy(&res, &tmp, sizeof(value_type)); + return res; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s, desired_s; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + storage_type previous_s = expected_s; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgb %2, %1" + : "+a" (previous_s), "+m" (v_) + : "q" (desired_s) + ); + bool success = (previous_s == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &previous_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint16_t storage_type; +public: + explicit base_atomic(value_type const& v) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + storage_type tmp; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + __asm__ ( + "xchgw %0, %1" + : "+q" (tmp), "+m" (v_) + ); + platform_fence_after(order); + value_type res; + memcpy(&res, &tmp, sizeof(value_type)); + return res; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s, desired_s; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + storage_type previous_s = expected_s; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgw %2, %1" + : "+a" (previous_s), "+m" (v_) + : "q" (desired_s) + ); + bool success = (previous_s == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &previous_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + __asm__ ( + "xchgl %0, %1" + : "+q" (tmp), "+m" (v_) + ); + platform_fence_after(order); + value_type res; + memcpy(&res, &tmp, sizeof(value_type)); + return res; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + storage_type previous_s = expected_s; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgl %2, %1" + : "+a" (previous_s), "+m" (v_) + : "q" (desired_s) + ); + bool success = (previous_s == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &previous_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +#if defined(__x86_64__) +template +class base_atomic { + typedef base_atomic this_type; + typedef T value_type; + typedef uint64_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + __asm__ ( + "xchgq %0, %1" + : "+q" (tmp), "+m" (v_) + ); + platform_fence_after(order); + value_type res; + memcpy(&res, &tmp, sizeof(value_type)); + return res; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + storage_type previous_s = expected_s; + platform_fence_before(success_order); + __asm__ ( + "lock ; cmpxchgq %2, %1" + : "+a" (previous_s), "+m" (v_) + : "q" (desired_s) + ); + bool success = (previous_s == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &previous_s, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; +#endif + +#if !defined(__x86_64__) && (defined(__i686__) || defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) + +template +inline bool +platform_cmpxchg64_strong(T & expected, T desired, volatile T * ptr) +{ +#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 + const T oldval = __sync_val_compare_and_swap(ptr, expected, desired); + const bool result = (oldval == expected); + expected = oldval; + return result; +#else + int scratch; + T prev = expected; + /* Make sure ebx is saved and restored properly in case + this object is compiled as "position independent". Since + programmers on x86 tend to forget specifying -DPIC or + similar, always assume PIC. + + To make this work uniformly even in the non-PIC case, + setup register constraints such that ebx can not be + used by accident e.g. as base address for the variable + to be modified. Accessing "scratch" should always be okay, + as it can only be placed on the stack (and therefore + accessed through ebp or esp only). + + In theory, could push/pop ebx onto/off the stack, but movs + to a prepared stack slot turn out to be faster. */ + __asm__ __volatile__ ( + "movl %%ebx, %1\n" + "movl %2, %%ebx\n" + "lock; cmpxchg8b 0(%4)\n" + "movl %1, %%ebx\n" + : "=A" (prev), "=m" (scratch) + : "D" ((int)desired), "c" ((int)(desired >> 32)), "S" (ptr), "0" (prev) + : "memory"); + bool success = (prev == expected); + expected = prev; + return success; +#endif +} + +template +inline void +platform_store64(T value, volatile T * ptr) +{ + T expected = *ptr; + for (; !platform_cmpxchg64_strong(expected, value, ptr);) + { + BOOST_ATOMIC_X86_PAUSE(); + } +} + +template +inline T +platform_load64(const volatile T * ptr) +{ + T expected = *ptr; + for (; !platform_cmpxchg64_strong(expected, expected, const_cast(ptr));) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return expected; +} + +#endif + +} +} +} + +/* pull in 64-bit atomic type using cmpxchg8b above */ +#if !defined(__x86_64__) && (defined(__i686__) || defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)) +#include +#endif + +#endif /* !defined(BOOST_ATOMIC_FORCE_FALLBACK) */ + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/generic-cas.hpp b/cpp/BoostParts/boost/atomic/detail/generic-cas.hpp new file mode 100644 index 00000000..d87c87d7 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/generic-cas.hpp @@ -0,0 +1,199 @@ +#ifndef BOOST_ATOMIC_DETAIL_GENERIC_CAS_HPP +#define BOOST_ATOMIC_DETAIL_GENERIC_CAS_HPP + +// Copyright (c) 2009 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* fallback implementation for various compilation targets; +this is *not* efficient, particularly because all operations +are fully fenced (full memory barriers before and after +each operation) */ + +#if defined(__GNUC__) + namespace boost { namespace atomics { namespace detail { + inline int32_t + fenced_compare_exchange_strong_32(volatile int32_t *ptr, int32_t expected, int32_t desired) + { + return __sync_val_compare_and_swap_4(ptr, expected, desired); + } + #define BOOST_ATOMIC_HAVE_CAS32 1 + + #if defined(__amd64__) || defined(__i686__) + inline int64_t + fenced_compare_exchange_strong_64(int64_t *ptr, int64_t expected, int64_t desired) + { + return __sync_val_compare_and_swap_8(ptr, expected, desired); + } + #define BOOST_ATOMIC_HAVE_CAS64 1 + #endif + }}} + +#elif defined(__ICL) || defined(_MSC_VER) + + #if defined(_MSC_VER) + #include + #include + #endif + + namespace boost { namespace atomics { namespace detail { + inline int32_t + fenced_compare_exchange_strong(int32_t *ptr, int32_t expected, int32_t desired) + { + return _InterlockedCompareExchange(reinterpret_cast(ptr), desired, expected); + } + #define BOOST_ATOMIC_HAVE_CAS32 1 + #if defined(_WIN64) + inline int64_t + fenced_compare_exchange_strong(int64_t *ptr, int64_t expected, int64_t desired) + { + return _InterlockedCompareExchange64(ptr, desired, expected); + } + #define BOOST_ATOMIC_HAVE_CAS64 1 + #endif + }}} + +#elif (defined(__ICC) || defined(__ECC)) + namespace boost { namespace atomics { namespace detail { + inline int32_t + fenced_compare_exchange_strong_32(int32_t *ptr, int32_t expected, int32_t desired) + { + return _InterlockedCompareExchange((void*)ptr, desired, expected); + } + #define BOOST_ATOMIC_HAVE_CAS32 1 + #if defined(__x86_64) + inline int64_t + fenced_compare_exchange_strong(int64_t *ptr, int64_t expected, int64_t desired) + { + return cas64(ptr, expected, desired); + } + #define BOOST_ATOMIC_HAVE_CAS64 1 + #elif defined(__ECC) //IA-64 version + inline int64_t + fenced_compare_exchange_strong(int64_t *ptr, int64_t expected, int64_t desired) + { + return _InterlockedCompareExchange64((void*)ptr, desired, expected); + } + #define BOOST_ATOMIC_HAVE_CAS64 1 + #endif + }}} + +#elif (defined(__SUNPRO_CC) && defined(__sparc)) + #include + namespace boost { namespace atomics { namespace detail { + inline int32_t + fenced_compare_exchange_strong_32(int32_t *ptr, int32_t expected, int32_t desired) + { + return atomic_cas_32((volatile unsigned int*)ptr, expected, desired); + } + #define BOOST_ATOMIC_HAVE_CAS32 1 + + /* FIXME: check for 64 bit mode */ + inline int64_t + fenced_compare_exchange_strong_64(int64_t *ptr, int64_t expected, int64_t desired) + { + return atomic_cas_64((volatile unsigned long long*)ptr, expected, desired); + } + #define BOOST_ATOMIC_HAVE_CAS64 1 + }}} +#endif + + +namespace boost { +namespace atomics { +namespace detail { + +#ifdef BOOST_ATOMIC_HAVE_CAS32 +template +class atomic_generic_cas32 { +private: + typedef atomic_generic_cas32 this_type; +public: + explicit atomic_generic_cas32(T v) : i((int32_t)v) {} + atomic_generic_cas32() {} + T load(memory_order order=memory_order_seq_cst) const volatile + { + T expected=(T)i; + do { } while(!const_cast(this)->compare_exchange_weak(expected, expected, order, memory_order_relaxed)); + return expected; + } + void store(T v, memory_order order=memory_order_seq_cst) volatile + { + exchange(v); + } + bool compare_exchange_strong( + T &expected, + T desired, + memory_order success_order, + memory_order failure_order) volatile + { + T found; + found=(T)fenced_compare_exchange_strong_32(&i, (int32_t)expected, (int32_t)desired); + bool success=(found==expected); + expected=found; + return success; + } + bool compare_exchange_weak( + T &expected, + T desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + T exchange(T r, memory_order order=memory_order_seq_cst) volatile + { + T expected=(T)i; + do { } while(!compare_exchange_weak(expected, r, order, memory_order_relaxed)); + return expected; + } + + bool is_lock_free(void) const volatile {return true;} + typedef T integral_type; +private: + mutable int32_t i; +}; + +template +class platform_atomic_integral : public build_atomic_from_exchange > { +public: + typedef build_atomic_from_exchange > super; + explicit platform_atomic_integral(T v) : super(v) {} + platform_atomic_integral(void) {} +}; + +template +class platform_atomic_integral: public build_atomic_from_larger_type, T> { +public: + typedef build_atomic_from_larger_type, T> super; + + explicit platform_atomic_integral(T v) : super(v) {} + platform_atomic_integral(void) {} +}; + +template +class platform_atomic_integral: public build_atomic_from_larger_type, T> { +public: + typedef build_atomic_from_larger_type, T> super; + + explicit platform_atomic_integral(T v) : super(v) {} + platform_atomic_integral(void) {} +}; +#endif + +} } } + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/interlocked.hpp b/cpp/BoostParts/boost/atomic/detail/interlocked.hpp new file mode 100644 index 00000000..84a71316 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/interlocked.hpp @@ -0,0 +1,206 @@ +#ifndef BOOST_ATOMIC_DETAIL_INTERLOCKED_HPP +#define BOOST_ATOMIC_DETAIL_INTERLOCKED_HPP + +// Copyright (c) 2009 Helge Bahmann +// Copyright (c) 2012 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(_WIN32_WCE) + +#include + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)(dest), exchange, compare) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) BOOST_INTERLOCKED_EXCHANGE((long*)(dest), newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) BOOST_INTERLOCKED_EXCHANGE_ADD((long*)(dest), addend) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_INTERLOCKED_EXCHANGE_ADD((long*)(dest), byte_offset)) + +#elif defined(_MSC_VER) + +#include + +#pragma intrinsic(_InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd) +#pragma intrinsic(_InterlockedExchange) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) _InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) _InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) _InterlockedExchange((long*)(dest), (long)(newval)) + +#if _MSC_VER >= 1400 + +#pragma intrinsic(_InterlockedAnd) +#pragma intrinsic(_InterlockedOr) +#pragma intrinsic(_InterlockedXor) + +#define BOOST_ATOMIC_INTERLOCKED_AND(dest, arg) _InterlockedAnd((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR(dest, arg) _InterlockedOr((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR(dest, arg) _InterlockedXor((long*)(dest), (long)(arg)) + +#endif // _MSC_VER >= 1400 + +#if _MSC_VER >= 1600 + +// MSVC 2010 and later provide intrinsics for 8 and 16 bit integers. +// Note that for each bit count these macros must be either all defined or all not defined. +// Otherwise atomic<> operations will be implemented inconsistently. + +#pragma intrinsic(_InterlockedCompareExchange8) +#pragma intrinsic(_InterlockedExchangeAdd8) +#pragma intrinsic(_InterlockedExchange8) +#pragma intrinsic(_InterlockedAnd8) +#pragma intrinsic(_InterlockedOr8) +#pragma intrinsic(_InterlockedXor8) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(dest, exchange, compare) _InterlockedCompareExchange8((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(dest, addend) _InterlockedExchangeAdd8((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(dest, newval) _InterlockedExchange8((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND8(dest, arg) _InterlockedAnd8((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR8(dest, arg) _InterlockedOr8((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR8(dest, arg) _InterlockedXor8((char*)(dest), (char)(arg)) + +#pragma intrinsic(_InterlockedCompareExchange16) +#pragma intrinsic(_InterlockedExchangeAdd16) +#pragma intrinsic(_InterlockedExchange16) +#pragma intrinsic(_InterlockedAnd16) +#pragma intrinsic(_InterlockedOr16) +#pragma intrinsic(_InterlockedXor16) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(dest, exchange, compare) _InterlockedCompareExchange16((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(dest, addend) _InterlockedExchangeAdd16((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(dest, newval) _InterlockedExchange16((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND16(dest, arg) _InterlockedAnd16((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16(dest, arg) _InterlockedOr16((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16(dest, arg) _InterlockedXor16((short*)(dest), (short)(arg)) + +#endif // _MSC_VER >= 1600 + +#if defined(_M_AMD64) || defined(_M_IA64) + +#pragma intrinsic(_InterlockedCompareExchange64) +#pragma intrinsic(_InterlockedExchangeAdd64) +#pragma intrinsic(_InterlockedExchange64) +#pragma intrinsic(_InterlockedAnd64) +#pragma intrinsic(_InterlockedOr64) +#pragma intrinsic(_InterlockedXor64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) _InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) _InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) _InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND64(dest, arg) _InterlockedAnd64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64(dest, arg) _InterlockedOr64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64(dest, arg) _InterlockedXor64((__int64*)(dest), (__int64)(arg)) + +#pragma intrinsic(_InterlockedCompareExchangePointer) +#pragma intrinsic(_InterlockedExchangePointer) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) _InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) _InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64((long*)(dest), byte_offset)) + +#else // defined(_M_AMD64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)_InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)_InterlockedExchange((long*)(dest), (long)(newval))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD((long*)(dest), byte_offset)) + +#endif // defined(_M_AMD64) + +#else // defined(_MSC_VER) + +#if defined(BOOST_USE_WINDOWS_H) + +#include + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) InterlockedExchange((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) InterlockedExchangeAdd((long*)(dest), (long)(addend)) + +#if defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, byte_offset)) + +#else // defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, byte_offset)) + +#endif // defined(_WIN64) + +#else // defined(BOOST_USE_WINDOWS_H) + +#if defined(__MINGW64__) +#define BOOST_ATOMIC_INTERLOCKED_IMPORT +#else +#define BOOST_ATOMIC_INTERLOCKED_IMPORT __declspec(dllimport) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +extern "C" { + +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedCompareExchange(long volatile*, long, long); +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedExchange(long volatile*, long); +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedExchangeAdd(long volatile*, long); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) boost::atomics::detail::InterlockedExchange((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) boost::atomics::detail::InterlockedExchangeAdd((long*)(dest), (long)(addend)) + +#if defined(_WIN64) + +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedCompareExchange64(__int64 volatile*, __int64, __int64); +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedExchange64(__int64 volatile*, __int64); +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedExchangeAdd64(__int64 volatile*, __int64); + +BOOST_ATOMIC_INTERLOCKED_IMPORT void* __stdcall InterlockedCompareExchangePointer(void* volatile *, void*, void*); +BOOST_ATOMIC_INTERLOCKED_IMPORT void* __stdcall InterlockedExchangePointer(void* volatile *, void*); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) boost::atomics::detail::InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) boost::atomics::detail::InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) boost::atomics::detail::InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, byte_offset)) + +#else // defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, byte_offset)) + +#endif // defined(_WIN64) + +} // extern "C" + +} // namespace detail +} // namespace atomics +} // namespace boost + +#undef BOOST_ATOMIC_INTERLOCKED_IMPORT + +#endif // defined(BOOST_USE_WINDOWS_H) + +#endif // defined(_MSC_VER) + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/linux-arm.hpp b/cpp/BoostParts/boost/atomic/detail/linux-arm.hpp new file mode 100644 index 00000000..9831d81e --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/linux-arm.hpp @@ -0,0 +1,187 @@ +#ifndef BOOST_ATOMIC_DETAIL_LINUX_ARM_HPP +#define BOOST_ATOMIC_DETAIL_LINUX_ARM_HPP + +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Copyright (c) 2009, 2011 Helge Bahmann +// Copyright (c) 2009 Phil Endecott +// Linux-specific code by Phil Endecott + +// Different ARM processors have different atomic instructions. In particular, +// architecture versions before v6 (which are still in widespread use, e.g. the +// Intel/Marvell XScale chips like the one in the NSLU2) have only atomic swap. +// On Linux the kernel provides some support that lets us abstract away from +// these differences: it provides emulated CAS and barrier functions at special +// addresses that are guaranteed not to be interrupted by the kernel. Using +// this facility is slightly slower than inline assembler would be, but much +// faster than a system call. +// +// While this emulated CAS is "strong" in the sense that it does not fail +// "spuriously" (i.e.: it never fails to perform the exchange when the value +// found equals the value expected), it does not return the found value on +// failure. To satisfy the atomic API, compare_exchange_{weak|strong} must +// return the found value on failure, and we have to manually load this value +// after the emulated CAS reports failure. This in turn introduces a race +// between the CAS failing (due to the "wrong" value being found) and subsequently +// loading (which might turn up the "right" value). From an application's +// point of view this looks like "spurious failure", and therefore the +// emulated CAS is only good enough to provide compare_exchange_weak +// semantics. + +#include +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +inline void +arm_barrier(void) +{ + void (*kernel_dmb)(void) = (void (*)(void)) 0xffff0fa0; + kernel_dmb(); +} + +inline void +platform_fence_before(memory_order order) +{ + switch(order) { + case memory_order_release: + case memory_order_acq_rel: + case memory_order_seq_cst: + arm_barrier(); + case memory_order_consume: + default:; + } +} + +inline void +platform_fence_after(memory_order order) +{ + switch(order) { + case memory_order_acquire: + case memory_order_acq_rel: + case memory_order_seq_cst: + arm_barrier(); + default:; + } +} + +inline void +platform_fence_before_store(memory_order order) +{ + platform_fence_before(order); +} + +inline void +platform_fence_after_store(memory_order order) +{ + if (order == memory_order_seq_cst) + arm_barrier(); +} + +inline void +platform_fence_after_load(memory_order order) +{ + platform_fence_after(order); +} + +template +inline bool +platform_cmpxchg32(T & expected, T desired, volatile T * ptr) +{ + typedef T (*kernel_cmpxchg32_t)(T oldval, T newval, volatile T * ptr); + + if (((kernel_cmpxchg32_t) 0xffff0fc0)(expected, desired, ptr) == 0) { + return true; + } else { + expected = *ptr; + return false; + } +} + +} +} + +#define BOOST_ATOMIC_THREAD_FENCE 2 +inline void +atomic_thread_fence(memory_order order) +{ + switch(order) { + case memory_order_acquire: + case memory_order_release: + case memory_order_acq_rel: + case memory_order_seq_cst: + atomics::detail::arm_barrier(); + default:; + } +} + +#define BOOST_ATOMIC_SIGNAL_FENCE 2 +inline void +atomic_signal_fence(memory_order) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +class atomic_flag { +private: + atomic_flag(const atomic_flag &) /* = delete */ ; + atomic_flag & operator=(const atomic_flag &) /* = delete */ ; + uint32_t v_; +public: + atomic_flag(void) : v_(false) {} + + void + clear(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before_store(order); + const_cast(v_) = 0; + atomics::detail::platform_fence_after_store(order); + } + + bool + test_and_set(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before(order); + uint32_t expected = v_; + do { + if (expected == 1) + break; + } while (!atomics::detail::platform_cmpxchg32(expected, (uint32_t)1, &v_)); + atomics::detail::platform_fence_after(order); + return expected; + } +}; +#define BOOST_ATOMIC_FLAG_LOCK_FREE 2 + +} + +#include + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE 2 +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE 2 +#define BOOST_ATOMIC_LLONG_LOCK_FREE 0 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 +#define BOOST_ATOMIC_BOOL_LOCK_FREE 2 + +#include + +#endif /* !defined(BOOST_ATOMIC_FORCE_FALLBACK) */ + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/lockpool.hpp b/cpp/BoostParts/boost/atomic/detail/lockpool.hpp new file mode 100644 index 00000000..ea96cd29 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/lockpool.hpp @@ -0,0 +1,96 @@ +#ifndef BOOST_ATOMIC_DETAIL_LOCKPOOL_HPP +#define BOOST_ATOMIC_DETAIL_LOCKPOOL_HPP + +// Copyright (c) 2011 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#ifndef BOOST_ATOMIC_FLAG_LOCK_FREE +#include +#endif + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#ifndef BOOST_ATOMIC_FLAG_LOCK_FREE + +class lockpool +{ +public: + typedef mutex lock_type; + class scoped_lock + { + private: + lock_type& mtx_; + + scoped_lock(scoped_lock const&) /* = delete */; + scoped_lock& operator=(scoped_lock const&) /* = delete */; + + public: + explicit + scoped_lock(const volatile void * addr) : mtx_(get_lock_for(addr)) + { + mtx_.lock(); + } + ~scoped_lock() + { + mtx_.unlock(); + } + }; + +private: + static BOOST_ATOMIC_DECL lock_type& get_lock_for(const volatile void * addr); +}; + +#else + +class lockpool +{ +public: + typedef atomic_flag lock_type; + + class scoped_lock + { + private: + atomic_flag& flag_; + + scoped_lock(const scoped_lock &) /* = delete */; + scoped_lock& operator=(const scoped_lock &) /* = delete */; + + public: + explicit + scoped_lock(const volatile void * addr) : flag_(get_lock_for(addr)) + { + for (; flag_.test_and_set(memory_order_acquire);) + { +#if defined(BOOST_ATOMIC_X86_PAUSE) + BOOST_ATOMIC_X86_PAUSE(); +#endif + } + } + + ~scoped_lock(void) + { + flag_.clear(memory_order_release); + } + }; + +private: + static BOOST_ATOMIC_DECL lock_type& get_lock_for(const volatile void * addr); +}; + +#endif + +} +} +} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/platform.hpp b/cpp/BoostParts/boost/atomic/detail/platform.hpp new file mode 100644 index 00000000..a31ececa --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/platform.hpp @@ -0,0 +1,62 @@ +#ifndef BOOST_ATOMIC_DETAIL_PLATFORM_HPP +#define BOOST_ATOMIC_DETAIL_PLATFORM_HPP + +// Copyright (c) 2009 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Platform selection file + +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + + #include + +#elif 0 && defined(__GNUC__) && defined(__alpha__) /* currently does not work correctly */ + + #include + #include + +#elif defined(__GNUC__) && (defined(__POWERPC__) || defined(__PPC__)) + + #include + +// This list of ARM architecture versions comes from Apple's arm/arch.h header. +// I don't know how complete it is. +#elif defined(__GNUC__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_7A__)) + + #include + +#elif defined(__linux__) && defined(__arm__) + + #include + +#elif defined(__GNUC__) && defined(__sparc_v9__) + + #include + +#elif defined(BOOST_WINDOWS) || defined(_WIN32_CE) + + #include + +#elif 0 && defined(__GNUC__) /* currently does not work correctly */ + + #include + #include + +#else + +#include + +#endif + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/type-classification.hpp b/cpp/BoostParts/boost/atomic/detail/type-classification.hpp new file mode 100644 index 00000000..f7c2f8bf --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/type-classification.hpp @@ -0,0 +1,45 @@ +#ifndef BOOST_ATOMIC_DETAIL_TYPE_CLASSIFICATION_HPP +#define BOOST_ATOMIC_DETAIL_TYPE_CLASSIFICATION_HPP + +// Copyright (c) 2011 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template::value> +struct classify +{ + typedef void type; +}; + +template +struct classify {typedef int type;}; + +template +struct classify {typedef void* type;}; + +template +struct storage_size_of +{ + enum _ + { + size = sizeof(T), + value = (size == 3 ? 4 : (size == 5 || size == 6 || size == 7 ? 8 : size)) + }; +}; + +}}} + +#endif diff --git a/cpp/BoostParts/boost/atomic/detail/windows.hpp b/cpp/BoostParts/boost/atomic/detail/windows.hpp new file mode 100644 index 00000000..4c401ae6 --- /dev/null +++ b/cpp/BoostParts/boost/atomic/detail/windows.hpp @@ -0,0 +1,1441 @@ +#ifndef BOOST_ATOMIC_DETAIL_WINDOWS_HPP +#define BOOST_ATOMIC_DETAIL_WINDOWS_HPP + +// Copyright (c) 2009 Helge Bahmann +// Copyright (c) 2012 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +#ifdef BOOST_ATOMIC_HAS_PRAGMA_ONCE +#pragma once +#endif + +#ifdef _MSC_VER +#pragma warning(push) +// 'order' : unreferenced formal parameter +#pragma warning(disable: 4100) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_IX86)) +extern "C" void _mm_pause(void); +#pragma intrinsic(_mm_pause) +#define BOOST_ATOMIC_X86_PAUSE() _mm_pause() +#else +#define BOOST_ATOMIC_X86_PAUSE() +#endif + +// Define hardware barriers +#if defined(_MSC_VER) && (defined(_M_AMD64) || (defined(_M_IX86) && defined(_M_IX86_FP) && _M_IX86_FP >= 2)) +extern "C" void _mm_mfence(void); +#pragma intrinsic(_mm_mfence) +#endif + +BOOST_FORCEINLINE void hardware_full_fence(void) +{ +#if defined(_MSC_VER) && (defined(_M_AMD64) || (defined(_M_IX86) && defined(_M_IX86_FP) && _M_IX86_FP >= 2)) + // Use mfence only if SSE2 is available + _mm_mfence(); +#else + long tmp; + BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&tmp, 0); +#endif +} + +// Define compiler barriers +#if defined(_MSC_VER) && _MSC_VER >= 1310 && !defined(_WIN32_WCE) +extern "C" void _ReadWriteBarrier(); +#pragma intrinsic(_ReadWriteBarrier) +#define BOOST_ATOMIC_READ_WRITE_BARRIER() _ReadWriteBarrier() +#endif + +#ifndef BOOST_ATOMIC_READ_WRITE_BARRIER +#define BOOST_ATOMIC_READ_WRITE_BARRIER() +#endif + +BOOST_FORCEINLINE void +platform_fence_before(memory_order) +{ + BOOST_ATOMIC_READ_WRITE_BARRIER(); +} + +BOOST_FORCEINLINE void +platform_fence_after(memory_order) +{ + BOOST_ATOMIC_READ_WRITE_BARRIER(); +} + +BOOST_FORCEINLINE void +platform_fence_before_store(memory_order) +{ + BOOST_ATOMIC_READ_WRITE_BARRIER(); +} + +BOOST_FORCEINLINE void +platform_fence_after_store(memory_order) +{ + BOOST_ATOMIC_READ_WRITE_BARRIER(); +} + +BOOST_FORCEINLINE void +platform_fence_after_load(memory_order order) +{ + BOOST_ATOMIC_READ_WRITE_BARRIER(); + + // On x86 and x86_64 there is no need for a hardware barrier, + // even if seq_cst memory order is requested, because all + // seq_cst writes are implemented with lock-prefixed operations + // or xchg which has implied lock prefix. Therefore normal loads + // are already ordered with seq_cst stores on these architectures. + +#if !(defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_IX86))) + if (order == memory_order_seq_cst) + hardware_full_fence(); +#endif +} + +} // namespace detail +} // namespace atomics + +#define BOOST_ATOMIC_THREAD_FENCE 2 +BOOST_FORCEINLINE void +atomic_thread_fence(memory_order order) +{ + BOOST_ATOMIC_READ_WRITE_BARRIER(); + if (order == memory_order_seq_cst) + atomics::detail::hardware_full_fence(); +} + +#define BOOST_ATOMIC_SIGNAL_FENCE 2 +BOOST_FORCEINLINE void +atomic_signal_fence(memory_order) +{ + BOOST_ATOMIC_READ_WRITE_BARRIER(); +} + +#undef BOOST_ATOMIC_READ_WRITE_BARRIER + +class atomic_flag +{ +private: + atomic_flag(const atomic_flag &) /* = delete */ ; + atomic_flag & operator=(const atomic_flag &) /* = delete */ ; + uint32_t v_; +public: + atomic_flag(void) : v_(0) {} + + bool + test_and_set(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before(order); + const uint32_t old = (uint32_t)BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&v_, 1); + atomics::detail::platform_fence_after(order); + return old != 0; + } + + void + clear(memory_order order = memory_order_seq_cst) volatile + { + atomics::detail::platform_fence_before_store(order); + BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&v_, 0); + atomics::detail::platform_fence_after_store(order); + } +}; + +} // namespace boost + +#define BOOST_ATOMIC_FLAG_LOCK_FREE 2 + +#include + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE 2 +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64) +#define BOOST_ATOMIC_LLONG_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_LLONG_LOCK_FREE 0 +#endif +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 +#define BOOST_ATOMIC_BOOL_LOCK_FREE 2 + +namespace boost { +namespace atomics { +namespace detail { + +#if defined(_MSC_VER) +#pragma warning(push) +// 'char' : forcing value to bool 'true' or 'false' (performance warning) +#pragma warning(disable: 4800) +#endif + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T value_type; +#ifdef BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8 + typedef value_type storage_type; +#else + typedef uint32_t storage_type; +#endif + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + v_ = static_cast< storage_type >(v); + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = static_cast< value_type >(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); +#ifdef BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8 + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(&v_, v)); +#else + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&v_, v)); +#endif + platform_fence_after(order); + return v; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + typedef typename make_signed< value_type >::type signed_value_type; + return fetch_add(static_cast< value_type >(-static_cast< signed_value_type >(v)), order); + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); +#ifdef BOOST_ATOMIC_INTERLOCKED_EXCHANGE8 + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(&v_, v)); +#else + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&v_, v)); +#endif + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); +#ifdef BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8 + value_type oldval = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(&v_, desired, previous)); +#else + value_type oldval = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&v_, desired, previous)); +#endif + bool success = (previous == oldval); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = oldval; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#ifdef BOOST_ATOMIC_INTERLOCKED_AND8 + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_AND8(&v_, v)); + platform_fence_after(order); + return v; +#elif defined(BOOST_ATOMIC_INTERLOCKED_AND) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_AND(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#ifdef BOOST_ATOMIC_INTERLOCKED_OR8 + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_OR8(&v_, v)); + platform_fence_after(order); + return v; +#elif defined(BOOST_ATOMIC_INTERLOCKED_OR) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_OR(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#ifdef BOOST_ATOMIC_INTERLOCKED_XOR8 + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_XOR8(&v_, v)); + platform_fence_after(order); + return v; +#elif defined(BOOST_ATOMIC_INTERLOCKED_XOR) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T value_type; +#ifdef BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16 + typedef value_type storage_type; +#else + typedef uint32_t storage_type; +#endif + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + v_ = static_cast< storage_type >(v); + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = static_cast< value_type >(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); +#ifdef BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16 + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(&v_, v)); +#else + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&v_, v)); +#endif + platform_fence_after(order); + return v; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + typedef typename make_signed< value_type >::type signed_value_type; + return fetch_add(static_cast< value_type >(-static_cast< signed_value_type >(v)), order); + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); +#ifdef BOOST_ATOMIC_INTERLOCKED_EXCHANGE16 + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(&v_, v)); +#else + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&v_, v)); +#endif + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); +#ifdef BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16 + value_type oldval = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(&v_, desired, previous)); +#else + value_type oldval = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&v_, desired, previous)); +#endif + bool success = (previous == oldval); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = oldval; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#ifdef BOOST_ATOMIC_INTERLOCKED_AND16 + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_AND16(&v_, v)); + platform_fence_after(order); + return v; +#elif defined(BOOST_ATOMIC_INTERLOCKED_AND) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_AND(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#ifdef BOOST_ATOMIC_INTERLOCKED_OR16 + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_OR16(&v_, v)); + platform_fence_after(order); + return v; +#elif defined(BOOST_ATOMIC_INTERLOCKED_OR) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_OR(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#ifdef BOOST_ATOMIC_INTERLOCKED_XOR16 + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_XOR16(&v_, v)); + platform_fence_after(order); + return v; +#elif defined(BOOST_ATOMIC_INTERLOCKED_XOR) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T value_type; + typedef value_type storage_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + v_ = static_cast< storage_type >(v); + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = static_cast< value_type >(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&v_, v)); + platform_fence_after(order); + return v; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + typedef typename make_signed< value_type >::type signed_value_type; + return fetch_add(static_cast< value_type >(-static_cast< signed_value_type >(v)), order); + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&v_, v)); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + value_type oldval = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&v_, desired, previous)); + bool success = (previous == oldval); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = oldval; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#if defined(BOOST_ATOMIC_INTERLOCKED_AND) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_AND(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#if defined(BOOST_ATOMIC_INTERLOCKED_OR) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_OR(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for(; !compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#if defined(BOOST_ATOMIC_INTERLOCKED_XOR) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64) + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T value_type; + typedef value_type storage_type; + typedef T difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + v_ = static_cast< storage_type >(v); + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = static_cast< value_type >(v_); + platform_fence_after_load(order); + return v; + } + + value_type + fetch_add(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(&v_, v)); + platform_fence_after(order); + return v; + } + + value_type + fetch_sub(value_type v, memory_order order = memory_order_seq_cst) volatile + { + typedef typename make_signed< value_type >::type signed_value_type; + return fetch_add(static_cast< value_type >(-static_cast< signed_value_type >(v)), order); + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(&v_, v)); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + value_type oldval = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(&v_, desired, previous)); + bool success = (previous == oldval); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = oldval; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_and(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#if defined(BOOST_ATOMIC_INTERLOCKED_AND64) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_AND64(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp & v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + value_type + fetch_or(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#if defined(BOOST_ATOMIC_INTERLOCKED_OR64) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_OR64(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp | v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + value_type + fetch_xor(value_type v, memory_order order = memory_order_seq_cst) volatile + { +#if defined(BOOST_ATOMIC_INTERLOCKED_XOR64) + platform_fence_before(order); + v = static_cast< value_type >(BOOST_ATOMIC_INTERLOCKED_XOR64(&v_, v)); + platform_fence_after(order); + return v; +#else + value_type tmp = load(memory_order_relaxed); + for (; !compare_exchange_weak(tmp, tmp ^ v, order, memory_order_relaxed);) + { + BOOST_ATOMIC_X86_PAUSE(); + } + return tmp; +#endif + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_INTEGRAL_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +#endif // defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64) + +// MSVC 2012 fails to recognize sizeof(T) as a constant expression in template specializations +enum msvc_sizeof_pointer_workaround { sizeof_pointer = sizeof(void*) }; + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef void* value_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + v = (value_type)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(&v_, v); + platform_fence_after(order); + return v; + } + + bool compare_exchange_strong(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + value_type oldval = (value_type)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&v_, desired, previous); + bool success = (previous == oldval); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = oldval; + return success; + } + + bool compare_exchange_weak(value_type & expected, value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T* value_type; + typedef ptrdiff_t difference_type; +public: + explicit base_atomic(value_type v) : v_(v) {} + base_atomic(void) {} + + void + store(value_type v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + platform_fence_before(order); + const_cast(v_) = v; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + value_type v = const_cast(v_); + platform_fence_after_load(order); + return v; + } + + value_type + exchange(value_type v, memory_order order = memory_order_seq_cst) volatile + { + platform_fence_before(order); + v = (value_type)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(&v_, v); + platform_fence_after(order); + return v; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + value_type previous = expected; + platform_fence_before(success_order); + value_type oldval = (value_type)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&v_, desired, previous); + bool success = (previous == oldval); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + expected = oldval; + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + value_type + fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + v = v * sizeof(*v_); + platform_fence_before(order); + value_type res = (value_type)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(&v_, v); + platform_fence_after(order); + return res; + } + + value_type + fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile + { + return fetch_add(-v, order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_POINTER_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + value_type v_; +}; + + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T value_type; +#ifdef BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8 + typedef uint8_t storage_type; +#else + typedef uint32_t storage_type; +#endif +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); +#ifdef BOOST_ATOMIC_INTERLOCKED_EXCHANGE8 + tmp = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(&v_, tmp)); +#else + tmp = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&v_, tmp)); +#endif + platform_fence_after(order); + value_type res; + memcpy(&res, &tmp, sizeof(value_type)); + return res; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + platform_fence_before(success_order); +#ifdef BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8 + storage_type oldval = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(&v_, desired_s, expected_s)); +#else + storage_type oldval = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&v_, desired_s, expected_s)); +#endif + bool success = (oldval == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &oldval, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T value_type; +#ifdef BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16 + typedef uint16_t storage_type; +#else + typedef uint32_t storage_type; +#endif +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); +#ifdef BOOST_ATOMIC_INTERLOCKED_EXCHANGE16 + tmp = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(&v_, tmp)); +#else + tmp = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&v_, tmp)); +#endif + platform_fence_after(order); + value_type res; + memcpy(&res, &tmp, sizeof(value_type)); + return res; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + platform_fence_before(success_order); +#ifdef BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16 + storage_type oldval = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(&v_, desired_s, expected_s)); +#else + storage_type oldval = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&v_, desired_s, expected_s)); +#endif + bool success = (oldval == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &oldval, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T value_type; + typedef uint32_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + tmp = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&v_, tmp)); + platform_fence_after(order); + value_type res; + memcpy(&res, &tmp, sizeof(value_type)); + return res; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + platform_fence_before(success_order); + storage_type oldval = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&v_, desired_s, expected_s)); + bool success = (oldval == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &oldval, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64) + +template +class base_atomic +{ + typedef base_atomic this_type; + typedef T value_type; + typedef uint64_t storage_type; +public: + explicit base_atomic(value_type const& v) : v_(0) + { + memcpy(&v_, &v, sizeof(value_type)); + } + base_atomic(void) {} + + void + store(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + if (order != memory_order_seq_cst) { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + const_cast(v_) = tmp; + } else { + exchange(v, order); + } + } + + value_type + load(memory_order order = memory_order_seq_cst) const volatile + { + storage_type tmp = const_cast(v_); + platform_fence_after_load(order); + value_type v; + memcpy(&v, &tmp, sizeof(value_type)); + return v; + } + + value_type + exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile + { + storage_type tmp = 0; + memcpy(&tmp, &v, sizeof(value_type)); + platform_fence_before(order); + tmp = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(&v_, tmp)); + platform_fence_after(order); + value_type res; + memcpy(&res, &tmp, sizeof(value_type)); + return res; + } + + bool + compare_exchange_strong( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + storage_type expected_s = 0, desired_s = 0; + memcpy(&expected_s, &expected, sizeof(value_type)); + memcpy(&desired_s, &desired, sizeof(value_type)); + platform_fence_before(success_order); + storage_type oldval = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(&v_, desired_s, expected_s)); + bool success = (oldval == expected_s); + if (success) + platform_fence_after(success_order); + else + platform_fence_after(failure_order); + memcpy(&expected, &oldval, sizeof(value_type)); + return success; + } + + bool + compare_exchange_weak( + value_type & expected, + value_type const& desired, + memory_order success_order, + memory_order failure_order) volatile + { + return compare_exchange_strong(expected, desired, success_order, failure_order); + } + + bool + is_lock_free(void) const volatile + { + return true; + } + + BOOST_ATOMIC_DECLARE_BASE_OPERATORS +private: + base_atomic(const base_atomic &) /* = delete */ ; + void operator=(const base_atomic &) /* = delete */ ; + storage_type v_; +}; + +#endif // defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif /* !defined(BOOST_ATOMIC_FORCE_FALLBACK) */ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/cpp/BoostParts/boost/container/detail/algorithms.hpp b/cpp/BoostParts/boost/container/detail/algorithms.hpp new file mode 100644 index 00000000..824e44b9 --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/algorithms.hpp @@ -0,0 +1,84 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ALGORITHMS_HPP +#define BOOST_CONTAINER_DETAIL_ALGORITHMS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include "config_begin.hpp" +#include + +#include +#include +#include + +#include +#include +#include + + +#include + +namespace boost { +namespace container { + +template +struct is_default_construct_iterator +{ + static const bool value = false; +}; + +template +struct is_default_construct_iterator > +{ + static const bool value = true; +}; + +template +struct is_emplace_iterator +{ + static const bool value = false; +}; + +template +struct is_emplace_iterator > +{ + static const bool value = true; +}; + +template +inline void construct_in_place(A &a, T* dest, InpIt source) +{ boost::container::allocator_traits::construct(a, dest, *source); } +//#endif + +template +inline void construct_in_place(A &a, T *dest, default_construct_iterator) +{ + boost::container::allocator_traits::construct(a, dest); +} + +template +inline void construct_in_place(A &a, T *dest, emplace_iterator ei) +{ + ei.construct_in_place(a, dest); +} + +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_DETAIL_ALGORITHMS_HPP + diff --git a/cpp/BoostParts/boost/container/detail/allocation_type.hpp b/cpp/BoostParts/boost/container/detail/allocation_type.hpp new file mode 100644 index 00000000..1ebf20ed --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/allocation_type.hpp @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_ALLOCATION_TYPE_HPP +#define BOOST_CONTAINER_ALLOCATION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include "config_begin.hpp" +#include + +namespace boost { +namespace container { + +/// @cond +enum allocation_type_v +{ + // constants for allocation commands + allocate_new_v = 0x01, + expand_fwd_v = 0x02, + expand_bwd_v = 0x04, +// expand_both = expand_fwd | expand_bwd, +// expand_or_new = allocate_new | expand_both, + shrink_in_place_v = 0x08, + nothrow_allocation_v = 0x10, + zero_memory_v = 0x20, + try_shrink_in_place_v = 0x40 +}; + +typedef int allocation_type; +/// @endcond +static const allocation_type allocate_new = (allocation_type)allocate_new_v; +static const allocation_type expand_fwd = (allocation_type)expand_fwd_v; +static const allocation_type expand_bwd = (allocation_type)expand_bwd_v; +static const allocation_type shrink_in_place = (allocation_type)shrink_in_place_v; +static const allocation_type try_shrink_in_place= (allocation_type)try_shrink_in_place_v; +static const allocation_type nothrow_allocation = (allocation_type)nothrow_allocation_v; +static const allocation_type zero_memory = (allocation_type)zero_memory_v; + +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_ALLOCATION_TYPE_HPP diff --git a/cpp/BoostParts/boost/container/detail/allocator_version_traits.hpp b/cpp/BoostParts/boost/container/detail/allocator_version_traits.hpp new file mode 100644 index 00000000..d69e61bc --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/allocator_version_traits.hpp @@ -0,0 +1,163 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP +#define BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include //allocator_traits +#include //multiallocation_chain +#include //version_type +#include //allocation_type +#include //integral_constant +#include //pointer_traits +#include //pair +#include //runtime_error +#include //BOOST_TRY + +namespace boost { +namespace container { +namespace container_detail { + +template::value> +struct allocator_version_traits +{ + typedef ::boost::container::container_detail::integral_constant + alloc_version; + + typedef typename Allocator::multiallocation_chain multiallocation_chain; + + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + + //Node allocation interface + static pointer allocate_one(Allocator &a) + { return a.allocate_one(); } + + static void deallocate_one(Allocator &a, const pointer &p) + { a.deallocate_one(p); } + + static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m) + { return a.allocate_individual(n, m); } + + static void deallocate_individual(Allocator &a, multiallocation_chain &holder) + { a.deallocate_individual(holder); } + + static std::pair + allocation_command(Allocator &a, allocation_type command, + size_type limit_size, size_type preferred_size, + size_type &received_size, const pointer &reuse) + { + return a.allocation_command + (command, limit_size, preferred_size, received_size, reuse); + } +}; + +template +struct allocator_version_traits +{ + typedef ::boost::container::container_detail::integral_constant + alloc_version; + + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + typedef typename boost::container::allocator_traits::value_type value_type; + + typedef typename boost::intrusive::pointer_traits:: + template rebind_pointer::type void_ptr; + typedef container_detail::basic_multiallocation_chain + multialloc_cached_counted; + typedef boost::container::container_detail:: + transform_multiallocation_chain + < multialloc_cached_counted, value_type> multiallocation_chain; + + //Node allocation interface + static pointer allocate_one(Allocator &a) + { return a.allocate(1); } + + static void deallocate_one(Allocator &a, const pointer &p) + { a.deallocate(p, 1); } + + static void deallocate_individual(Allocator &a, multiallocation_chain &holder) + { + while(!holder.empty()){ + a.deallocate(holder.pop_front(), 1); + } + } + + struct allocate_individual_rollback + { + allocate_individual_rollback(Allocator &a, multiallocation_chain &chain) + : mr_a(a), mp_chain(&chain) + {} + + ~allocate_individual_rollback() + { + if(mp_chain) + allocator_version_traits::deallocate_individual(mr_a, *mp_chain); + } + + void release() + { + mp_chain = 0; + } + + Allocator &mr_a; + multiallocation_chain * mp_chain; + }; + + static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m) + { + allocate_individual_rollback rollback(a, m); + while(n--){ + m.push_front(a.allocate(1)); + } + rollback.release(); + } + + static std::pair + allocation_command(Allocator &a, allocation_type command, + size_type, size_type preferred_size, + size_type &received_size, const pointer &) + { + std::pair ret(pointer(), false); + if(!(command & allocate_new)){ + if(!(command & nothrow_allocation)){ + throw std::runtime_error("version 1 allocator without allocate_new flag"); + } + } + else{ + received_size = preferred_size; + BOOST_TRY{ + ret.first = a.allocate(received_size); + } + BOOST_CATCH(...){ + if(!(command & nothrow_allocation)){ + BOOST_RETHROW + } + } + BOOST_CATCH_END + } + return ret; + } +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#include + +#endif // ! defined(BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP) diff --git a/cpp/BoostParts/boost/container/detail/destroyers.hpp b/cpp/BoostParts/boost/container/detail/destroyers.hpp new file mode 100644 index 00000000..f9bfd867 --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/destroyers.hpp @@ -0,0 +1,365 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DESTROYERS_HPP +#define BOOST_CONTAINER_DESTROYERS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include "config_begin.hpp" +#include +#include +#include +#include + +namespace boost { +namespace container { +namespace container_detail { + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_deallocator +{ + typedef allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::pointer pointer; + typedef container_detail::integral_constant::value> alloc_version; + typedef container_detail::integral_constant allocator_v1; + typedef container_detail::integral_constant allocator_v2; + + private: + void priv_deallocate(allocator_v1) + { m_alloc.deallocate(m_ptr, 1); } + + void priv_deallocate(allocator_v2) + { m_alloc.deallocate_one(m_ptr); } + + BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_deallocator) + + public: + + pointer m_ptr; + A& m_alloc; + + scoped_deallocator(pointer p, A& a) + : m_ptr(p), m_alloc(a) + {} + + ~scoped_deallocator() + { if (m_ptr)priv_deallocate(alloc_version()); } + + scoped_deallocator(BOOST_RV_REF(scoped_deallocator) o) + : m_ptr(o.m_ptr), m_alloc(o.m_alloc) + { o.release(); } + + pointer get() const + { return m_ptr; } + + void release() + { m_ptr = 0; } +}; + +template +struct null_scoped_deallocator +{ + typedef boost::container::allocator_traits AllocTraits; + typedef typename AllocTraits::pointer pointer; + typedef typename AllocTraits::size_type size_type; + + null_scoped_deallocator(pointer, Allocator&, size_type) + {} + + void release() + {} + + pointer get() const + { return pointer(); } +}; + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an array of objects using a STL allocator. +template +struct scoped_array_deallocator +{ + typedef boost::container::allocator_traits AllocTraits; + typedef typename AllocTraits::pointer pointer; + typedef typename AllocTraits::size_type size_type; + + scoped_array_deallocator(pointer p, Allocator& a, size_type length) + : m_ptr(p), m_alloc(a), m_length(length) {} + + ~scoped_array_deallocator() + { if (m_ptr) m_alloc.deallocate(m_ptr, m_length); } + + void release() + { m_ptr = 0; } + + private: + pointer m_ptr; + Allocator& m_alloc; + size_type m_length; +}; + +template +struct null_scoped_array_deallocator +{ + typedef boost::container::allocator_traits AllocTraits; + typedef typename AllocTraits::pointer pointer; + typedef typename AllocTraits::size_type size_type; + + null_scoped_array_deallocator(pointer, Allocator&, size_type) + {} + + void release() + {} +}; + +template +struct scoped_destroy_deallocator +{ + typedef boost::container::allocator_traits AllocTraits; + typedef typename AllocTraits::pointer pointer; + typedef typename AllocTraits::size_type size_type; + typedef container_detail::integral_constant::value> alloc_version; + typedef container_detail::integral_constant allocator_v1; + typedef container_detail::integral_constant allocator_v2; + + scoped_destroy_deallocator(pointer p, Allocator& a) + : m_ptr(p), m_alloc(a) {} + + ~scoped_destroy_deallocator() + { + if(m_ptr){ + AllocTraits::destroy(m_alloc, container_detail::to_raw_pointer(m_ptr)); + priv_deallocate(m_ptr, alloc_version()); + } + } + + void release() + { m_ptr = 0; } + + private: + + void priv_deallocate(const pointer &p, allocator_v1) + { AllocTraits::deallocate(m_alloc, p, 1); } + + void priv_deallocate(const pointer &p, allocator_v2) + { m_alloc.deallocate_one(p); } + + pointer m_ptr; + Allocator& m_alloc; +}; + + +//!A deleter for scoped_ptr that destroys +//!an object using a STL allocator. +template +struct scoped_destructor_n +{ + typedef boost::container::allocator_traits AllocTraits; + typedef typename AllocTraits::pointer pointer; + typedef typename AllocTraits::value_type value_type; + typedef typename AllocTraits::size_type size_type; + + scoped_destructor_n(pointer p, Allocator& a, size_type n) + : m_p(p), m_a(a), m_n(n) + {} + + void release() + { m_p = 0; } + + void increment_size(size_type inc) + { m_n += inc; } + + void increment_size_backwards(size_type inc) + { m_n += inc; m_p -= inc; } + + void shrink_forward(size_type inc) + { m_n -= inc; m_p += inc; } + + ~scoped_destructor_n() + { + if(!m_p) return; + value_type *raw_ptr = container_detail::to_raw_pointer(m_p); + while(m_n--){ + AllocTraits::destroy(m_a, raw_ptr); + } + } + + private: + pointer m_p; + Allocator & m_a; + size_type m_n; +}; + +//!A deleter for scoped_ptr that destroys +//!an object using a STL allocator. +template +struct null_scoped_destructor_n +{ + typedef boost::container::allocator_traits AllocTraits; + typedef typename AllocTraits::pointer pointer; + typedef typename AllocTraits::size_type size_type; + + null_scoped_destructor_n(pointer, Allocator&, size_type) + {} + + void increment_size(size_type) + {} + + void increment_size_backwards(size_type) + {} + + void release() + {} +}; + +template +class scoped_destructor +{ + typedef boost::container::allocator_traits AllocTraits; + public: + typedef typename A::value_type value_type; + scoped_destructor(A &a, value_type *pv) + : pv_(pv), a_(a) + {} + + ~scoped_destructor() + { + if(pv_){ + AllocTraits::destroy(a_, pv_); + } + } + + void release() + { pv_ = 0; } + + private: + value_type *pv_; + A &a_; +}; + + +template +class value_destructor +{ + typedef boost::container::allocator_traits AllocTraits; + public: + typedef typename A::value_type value_type; + value_destructor(A &a, value_type &rv) + : rv_(rv), a_(a) + {} + + ~value_destructor() + { + AllocTraits::destroy(a_, &rv_); + } + + private: + value_type &rv_; + A &a_; +}; + +template +class allocator_destroyer +{ + typedef boost::container::allocator_traits AllocTraits; + typedef typename AllocTraits::value_type value_type; + typedef typename AllocTraits::pointer pointer; + typedef container_detail::integral_constant::value> alloc_version; + typedef container_detail::integral_constant allocator_v1; + typedef container_detail::integral_constant allocator_v2; + + private: + Allocator & a_; + + private: + void priv_deallocate(const pointer &p, allocator_v1) + { AllocTraits::deallocate(a_,p, 1); } + + void priv_deallocate(const pointer &p, allocator_v2) + { a_.deallocate_one(p); } + + public: + allocator_destroyer(Allocator &a) + : a_(a) + {} + + void operator()(const pointer &p) + { + AllocTraits::destroy(a_, container_detail::to_raw_pointer(p)); + this->priv_deallocate(p, alloc_version()); + } +}; + +template +class allocator_destroyer_and_chain_builder +{ + typedef allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + + A & a_; + multiallocation_chain &c_; + + public: + allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) + : a_(a), c_(c) + {} + + void operator()(const typename A::pointer &p) + { + allocator_traits::destroy(a_, container_detail::to_raw_pointer(p)); + c_.push_back(p); + } +}; + +template +class allocator_multialloc_chain_node_deallocator +{ + typedef allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + typedef allocator_destroyer_and_chain_builder chain_builder; + + A & a_; + multiallocation_chain c_; + + public: + allocator_multialloc_chain_node_deallocator(A &a) + : a_(a), c_() + {} + + chain_builder get_chain_builder() + { return chain_builder(a_, c_); } + + ~allocator_multialloc_chain_node_deallocator() + { + a_.deallocate_individual(c_); + } +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_DESTROYERS_HPP diff --git a/cpp/BoostParts/boost/container/detail/iterators.hpp b/cpp/BoostParts/boost/container/detail/iterators.hpp new file mode 100644 index 00000000..f58c4ce6 --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/iterators.hpp @@ -0,0 +1,611 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ITERATORS_HPP +#define BOOST_CONTAINER_DETAIL_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include "config_begin.hpp" +#include +#include +#include +#include + +#ifdef BOOST_CONTAINER_PERFECT_FORWARDING +#include +#else +#include +#endif + +#include + +namespace boost { +namespace container { + +template +class constant_iterator + : public std::iterator + +{ + typedef constant_iterator this_type; + + public: + explicit constant_iterator(const T &ref, Difference range_size) + : m_ptr(&ref), m_num(range_size){} + + //Constructors + constant_iterator() + : m_ptr(0), m_num(0){} + + constant_iterator& operator++() + { increment(); return *this; } + + constant_iterator operator++(int) + { + constant_iterator result (*this); + increment(); + return result; + } + + constant_iterator& operator--() + { decrement(); return *this; } + + constant_iterator operator--(int) + { + constant_iterator result (*this); + decrement(); + return result; + } + + friend bool operator== (const constant_iterator& i, const constant_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const constant_iterator& i, const constant_iterator& i2) + { return !(i == i2); } + + friend bool operator< (const constant_iterator& i, const constant_iterator& i2) + { return i.less(i2); } + + friend bool operator> (const constant_iterator& i, const constant_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const constant_iterator& i, const constant_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const constant_iterator& i, const constant_iterator& i2) + { return !(i < i2); } + + friend Difference operator- (const constant_iterator& i, const constant_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + constant_iterator& operator+=(Difference off) + { this->advance(off); return *this; } + + constant_iterator operator+(Difference off) const + { + constant_iterator other(*this); + other.advance(off); + return other; + } + + friend constant_iterator operator+(Difference off, const constant_iterator& right) + { return right + off; } + + constant_iterator& operator-=(Difference off) + { this->advance(-off); return *this; } + + constant_iterator operator-(Difference off) const + { return *this + (-off); } + + const T& operator*() const + { return dereference(); } + + const T& operator[] (Difference n) const + { return dereference(); } + + const T* operator->() const + { return &(dereference()); } + + private: + const T * m_ptr; + Difference m_num; + + void increment() + { --m_num; } + + void decrement() + { ++m_num; } + + bool equal(const this_type &other) const + { return m_num == other.m_num; } + + bool less(const this_type &other) const + { return other.m_num < m_num; } + + const T & dereference() const + { return *m_ptr; } + + void advance(Difference n) + { m_num -= n; } + + Difference distance_to(const this_type &other)const + { return m_num - other.m_num; } +}; + +template +class default_construct_iterator + : public std::iterator + +{ + typedef default_construct_iterator this_type; + + public: + explicit default_construct_iterator(Difference range_size) + : m_num(range_size){} + + //Constructors + default_construct_iterator() + : m_num(0){} + + default_construct_iterator& operator++() + { increment(); return *this; } + + default_construct_iterator operator++(int) + { + default_construct_iterator result (*this); + increment(); + return result; + } + + default_construct_iterator& operator--() + { decrement(); return *this; } + + default_construct_iterator operator--(int) + { + default_construct_iterator result (*this); + decrement(); + return result; + } + + friend bool operator== (const default_construct_iterator& i, const default_construct_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const default_construct_iterator& i, const default_construct_iterator& i2) + { return !(i == i2); } + + friend bool operator< (const default_construct_iterator& i, const default_construct_iterator& i2) + { return i.less(i2); } + + friend bool operator> (const default_construct_iterator& i, const default_construct_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const default_construct_iterator& i, const default_construct_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const default_construct_iterator& i, const default_construct_iterator& i2) + { return !(i < i2); } + + friend Difference operator- (const default_construct_iterator& i, const default_construct_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + default_construct_iterator& operator+=(Difference off) + { this->advance(off); return *this; } + + default_construct_iterator operator+(Difference off) const + { + default_construct_iterator other(*this); + other.advance(off); + return other; + } + + friend default_construct_iterator operator+(Difference off, const default_construct_iterator& right) + { return right + off; } + + default_construct_iterator& operator-=(Difference off) + { this->advance(-off); return *this; } + + default_construct_iterator operator-(Difference off) const + { return *this + (-off); } + + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; + + private: + Difference m_num; + + void increment() + { --m_num; } + + void decrement() + { ++m_num; } + + bool equal(const this_type &other) const + { return m_num == other.m_num; } + + bool less(const this_type &other) const + { return other.m_num < m_num; } + + const T & dereference() const + { + static T dummy; + return dummy; + } + + void advance(Difference n) + { m_num -= n; } + + Difference distance_to(const this_type &other)const + { return m_num - other.m_num; } +}; + +template +class repeat_iterator + : public std::iterator + +{ + typedef repeat_iterator this_type; + public: + explicit repeat_iterator(T &ref, Difference range_size) + : m_ptr(&ref), m_num(range_size){} + + //Constructors + repeat_iterator() + : m_ptr(0), m_num(0){} + + this_type& operator++() + { increment(); return *this; } + + this_type operator++(int) + { + this_type result (*this); + increment(); + return result; + } + + this_type& operator--() + { increment(); return *this; } + + this_type operator--(int) + { + this_type result (*this); + increment(); + return result; + } + + friend bool operator== (const this_type& i, const this_type& i2) + { return i.equal(i2); } + + friend bool operator!= (const this_type& i, const this_type& i2) + { return !(i == i2); } + + friend bool operator< (const this_type& i, const this_type& i2) + { return i.less(i2); } + + friend bool operator> (const this_type& i, const this_type& i2) + { return i2 < i; } + + friend bool operator<= (const this_type& i, const this_type& i2) + { return !(i > i2); } + + friend bool operator>= (const this_type& i, const this_type& i2) + { return !(i < i2); } + + friend Difference operator- (const this_type& i, const this_type& i2) + { return i2.distance_to(i); } + + //Arithmetic + this_type& operator+=(Difference off) + { this->advance(off); return *this; } + + this_type operator+(Difference off) const + { + this_type other(*this); + other.advance(off); + return other; + } + + friend this_type operator+(Difference off, const this_type& right) + { return right + off; } + + this_type& operator-=(Difference off) + { this->advance(-off); return *this; } + + this_type operator-(Difference off) const + { return *this + (-off); } + + T& operator*() const + { return dereference(); } + + T& operator[] (Difference n) const + { return dereference(); } + + T *operator->() const + { return &(dereference()); } + + private: + T * m_ptr; + Difference m_num; + + void increment() + { --m_num; } + + void decrement() + { ++m_num; } + + bool equal(const this_type &other) const + { return m_num == other.m_num; } + + bool less(const this_type &other) const + { return other.m_num < m_num; } + + T & dereference() const + { return *m_ptr; } + + void advance(Difference n) + { m_num -= n; } + + Difference distance_to(const this_type &other)const + { return m_num - other.m_num; } +}; + +template +class emplace_iterator + : public std::iterator + +{ + typedef emplace_iterator this_type; + + public: + typedef Difference difference_type; + explicit emplace_iterator(EmplaceFunctor&e) + : m_num(1), m_pe(&e){} + + emplace_iterator() + : m_num(0), m_pe(0){} + + this_type& operator++() + { increment(); return *this; } + + this_type operator++(int) + { + this_type result (*this); + increment(); + return result; + } + + this_type& operator--() + { decrement(); return *this; } + + this_type operator--(int) + { + this_type result (*this); + decrement(); + return result; + } + + friend bool operator== (const this_type& i, const this_type& i2) + { return i.equal(i2); } + + friend bool operator!= (const this_type& i, const this_type& i2) + { return !(i == i2); } + + friend bool operator< (const this_type& i, const this_type& i2) + { return i.less(i2); } + + friend bool operator> (const this_type& i, const this_type& i2) + { return i2 < i; } + + friend bool operator<= (const this_type& i, const this_type& i2) + { return !(i > i2); } + + friend bool operator>= (const this_type& i, const this_type& i2) + { return !(i < i2); } + + friend difference_type operator- (const this_type& i, const this_type& i2) + { return i2.distance_to(i); } + + //Arithmetic + this_type& operator+=(difference_type off) + { this->advance(off); return *this; } + + this_type operator+(difference_type off) const + { + this_type other(*this); + other.advance(off); + return other; + } + + friend this_type operator+(difference_type off, const this_type& right) + { return right + off; } + + this_type& operator-=(difference_type off) + { this->advance(-off); return *this; } + + this_type operator-(difference_type off) const + { return *this + (-off); } + + //This pseudo-iterator's dereference operations have no sense since value is not + //constructed until ::boost::container::construct_in_place is called. + //So comment them to catch bad uses + //const T& operator*() const; + //const T& operator[](difference_type) const; + //const T* operator->() const; + + template + void construct_in_place(A &a, T* ptr) + { (*m_pe)(a, ptr); } + + private: + difference_type m_num; + EmplaceFunctor * m_pe; + + void increment() + { --m_num; } + + void decrement() + { ++m_num; } + + bool equal(const this_type &other) const + { return m_num == other.m_num; } + + bool less(const this_type &other) const + { return other.m_num < m_num; } + + const T & dereference() const + { + static T dummy; + return dummy; + } + + void advance(difference_type n) + { m_num -= n; } + + difference_type distance_to(const this_type &other)const + { return difference_type(m_num - other.m_num); } +}; + +#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + +template +struct emplace_functor +{ + typedef typename container_detail::build_number_seq::type index_tuple_t; + + emplace_functor(Args&&... args) + : args_(args...) + {} + + template + void operator()(A &a, T *ptr) + { emplace_functor::inplace_impl(a, ptr, index_tuple_t()); } + + template + void inplace_impl(A &a, T* ptr, const container_detail::index_tuple&) + { + allocator_traits::construct + (a, ptr, ::boost::forward(container_detail::get(args_))...); + } + + container_detail::tuple args_; +}; + +#else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + +#define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template <) \ + BOOST_PP_ENUM_PARAMS(n, class P) \ + BOOST_PP_EXPR_IF(n, >) \ + struct BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + { \ + BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + ( BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _) ) \ + BOOST_PP_EXPR_IF(n, :) BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_INIT, _){} \ + \ + template \ + void operator()(A &a, T *ptr) \ + { \ + allocator_traits::construct \ + (a, ptr BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_MEMBER_FORWARD, _) ); \ + } \ + BOOST_PP_REPEAT(n, BOOST_CONTAINER_PP_PARAM_DEFINE, _) \ + }; \ + //! +#define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) +#include BOOST_PP_LOCAL_ITERATE() + +#endif + +namespace container_detail { + +template +struct has_iterator_category +{ + template + static char test(int, typename X::iterator_category*); + + template + static int test(int, ...); + + static const bool value = (1 == sizeof(test(0, 0))); +}; + + +template::value > +struct is_input_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_input_iterator +{ + static const bool value = false; +}; + +template::value > +struct is_forward_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_forward_iterator +{ + static const bool value = false; +}; + +template::value > +struct is_bidirectional_iterator +{ + static const bool value = is_same::value; +}; + +template +struct is_bidirectional_iterator +{ + static const bool value = false; +}; + +template +struct iiterator_types +{ + typedef typename std::iterator_traits::pointer it_pointer; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename ::boost::intrusive::pointer_traits:: + template rebind_pointer::type pointer; + typedef typename ::boost::intrusive::pointer_traits:: + template rebind_pointer::type const_pointer; + typedef typename ::boost::intrusive:: + pointer_traits::reference reference; + typedef typename ::boost::intrusive:: + pointer_traits::reference const_reference; +}; + + +} //namespace container_detail { + +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_DETAIL_ITERATORS_HPP diff --git a/cpp/BoostParts/boost/container/detail/multiallocation_chain.hpp b/cpp/BoostParts/boost/container/detail/multiallocation_chain.hpp new file mode 100644 index 00000000..2e29f9c1 --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/multiallocation_chain.hpp @@ -0,0 +1,286 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_MULTIALLOCATION_CHAIN_HPP +#define BOOST_CONTAINER_DETAIL_MULTIALLOCATION_CHAIN_HPP + +#include "config_begin.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace container { +namespace container_detail { + +template +class basic_multiallocation_chain +{ + private: + typedef bi::slist_base_hook + ,bi::link_mode + > node; + + typedef typename boost::intrusive::pointer_traits + ::template rebind_pointer::type char_ptr; + typedef typename boost::intrusive:: + pointer_traits::difference_type difference_type; + + typedef bi::slist< node + , bi::linear + , bi::cache_last + , bi::size_type::type> + > slist_impl_t; + slist_impl_t slist_impl_; + + typedef typename boost::intrusive::pointer_traits + ::template rebind_pointer::type node_ptr; + typedef typename boost::intrusive:: + pointer_traits node_ptr_traits; + + static node & to_node(const VoidPointer &p) + { return *static_cast(static_cast(container_detail::to_raw_pointer(p))); } + + static VoidPointer from_node(node &n) + { return node_ptr_traits::pointer_to(n); } + + static node_ptr to_node_ptr(const VoidPointer &p) + { return node_ptr_traits::static_cast_from(p); } + + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain) + + public: + + typedef VoidPointer void_pointer; + typedef typename slist_impl_t::iterator iterator; + typedef typename slist_impl_t::size_type size_type; + + basic_multiallocation_chain() + : slist_impl_() + {} + + basic_multiallocation_chain(const void_pointer &b, const void_pointer &before_e, size_type n) + : slist_impl_(to_node_ptr(b), to_node_ptr(before_e), n) + {} + + basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other) + : slist_impl_(::boost::move(other.slist_impl_)) + {} + + basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other) + { + slist_impl_ = ::boost::move(other.slist_impl_); + return *this; + } + + bool empty() const + { return slist_impl_.empty(); } + + size_type size() const + { return slist_impl_.size(); } + + iterator before_begin() + { return slist_impl_.before_begin(); } + + iterator begin() + { return slist_impl_.begin(); } + + iterator end() + { return slist_impl_.end(); } + + iterator last() + { return slist_impl_.last(); } + + void clear() + { slist_impl_.clear(); } + + iterator insert_after(iterator it, void_pointer m) + { return slist_impl_.insert_after(it, to_node(m)); } + + void push_front(const void_pointer &m) + { return slist_impl_.push_front(to_node(m)); } + + void push_back(const void_pointer &m) + { return slist_impl_.push_back(to_node(m)); } + + void_pointer pop_front() + { + node & n = slist_impl_.front(); + void_pointer ret = from_node(n); + slist_impl_.pop_front(); + return ret; + } + + void splice_after(iterator after_this, basic_multiallocation_chain &x, iterator before_b, iterator before_e, size_type n) + { slist_impl_.splice_after(after_this, x.slist_impl_, before_b, before_e, n); } + + void splice_after(iterator after_this, basic_multiallocation_chain &x) + { slist_impl_.splice_after(after_this, x.slist_impl_); } + + void erase_after(iterator before_b, iterator e, size_type n) + { slist_impl_.erase_after(before_b, e, n); } + + void_pointer incorporate_after(iterator after_this, const void_pointer &b, size_type unit_bytes, size_type num_units) + { + typedef typename boost::intrusive::pointer_traits char_pointer_traits; + char_ptr elem = char_pointer_traits::static_cast_from(b); + if(num_units){ + char_ptr prev_elem = elem; + elem += unit_bytes; + for(size_type i = 0; i != num_units-1; ++i, elem += unit_bytes){ + ::new (container_detail::to_raw_pointer(prev_elem)) void_pointer(elem); + prev_elem = elem; + } + slist_impl_.incorporate_after(after_this, to_node_ptr(b), to_node_ptr(prev_elem), num_units); + } + return elem; + } + + void incorporate_after(iterator after_this, void_pointer b, void_pointer before_e, size_type n) + { slist_impl_.incorporate_after(after_this, to_node_ptr(b), to_node_ptr(before_e), n); } + + void swap(basic_multiallocation_chain &x) + { slist_impl_.swap(x.slist_impl_); } + + static iterator iterator_to(const void_pointer &p) + { return slist_impl_t::s_iterator_to(to_node(p)); } + + std::pair extract_data() + { + std::pair ret + (slist_impl_.begin().operator->() + ,slist_impl_.last().operator->()); + slist_impl_.clear(); + return ret; + } +}; + +template +struct cast_functor +{ + typedef typename container_detail::add_reference::type result_type; + template + result_type operator()(U &ptr) const + { return *static_cast(static_cast(&ptr)); } +}; + +template +class transform_multiallocation_chain + : public MultiallocationChain +{ + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(transform_multiallocation_chain) + //transform_multiallocation_chain(const transform_multiallocation_chain &); + //transform_multiallocation_chain & operator=(const transform_multiallocation_chain &); + + typedef typename MultiallocationChain::void_pointer void_pointer; + typedef typename boost::intrusive::pointer_traits + void_pointer_traits; + typedef typename void_pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive::pointer_traits + pointer_traits; + + static pointer cast(const void_pointer &p) + { return pointer_traits::static_cast_from(p); } + + public: + typedef transform_iterator + < typename MultiallocationChain::iterator + , container_detail::cast_functor > iterator; + typedef typename MultiallocationChain::size_type size_type; + + transform_multiallocation_chain() + : MultiallocationChain() + {} + + transform_multiallocation_chain(BOOST_RV_REF(transform_multiallocation_chain) other) + : MultiallocationChain(::boost::move(static_cast(other))) + {} + + transform_multiallocation_chain(BOOST_RV_REF(MultiallocationChain) other) + : MultiallocationChain(::boost::move(static_cast(other))) + {} + + transform_multiallocation_chain& operator=(BOOST_RV_REF(transform_multiallocation_chain) other) + { + return static_cast + (this->MultiallocationChain::operator=(::boost::move(static_cast(other)))); + } +/* + void push_front(const pointer &mem) + { holder_.push_front(mem); } + + void push_back(const pointer &mem) + { return holder_.push_back(mem); } + + void swap(transform_multiallocation_chain &other_chain) + { holder_.swap(other_chain.holder_); } + + void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_b, iterator before_e, size_type n) + { holder_.splice_after(after_this.base(), x.holder_, before_b.base(), before_e.base(), n); } + + void incorporate_after(iterator after_this, pointer b, pointer before_e, size_type n) + { holder_.incorporate_after(after_this.base(), b, before_e, n); } +*/ + pointer pop_front() + { return cast(this->MultiallocationChain::pop_front()); } +/* + bool empty() const + { return holder_.empty(); } + + iterator before_begin() + { return iterator(holder_.before_begin()); } + + iterator begin() + { return iterator(holder_.begin()); } + + iterator end() + { return iterator(holder_.end()); } + + iterator last() + { return iterator(holder_.last()); } + + size_type size() const + { return holder_.size(); } + + void clear() + { holder_.clear(); } +*/ + iterator insert_after(iterator it, pointer m) + { return iterator(this->MultiallocationChain::insert_after(it.base(), m)); } + + static iterator iterator_to(const pointer &p) + { return iterator(MultiallocationChain::iterator_to(p)); } + + std::pair extract_data() + { + std::pair data(this->MultiallocationChain::extract_data()); + return std::pair(cast(data.first), cast(data.second)); + } +/* + MultiallocationChain &extract_multiallocation_chain() + { return holder_; }*/ +}; + +}}} + +// namespace container_detail { +// namespace container { +// namespace boost { + +#include + +#endif //BOOST_CONTAINER_DETAIL_MULTIALLOCATION_CHAIN_HPP diff --git a/cpp/BoostParts/boost/container/detail/node_alloc_holder.hpp b/cpp/BoostParts/boost/container/detail/node_alloc_holder.hpp new file mode 100644 index 00000000..7d851c06 --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/node_alloc_holder.hpp @@ -0,0 +1,384 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_ +#define BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_ + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include "config_begin.hpp" +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_CONTAINER_PERFECT_FORWARDING +#include +#endif + +#include +#include + + +namespace boost { +namespace container { +namespace container_detail { + +template +struct node_compare + : private ValueCompare +{ + typedef typename ValueCompare::key_type key_type; + typedef typename ValueCompare::value_type value_type; + typedef typename ValueCompare::key_of_value key_of_value; + + node_compare(const ValueCompare &pred) + : ValueCompare(pred) + {} + + ValueCompare &value_comp() + { return static_cast(*this); } + + ValueCompare &value_comp() const + { return static_cast(*this); } + + bool operator()(const Node &a, const Node &b) const + { return ValueCompare::operator()(a.get_data(), b.get_data()); } +}; + +template +struct node_alloc_holder +{ + typedef allocator_traits allocator_traits_type; + typedef node_alloc_holder self_t; + typedef typename allocator_traits_type::value_type value_type; + typedef typename ICont::value_type Node; + typedef typename allocator_traits_type::template + portable_rebind_alloc::type NodeAlloc; + typedef allocator_traits node_allocator_traits_type; + typedef A ValAlloc; + typedef typename node_allocator_traits_type::pointer NodePtr; + typedef container_detail::scoped_deallocator Deallocator; + typedef typename node_allocator_traits_type::size_type size_type; + typedef typename node_allocator_traits_type::difference_type difference_type; + typedef container_detail::integral_constant allocator_v1; + typedef container_detail::integral_constant allocator_v2; + typedef container_detail::integral_constant::value> alloc_version; + typedef typename ICont::iterator icont_iterator; + typedef typename ICont::const_iterator icont_citerator; + typedef allocator_destroyer Destroyer; + typedef allocator_traits NodeAllocTraits; + typedef allocator_version_traits AllocVersionTraits; + + private: + BOOST_COPYABLE_AND_MOVABLE(node_alloc_holder) + + public: + + //Constructors for sequence containers + node_alloc_holder() + : members_() + {} + + explicit node_alloc_holder(const ValAlloc &a) + : members_(a) + {} + + explicit node_alloc_holder(const node_alloc_holder &x) + : members_(NodeAllocTraits::select_on_container_copy_construction(x.node_alloc())) + {} + + explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x) + : members_(boost::move(x.node_alloc())) + { this->icont().swap(x.icont()); } + + //Constructors for associative containers + explicit node_alloc_holder(const ValAlloc &a, const Pred &c) + : members_(a, c) + {} + + explicit node_alloc_holder(const node_alloc_holder &x, const Pred &c) + : members_(NodeAllocTraits::select_on_container_copy_construction(x.node_alloc()), c) + {} + + explicit node_alloc_holder(const Pred &c) + : members_(c) + {} + + //helpers for move assignments + explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x, const Pred &c) + : members_(boost::move(x.node_alloc()), c) + { this->icont().swap(x.icont()); } + + void copy_assign_alloc(const node_alloc_holder &x) + { + container_detail::bool_ flag; + container_detail::assign_alloc( static_cast(this->members_) + , static_cast(x.members_), flag); + } + + void move_assign_alloc( node_alloc_holder &x) + { + container_detail::bool_ flag; + container_detail::move_alloc( static_cast(this->members_) + , static_cast(x.members_), flag); + } + + ~node_alloc_holder() + { this->clear(alloc_version()); } + + size_type max_size() const + { return allocator_traits_type::max_size(this->node_alloc()); } + + NodePtr allocate_one() + { return AllocVersionTraits::allocate_one(this->node_alloc()); } + + void deallocate_one(const NodePtr &p) + { AllocVersionTraits::deallocate_one(this->node_alloc(), p); } + + #ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + template + NodePtr create_node(Args &&...args) + { + NodePtr p = this->allocate_one(); + Deallocator node_deallocator(p, this->node_alloc()); + allocator_traits::construct + ( this->node_alloc() + , container_detail::addressof(p->m_data), boost::forward(args)...); + node_deallocator.release(); + //This does not throw + typedef typename Node::hook_type hook_type; + ::new(static_cast(container_detail::to_raw_pointer(p))) hook_type; + return (p); + } + + #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + #define BOOST_PP_LOCAL_MACRO(n) \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + NodePtr create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + NodePtr p = this->allocate_one(); \ + Deallocator node_deallocator(p, this->node_alloc()); \ + allocator_traits::construct \ + (this->node_alloc(), container_detail::addressof(p->m_data) \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ + node_deallocator.release(); \ + typedef typename Node::hook_type hook_type; \ + ::new(static_cast(container_detail::to_raw_pointer(p))) hook_type; \ + return (p); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + template + NodePtr create_node_from_it(const It &it) + { + NodePtr p = this->allocate_one(); + Deallocator node_deallocator(p, this->node_alloc()); + ::boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->m_data), it); + node_deallocator.release(); + //This does not throw + typedef typename Node::hook_type hook_type; + ::new(static_cast(container_detail::to_raw_pointer(p))) hook_type; + return (p); + } + + void destroy_node(const NodePtr &nodep) + { + allocator_traits::destroy(this->node_alloc(), container_detail::to_raw_pointer(nodep)); + this->deallocate_one(nodep); + } + + void swap(node_alloc_holder &x) + { + this->icont().swap(x.icont()); + container_detail::bool_ flag; + container_detail::swap_alloc(this->node_alloc(), x.node_alloc(), flag); + } + + template + void allocate_many_and_construct + (FwdIterator beg, difference_type n, Inserter inserter) + { + /* + NodePtr p = this->allocate_one(); + Deallocator node_deallocator(p, this->node_alloc()); + ::boost::container::construct_in_place(this->node_alloc(), container_detail::addressof(p->m_data), it); + node_deallocator.release(); + //This does not throw + typedef typename Node::hook_type hook_type; + ::new(static_cast(container_detail::to_raw_pointer(p))) hook_type; + return (p); + */ + typedef typename NodeAlloc::multiallocation_chain multiallocation_chain; + + //Try to allocate memory in a single block + typedef typename multiallocation_chain::iterator multialloc_iterator; + multiallocation_chain mem; + this->node_alloc().allocate_individual(n, mem); + multialloc_iterator itbeg(mem.begin()), itlast(mem.last()); + mem.clear(); + Node *p = 0; + NodeAlloc &nalloc = this->node_alloc(); + BOOST_TRY{ + while(n--){ + p = container_detail::to_raw_pointer(&*itbeg); + ++itbeg; + //This can throw + Deallocator node_deallocator(p, nalloc); + boost::container::construct_in_place(nalloc, container_detail::addressof(p->m_data), beg); + ++beg; + node_deallocator.release(); + //This does not throw + typedef typename Node::hook_type hook_type; + ::new(static_cast(p)) hook_type; + //This can throw in some containers (predicate might throw) + inserter(*p); + } + } + BOOST_CATCH(...){ + mem.incorporate_after(mem.last(), &*itbeg, &*itlast, n); + this->node_alloc().deallocate_individual(mem); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + void clear(allocator_v1) + { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } + + void clear(allocator_v2) + { + typename NodeAlloc::multiallocation_chain chain; + allocator_destroyer_and_chain_builder builder(this->node_alloc(), chain); + this->icont().clear_and_dispose(builder); + //BOOST_STATIC_ASSERT((::boost::has_move_emulation_enabled::value == true)); + if(!chain.empty()) + this->node_alloc().deallocate_individual(chain); + } + + icont_iterator erase_range(const icont_iterator &first, const icont_iterator &last, allocator_v1) + { return this->icont().erase_and_dispose(first, last, Destroyer(this->node_alloc())); } + + icont_iterator erase_range(const icont_iterator &first, const icont_iterator &last, allocator_v2) + { + typedef typename NodeAlloc::multiallocation_chain multiallocation_chain; + NodeAlloc & nalloc = this->node_alloc(); + multiallocation_chain chain; + allocator_destroyer_and_chain_builder chain_builder(nalloc, chain); + icont_iterator ret_it = this->icont().erase_and_dispose(first, last, chain_builder); + nalloc.deallocate_individual(chain); + return ret_it; + } + + template + size_type erase_key(const Key& k, const Comparator &comp, allocator_v1) + { return this->icont().erase_and_dispose(k, comp, Destroyer(this->node_alloc())); } + + template + size_type erase_key(const Key& k, const Comparator &comp, allocator_v2) + { + allocator_multialloc_chain_node_deallocator chain_holder(this->node_alloc()); + return this->icont().erase_and_dispose(k, comp, chain_holder.get_chain_builder()); + } + + protected: + struct cloner + { + cloner(node_alloc_holder &holder) + : m_holder(holder) + {} + + NodePtr operator()(const Node &other) const + { return m_holder.create_node(other.get_data()); } + + node_alloc_holder &m_holder; + }; + + struct members_holder + : public NodeAlloc + { + private: + members_holder(const members_holder&); + members_holder & operator=(const members_holder&); + + public: + members_holder() + : NodeAlloc(), m_icont() + {} + + template + explicit members_holder(BOOST_FWD_REF(ConvertibleToAlloc) c2alloc) + : NodeAlloc(boost::forward(c2alloc)) + , m_icont() + {} + + template + members_holder(BOOST_FWD_REF(ConvertibleToAlloc) c2alloc, const Pred &c) + : NodeAlloc(boost::forward(c2alloc)) + , m_icont(typename ICont::value_compare(c)) + {} + + explicit members_holder(const Pred &c) + : NodeAlloc() + , m_icont(typename ICont::value_compare(c)) + {} + + //The intrusive container + ICont m_icont; + }; + + ICont &non_const_icont() const + { return const_cast(this->members_.m_icont); } + + ICont &icont() + { return this->members_.m_icont; } + + const ICont &icont() const + { return this->members_.m_icont; } + + NodeAlloc &node_alloc() + { return static_cast(this->members_); } + + const NodeAlloc &node_alloc() const + { return static_cast(this->members_); } + + members_holder members_; +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#include + +#endif // BOOST_CONTAINER_DETAIL_NODE_ALLOC_HPP_ diff --git a/cpp/BoostParts/boost/container/detail/transform_iterator.hpp b/cpp/BoostParts/boost/container/detail/transform_iterator.hpp new file mode 100644 index 00000000..98f5c04d --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/transform_iterator.hpp @@ -0,0 +1,176 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_CONTAINER_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include "config_begin.hpp" +#include +#include +#include + +namespace boost { +namespace container { + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(const PseudoReference &px) + : m_value(px) + {} + + PseudoReference* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable PseudoReference m_value; +}; + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(T &px) + : m_value(px) + {} + + T* operator->() const { return const_cast(&m_value); } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + T &m_value; +}; + +template +class transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename container_detail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , typename UnaryFunction::result_type> +{ + public: + explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) + : UnaryFunction(f), m_it(it) + {} + + explicit transform_iterator() + : UnaryFunction(), m_it() + {} + + //Constructors + transform_iterator& operator++() + { increment(); return *this; } + + transform_iterator operator++(int) + { + transform_iterator result (*this); + increment(); + return result; + } + + friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + { return !(i == i2); } + +/* + friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + { return !(i < i2); } +*/ + friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + transform_iterator& operator+=(typename Iterator::difference_type off) + { this->advance(off); return *this; } + + transform_iterator operator+(typename Iterator::difference_type off) const + { + transform_iterator other(*this); + other.advance(off); + return other; + } + + friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + { return right + off; } + + transform_iterator& operator-=(typename Iterator::difference_type off) + { this->advance(-off); return *this; } + + transform_iterator operator-(typename Iterator::difference_type off) const + { return *this + (-off); } + + typename UnaryFunction::result_type operator*() const + { return dereference(); } + + operator_arrow_proxy + operator->() const + { return operator_arrow_proxy(dereference()); } + + Iterator & base() + { return m_it; } + + const Iterator & base() const + { return m_it; } + + private: + Iterator m_it; + + void increment() + { ++m_it; } + + void decrement() + { --m_it; } + + bool equal(const transform_iterator &other) const + { return m_it == other.m_it; } + + bool less(const transform_iterator &other) const + { return other.m_it < m_it; } + + typename UnaryFunction::result_type dereference() const + { return UnaryFunction::operator()(*m_it); } + + void advance(typename Iterator::difference_type n) + { std::advance(m_it, n); } + + typename Iterator::difference_type distance_to(const transform_iterator &other)const + { return std::distance(other.m_it, m_it); } +}; + +template +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_DETAIL_TRANSFORM_ITERATORS_HPP diff --git a/cpp/BoostParts/boost/container/detail/tree.hpp b/cpp/BoostParts/boost/container/detail/tree.hpp new file mode 100644 index 00000000..9cb3c9f8 --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/tree.hpp @@ -0,0 +1,1134 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TREE_HPP +#define BOOST_CONTAINER_TREE_HPP + +#include "config_begin.hpp" +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef BOOST_CONTAINER_PERFECT_FORWARDING +#include +#endif + +#include //std::pair +#include +#include + +namespace boost { +namespace container { +namespace container_detail { + +template +struct tree_value_compare + : public KeyCompare +{ + typedef Value value_type; + typedef KeyCompare key_compare; + typedef KeyOfValue key_of_value; + typedef Key key_type; + + tree_value_compare(const key_compare &kcomp) + : key_compare(kcomp) + {} + + const key_compare &key_comp() const + { return static_cast(*this); } + + key_compare &key_comp() + { return static_cast(*this); } + + template + struct is_key + { + static const bool value = is_same::value; + }; + + template + typename enable_if_c::value, const key_type &>::type + key_forward(const T &key) const + { return key; } + + template + typename enable_if_c::value, const key_type &>::type + key_forward(const T &key) const + { return KeyOfValue()(key); } + + template + bool operator()(const KeyType &key1, const KeyType2 &key2) const + { return key_compare::operator()(this->key_forward(key1), this->key_forward(key2)); } +}; + +template +struct rbtree_hook +{ + typedef typename container_detail::bi::make_set_base_hook + < container_detail::bi::void_pointer + , container_detail::bi::link_mode + , container_detail::bi::optimize_size + >::type type; +}; + +//This trait is used to type-pun std::pair because in C++03 +//compilers std::pair is useless for C++11 features +template +struct rbtree_internal_data_type +{ + typedef T type; +}; + +template +struct rbtree_internal_data_type< std::pair > +{ + typedef pair type; +}; + + +//The node to be store in the tree +template +struct rbtree_node + : public rbtree_hook::type +{ + private: + //BOOST_COPYABLE_AND_MOVABLE(rbtree_node) + rbtree_node(); + + public: + typedef typename rbtree_hook::type hook_type; + + typedef T value_type; + typedef typename rbtree_internal_data_type::type internal_type; + + typedef rbtree_node node_type; + + T &get_data() + { + T* ptr = reinterpret_cast(&this->m_data); + return *ptr; + } + + const T &get_data() const + { + const T* ptr = reinterpret_cast(&this->m_data); + return *ptr; + } + + internal_type m_data; + + template + void do_assign(const std::pair &p) + { + const_cast(m_data.first) = p.first; + m_data.second = p.second; + } + + template + void do_assign(const pair &p) + { + const_cast(m_data.first) = p.first; + m_data.second = p.second; + } + + template + void do_assign(const V &v) + { m_data = v; } + + template + void do_move_assign(std::pair &p) + { + const_cast(m_data.first) = ::boost::move(p.first); + m_data.second = ::boost::move(p.second); + } + + template + void do_move_assign(pair &p) + { + const_cast(m_data.first) = ::boost::move(p.first); + m_data.second = ::boost::move(p.second); + } + + template + void do_move_assign(V &v) + { m_data = ::boost::move(v); } +}; + +}//namespace container_detail { + +namespace container_detail { + +template +struct intrusive_rbtree_type +{ + typedef typename boost::container:: + allocator_traits::value_type value_type; + typedef typename boost::container:: + allocator_traits::void_pointer void_pointer; + typedef typename boost::container:: + allocator_traits::size_type size_type; + typedef typename container_detail::rbtree_node + node_type; + typedef node_compare node_compare_type; + typedef typename container_detail::bi::make_rbtree + + ,container_detail::bi::base_hook::type> + ,container_detail::bi::constant_time_size + ,container_detail::bi::size_type + >::type container_type; + typedef container_type type ; +}; + +} //namespace container_detail { + +namespace container_detail { + +template +class rbtree + : protected container_detail::node_alloc_holder + < A + , typename container_detail::intrusive_rbtree_type + + >::type + , KeyCompare + > +{ + typedef typename container_detail::intrusive_rbtree_type + < A, tree_value_compare + + >::type Icont; + typedef container_detail::node_alloc_holder + AllocHolder; + typedef typename AllocHolder::NodePtr NodePtr; + typedef rbtree < Key, Value, KeyOfValue + , KeyCompare, A> ThisType; + typedef typename AllocHolder::NodeAlloc NodeAlloc; + typedef typename AllocHolder::ValAlloc ValAlloc; + typedef typename AllocHolder::Node Node; + typedef typename Icont::iterator iiterator; + typedef typename Icont::const_iterator iconst_iterator; + typedef container_detail::allocator_destroyer Destroyer; + typedef typename AllocHolder::allocator_v1 allocator_v1; + typedef typename AllocHolder::allocator_v2 allocator_v2; + typedef typename AllocHolder::alloc_version alloc_version; + + class RecyclingCloner; + friend class RecyclingCloner; + + class RecyclingCloner + { + public: + RecyclingCloner(AllocHolder &holder, Icont &irbtree) + : m_holder(holder), m_icont(irbtree) + {} + + NodePtr operator()(const Node &other) const + { + if(NodePtr p = m_icont.unlink_leftmost_without_rebalance()){ + //First recycle a node (this can't throw) + BOOST_TRY{ + //This can throw + p->do_assign(other.m_data); + return p; + } + BOOST_CATCH(...){ + //If there is an exception destroy the whole source + m_holder.destroy_node(p); + while((p = m_icont.unlink_leftmost_without_rebalance())){ + m_holder.destroy_node(p); + } + BOOST_RETHROW + } + BOOST_CATCH_END + } + else{ + return m_holder.create_node(other.m_data); + } + } + + AllocHolder &m_holder; + Icont &m_icont; + }; + + class RecyclingMoveCloner; + friend class RecyclingMoveCloner; + + class RecyclingMoveCloner + { + public: + RecyclingMoveCloner(AllocHolder &holder, Icont &irbtree) + : m_holder(holder), m_icont(irbtree) + {} + + NodePtr operator()(const Node &other) const + { + if(NodePtr p = m_icont.unlink_leftmost_without_rebalance()){ + //First recycle a node (this can't throw) + BOOST_TRY{ + //This can throw + p->do_move_assign(const_cast(other).m_data); + return p; + } + BOOST_CATCH(...){ + //If there is an exception destroy the whole source + m_holder.destroy_node(p); + while((p = m_icont.unlink_leftmost_without_rebalance())){ + m_holder.destroy_node(p); + } + BOOST_RETHROW + } + BOOST_CATCH_END + } + else{ + return m_holder.create_node(other.m_data); + } + } + + AllocHolder &m_holder; + Icont &m_icont; + }; + + BOOST_COPYABLE_AND_MOVABLE(rbtree) + + public: + + typedef Key key_type; + typedef Value value_type; + typedef A allocator_type; + typedef KeyCompare key_compare; + typedef tree_value_compare< Key, Value + , KeyCompare, KeyOfValue> value_compare; + typedef typename boost::container:: + allocator_traits::pointer pointer; + typedef typename boost::container:: + allocator_traits::const_pointer const_pointer; + typedef typename boost::container:: + allocator_traits::reference reference; + typedef typename boost::container:: + allocator_traits::const_reference const_reference; + typedef typename boost::container:: + allocator_traits::size_type size_type; + typedef typename boost::container:: + allocator_traits::difference_type difference_type; + typedef difference_type rbtree_difference_type; + typedef pointer rbtree_pointer; + typedef const_pointer rbtree_const_pointer; + typedef reference rbtree_reference; + typedef const_reference rbtree_const_reference; + typedef NodeAlloc stored_allocator_type; + + private: + + template + struct key_node_compare + : private KeyValueCompare + { + key_node_compare(const KeyValueCompare &comp) + : KeyValueCompare(comp) + {} + + template + struct is_node + { + static const bool value = is_same::value; + }; + + template + typename enable_if_c::value, const value_type &>::type + key_forward(const T &node) const + { return node.get_data(); } + + template + typename enable_if_c::value, const T &>::type + key_forward(const T &key) const + { return key; } + + template + bool operator()(const KeyType &key1, const KeyType2 &key2) const + { return KeyValueCompare::operator()(this->key_forward(key1), this->key_forward(key2)); } + }; + + typedef key_node_compare KeyNodeCompare; + + public: + //rbtree const_iterator + class const_iterator + : public std::iterator + < std::bidirectional_iterator_tag + , value_type , rbtree_difference_type + , rbtree_const_pointer , rbtree_const_reference> + { + protected: + typedef typename Icont::iterator iiterator; + iiterator m_it; + explicit const_iterator(iiterator it) : m_it(it){} + void prot_incr() { ++m_it; } + void prot_decr() { --m_it; } + + private: + iiterator get() + { return this->m_it; } + + public: + friend class rbtree ; + typedef rbtree_difference_type difference_type; + + //Constructors + const_iterator() + : m_it() + {} + + //Pointer like operators + const_reference operator*() const + { return m_it->get_data(); } + + const_pointer operator->() const + { return const_pointer(&m_it->get_data()); } + + //Increment / Decrement + const_iterator& operator++() + { prot_incr(); return *this; } + + const_iterator operator++(int) + { iiterator tmp = m_it; ++*this; return const_iterator(tmp); } + + const_iterator& operator--() + { prot_decr(); return *this; } + + const_iterator operator--(int) + { iiterator tmp = m_it; --*this; return const_iterator(tmp); } + + //Comparison operators + bool operator== (const const_iterator& r) const + { return m_it == r.m_it; } + + bool operator!= (const const_iterator& r) const + { return m_it != r.m_it; } + }; + + //rbtree iterator + class iterator : public const_iterator + { + private: + explicit iterator(iiterator it) + : const_iterator(it) + {} + + iiterator get() + { return this->m_it; } + + public: + friend class rbtree ; + typedef rbtree_pointer pointer; + typedef rbtree_reference reference; + + //Constructors + iterator(){} + + //Pointer like operators + reference operator*() const + { return this->m_it->get_data(); } + pointer operator->() const + { return boost::intrusive::pointer_traits::pointer_to(this->m_it->get_data()); } + + //Increment / Decrement + iterator& operator++() + { this->prot_incr(); return *this; } + + iterator operator++(int) + { iiterator tmp = this->m_it; ++*this; return iterator(tmp); } + + iterator& operator--() + { this->prot_decr(); return *this; } + + iterator operator--(int) + { iterator tmp = *this; --*this; return tmp; } + }; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + rbtree() + : AllocHolder(key_compare()) + {} + + rbtree(const key_compare& comp, const allocator_type& a = allocator_type()) + : AllocHolder(a, comp) + {} + + template + rbtree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, + const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + || container_detail::is_same::value + >::type * = 0 + #endif + ) + : AllocHolder(a, comp) + { + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + this->insert_equal(first, last); + } + } + + template + rbtree(bool unique_insertion, InputIterator first, InputIterator last, const key_compare& comp, + const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator::value + || container_detail::is_same::value) + >::type * = 0 + #endif + ) + : AllocHolder(a, comp) + { + if(unique_insertion){ + this->insert_unique(first, last); + } + else{ + //Optimized allocation and construction + this->allocate_many_and_construct + (first, std::distance(first, last), insert_equal_end_hint_functor(this->icont())); + } + } + + template + rbtree( ordered_range_t, InputIterator first, InputIterator last + , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < container_detail::is_input_iterator::value + || container_detail::is_same::value + >::type * = 0 + #endif + ) + : AllocHolder(a, comp) + { + this->insert_equal(first, last); + } + + template + rbtree( ordered_range_t, InputIterator first, InputIterator last + , const key_compare& comp = key_compare(), const allocator_type& a = allocator_type() + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename container_detail::enable_if_c + < !(container_detail::is_input_iterator::value + || container_detail::is_same::value) + >::type * = 0 + #endif + ) + : AllocHolder(a, comp) + { + //Optimized allocation and construction + this->allocate_many_and_construct + (first, std::distance(first, last), push_back_functor(this->icont())); + } + + rbtree(const rbtree& x) + : AllocHolder(x, x.key_comp()) + { + this->icont().clone_from + (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); + } + + rbtree(BOOST_RV_REF(rbtree) x) + : AllocHolder(::boost::move(static_cast(x)), x.key_comp()) + {} + + rbtree(const rbtree& x, const allocator_type &a) + : AllocHolder(a, x.key_comp()) + { + this->icont().clone_from + (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); + } + + rbtree(BOOST_RV_REF(rbtree) x, const allocator_type &a) + : AllocHolder(a, x.key_comp()) + { + if(this->node_alloc() == x.node_alloc()){ + this->icont().swap(x.icont()); + } + else{ + this->icont().clone_from + (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); + } + } + + ~rbtree() + {} //AllocHolder clears the tree + + rbtree& operator=(BOOST_COPY_ASSIGN_REF(rbtree) x) + { + if (&x != this){ + NodeAlloc &this_alloc = this->get_stored_allocator(); + const NodeAlloc &x_alloc = x.get_stored_allocator(); + container_detail::bool_:: + propagate_on_container_copy_assignment::value> flag; + if(flag && this_alloc != x_alloc){ + this->clear(); + } + this->AllocHolder::copy_assign_alloc(x); + //Transfer all the nodes to a temporary tree + //If anything goes wrong, all the nodes will be destroyed + //automatically + Icont other_tree(::boost::move(this->icont())); + + //Now recreate the source tree reusing nodes stored by other_tree + this->icont().clone_from + (x.icont() + , RecyclingCloner(*this, other_tree) + , Destroyer(this->node_alloc())); + + //If there are remaining nodes, destroy them + NodePtr p; + while((p = other_tree.unlink_leftmost_without_rebalance())){ + AllocHolder::destroy_node(p); + } + } + return *this; + } + + rbtree& operator=(BOOST_RV_REF(rbtree) x) + { + if (&x != this){ + NodeAlloc &this_alloc = this->node_alloc(); + NodeAlloc &x_alloc = x.node_alloc(); + //If allocators are equal we can just swap pointers + if(this_alloc == x_alloc){ + //Destroy and swap pointers + this->clear(); + this->icont() = ::boost::move(x.icont()); + //Move allocator if needed + this->AllocHolder::move_assign_alloc(x); + } + //If unequal allocators, then do a one by one move + else{ + //Transfer all the nodes to a temporary tree + //If anything goes wrong, all the nodes will be destroyed + //automatically + Icont other_tree(::boost::move(this->icont())); + + //Now recreate the source tree reusing nodes stored by other_tree + this->icont().clone_from + (x.icont() + , RecyclingMoveCloner(*this, other_tree) + , Destroyer(this->node_alloc())); + + //If there are remaining nodes, destroy them + NodePtr p; + while((p = other_tree.unlink_leftmost_without_rebalance())){ + AllocHolder::destroy_node(p); + } + } + } + return *this; + } + + public: + // accessors: + value_compare value_comp() const + { return this->icont().value_comp().value_comp(); } + + key_compare key_comp() const + { return this->icont().value_comp().value_comp().key_comp(); } + + allocator_type get_allocator() const + { return allocator_type(this->node_alloc()); } + + const stored_allocator_type &get_stored_allocator() const + { return this->node_alloc(); } + + stored_allocator_type &get_stored_allocator() + { return this->node_alloc(); } + + iterator begin() + { return iterator(this->icont().begin()); } + + const_iterator begin() const + { return this->cbegin(); } + + iterator end() + { return iterator(this->icont().end()); } + + const_iterator end() const + { return this->cend(); } + + reverse_iterator rbegin() + { return reverse_iterator(end()); } + + const_reverse_iterator rbegin() const + { return this->crbegin(); } + + reverse_iterator rend() + { return reverse_iterator(begin()); } + + const_reverse_iterator rend() const + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(cend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(cbegin()); } + + bool empty() const + { return !this->size(); } + + size_type size() const + { return this->icont().size(); } + + size_type max_size() const + { return AllocHolder::max_size(); } + + void swap(ThisType& x) + { AllocHolder::swap(x); } + + public: + + typedef typename Icont::insert_commit_data insert_commit_data; + + // insert/erase + std::pair insert_unique_check + (const key_type& key, insert_commit_data &data) + { + std::pair ret = + this->icont().insert_unique_check(key, KeyNodeCompare(value_comp()), data); + return std::pair(iterator(ret.first), ret.second); + } + + std::pair insert_unique_check + (const_iterator hint, const key_type& key, insert_commit_data &data) + { + std::pair ret = + this->icont().insert_unique_check(hint.get(), key, KeyNodeCompare(value_comp()), data); + return std::pair(iterator(ret.first), ret.second); + } + + iterator insert_unique_commit(const value_type& v, insert_commit_data &data) + { + NodePtr tmp = AllocHolder::create_node(v); + iiterator it(this->icont().insert_unique_commit(*tmp, data)); + return iterator(it); + } + + template + iterator insert_unique_commit + (BOOST_FWD_REF(MovableConvertible) mv, insert_commit_data &data) + { + NodePtr tmp = AllocHolder::create_node(boost::forward(mv)); + iiterator it(this->icont().insert_unique_commit(*tmp, data)); + return iterator(it); + } + + std::pair insert_unique(const value_type& v) + { + insert_commit_data data; + std::pair ret = + this->insert_unique_check(KeyOfValue()(v), data); + if(!ret.second) + return ret; + return std::pair + (this->insert_unique_commit(v, data), true); + } + + template + std::pair insert_unique(BOOST_FWD_REF(MovableConvertible) mv) + { + insert_commit_data data; + std::pair ret = + this->insert_unique_check(KeyOfValue()(mv), data); + if(!ret.second) + return ret; + return std::pair + (this->insert_unique_commit(boost::forward(mv), data), true); + } + + private: + std::pair emplace_unique_impl(NodePtr p) + { + value_type &v = p->get_data(); + insert_commit_data data; + scoped_destroy_deallocator destroy_deallocator(p, this->node_alloc()); + std::pair ret = + this->insert_unique_check(KeyOfValue()(v), data); + if(!ret.second){ + return ret; + } + //No throw insertion part, release rollback + destroy_deallocator.release(); + return std::pair + ( iterator(iiterator(this->icont().insert_unique_commit(*p, data))) + , true ); + } + + iterator emplace_unique_hint_impl(const_iterator hint, NodePtr p) + { + value_type &v = p->get_data(); + insert_commit_data data; + std::pair ret = + this->insert_unique_check(hint, KeyOfValue()(v), data); + if(!ret.second){ + Destroyer(this->node_alloc())(p); + return ret.first; + } + return iterator(iiterator(this->icont().insert_unique_commit(*p, data))); + } + + public: + + #ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + template + std::pair emplace_unique(Args&&... args) + { return this->emplace_unique_impl(AllocHolder::create_node(boost::forward(args)...)); } + + template + iterator emplace_hint_unique(const_iterator hint, Args&&... args) + { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(boost::forward(args)...)); } + + template + iterator emplace_equal(Args&&... args) + { + NodePtr p(AllocHolder::create_node(boost::forward(args)...)); + return iterator(this->icont().insert_equal(this->icont().end(), *p)); + } + + template + iterator emplace_hint_equal(const_iterator hint, Args&&... args) + { + NodePtr p(AllocHolder::create_node(boost::forward(args)...)); + return iterator(this->icont().insert_equal(hint.get(), *p)); + } + + #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + std::pair emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + return this->emplace_unique_impl \ + (AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + } \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace_hint_unique(const_iterator hint \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + return this->emplace_unique_hint_impl \ + (hint, AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + } \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + return iterator(this->icont().insert_equal(this->icont().end(), *p)); \ + } \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace_hint_equal(const_iterator hint \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _))); \ + return iterator(this->icont().insert_equal(hint.get(), *p)); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + iterator insert_unique(const_iterator hint, const value_type& v) + { + insert_commit_data data; + std::pair ret = + this->insert_unique_check(hint, KeyOfValue()(v), data); + if(!ret.second) + return ret.first; + return this->insert_unique_commit(v, data); + } + + template + iterator insert_unique(const_iterator hint, BOOST_FWD_REF(MovableConvertible) mv) + { + insert_commit_data data; + std::pair ret = + this->insert_unique_check(hint, KeyOfValue()(mv), data); + if(!ret.second) + return ret.first; + return this->insert_unique_commit(boost::forward(mv), data); + } + + template + void insert_unique(InputIterator first, InputIterator last) + { + if(this->empty()){ + //Insert with end hint, to achieve linear + //complexity if [first, last) is ordered + const_iterator hint(this->cend()); + for( ; first != last; ++first) + hint = this->insert_unique(hint, *first); + } + else{ + for( ; first != last; ++first) + this->insert_unique(*first); + } + } + + iterator insert_equal(const value_type& v) + { + NodePtr p(AllocHolder::create_node(v)); + return iterator(this->icont().insert_equal(this->icont().end(), *p)); + } + + template + iterator insert_equal(BOOST_FWD_REF(MovableConvertible) mv) + { + NodePtr p(AllocHolder::create_node(boost::forward(mv))); + return iterator(this->icont().insert_equal(this->icont().end(), *p)); + } + + iterator insert_equal(const_iterator hint, const value_type& v) + { + NodePtr p(AllocHolder::create_node(v)); + return iterator(this->icont().insert_equal(hint.get(), *p)); + } + + template + iterator insert_equal(const_iterator hint, BOOST_FWD_REF(MovableConvertible) mv) + { + NodePtr p(AllocHolder::create_node(boost::forward(mv))); + return iterator(this->icont().insert_equal(hint.get(), *p)); + } + + template + void insert_equal(InputIterator first, InputIterator last) + { + //Insert with end hint, to achieve linear + //complexity if [first, last) is ordered + const_iterator hint(this->cend()); + for( ; first != last; ++first) + hint = this->insert_equal(hint, *first); + } + + iterator erase(const_iterator position) + { return iterator(this->icont().erase_and_dispose(position.get(), Destroyer(this->node_alloc()))); } + + size_type erase(const key_type& k) + { return AllocHolder::erase_key(k, KeyNodeCompare(value_comp()), alloc_version()); } + + iterator erase(const_iterator first, const_iterator last) + { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } + + void clear() + { AllocHolder::clear(alloc_version()); } + + // set operations: + iterator find(const key_type& k) + { return iterator(this->icont().find(k, KeyNodeCompare(value_comp()))); } + + const_iterator find(const key_type& k) const + { return const_iterator(this->non_const_icont().find(k, KeyNodeCompare(value_comp()))); } + + size_type count(const key_type& k) const + { return size_type(this->icont().count(k, KeyNodeCompare(value_comp()))); } + + iterator lower_bound(const key_type& k) + { return iterator(this->icont().lower_bound(k, KeyNodeCompare(value_comp()))); } + + const_iterator lower_bound(const key_type& k) const + { return const_iterator(this->non_const_icont().lower_bound(k, KeyNodeCompare(value_comp()))); } + + iterator upper_bound(const key_type& k) + { return iterator(this->icont().upper_bound(k, KeyNodeCompare(value_comp()))); } + + const_iterator upper_bound(const key_type& k) const + { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(value_comp()))); } + + std::pair equal_range(const key_type& k) + { + std::pair ret = + this->icont().equal_range(k, KeyNodeCompare(value_comp())); + return std::pair(iterator(ret.first), iterator(ret.second)); + } + + std::pair equal_range(const key_type& k) const + { + std::pair ret = + this->non_const_icont().equal_range(k, KeyNodeCompare(value_comp())); + return std::pair + (const_iterator(ret.first), const_iterator(ret.second)); + } + + private: + + class insert_equal_end_hint_functor; + friend class insert_equal_end_hint_functor; + + class insert_equal_end_hint_functor + { + Icont &icont_; + const iconst_iterator cend_; + + public: + insert_equal_end_hint_functor(Icont &icont) + : icont_(icont), cend_(this->icont_.cend()) + {} + + void operator()(Node &n) + { this->icont_.insert_equal(cend_, n); } + }; + + class push_back_functor; + friend class push_back_functor; + + class push_back_functor + { + Icont &icont_; + + public: + push_back_functor(Icont &icont) + : icont_(icont) + {} + + void operator()(Node &n) + { this->icont_.push_back(n); } + }; +}; + +template +inline bool +operator==(const rbtree& x, + const rbtree& y) +{ + return x.size() == y.size() && + std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const rbtree& x, + const rbtree& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), + y.begin(), y.end()); +} + +template +inline bool +operator!=(const rbtree& x, + const rbtree& y) { + return !(x == y); +} + +template +inline bool +operator>(const rbtree& x, + const rbtree& y) { + return y < x; +} + +template +inline bool +operator<=(const rbtree& x, + const rbtree& y) { + return !(y < x); +} + +template +inline bool +operator>=(const rbtree& x, + const rbtree& y) { + return !(x < y); +} + + +template +inline void +swap(rbtree& x, + rbtree& y) +{ + x.swap(y); +} + +} //namespace container_detail { +} //namespace container { +/* +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move + > +{ + static const bool value = has_trivial_destructor_after_move::value && has_trivial_destructor_after_move::value; +}; +*/ +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_TREE_HPP diff --git a/cpp/BoostParts/boost/container/detail/value_init.hpp b/cpp/BoostParts/boost/container/detail/value_init.hpp new file mode 100644 index 00000000..ec1a99c5 --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/value_init.hpp @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_VALUE_INIT_HPP +#define BOOST_CONTAINER_DETAIL_VALUE_INIT_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include "config_begin.hpp" +#include + +namespace boost { +namespace container { +namespace container_detail { + +template +struct value_init +{ + value_init() + : m_t() + {} + + operator T &() { return m_t; } + + T m_t; +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_DETAIL_VALUE_INIT_HPP diff --git a/cpp/BoostParts/boost/container/detail/variadic_templates_tools.hpp b/cpp/BoostParts/boost/container/detail/variadic_templates_tools.hpp new file mode 100644 index 00000000..d903dfa0 --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/variadic_templates_tools.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP +#define BOOST_CONTAINER_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include "config_begin.hpp" +#include +#include +#include //std::size_t + +namespace boost { +namespace container { +namespace container_detail { + +template +class tuple; + +template<> class tuple<> +{}; + +template +class tuple + : private tuple +{ + typedef tuple inherited; + + public: + tuple() { } + + // implicit copy-constructor is okay + // Construct tuple from separate arguments. + tuple(typename add_const_reference::type v, + typename add_const_reference::type... vtail) + : inherited(vtail...), m_head(v) + {} + + // Construct tuple from another tuple. + template + tuple(const tuple& other) + : m_head(other.head()), inherited(other.tail()) + {} + + template + tuple& operator=(const tuple& other) + { + m_head = other.head(); + tail() = other.tail(); + return this; + } + + typename add_reference::type head() { return m_head; } + typename add_reference::type head() const { return m_head; } + + inherited& tail() { return *this; } + const inherited& tail() const { return *this; } + + protected: + Head m_head; +}; + + +template +tuple tie_forward(Values&&... values) +{ return tuple(values...); } + +template +struct tuple_element; + +template +struct tuple_element > +{ + typedef typename tuple_element >::type type; +}; + +template +struct tuple_element<0, tuple > +{ + typedef Head type; +}; + +template +class get_impl; + +template +class get_impl > +{ + typedef typename tuple_element >::type Element; + typedef get_impl > Next; + + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return Next::get(t.tail()); } + static const_type get(const tuple& t) { return Next::get(t.tail()); } +}; + +template +class get_impl<0, tuple > +{ + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return t.head(); } + static const_type get(const tuple& t){ return t.head(); } +}; + +template +typename get_impl >::type get(tuple& t) +{ return get_impl >::get(t); } + +template +typename get_impl >::const_type get(const tuple& t) +{ return get_impl >::get(t); } + +//////////////////////////////////////////////////// +// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will +// be used to "unpack" into comma-separated values +// in a function call. +//////////////////////////////////////////////////// + +template +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + + +}}} //namespace boost { namespace container { namespace container_detail { + +#include + +#endif //#ifndef BOOST_CONTAINER_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP diff --git a/cpp/BoostParts/boost/container/detail/version_type.hpp b/cpp/BoostParts/boost/container/detail/version_type.hpp new file mode 100644 index 00000000..e47ba26f --- /dev/null +++ b/cpp/BoostParts/boost/container/detail/version_type.hpp @@ -0,0 +1,92 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This code comes from N1953 document by Howard E. Hinnant +// +////////////////////////////////////////////////////////////////////////////// + + +#ifndef BOOST_CONTAINER_DETAIL_VERSION_TYPE_HPP +#define BOOST_CONTAINER_DETAIL_VERSION_TYPE_HPP + +#include "config_begin.hpp" + +#include +#include + +namespace boost{ +namespace container { +namespace container_detail { + +//using namespace boost; + +template +struct version_type + : public container_detail::integral_constant +{ + typedef T type; + + version_type(const version_type&); +}; + +namespace impl{ + +template , typename T::version>::value> +struct extract_version +{ + static const unsigned value = 1; +}; + +template +struct extract_version +{ + static const unsigned value = T::version::value; +}; + +template +struct has_version +{ + private: + struct two {char _[2];}; + template static two test(...); + template static char test(const typename U::version*); + public: + static const bool value = sizeof(test(0)) == 1; + void dummy(){} +}; + +template ::value> +struct version +{ + static const unsigned value = 1; +}; + +template +struct version +{ + static const unsigned value = extract_version::value; +}; + +} //namespace impl + +template +struct version + : public container_detail::integral_constant::value> +{ +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost{ + +#include "config_end.hpp" + +#endif //#define BOOST_CONTAINER_DETAIL_VERSION_TYPE_HPP diff --git a/cpp/BoostParts/boost/container/map.hpp b/cpp/BoostParts/boost/container/map.hpp new file mode 100644 index 00000000..d4ab4236 --- /dev/null +++ b/cpp/BoostParts/boost/container/map.hpp @@ -0,0 +1,1507 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_MAP_HPP +#define BOOST_CONTAINER_MAP_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace container { + +/// @cond +// Forward declarations of operators == and <, needed for friend declarations. +template +inline bool operator==(const map& x, + const map& y); + +template +inline bool operator<(const map& x, + const map& y); +/// @endcond + +//! A 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. The map class supports bidirectional iterators. +//! +//! A map satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! map the key_type is Key and the value_type is std::pair. +//! +//! Compare is the ordering function for Keys (e.g. std::less). +//! +//! Allocator is the allocator to allocate the value_types +//! (e.g. allocator< std::pair > ). +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED +template , class Allocator = std::allocator< std::pair< const Key, T> > > +#else +template +#endif +class map +{ + /// @cond + private: + BOOST_COPYABLE_AND_MOVABLE(map) + + typedef std::pair value_type_impl; + typedef container_detail::rbtree + , Compare, Allocator> tree_t; + typedef container_detail::pair movable_value_type_impl; + typedef container_detail::tree_value_compare + < Key, value_type_impl, Compare, container_detail::select1st + > value_compare_impl; + tree_t m_tree; // red-black tree representing map + /// @endcond + + public: + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// + + typedef Key key_type; + typedef T mapped_type; + typedef std::pair value_type; + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::const_pointer const_pointer; + typedef typename boost::container::allocator_traits::reference reference; + typedef typename boost::container::allocator_traits::const_reference const_reference; + typedef typename boost::container::allocator_traits::size_type size_type; + typedef typename boost::container::allocator_traits::difference_type difference_type; + typedef Allocator allocator_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::stored_allocator_type) stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(value_compare_impl) value_compare; + typedef Compare key_compare; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::iterator) iterator; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::const_iterator) const_iterator; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::reverse_iterator) reverse_iterator; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::const_reverse_iterator) const_reverse_iterator; + typedef std::pair nonconst_value_type; + typedef BOOST_CONTAINER_IMPDEF(movable_value_type_impl) movable_value_type; + + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// + + //! Effects: Default constructs an empty map. + //! + //! Complexity: Constant. + map() + : m_tree() + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Constructs an empty map using the specified comparison object + //! and allocator. + //! + //! Complexity: Constant. + explicit map(const Compare& comp, + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Constructs an empty map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + map(InputIterator first, InputIterator last, const Compare& comp = Compare(), + const allocator_type& a = allocator_type()) + : m_tree(true, first, last, comp, a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Constructs an empty map using the specified comparison object and + //! allocator, and inserts elements from the ordered unique range [first ,last). This function + //! is more efficient than the normal range creation for ordered ranges. + //! + //! Requires: [first ,last) must be ordered according to the predicate and must be + //! unique values. + //! + //! Complexity: Linear in N. + template + map( ordered_unique_range_t, InputIterator first, InputIterator last + , const Compare& comp = Compare(), const allocator_type& a = allocator_type()) + : m_tree(ordered_range, first, last, comp, a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Copy constructs a map. + //! + //! Complexity: Linear in x.size(). + map(const map& x) + : m_tree(x.m_tree) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Move constructs a map. Constructs *this using x's resources. + //! + //! Complexity: Constant. + //! + //! Postcondition: x is emptied. + map(BOOST_RV_REF(map) x) + : m_tree(boost::move(x.m_tree)) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Copy constructs a map using the specified allocator. + //! + //! Complexity: Linear in x.size(). + map(const map& x, const allocator_type &a) + : m_tree(x.m_tree, a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Move constructs a map using the specified allocator. + //! Constructs *this using x's resources. + //! + //! Complexity: Constant if x == x.get_allocator(), linear otherwise. + //! + //! Postcondition: x is emptied. + map(BOOST_RV_REF(map) x, const allocator_type &a) + : m_tree(boost::move(x.m_tree), a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + map& operator=(BOOST_COPY_ASSIGN_REF(map) x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + map& operator=(BOOST_RV_REF(map) x) + { m_tree = boost::move(x.m_tree); return *this; } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.get_allocator(); } + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.get_stored_allocator(); } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() BOOST_CONTAINER_NOEXCEPT + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const BOOST_CONTAINER_NOEXCEPT + { return this->cbegin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() BOOST_CONTAINER_NOEXCEPT + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const BOOST_CONTAINER_NOEXCEPT + { return this->cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT + { return this->crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.end(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.rend(); } + + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.max_size(); } + + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: If there is no key equivalent to x in the map, inserts + //! value_type(x, T()) into the map. + //! + //! Returns: Allocator reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + mapped_type& operator[](const key_type &k); + + //! Effects: If there is no key equivalent to x in the map, inserts + //! value_type(boost::move(x), T()) into the map (the key is move-constructed) + //! + //! Returns: Allocator reference to the mapped_type corresponding to x in *this. + //! + //! Complexity: Logarithmic. + mapped_type& operator[](key_type &&k); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript) + #endif + + //! Returns: Allocator 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. + T& at(const key_type& k) + { + iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + //! Returns: Allocator 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. + const T& at(const key_type& k) const + { + const_iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); + } + return i->second; + } + + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(const value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: Inserts a new value_type created from the pair if and only if + //! there is no element in the container with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(const nonconst_value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_RV_REF(nonconst_value_type) x) + { return m_tree.insert_unique(boost::move(x)); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_RV_REF(movable_value_type) x) + { return m_tree.insert_unique(boost::move(x)); } + + //! Effects: Move constructs a new value from x if and only if there is + //! no element in the container with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_RV_REF(value_type) x) + { return m_tree.insert_unique(boost::move(x)); } + + //! Effects: 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator position, const value_type& x) + { return m_tree.insert_unique(position, x); } + + //! Effects: Move constructs a new value from x 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator position, BOOST_RV_REF(nonconst_value_type) x) + { return m_tree.insert_unique(position, boost::move(x)); } + + //! Effects: Move constructs a new value from x 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator position, BOOST_RV_REF(movable_value_type) x) + { return m_tree.insert_unique(position, boost::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(const_iterator position, const nonconst_value_type& x) + { return m_tree.insert_unique(position, x); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(const_iterator position, BOOST_RV_REF(value_type) x) + { return m_tree.insert_unique(position, boost::move(x)); } + + //! Requires: first, last are not iterators into *this. + //! + //! Effects: 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. + //! + //! Complexity: At most N log(size()+N) (N is the distance from first to last) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: Inserts an object x of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with an equivalent key. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + std::pair emplace(Args&&... args) + { return m_tree.emplace_unique(boost::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container if and only if there is + //! no element in the container with an equivalent key. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, boost::forward(args)...); } + + #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + std::pair emplace(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); } \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace_hint(const_iterator hint \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_unique(hint \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _));} \ + //! + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator position) BOOST_CONTAINER_NOEXCEPT + { return m_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) BOOST_CONTAINER_NOEXCEPT + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) BOOST_CONTAINER_NOEXCEPT + { return m_tree.erase(first, last); } + + //! Effects: Swaps the contents of *this and x. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(map& x) + { m_tree.swap(x.m_tree); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() BOOST_CONTAINER_NOEXCEPT + { m_tree.clear(); } + + ////////////////////////////////////////////// + // + // observers + // + ////////////////////////////////////////////// + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(m_tree.key_comp()); } + + ////////////////////////////////////////////// + // + // map operations + // + ////////////////////////////////////////////// + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: Allocator const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: Allocator const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: Allocator const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const map&, + const map&); + template + friend bool operator< (const map&, + const map&); + private: + mapped_type& priv_subscript(const key_type &k) + { + //we can optimize this + iterator i = lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)){ + container_detail::value_init m; + movable_value_type val(k, boost::move(m.m_t)); + i = insert(i, boost::move(val)); + } + return (*i).second; + } + + mapped_type& priv_subscript(BOOST_RV_REF(key_type) mk) + { + key_type &k = mk; + //we can optimize this + iterator i = lower_bound(k); + // i->first is greater than or equivalent to k. + if (i == end() || key_comp()(k, (*i).first)){ + container_detail::value_init m; + movable_value_type val(boost::move(k), boost::move(m.m_t)); + i = insert(i, boost::move(val)); + } + return (*i).second; + } + + /// @endcond +}; + +template +inline bool operator==(const map& x, + const map& y) + { return x.m_tree == y.m_tree; } + +template +inline bool operator<(const map& x, + const map& y) + { return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const map& x, + const map& y) + { return !(x == y); } + +template +inline bool operator>(const map& x, + const map& y) + { return y < x; } + +template +inline bool operator<=(const map& x, + const map& y) + { return !(y < x); } + +template +inline bool operator>=(const map& x, + const map& y) + { return !(x < y); } + +template +inline void swap(map& x, map& y) + { x.swap(y); } + +/// @cond + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multimap& x, + const multimap& y); + +template +inline bool operator<(const multimap& x, + const multimap& y); + +} //namespace container { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor_after_move::value && has_trivial_destructor_after_move::value; +}; + +namespace container { + +/// @endcond + +//! A 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. The multimap class +//! supports bidirectional iterators. +//! +//! A multimap satisfies all of the requirements of a container and of a reversible +//! container and of an associative container. For a +//! map the key_type is Key and the value_type is std::pair. +//! +//! Compare is the ordering function for Keys (e.g. std::less). +//! +//! Allocator is the allocator to allocate the value_types +//!(e.g. allocator< std::pair<const Key, T> >). +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED +template , class Allocator = std::allocator< std::pair< const Key, T> > > +#else +template +#endif +class multimap +{ + /// @cond + private: + BOOST_COPYABLE_AND_MOVABLE(multimap) + + typedef std::pair value_type_impl; + typedef container_detail::rbtree + , Compare, Allocator> tree_t; + typedef container_detail::pair movable_value_type_impl; + typedef container_detail::tree_value_compare + < Key, value_type_impl, Compare, container_detail::select1st + > value_compare_impl; + tree_t m_tree; // red-black tree representing map + /// @endcond + + public: + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// + + typedef Key key_type; + typedef T mapped_type; + typedef std::pair value_type; + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::const_pointer const_pointer; + typedef typename boost::container::allocator_traits::reference reference; + typedef typename boost::container::allocator_traits::const_reference const_reference; + typedef typename boost::container::allocator_traits::size_type size_type; + typedef typename boost::container::allocator_traits::difference_type difference_type; + typedef Allocator allocator_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::stored_allocator_type) stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(value_compare_impl) value_compare; + typedef Compare key_compare; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::iterator) iterator; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::const_iterator) const_iterator; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::reverse_iterator) reverse_iterator; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::const_reverse_iterator) const_reverse_iterator; + typedef std::pair nonconst_value_type; + typedef BOOST_CONTAINER_IMPDEF(movable_value_type_impl) movable_value_type; + + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// + + //! Effects: Default constructs an empty multimap. + //! + //! Complexity: Constant. + multimap() + : m_tree() + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Constructs an empty multimap using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit multimap(const Compare& comp, const allocator_type& a = allocator_type()) + : m_tree(comp, a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Constructs an empty multimap using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + multimap(InputIterator first, InputIterator last, + const Compare& comp = Compare(), + const allocator_type& a = allocator_type()) + : m_tree(false, first, last, comp, a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Constructs an empty 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. + //! + //! Requires: [first ,last) must be ordered according to the predicate. + //! + //! Complexity: Linear in N. + template + multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp = Compare(), + const allocator_type& a = allocator_type()) + : m_tree(ordered_range, first, last, comp, a) + {} + + //! Effects: Copy constructs a multimap. + //! + //! Complexity: Linear in x.size(). + multimap(const multimap& x) + : m_tree(x.m_tree) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Move constructs a multimap. Constructs *this using x's resources. + //! + //! Complexity: Constant. + //! + //! Postcondition: x is emptied. + multimap(BOOST_RV_REF(multimap) x) + : m_tree(boost::move(x.m_tree)) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Copy constructs a multimap. + //! + //! Complexity: Linear in x.size(). + multimap(const multimap& x, const allocator_type &a) + : m_tree(x.m_tree, a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Move constructs a multimap using the specified allocator. + //! Constructs *this using x's resources. + //! Complexity: Constant if a == x.get_allocator(), linear otherwise. + //! + //! Postcondition: x is emptied. + multimap(BOOST_RV_REF(multimap) x, const allocator_type &a) + : m_tree(boost::move(x.m_tree), a) + { + //Allocator type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + } + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + multimap& operator=(BOOST_COPY_ASSIGN_REF(multimap) x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + multimap& operator=(BOOST_RV_REF(multimap) x) + { m_tree = boost::move(x.m_tree); return *this; } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.get_allocator(); } + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT + { return m_tree.get_stored_allocator(); } + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.get_stored_allocator(); } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() BOOST_CONTAINER_NOEXCEPT + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const BOOST_CONTAINER_NOEXCEPT + { return this->cbegin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() BOOST_CONTAINER_NOEXCEPT + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const BOOST_CONTAINER_NOEXCEPT + { return this->cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT + { return this->crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.end(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.rend(); } + + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const BOOST_CONTAINER_NOEXCEPT + { return m_tree.max_size(); } + + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// + + #if defined(BOOST_CONTAINER_PERFECT_FORWARDING) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(boost::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, boost::forward(args)...); } + + #else //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); } \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace_hint(const_iterator hint \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_equal(hint \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _));} \ + //! + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINER_PERFECT_FORWARDING + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a new value constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const nonconst_value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(BOOST_RV_REF(nonconst_value_type) x) + { return m_tree.insert_equal(boost::move(x)); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(BOOST_RV_REF(movable_value_type) x) + { return m_tree.insert_equal(boost::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator position, const value_type& x) + { return m_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator position, const nonconst_value_type& x) + { return m_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator position, BOOST_RV_REF(nonconst_value_type) x) + { return m_tree.insert_equal(position, boost::move(x)); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator position, BOOST_RV_REF(movable_value_type) x) + { return m_tree.insert_equal(position, boost::move(x)); } + + //! Requires: first, last are not iterators into *this. + //! + //! Effects: inserts each element from the range [first,last) . + //! + //! Complexity: At most N log(size()+N) (N is the distance from first to last) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_equal(first, last); } + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator position) BOOST_CONTAINER_NOEXCEPT + { return m_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) BOOST_CONTAINER_NOEXCEPT + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: log(size())+N where N is the distance from first to last. + iterator erase(const_iterator first, const_iterator last) BOOST_CONTAINER_NOEXCEPT + { return m_tree.erase(first, last); } + + //! Effects: Swaps the contents of *this and x. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(multimap& x) + { m_tree.swap(x.m_tree); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() BOOST_CONTAINER_NOEXCEPT + { m_tree.clear(); } + + ////////////////////////////////////////////// + // + // observers + // + ////////////////////////////////////////////// + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(m_tree.key_comp()); } + + ////////////////////////////////////////////// + // + // map operations + // + ////////////////////////////////////////////// + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: Allocator const iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + {return m_tree.lower_bound(x); } + + //! Returns: Allocator const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: Allocator const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const multimap& x, + const multimap& y); + + template + friend bool operator< (const multimap& x, + const multimap& y); + /// @endcond +}; + +template +inline bool operator==(const multimap& x, + const multimap& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multimap& x, + const multimap& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multimap& x, + const multimap& y) +{ return !(x == y); } + +template +inline bool operator>(const multimap& x, + const multimap& y) +{ return y < x; } + +template +inline bool operator<=(const multimap& x, + const multimap& y) +{ return !(y < x); } + +template +inline bool operator>=(const multimap& x, + const multimap& y) +{ return !(x < y); } + +template +inline void swap(multimap& x, multimap& y) +{ x.swap(y); } + +/// @cond + +} //namespace container { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor_after_move::value && has_trivial_destructor_after_move::value; +}; + +namespace container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINER_MAP_HPP */ + diff --git a/cpp/BoostParts/boost/cstdlib.hpp b/cpp/BoostParts/boost/cstdlib.hpp new file mode 100644 index 00000000..63221463 --- /dev/null +++ b/cpp/BoostParts/boost/cstdlib.hpp @@ -0,0 +1,41 @@ +// boost/cstdlib.hpp header ------------------------------------------------// + +// Copyright Beman Dawes 2001. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/utility/cstdlib.html for documentation. + +// Revision History +// 26 Feb 01 Initial version (Beman Dawes) + +#ifndef BOOST_CSTDLIB_HPP +#define BOOST_CSTDLIB_HPP + +#include + +namespace boost +{ + // The intent is to propose the following for addition to namespace std + // in the C++ Standard Library, and to then deprecate EXIT_SUCCESS and + // EXIT_FAILURE. As an implementation detail, this header defines the + // new constants in terms of EXIT_SUCCESS and EXIT_FAILURE. In a new + // standard, the constants would be implementation-defined, although it + // might be worthwhile to "suggest" (which a standard is allowed to do) + // values of 0 and 1 respectively. + + // Rationale for having multiple failure values: some environments may + // wish to distinguish between different classes of errors. + // Rationale for choice of values: programs often use values < 100 for + // their own error reporting. Values > 255 are sometimes reserved for + // system detected errors. 200/201 were suggested to minimize conflict. + + const int exit_success = EXIT_SUCCESS; // implementation-defined value + const int exit_failure = EXIT_FAILURE; // implementation-defined value + const int exit_exception_failure = 200; // otherwise uncaught exception + const int exit_test_failure = 201; // report_error or + // report_critical_error called. +} + +#endif + diff --git a/cpp/BoostParts/boost/date_time/date_facet.hpp b/cpp/BoostParts/boost/date_time/date_facet.hpp new file mode 100644 index 00000000..fc2ddc24 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/date_facet.hpp @@ -0,0 +1,767 @@ +#ifndef _DATE_TIME_DATE_FACET__HPP___ +#define _DATE_TIME_DATE_FACET__HPP___ + +/* Copyright (c) 2004-2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Martin Andrian, Jeff Garland, Bart Garst + * $Date: 2012-09-30 16:25:22 -0700 (Sun, 30 Sep 2012) $ + */ + +#include +#include +#include +#include // ostreambuf_iterator +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace date_time { + + + /*! Class that provides format based I/O facet for date types. + * + * This class allows the formatting of dates by using format string. + * Format strings are: + * + * - %A => long_weekday_format - Full name Ex: Tuesday + * - %a => short_weekday_format - Three letter abbreviation Ex: Tue + * - %B => long_month_format - Full name Ex: October + * - %b => short_month_format - Three letter abbreviation Ex: Oct + * - %x => standard_format_specifier - defined by the locale + * - %Y-%b-%d => default_date_format - YYYY-Mon-dd + * + * Default month format == %b + * Default weekday format == %a + */ + template > > + class date_facet : public std::locale::facet { + public: + typedef typename date_type::duration_type duration_type; + // greg_weekday is gregorian_calendar::day_of_week_type + typedef typename date_type::day_of_week_type day_of_week_type; + typedef typename date_type::day_type day_type; + typedef typename date_type::month_type month_type; + typedef boost::date_time::period period_type; + typedef std::basic_string string_type; + typedef CharT char_type; + typedef boost::date_time::period_formatter period_formatter_type; + typedef boost::date_time::special_values_formatter special_values_formatter_type; + typedef std::vector > input_collection_type; + // used for the output of the date_generators + typedef date_generator_formatter date_gen_formatter_type; + typedef partial_date partial_date_type; + typedef nth_kday_of_month nth_kday_type; + typedef first_kday_of_month first_kday_type; + typedef last_kday_of_month last_kday_type; + typedef first_kday_after kday_after_type; + typedef first_kday_before kday_before_type; + static const char_type long_weekday_format[3]; + static const char_type short_weekday_format[3]; + static const char_type long_month_format[3]; + static const char_type short_month_format[3]; + static const char_type default_period_separator[4]; + static const char_type standard_format_specifier[3]; + static const char_type iso_format_specifier[7]; + static const char_type iso_format_extended_specifier[9]; + static const char_type default_date_format[9]; // YYYY-Mon-DD + static std::locale::id id; + +#if defined (__SUNPRO_CC) && defined (_RWSTD_VER) + std::locale::id& __get_id (void) const { return id; } +#endif + + explicit date_facet(::size_t a_ref = 0) + : std::locale::facet(a_ref), + //m_format(standard_format_specifier) + m_format(default_date_format), + m_month_format(short_month_format), + m_weekday_format(short_weekday_format) + {} + + explicit date_facet(const char_type* format_str, + const input_collection_type& short_names, + ::size_t ref_count = 0) + : std::locale::facet(ref_count), + m_format(format_str), + m_month_format(short_month_format), + m_weekday_format(short_weekday_format), + m_month_short_names(short_names) + {} + + + explicit date_facet(const char_type* format_str, + period_formatter_type per_formatter = period_formatter_type(), + special_values_formatter_type sv_formatter = special_values_formatter_type(), + date_gen_formatter_type dg_formatter = date_gen_formatter_type(), + ::size_t ref_count = 0) + : std::locale::facet(ref_count), + m_format(format_str), + m_month_format(short_month_format), + m_weekday_format(short_weekday_format), + m_period_formatter(per_formatter), + m_date_gen_formatter(dg_formatter), + m_special_values_formatter(sv_formatter) + {} + void format(const char_type* const format_str) { + m_format = format_str; + } + virtual void set_iso_format() + { + m_format = iso_format_specifier; + } + virtual void set_iso_extended_format() + { + m_format = iso_format_extended_specifier; + } + void month_format(const char_type* const format_str) { + m_month_format = format_str; + } + void weekday_format(const char_type* const format_str) { + m_weekday_format = format_str; + } + + void period_formatter(period_formatter_type per_formatter) { + m_period_formatter= per_formatter; + } + void special_values_formatter(const special_values_formatter_type& svf) + { + m_special_values_formatter = svf; + } + void short_weekday_names(const input_collection_type& short_names) + { + m_weekday_short_names = short_names; + } + void long_weekday_names(const input_collection_type& long_names) + { + m_weekday_long_names = long_names; + } + + void short_month_names(const input_collection_type& short_names) + { + m_month_short_names = short_names; + } + + void long_month_names(const input_collection_type& long_names) + { + m_month_long_names = long_names; + } + + void date_gen_phrase_strings(const input_collection_type& new_strings, + typename date_gen_formatter_type::phrase_elements beg_pos=date_gen_formatter_type::first) + { + m_date_gen_formatter.elements(new_strings, beg_pos); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const date_type& d) const + { + if (d.is_special()) { + return do_put_special(next, a_ios, fill_char, d.as_special()); + } + //The following line of code required the date to support a to_tm function + return do_put_tm(next, a_ios, fill_char, to_tm(d), m_format); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const duration_type& dd) const + { + if (dd.is_special()) { + return do_put_special(next, a_ios, fill_char, dd.get_rep().as_special()); + } + + typedef std::num_put num_put; + if (std::has_facet(a_ios.getloc())) { + return std::use_facet(a_ios.getloc()).put(next, a_ios, fill_char, dd.get_rep().as_number()); + } + else { + num_put* f = new num_put(); + std::locale l = std::locale(a_ios.getloc(), f); + a_ios.imbue(l); + return f->put(next, a_ios, fill_char, dd.get_rep().as_number()); + } + + } + + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const month_type& m) const + { + //if (d.is_special()) { + // return do_put_special(next, a_ios, fill_char, d.as_special()); + //} + //The following line of code required the date to support a to_tm function + std::tm dtm; + std::memset(&dtm, 0, sizeof(dtm)); + dtm.tm_mon = m - 1; + return do_put_tm(next, a_ios, fill_char, dtm, m_month_format); + } + + //! puts the day of month + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const day_type& day) const + { + std::tm dtm; + std::memset(&dtm, 0, sizeof(dtm)); + dtm.tm_mday = day.as_number(); + char_type tmp[3] = {'%','d'}; + string_type temp_format(tmp); + return do_put_tm(next, a_ios, fill_char, dtm, temp_format); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const day_of_week_type& dow) const + { + //if (d.is_special()) { + // return do_put_special(next, a_ios, fill_char, d.as_special()); + //} + //The following line of code required the date to support a to_tm function + std::tm dtm; + std::memset(&dtm, 0, sizeof(dtm)); + dtm.tm_wday = dow; + return do_put_tm(next, a_ios, fill_char, dtm, m_weekday_format); + } + + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const period_type& p) const + { + return m_period_formatter.put_period(next, a_ios, fill_char, p, *this); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const partial_date_type& pd) const + { + return m_date_gen_formatter.put_partial_date(next, a_ios, fill_char, pd, *this); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const nth_kday_type& nkd) const + { + return m_date_gen_formatter.put_nth_kday(next, a_ios, fill_char, nkd, *this); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const first_kday_type& fkd) const + { + return m_date_gen_formatter.put_first_kday(next, a_ios, fill_char, fkd, *this); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const last_kday_type& lkd) const + { + return m_date_gen_formatter.put_last_kday(next, a_ios, fill_char, lkd, *this); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const kday_before_type& fkb) const + { + return m_date_gen_formatter.put_kday_before(next, a_ios, fill_char, fkb, *this); + } + + OutItrT put(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const kday_after_type& fka) const + { + return m_date_gen_formatter.put_kday_after(next, a_ios, fill_char, fka, *this); + } + + protected: + virtual OutItrT do_put_special(OutItrT next, + std::ios_base& /*a_ios*/, + char_type /*fill_char*/, + const boost::date_time::special_values sv) const + { + m_special_values_formatter.put_special(next, sv); + return next; + } + virtual OutItrT do_put_tm(OutItrT next, + std::ios_base& a_ios, + char_type fill_char, + const tm& tm_value, + string_type a_format) const + { + // update format string with custom names + if (m_weekday_long_names.size()) { + boost::algorithm::replace_all(a_format, + long_weekday_format, + m_weekday_long_names[tm_value.tm_wday]); + } + if (m_weekday_short_names.size()) { + boost::algorithm::replace_all(a_format, + short_weekday_format, + m_weekday_short_names[tm_value.tm_wday]); + + } + if (m_month_long_names.size()) { + boost::algorithm::replace_all(a_format, + long_month_format, + m_month_long_names[tm_value.tm_mon]); + } + if (m_month_short_names.size()) { + boost::algorithm::replace_all(a_format, + short_month_format, + m_month_short_names[tm_value.tm_mon]); + } + // use time_put facet to create final string + const char_type* p_format = a_format.c_str(); + return std::use_facet >(a_ios.getloc()).put(next, a_ios, + fill_char, + &tm_value, + p_format, + p_format + a_format.size()); + } + protected: + string_type m_format; + string_type m_month_format; + string_type m_weekday_format; + period_formatter_type m_period_formatter; + date_gen_formatter_type m_date_gen_formatter; + special_values_formatter_type m_special_values_formatter; + input_collection_type m_month_short_names; + input_collection_type m_month_long_names; + input_collection_type m_weekday_short_names; + input_collection_type m_weekday_long_names; + private: + }; + + template + std::locale::id date_facet::id; + + template + const typename date_facet::char_type + date_facet::long_weekday_format[3] = {'%','A'}; + + template + const typename date_facet::char_type + date_facet::short_weekday_format[3] = {'%','a'}; + + template + const typename date_facet::char_type + date_facet::long_month_format[3] = {'%','B'}; + + template + const typename date_facet::char_type + date_facet::short_month_format[3] = {'%','b'}; + + template + const typename date_facet::char_type + date_facet::default_period_separator[4] = { ' ', '/', ' '}; + + template + const typename date_facet::char_type + date_facet::standard_format_specifier[3] = + {'%', 'x' }; + + template + const typename date_facet::char_type + date_facet::iso_format_specifier[7] = + {'%', 'Y', '%', 'm', '%', 'd' }; + + template + const typename date_facet::char_type + date_facet::iso_format_extended_specifier[9] = + {'%', 'Y', '-', '%', 'm', '-', '%', 'd' }; + + template + const typename date_facet::char_type + date_facet::default_date_format[9] = + {'%','Y','-','%','b','-','%','d'}; + + + + //! Input facet + template > > + class date_input_facet : public std::locale::facet { + public: + typedef typename date_type::duration_type duration_type; + // greg_weekday is gregorian_calendar::day_of_week_type + typedef typename date_type::day_of_week_type day_of_week_type; + typedef typename date_type::day_type day_type; + typedef typename date_type::month_type month_type; + typedef typename date_type::year_type year_type; + typedef boost::date_time::period period_type; + typedef std::basic_string string_type; + typedef CharT char_type; + typedef boost::date_time::period_parser period_parser_type; + typedef boost::date_time::special_values_parser special_values_parser_type; + typedef std::vector > input_collection_type; + typedef format_date_parser format_date_parser_type; + // date_generators stuff goes here + typedef date_generator_parser date_gen_parser_type; + typedef partial_date partial_date_type; + typedef nth_kday_of_month nth_kday_type; + typedef first_kday_of_month first_kday_type; + typedef last_kday_of_month last_kday_type; + typedef first_kday_after kday_after_type; + typedef first_kday_before kday_before_type; + + static const char_type long_weekday_format[3]; + static const char_type short_weekday_format[3]; + static const char_type long_month_format[3]; + static const char_type short_month_format[3]; + static const char_type four_digit_year_format[3]; + static const char_type two_digit_year_format[3]; + static const char_type default_period_separator[4]; + static const char_type standard_format_specifier[3]; + static const char_type iso_format_specifier[7]; + static const char_type iso_format_extended_specifier[9]; + static const char_type default_date_format[9]; // YYYY-Mon-DD + static std::locale::id id; + + explicit date_input_facet(::size_t a_ref = 0) + : std::locale::facet(a_ref), + m_format(default_date_format), + m_month_format(short_month_format), + m_weekday_format(short_weekday_format), + m_year_format(four_digit_year_format), + m_parser(m_format, std::locale::classic()) + // default period_parser & special_values_parser used + {} + + explicit date_input_facet(const string_type& format_str, + ::size_t a_ref = 0) + : std::locale::facet(a_ref), + m_format(format_str), + m_month_format(short_month_format), + m_weekday_format(short_weekday_format), + m_year_format(four_digit_year_format), + m_parser(m_format, std::locale::classic()) + // default period_parser & special_values_parser used + {} + + explicit date_input_facet(const string_type& format_str, + const format_date_parser_type& date_parser, + const special_values_parser_type& sv_parser, + const period_parser_type& per_parser, + const date_gen_parser_type& date_gen_parser, + ::size_t ref_count = 0) + : std::locale::facet(ref_count), + m_format(format_str), + m_month_format(short_month_format), + m_weekday_format(short_weekday_format), + m_year_format(four_digit_year_format), + m_parser(date_parser), + m_date_gen_parser(date_gen_parser), + m_period_parser(per_parser), + m_sv_parser(sv_parser) + {} + + + void format(const char_type* const format_str) { + m_format = format_str; + } + virtual void set_iso_format() + { + m_format = iso_format_specifier; + } + virtual void set_iso_extended_format() + { + m_format = iso_format_extended_specifier; + } + void month_format(const char_type* const format_str) { + m_month_format = format_str; + } + void weekday_format(const char_type* const format_str) { + m_weekday_format = format_str; + } + void year_format(const char_type* const format_str) { + m_year_format = format_str; + } + + void period_parser(period_parser_type per_parser) { + m_period_parser = per_parser; + } + void short_weekday_names(const input_collection_type& weekday_names) + { + m_parser.short_weekday_names(weekday_names); + } + void long_weekday_names(const input_collection_type& weekday_names) + { + m_parser.long_weekday_names(weekday_names); + } + + void short_month_names(const input_collection_type& month_names) + { + m_parser.short_month_names(month_names); + } + + void long_month_names(const input_collection_type& month_names) + { + m_parser.long_month_names(month_names); + } + + void date_gen_element_strings(const input_collection_type& col) + { + m_date_gen_parser.element_strings(col); + } + void date_gen_element_strings(const string_type& first, + const string_type& second, + const string_type& third, + const string_type& fourth, + const string_type& fifth, + const string_type& last, + const string_type& before, + const string_type& after, + const string_type& of) + + { + m_date_gen_parser.element_strings(first,second,third,fourth,fifth,last,before,after,of); + } + + void special_values_parser(special_values_parser_type sv_parser) + { + m_sv_parser = sv_parser; + } + + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& /*a_ios*/, + date_type& d) const + { + d = m_parser.parse_date(from, to, m_format, m_sv_parser); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& /*a_ios*/, + month_type& m) const + { + m = m_parser.parse_month(from, to, m_month_format); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& /*a_ios*/, + day_of_week_type& wd) const + { + wd = m_parser.parse_weekday(from, to, m_weekday_format); + return from; + } + //! Expects 1 or 2 digit day range: 1-31 + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& /*a_ios*/, + day_type& d) const + { + d = m_parser.parse_var_day_of_month(from, to); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& /*a_ios*/, + year_type& y) const + { + y = m_parser.parse_year(from, to, m_year_format); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& a_ios, + duration_type& dd) const + { + // skip leading whitespace + while(std::isspace(*from) && from != to) { ++from; } + + /* num_get.get() will always consume the first character if it + * is a sign indicator (+/-). Special value strings may begin + * with one of these signs so we'll need a copy of it + * in case num_get.get() fails. */ + char_type c = '\0'; + // TODO Are these characters somewhere in the locale? + if(*from == '-' || *from == '+') { + c = *from; + } + typedef std::num_get num_get; + typename duration_type::duration_rep_type val = 0; + std::ios_base::iostate err = std::ios_base::goodbit; + + if (std::has_facet(a_ios.getloc())) { + from = std::use_facet(a_ios.getloc()).get(from, to, a_ios, err, val); + } + else { + num_get* ng = new num_get(); + std::locale l = std::locale(a_ios.getloc(), ng); + a_ios.imbue(l); + from = ng->get(from, to, a_ios, err, val); + } + if(err & std::ios_base::failbit){ + typedef typename special_values_parser_type::match_results match_results; + match_results mr; + if(c == '-' || c == '+') { // was the first character consumed? + mr.cache += c; + } + m_sv_parser.match(from, to, mr); + if(mr.current_match == match_results::PARSE_ERROR) { + boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'")); + BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return from); // should never reach + } + dd = duration_type(static_cast(mr.current_match)); + } + else { + dd = duration_type(val); + } + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& a_ios, + period_type& p) const + { + p = m_period_parser.get_period(from, to, a_ios, p, duration_type::unit(), *this); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& a_ios, + nth_kday_type& nkd) const + { + nkd = m_date_gen_parser.get_nth_kday_type(from, to, a_ios, *this); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& a_ios, + partial_date_type& pd) const + { + + pd = m_date_gen_parser.get_partial_date_type(from, to, a_ios, *this); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& a_ios, + first_kday_type& fkd) const + { + fkd = m_date_gen_parser.get_first_kday_type(from, to, a_ios, *this); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& a_ios, + last_kday_type& lkd) const + { + lkd = m_date_gen_parser.get_last_kday_type(from, to, a_ios, *this); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& a_ios, + kday_before_type& fkb) const + { + fkb = m_date_gen_parser.get_kday_before_type(from, to, a_ios, *this); + return from; + } + InItrT get(InItrT& from, + InItrT& to, + std::ios_base& a_ios, + kday_after_type& fka) const + { + fka = m_date_gen_parser.get_kday_after_type(from, to, a_ios, *this); + return from; + } + + protected: + string_type m_format; + string_type m_month_format; + string_type m_weekday_format; + string_type m_year_format; + format_date_parser_type m_parser; + date_gen_parser_type m_date_gen_parser; + period_parser_type m_period_parser; + special_values_parser_type m_sv_parser; + private: + }; + + + template + std::locale::id date_input_facet::id; + + template + const typename date_input_facet::char_type + date_input_facet::long_weekday_format[3] = {'%','A'}; + + template + const typename date_input_facet::char_type + date_input_facet::short_weekday_format[3] = {'%','a'}; + + template + const typename date_input_facet::char_type + date_input_facet::long_month_format[3] = {'%','B'}; + + template + const typename date_input_facet::char_type + date_input_facet::short_month_format[3] = {'%','b'}; + + template + const typename date_input_facet::char_type + date_input_facet::four_digit_year_format[3] = {'%','Y'}; + + template + const typename date_input_facet::char_type + date_input_facet::two_digit_year_format[3] = {'%','y'}; + + template + const typename date_input_facet::char_type + date_input_facet::default_period_separator[4] = { ' ', '/', ' '}; + + template + const typename date_input_facet::char_type + date_input_facet::standard_format_specifier[3] = + {'%', 'x' }; + + template + const typename date_input_facet::char_type + date_input_facet::iso_format_specifier[7] = + {'%', 'Y', '%', 'm', '%', 'd' }; + + template + const typename date_input_facet::char_type + date_input_facet::iso_format_extended_specifier[9] = + {'%', 'Y', '-', '%', 'm', '-', '%', 'd' }; + + template + const typename date_input_facet::char_type + date_input_facet::default_date_format[9] = + {'%','Y','-','%','b','-','%','d'}; + +} } // namespaces + + +#endif diff --git a/cpp/BoostParts/boost/date_time/date_generator_formatter.hpp b/cpp/BoostParts/boost/date_time/date_generator_formatter.hpp new file mode 100644 index 00000000..159cf36e --- /dev/null +++ b/cpp/BoostParts/boost/date_time/date_generator_formatter.hpp @@ -0,0 +1,265 @@ +#ifndef _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___ +#define _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___ + +/* Copyright (c) 2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-11-13 11:05:31 -0800 (Thu, 13 Nov 2008) $ + */ + +#include +#include +#include +#include +#include "boost/date_time/date_generators.hpp" + +namespace boost { +namespace date_time { + + //! Formats date_generators for output + /*! Formatting of date_generators follows specific orders for the + * various types of date_generators. + * - partial_date => "dd Month" + * - nth_day_of_the_week_in_month => "nth weekday of month" + * - first_day_of_the_week_in_month => "first weekday of month" + * - last_day_of_the_week_in_month => "last weekday of month" + * - first_day_of_the_week_after => "weekday after" + * - first_day_of_the_week_before => "weekday before" + * While the order of the elements in these phrases cannot be changed, + * the elements themselves can be. Weekday and Month get their formats + * and names from the date_facet. The remaining elements are stored in + * the date_generator_formatter and can be customized upon construction + * or via a member function. The default elements are those shown in the + * examples above. + */ + template > > + class date_generator_formatter { + public: + typedef partial_date partial_date_type; + typedef nth_kday_of_month nth_kday_type; + typedef first_kday_of_month first_kday_type; + typedef last_kday_of_month last_kday_type; + typedef first_kday_after kday_after_type; + typedef first_kday_before kday_before_type; + + typedef CharT char_type; + typedef std::basic_string string_type; + typedef std::vector collection_type; + static const char_type first_string[6]; + static const char_type second_string[7]; + static const char_type third_string[6]; + static const char_type fourth_string[7]; + static const char_type fifth_string[6]; + static const char_type last_string[5]; + static const char_type before_string[8]; + static const char_type after_string[6]; + static const char_type of_string[3]; + + enum phrase_elements {first=0, second, third, fourth, fifth, last, + before, after, of, number_of_phrase_elements}; + + //! Default format elements used + date_generator_formatter() + { + phrase_strings.reserve(number_of_phrase_elements); + phrase_strings.push_back(string_type(first_string)); + phrase_strings.push_back(string_type(second_string)); + phrase_strings.push_back(string_type(third_string)); + phrase_strings.push_back(string_type(fourth_string)); + phrase_strings.push_back(string_type(fifth_string)); + phrase_strings.push_back(string_type(last_string)); + phrase_strings.push_back(string_type(before_string)); + phrase_strings.push_back(string_type(after_string)); + phrase_strings.push_back(string_type(of_string)); + } + + //! Constructor that allows for a custom set of phrase elements + date_generator_formatter(const string_type& first_str, + const string_type& second_str, + const string_type& third_str, + const string_type& fourth_str, + const string_type& fifth_str, + const string_type& last_str, + const string_type& before_str, + const string_type& after_str, + const string_type& of_str) + { + phrase_strings.reserve(number_of_phrase_elements); + phrase_strings.push_back(first_str); + phrase_strings.push_back(second_str); + phrase_strings.push_back(third_str); + phrase_strings.push_back(fourth_str); + phrase_strings.push_back(fifth_str); + phrase_strings.push_back(last_str); + phrase_strings.push_back(before_str); + phrase_strings.push_back(after_str); + phrase_strings.push_back(of_str); + } + + //! Replace the set of phrase elements with those contained in new_strings + /*! The order of the strings in the given collection is important. + * They must follow: + * - first, second, third, fourth, fifth, last, before, after, of. + * + * It is not necessary to send in a complete set if only a few + * elements are to be replaced as long as the correct beg_pos is used. + * + * Ex: To keep the default first through fifth elements, but replace + * the rest with a collection of: + * - "final", "prior", "following", "in". + * The beg_pos of date_generator_formatter::last would be used. + */ + void elements(const collection_type& new_strings, + phrase_elements beg_pos=first) + { + if(beg_pos < number_of_phrase_elements) { + typename collection_type::iterator itr = phrase_strings.begin(); + itr += beg_pos; + std::copy(new_strings.begin(), new_strings.end(), + itr); + //phrase_strings.begin()); + } + } + + //!Put a partial_date => "dd Month" + template + OutItrT put_partial_date(OutItrT next, std::ios_base& a_ios, + CharT a_fill, const partial_date_type& pd, + const facet_type& facet) const + { + facet.put(next, a_ios, a_fill, pd.day()); + next = a_fill; //TODO change this ??? + facet.put(next, a_ios, a_fill, pd.month()); + return next; + } + + //! Put an nth_day_of_the_week_in_month => "nth weekday of month" + template + OutItrT put_nth_kday(OutItrT next, std::ios_base& a_ios, + CharT a_fill, const nth_kday_type& nkd, + const facet_type& facet) const + { + put_string(next, phrase_strings[nkd.nth_week() -1]); + next = a_fill; //TODO change this ??? + facet.put(next, a_ios, a_fill, nkd.day_of_week()); + next = a_fill; //TODO change this ??? + put_string(next, string_type(of_string)); + next = a_fill; //TODO change this ??? + facet.put(next, a_ios, a_fill, nkd.month()); + return next; + } + + //! Put a first_day_of_the_week_in_month => "first weekday of month" + template + OutItrT put_first_kday(OutItrT next, std::ios_base& a_ios, + CharT a_fill, const first_kday_type& fkd, + const facet_type& facet) const + { + put_string(next, phrase_strings[first]); + next = a_fill; //TODO change this ??? + facet.put(next, a_ios, a_fill, fkd.day_of_week()); + next = a_fill; //TODO change this ??? + put_string(next, string_type(of_string)); + next = a_fill; //TODO change this ??? + facet.put(next, a_ios, a_fill, fkd.month()); + return next; + } + + //! Put a last_day_of_the_week_in_month => "last weekday of month" + template + OutItrT put_last_kday(OutItrT next, std::ios_base& a_ios, + CharT a_fill, const last_kday_type& lkd, + const facet_type& facet) const + { + put_string(next, phrase_strings[last]); + next = a_fill; //TODO change this ??? + facet.put(next, a_ios, a_fill, lkd.day_of_week()); + next = a_fill; //TODO change this ??? + put_string(next, string_type(of_string)); + next = a_fill; //TODO change this ??? + facet.put(next, a_ios, a_fill, lkd.month()); + return next; + } + + //! Put a first_day_of_the_week_before => "weekday before" + template + OutItrT put_kday_before(OutItrT next, std::ios_base& a_ios, + CharT a_fill, const kday_before_type& fkb, + const facet_type& facet) const + { + facet.put(next, a_ios, a_fill, fkb.day_of_week()); + next = a_fill; //TODO change this ??? + put_string(next, phrase_strings[before]); + return next; + } + + //! Put a first_day_of_the_week_after => "weekday after" + template + OutItrT put_kday_after(OutItrT next, std::ios_base& a_ios, + CharT a_fill, const kday_after_type& fka, + const facet_type& facet) const + { + facet.put(next, a_ios, a_fill, fka.day_of_week()); + next = a_fill; //TODO change this ??? + put_string(next, phrase_strings[after]); + return next; + } + + + private: + collection_type phrase_strings; + + //! helper function to put the various member string into stream + OutItrT put_string(OutItrT next, const string_type& str) const + { + typename string_type::const_iterator itr = str.begin(); + while(itr != str.end()) { + *next = *itr; + ++itr; + ++next; + } + return next; + } + }; + + template + const typename date_generator_formatter::char_type + date_generator_formatter::first_string[6] = + {'f','i','r','s','t'}; + template + const typename date_generator_formatter::char_type + date_generator_formatter::second_string[7] = + {'s','e','c','o','n','d'}; + template + const typename date_generator_formatter::char_type + date_generator_formatter::third_string[6] = + {'t','h','i','r','d'}; + template + const typename date_generator_formatter::char_type + date_generator_formatter::fourth_string[7] = + {'f','o','u','r','t','h'}; + template + const typename date_generator_formatter::char_type + date_generator_formatter::fifth_string[6] = + {'f','i','f','t','h'}; + template + const typename date_generator_formatter::char_type + date_generator_formatter::last_string[5] = + {'l','a','s','t'}; + template + const typename date_generator_formatter::char_type + date_generator_formatter::before_string[8] = + {'b','e','f','o','r','e'}; + template + const typename date_generator_formatter::char_type + date_generator_formatter::after_string[6] = + {'a','f','t','e','r'}; + template + const typename date_generator_formatter::char_type + date_generator_formatter::of_string[3] = + {'o','f'}; +} } // namespaces + +#endif // _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___ diff --git a/cpp/BoostParts/boost/date_time/date_generator_parser.hpp b/cpp/BoostParts/boost/date_time/date_generator_parser.hpp new file mode 100644 index 00000000..7cff9ca3 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/date_generator_parser.hpp @@ -0,0 +1,330 @@ + +#ifndef DATE_TIME_DATE_GENERATOR_PARSER_HPP__ +#define DATE_TIME_DATE_GENERATOR_PARSER_HPP__ + +/* Copyright (c) 2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-11-12 11:37:53 -0800 (Wed, 12 Nov 2008) $ + */ + +#include +#include +#include // istreambuf_iterator +#include +#include +#include +#include +#include + +namespace boost { namespace date_time { + + //! Class for date_generator parsing + /*! The elements of a date_generator "phrase" are parsed from the input stream in a + * particular order. All elements are required and the order in which they appear + * cannot change, however, the elements themselves can be changed. The default + * elements and their order are as follows: + * + * - partial_date => "dd Month" + * - nth_day_of_the_week_in_month => "nth weekday of month" + * - first_day_of_the_week_in_month => "first weekday of month" + * - last_day_of_the_week_in_month => "last weekday of month" + * - first_day_of_the_week_after => "weekday after" + * - first_day_of_the_week_before => "weekday before" + * + * Weekday and Month names and formats are handled via the date_input_facet. + * + */ + template + class date_generator_parser + { + public: + typedef std::basic_string string_type; + typedef std::istreambuf_iterator stream_itr_type; + + typedef typename date_type::month_type month_type; + typedef typename date_type::day_of_week_type day_of_week_type; + typedef typename date_type::day_type day_type; + + typedef string_parse_tree parse_tree_type; + typedef typename parse_tree_type::parse_match_result_type match_results; + typedef std::vector > collection_type; + + typedef partial_date partial_date_type; + typedef nth_kday_of_month nth_kday_type; + typedef first_kday_of_month first_kday_type; + typedef last_kday_of_month last_kday_type; + typedef first_kday_after kday_after_type; + typedef first_kday_before kday_before_type; + + typedef charT char_type; + static const char_type first_string[6]; + static const char_type second_string[7]; + static const char_type third_string[6]; + static const char_type fourth_string[7]; + static const char_type fifth_string[6]; + static const char_type last_string[5]; + static const char_type before_string[8]; + static const char_type after_string[6]; + static const char_type of_string[3]; + + enum phrase_elements {first=0, second, third, fourth, fifth, last, + before, after, of, number_of_phrase_elements}; + + //! Creates a date_generator_parser with the default set of "element_strings" + date_generator_parser() + { + element_strings(string_type(first_string), + string_type(second_string), + string_type(third_string), + string_type(fourth_string), + string_type(fifth_string), + string_type(last_string), + string_type(before_string), + string_type(after_string), + string_type(of_string)); + } + + //! Creates a date_generator_parser using a user defined set of element strings + date_generator_parser(const string_type& first_str, + const string_type& second_str, + const string_type& third_str, + const string_type& fourth_str, + const string_type& fifth_str, + const string_type& last_str, + const string_type& before_str, + const string_type& after_str, + const string_type& of_str) + { + element_strings(first_str, second_str, third_str, fourth_str, fifth_str, + last_str, before_str, after_str, of_str); + } + + //! Replace strings that determine nth week for generator + void element_strings(const string_type& first_str, + const string_type& second_str, + const string_type& third_str, + const string_type& fourth_str, + const string_type& fifth_str, + const string_type& last_str, + const string_type& before_str, + const string_type& after_str, + const string_type& of_str) + { + collection_type phrases; + phrases.push_back(first_str); + phrases.push_back(second_str); + phrases.push_back(third_str); + phrases.push_back(fourth_str); + phrases.push_back(fifth_str); + phrases.push_back(last_str); + phrases.push_back(before_str); + phrases.push_back(after_str); + phrases.push_back(of_str); + m_element_strings = parse_tree_type(phrases, this->first); // enum first + } + + void element_strings(const collection_type& col) + { + m_element_strings = parse_tree_type(col, this->first); // enum first + } + + //! returns partial_date parsed from stream + template + partial_date_type + get_partial_date_type(stream_itr_type& sitr, + stream_itr_type& stream_end, + std::ios_base& a_ios, + const facet_type& facet) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + day_type d(1); + month_type m(1); + facet.get(sitr, stream_end, a_ios, d); + facet.get(sitr, stream_end, a_ios, m); + + return partial_date_type(d,m); + } + + //! returns nth_kday_of_week parsed from stream + template + nth_kday_type + get_nth_kday_type(stream_itr_type& sitr, + stream_itr_type& stream_end, + std::ios_base& a_ios, + const facet_type& facet) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + typename nth_kday_type::week_num wn; + day_of_week_type wd(0); // no default constructor + month_type m(1); // no default constructor + + match_results mr = m_element_strings.match(sitr, stream_end); + switch(mr.current_match) { + case first : { wn = nth_kday_type::first; break; } + case second : { wn = nth_kday_type::second; break; } + case third : { wn = nth_kday_type::third; break; } + case fourth : { wn = nth_kday_type::fourth; break; } + case fifth : { wn = nth_kday_type::fifth; break; } + default: + { + boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'")); + BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(wn = nth_kday_type::first); + } + } // week num + facet.get(sitr, stream_end, a_ios, wd); // day_of_week + extract_element(sitr, stream_end, of); // "of" element + facet.get(sitr, stream_end, a_ios, m); // month + + return nth_kday_type(wn, wd, m); + } + + //! returns first_kday_of_week parsed from stream + template + first_kday_type + get_first_kday_type(stream_itr_type& sitr, + stream_itr_type& stream_end, + std::ios_base& a_ios, + const facet_type& facet) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + day_of_week_type wd(0); // no default constructor + month_type m(1); // no default constructor + + extract_element(sitr, stream_end, first); // "first" element + facet.get(sitr, stream_end, a_ios, wd); // day_of_week + extract_element(sitr, stream_end, of); // "of" element + facet.get(sitr, stream_end, a_ios, m); // month + + + return first_kday_type(wd, m); + } + + //! returns last_kday_of_week parsed from stream + template + last_kday_type + get_last_kday_type(stream_itr_type& sitr, + stream_itr_type& stream_end, + std::ios_base& a_ios, + const facet_type& facet) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + day_of_week_type wd(0); // no default constructor + month_type m(1); // no default constructor + + extract_element(sitr, stream_end, last); // "last" element + facet.get(sitr, stream_end, a_ios, wd); // day_of_week + extract_element(sitr, stream_end, of); // "of" element + facet.get(sitr, stream_end, a_ios, m); // month + + + return last_kday_type(wd, m); + } + + //! returns first_kday_of_week parsed from stream + template + kday_before_type + get_kday_before_type(stream_itr_type& sitr, + stream_itr_type& stream_end, + std::ios_base& a_ios, + const facet_type& facet) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + day_of_week_type wd(0); // no default constructor + + facet.get(sitr, stream_end, a_ios, wd); // day_of_week + extract_element(sitr, stream_end, before);// "before" element + + return kday_before_type(wd); + } + + //! returns first_kday_of_week parsed from stream + template + kday_after_type + get_kday_after_type(stream_itr_type& sitr, + stream_itr_type& stream_end, + std::ios_base& a_ios, + const facet_type& facet) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + day_of_week_type wd(0); // no default constructor + + facet.get(sitr, stream_end, a_ios, wd); // day_of_week + extract_element(sitr, stream_end, after); // "after" element + + return kday_after_type(wd); + } + + private: + parse_tree_type m_element_strings; + + //! Extracts phrase element from input. Throws ios_base::failure on error. + void extract_element(stream_itr_type& sitr, + stream_itr_type& stream_end, + typename date_generator_parser::phrase_elements ele) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + match_results mr = m_element_strings.match(sitr, stream_end); + if(mr.current_match != ele) { + boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'")); + } + } + + }; + + template + const typename date_generator_parser::char_type + date_generator_parser::first_string[6] = + {'f','i','r','s','t'}; + template + const typename date_generator_parser::char_type + date_generator_parser::second_string[7] = + {'s','e','c','o','n','d'}; + template + const typename date_generator_parser::char_type + date_generator_parser::third_string[6] = + {'t','h','i','r','d'}; + template + const typename date_generator_parser::char_type + date_generator_parser::fourth_string[7] = + {'f','o','u','r','t','h'}; + template + const typename date_generator_parser::char_type + date_generator_parser::fifth_string[6] = + {'f','i','f','t','h'}; + template + const typename date_generator_parser::char_type + date_generator_parser::last_string[5] = + {'l','a','s','t'}; + template + const typename date_generator_parser::char_type + date_generator_parser::before_string[8] = + {'b','e','f','o','r','e'}; + template + const typename date_generator_parser::char_type + date_generator_parser::after_string[6] = + {'a','f','t','e','r'}; + template + const typename date_generator_parser::char_type + date_generator_parser::of_string[3] = + {'o','f'}; + +} } //namespace + +#endif // DATE_TIME_DATE_GENERATOR_PARSER_HPP__ + diff --git a/cpp/BoostParts/boost/date_time/format_date_parser.hpp b/cpp/BoostParts/boost/date_time/format_date_parser.hpp new file mode 100644 index 00000000..0c3503f8 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/format_date_parser.hpp @@ -0,0 +1,737 @@ + +#ifndef DATE_TIME_FORMAT_DATE_PARSER_HPP__ +#define DATE_TIME_FORMAT_DATE_PARSER_HPP__ + +/* Copyright (c) 2004-2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2012-09-30 16:25:22 -0700 (Sun, 30 Sep 2012) $ + */ + + +#include "boost/lexical_cast.hpp" +#include "boost/date_time/string_parse_tree.hpp" +#include "boost/date_time/strings_from_facet.hpp" +#include "boost/date_time/special_values_parser.hpp" +#include +#include +#include +#include +#ifndef BOOST_NO_STDC_NAMESPACE +# include +#else +# include +#endif + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { + using ::isspace; + using ::isdigit; +} +#endif +namespace boost { namespace date_time { + +//! Helper function for parsing fixed length strings into integers +/*! Will consume 'length' number of characters from stream. Consumed + * character are transfered to parse_match_result struct. + * Returns '-1' if no number can be parsed or incorrect number of + * digits in stream. */ +template +inline +int_type +fixed_string_to_int(std::istreambuf_iterator& itr, + std::istreambuf_iterator& stream_end, + parse_match_result& mr, + unsigned int length, + const charT& fill_char) +{ + //typedef std::basic_string string_type; + unsigned int j = 0; + //string_type s; + while (j < length && itr != stream_end && + (std::isdigit(*itr) || *itr == fill_char)) { + if(*itr == fill_char) { + /* Since a fill_char can be anything, we convert it to a zero. + * lexical_cast will behave predictably when zero is used as fill. */ + mr.cache += ('0'); + } + else { + mr.cache += (*itr); + } + itr++; + j++; + } + int_type i = -1; + // mr.cache will hold leading zeros. size() tells us when input is too short. + if(mr.cache.size() < length) { + return i; + } + try { + i = boost::lexical_cast(mr.cache); + }catch(bad_lexical_cast&){ + // we want to return -1 if the cast fails so nothing to do here + } + return i; +} + +//! Helper function for parsing fixed length strings into integers +/*! Will consume 'length' number of characters from stream. Consumed + * character are transfered to parse_match_result struct. + * Returns '-1' if no number can be parsed or incorrect number of + * digits in stream. */ +template +inline +int_type +fixed_string_to_int(std::istreambuf_iterator& itr, + std::istreambuf_iterator& stream_end, + parse_match_result& mr, + unsigned int length) +{ + return fixed_string_to_int(itr, stream_end, mr, length, '0'); +} + +//! Helper function for parsing varied length strings into integers +/*! Will consume 'max_length' characters from stream only if those + * characters are digits. Returns '-1' if no number can be parsed. + * Will not parse a number preceeded by a '+' or '-'. */ +template +inline +int_type +var_string_to_int(std::istreambuf_iterator& itr, + const std::istreambuf_iterator& stream_end, + unsigned int max_length) +{ + typedef std::basic_string string_type; + unsigned int j = 0; + string_type s; + while (itr != stream_end && (j < max_length) && std::isdigit(*itr)) { + s += (*itr); + ++itr; + ++j; + } + int_type i = -1; + if(!s.empty()) { + i = boost::lexical_cast(s); + } + return i; +} + + +//! Class with generic date parsing using a format string +/*! The following is the set of recognized format specifiers + - %a - Short weekday name + - %A - Long weekday name + - %b - Abbreviated month name + - %B - Full month name + - %d - Day of the month as decimal 01 to 31 + - %j - Day of year as decimal from 001 to 366 + - %m - Month name as a decimal 01 to 12 + - %U - Week number 00 to 53 with first Sunday as the first day of week 1? + - %w - Weekday as decimal number 0 to 6 where Sunday == 0 + - %W - Week number 00 to 53 where Monday is first day of week 1 + - %x - facet default date representation + - %y - Year without the century - eg: 04 for 2004 + - %Y - Year with century + + The weekday specifiers (%a and %A) do not add to the date construction, + but they provide a way to skip over the weekday names for formats that + provide them. + + todo -- Another interesting feature that this approach could provide is + an option to fill in any missing fields with the current values + from the clock. So if you have %m-%d the parser would detect + the missing year value and fill it in using the clock. + + todo -- What to do with the %x. %x in the classic facet is just bad... + + */ +template +class format_date_parser +{ + public: + typedef std::basic_string string_type; + typedef std::basic_istringstream stringstream_type; + typedef std::istreambuf_iterator stream_itr_type; + typedef typename string_type::const_iterator const_itr; + typedef typename date_type::year_type year_type; + typedef typename date_type::month_type month_type; + typedef typename date_type::day_type day_type; + typedef typename date_type::duration_type duration_type; + typedef typename date_type::day_of_week_type day_of_week_type; + typedef typename date_type::day_of_year_type day_of_year_type; + typedef string_parse_tree parse_tree_type; + typedef typename parse_tree_type::parse_match_result_type match_results; + typedef std::vector > input_collection_type; + + // TODO sv_parser uses its default constructor - write the others + + format_date_parser(const string_type& format_str, + const input_collection_type& month_short_names, + const input_collection_type& month_long_names, + const input_collection_type& weekday_short_names, + const input_collection_type& weekday_long_names) : + m_format(format_str), + m_month_short_names(month_short_names, 1), + m_month_long_names(month_long_names, 1), + m_weekday_short_names(weekday_short_names), + m_weekday_long_names(weekday_long_names) + {} + + format_date_parser(const string_type& format_str, + const std::locale& locale) : + m_format(format_str), + m_month_short_names(gather_month_strings(locale), 1), + m_month_long_names(gather_month_strings(locale, false), 1), + m_weekday_short_names(gather_weekday_strings(locale)), + m_weekday_long_names(gather_weekday_strings(locale, false)) + {} + + format_date_parser(const format_date_parser& fdp) + { + this->m_format = fdp.m_format; + this->m_month_short_names = fdp.m_month_short_names; + this->m_month_long_names = fdp.m_month_long_names; + this->m_weekday_short_names = fdp.m_weekday_short_names; + this->m_weekday_long_names = fdp.m_weekday_long_names; + } + + string_type format() const + { + return m_format; + } + + void format(string_type format_str) + { + m_format = format_str; + } + + void short_month_names(const input_collection_type& month_names) + { + m_month_short_names = parse_tree_type(month_names, 1); + } + void long_month_names(const input_collection_type& month_names) + { + m_month_long_names = parse_tree_type(month_names, 1); + } + void short_weekday_names(const input_collection_type& weekday_names) + { + m_weekday_short_names = parse_tree_type(weekday_names); + } + void long_weekday_names(const input_collection_type& weekday_names) + { + m_weekday_long_names = parse_tree_type(weekday_names); + } + + date_type + parse_date(const string_type& value, + const string_type& format_str, + const special_values_parser& sv_parser) const + { + stringstream_type ss(value); + stream_itr_type sitr(ss); + stream_itr_type stream_end; + return parse_date(sitr, stream_end, format_str, sv_parser); + } + + date_type + parse_date(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + const special_values_parser& sv_parser) const + { + return parse_date(sitr, stream_end, m_format, sv_parser); + } + + /*! Of all the objects that the format_date_parser can parse, only a + * date can be a special value. Therefore, only parse_date checks + * for special_values. */ + date_type + parse_date(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + string_type format_str, + const special_values_parser& sv_parser) const + { + bool use_current_char = false; + + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + short year(0), month(0), day(0), day_of_year(0);// wkday(0); + /* Initialized the following to their minimum values. These intermediate + * objects are used so we get specific exceptions when part of the input + * is unparsable. + * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/ + year_type t_year(1400); + month_type t_month(1); + day_type t_day(1); + day_of_week_type wkday(0); + + + const_itr itr(format_str.begin()); + while (itr != format_str.end() && (sitr != stream_end)) { + if (*itr == '%') { + itr++; + if (*itr != '%') { + switch(*itr) { + case 'a': + { + //this value is just throw away. It could be used for + //error checking potentially, but it isn't helpful in + //actually constructing the date - we just need to get it + //out of the stream + match_results mr = m_weekday_short_names.match(sitr, stream_end); + if(mr.current_match == match_results::PARSE_ERROR) { + // check special_values + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + wkday = mr.current_match; + if (mr.has_remaining()) { + use_current_char = true; + } + break; + } + case 'A': + { + //this value is just throw away. It could be used for + //error checking potentially, but it isn't helpful in + //actually constructing the date - we just need to get it + //out of the stream + match_results mr = m_weekday_long_names.match(sitr, stream_end); + if(mr.current_match == match_results::PARSE_ERROR) { + // check special_values + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + wkday = mr.current_match; + if (mr.has_remaining()) { + use_current_char = true; + } + break; + } + case 'b': + { + match_results mr = m_month_short_names.match(sitr, stream_end); + if(mr.current_match == match_results::PARSE_ERROR) { + // check special_values + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + t_month = month_type(mr.current_match); + if (mr.has_remaining()) { + use_current_char = true; + } + break; + } + case 'B': + { + match_results mr = m_month_long_names.match(sitr, stream_end); + if(mr.current_match == match_results::PARSE_ERROR) { + // check special_values + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + t_month = month_type(mr.current_match); + if (mr.has_remaining()) { + use_current_char = true; + } + break; + } + case 'd': + { + match_results mr; + day = fixed_string_to_int(sitr, stream_end, mr, 2); + if(day == -1) { + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + t_day = day_type(day); + break; + } + case 'e': + { + match_results mr; + day = fixed_string_to_int(sitr, stream_end, mr, 2, ' '); + if(day == -1) { + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + t_day = day_type(day); + break; + } + case 'j': + { + match_results mr; + day_of_year = fixed_string_to_int(sitr, stream_end, mr, 3); + if(day_of_year == -1) { + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + // these next two lines are so we get an exception with bad input + day_of_year_type t_day_of_year(1); + t_day_of_year = day_of_year_type(day_of_year); + break; + } + case 'm': + { + match_results mr; + month = fixed_string_to_int(sitr, stream_end, mr, 2); + if(month == -1) { + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + t_month = month_type(month); + break; + } + case 'Y': + { + match_results mr; + year = fixed_string_to_int(sitr, stream_end, mr, 4); + if(year == -1) { + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + t_year = year_type(year); + break; + } + case 'y': + { + match_results mr; + year = fixed_string_to_int(sitr, stream_end, mr, 2); + if(year == -1) { + if(sv_parser.match(sitr, stream_end, mr)) { + return date_type(static_cast(mr.current_match)); + } + } + year += 2000; //make 2 digit years in this century + t_year = year_type(year); + break; + } + default: + {} //ignore those we don't understand + + }//switch + + } + else { // itr == '%', second consecutive + sitr++; + } + + itr++; //advance past format specifier + } + else { //skip past chars in format and in buffer + itr++; + if (use_current_char) { + use_current_char = false; + } + else { + sitr++; + } + } + } + + if (day_of_year > 0) { + date_type d(static_cast(year-1),12,31); //end of prior year + return d + duration_type(day_of_year); + } + + return date_type(t_year, t_month, t_day); // exceptions were thrown earlier + // if input was no good + } + + //! Throws bad_month if unable to parse + month_type + parse_month(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + string_type format_str) const + { + match_results mr; + return parse_month(sitr, stream_end, format_str, mr); + } + + //! Throws bad_month if unable to parse + month_type + parse_month(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + string_type format_str, + match_results& mr) const + { + bool use_current_char = false; + + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + charT current_char = *sitr; + + short month(0); + + const_itr itr(format_str.begin()); + while (itr != format_str.end() && (sitr != stream_end)) { + if (*itr == '%') { + itr++; + if (*itr != '%') { + switch(*itr) { + case 'b': + { + mr = m_month_short_names.match(sitr, stream_end); + month = mr.current_match; + if (mr.has_remaining()) { + current_char = mr.last_char(); + use_current_char = true; + } + break; + } + case 'B': + { + mr = m_month_long_names.match(sitr, stream_end); + month = mr.current_match; + if (mr.has_remaining()) { + current_char = mr.last_char(); + use_current_char = true; + } + break; + } + case 'm': + { + month = var_string_to_int(sitr, stream_end, 2); + // var_string_to_int returns -1 if parse failed. That will + // cause a bad_month exception to be thrown so we do nothing here + break; + } + default: + {} //ignore those we don't understand + + }//switch + + } + else { // itr == '%', second consecutive + sitr++; + } + + itr++; //advance past format specifier + } + else { //skip past chars in format and in buffer + itr++; + if (use_current_char) { + use_current_char = false; + current_char = *sitr; + } + else { + sitr++; + } + } + } + + return month_type(month); // throws bad_month exception when values are zero + } + + //! Expects 1 or 2 digits 1-31. Throws bad_day_of_month if unable to parse + day_type + parse_var_day_of_month(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + return day_type(var_string_to_int(sitr, stream_end, 2)); + } + //! Expects 2 digits 01-31. Throws bad_day_of_month if unable to parse + day_type + parse_day_of_month(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + //return day_type(var_string_to_int(sitr, stream_end, 2)); + match_results mr; + return day_type(fixed_string_to_int(sitr, stream_end, mr, 2)); + } + + day_of_week_type + parse_weekday(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + string_type format_str) const + { + match_results mr; + return parse_weekday(sitr, stream_end, format_str, mr); + } + day_of_week_type + parse_weekday(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + string_type format_str, + match_results& mr) const + { + bool use_current_char = false; + + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + charT current_char = *sitr; + + short wkday(0); + + const_itr itr(format_str.begin()); + while (itr != format_str.end() && (sitr != stream_end)) { + if (*itr == '%') { + itr++; + if (*itr != '%') { + switch(*itr) { + case 'a': + { + //this value is just throw away. It could be used for + //error checking potentially, but it isn't helpful in + //actually constructing the date - we just need to get it + //out of the stream + mr = m_weekday_short_names.match(sitr, stream_end); + wkday = mr.current_match; + if (mr.has_remaining()) { + current_char = mr.last_char(); + use_current_char = true; + } + break; + } + case 'A': + { + //this value is just throw away. It could be used for + //error checking potentially, but it isn't helpful in + //actually constructing the date - we just need to get it + //out of the stream + mr = m_weekday_long_names.match(sitr, stream_end); + wkday = mr.current_match; + if (mr.has_remaining()) { + current_char = mr.last_char(); + use_current_char = true; + } + break; + } + case 'w': + { + // weekday as number 0-6, Sunday == 0 + wkday = var_string_to_int(sitr, stream_end, 2); + break; + } + default: + {} //ignore those we don't understand + + }//switch + + } + else { // itr == '%', second consecutive + sitr++; + } + + itr++; //advance past format specifier + } + else { //skip past chars in format and in buffer + itr++; + if (use_current_char) { + use_current_char = false; + current_char = *sitr; + } + else { + sitr++; + } + } + } + + return day_of_week_type(wkday); // throws bad_day_of_month exception + // when values are zero + } + + //! throws bad_year if unable to parse + year_type + parse_year(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + string_type format_str) const + { + match_results mr; + return parse_year(sitr, stream_end, format_str, mr); + } + + //! throws bad_year if unable to parse + year_type + parse_year(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + string_type format_str, + match_results& mr) const + { + bool use_current_char = false; + + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + charT current_char = *sitr; + + unsigned short year(0); + + const_itr itr(format_str.begin()); + while (itr != format_str.end() && (sitr != stream_end)) { + if (*itr == '%') { + itr++; + if (*itr != '%') { + //match_results mr; + switch(*itr) { + case 'Y': + { + // year from 4 digit string + year = fixed_string_to_int(sitr, stream_end, mr, 4); + break; + } + case 'y': + { + // year from 2 digit string (no century) + year = fixed_string_to_int(sitr, stream_end, mr, 2); + year += 2000; //make 2 digit years in this century + break; + } + default: + {} //ignore those we don't understand + + }//switch + + } + else { // itr == '%', second consecutive + sitr++; + } + + itr++; //advance past format specifier + } + else { //skip past chars in format and in buffer + itr++; + if (use_current_char) { + use_current_char = false; + current_char = *sitr; + } + else { + sitr++; + } + } + } + + return year_type(year); // throws bad_year exception when values are zero + } + + + private: + string_type m_format; + parse_tree_type m_month_short_names; + parse_tree_type m_month_long_names; + parse_tree_type m_weekday_short_names; + parse_tree_type m_weekday_long_names; + +}; + +} } //namespace + +#endif + + + diff --git a/cpp/BoostParts/boost/date_time/gregorian/gregorian.hpp b/cpp/BoostParts/boost/date_time/gregorian/gregorian.hpp new file mode 100644 index 00000000..becbc068 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/gregorian/gregorian.hpp @@ -0,0 +1,38 @@ +#ifndef GREGORIAN_HPP__ +#define GREGORIAN_HPP__ + +/* Copyright (c) 2002-2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 12:00:24 -0800 (Wed, 27 Feb 2008) $ + */ + +/*! @file gregorian.hpp + Single file header that provides overall include for all elements of + the gregorian date-time system. This includes the various types + defined, but also other functions for formatting and parsing. +*/ + + +#include "boost/date_time/compiler_config.hpp" +#include "boost/date_time/gregorian/gregorian_types.hpp" +#include "boost/date_time/gregorian/conversion.hpp" +#if defined(BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS) +#include "boost/date_time/gregorian/formatters_limited.hpp" +#else +#include "boost/date_time/gregorian/formatters.hpp" +#endif + +#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO) +#include "boost/date_time/gregorian/greg_facet.hpp" +#else +#include "boost/date_time/gregorian/gregorian_io.hpp" +#endif // USE_DATE_TIME_PRE_1_33_FACET_IO + +#include "boost/date_time/gregorian/parsers.hpp" + + + +#endif diff --git a/cpp/BoostParts/boost/date_time/gregorian/gregorian_io.hpp b/cpp/BoostParts/boost/date_time/gregorian/gregorian_io.hpp new file mode 100644 index 00000000..e6ba01fe --- /dev/null +++ b/cpp/BoostParts/boost/date_time/gregorian/gregorian_io.hpp @@ -0,0 +1,784 @@ +#ifndef DATE_TIME_GREGORIAN_IO_HPP__ +#define DATE_TIME_GREGORIAN_IO_HPP__ + +/* Copyright (c) 2004-2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-11-12 11:37:53 -0800 (Wed, 12 Nov 2008) $ + */ + +#include +#include +#include // i/ostreambuf_iterator +#include +#include +#include +#include +#include +#include +#include +#include // to_tm will be needed in the facets + +namespace boost { +namespace gregorian { + + + typedef boost::date_time::period_formatter wperiod_formatter; + typedef boost::date_time::period_formatter period_formatter; + + typedef boost::date_time::date_facet wdate_facet; + typedef boost::date_time::date_facet date_facet; + + typedef boost::date_time::period_parser period_parser; + typedef boost::date_time::period_parser wperiod_parser; + + typedef boost::date_time::special_values_formatter special_values_formatter; + typedef boost::date_time::special_values_formatter wspecial_values_formatter; + + typedef boost::date_time::special_values_parser special_values_parser; + typedef boost::date_time::special_values_parser wspecial_values_parser; + + typedef boost::date_time::date_input_facet date_input_facet; + typedef boost::date_time::date_input_facet wdate_input_facet; + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::date& d) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), d); + else { + //instantiate a custom facet for dealing with dates since the user + //has not put one in the stream so far. This is for efficiency + //since we would always need to reconstruct for every date + //if the locale did not already exist. Of course this will be overridden + //if the user imbues at some later point. With the default settings + //for the facet the resulting format will be the same as the + //std::time_facet settings. + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), d); + } + return os; + } + + //! input operator for date + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, date& d) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, d); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, d); + } + } + catch(...) { + // mask tells us what exceptions are turned on + std::ios_base::iostate exception_mask = is.exceptions(); + // if the user wants exceptions on failbit, we'll rethrow our + // date_time exception & set the failbit + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} // ignore this one + throw; // rethrow original exception + } + else { + // if the user want's to fail quietly, we simply set the failbit + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::date_duration& dd) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), dd); + else { + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), dd); + + } + return os; + } + + //! input operator for date_duration + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, date_duration& dd) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, dd); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, dd); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::date_period& dp) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), dp); + else { + //instantiate a custom facet for dealing with date periods since the user + //has not put one in the stream so far. This is for efficiency + //since we would always need to reconstruct for every time period + //if the local did not already exist. Of course this will be overridden + //if the user imbues at some later point. With the default settings + //for the facet the resulting format will be the same as the + //std::time_facet settings. + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), dp); + + } + return os; + } + + //! input operator for date_period + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, date_period& dp) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, dp); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, dp); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + /********** small gregorian types **********/ + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::greg_month& gm) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), gm); + else { + custom_date_facet* f = new custom_date_facet();//-> 10/1074199752/32 because year & day not initialized in put(...) + //custom_date_facet* f = new custom_date_facet("%B"); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), gm); + } + return os; + } + + //! input operator for greg_month + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, greg_month& m) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, m); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, m); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::greg_weekday& gw) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), gw); + else { + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), gw); + } + return os; + } + + //! input operator for greg_weekday + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, greg_weekday& wd) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, wd); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, wd); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + //NOTE: output operator for greg_day was not necessary + + //! input operator for greg_day + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, greg_day& gd) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, gd); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, gd); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + //NOTE: output operator for greg_year was not necessary + + //! input operator for greg_year + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, greg_year& gy) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, gy); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, gy); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + /********** date generator types **********/ + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::partial_date& pd) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), pd); + else { + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), pd); + } + return os; + } + + //! input operator for partial_date + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, partial_date& pd) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, pd); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, pd); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::nth_day_of_the_week_in_month& nkd) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), nkd); + else { + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), nkd); + } + return os; + } + + //! input operator for nth_day_of_the_week_in_month + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, + nth_day_of_the_week_in_month& nday) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, nday); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, nday); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::first_day_of_the_week_in_month& fkd) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), fkd); + else { + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), fkd); + } + return os; + } + + //! input operator for first_day_of_the_week_in_month + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, + first_day_of_the_week_in_month& fkd) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, fkd); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, fkd); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::last_day_of_the_week_in_month& lkd) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), lkd); + else { + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), lkd); + } + return os; + } + + //! input operator for last_day_of_the_week_in_month + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, + last_day_of_the_week_in_month& lkd) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, lkd); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, lkd); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::first_day_of_the_week_after& fda) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) { + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), fda); + } + else { + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), fda); + } + return os; + } + + //! input operator for first_day_of_the_week_after + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, + first_day_of_the_week_after& fka) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, fka); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, fka); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, const boost::gregorian::first_day_of_the_week_before& fdb) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::date_facet custom_date_facet; + std::ostreambuf_iterator output_itr(os); + if (std::has_facet(os.getloc())) { + std::use_facet(os.getloc()).put(output_itr, os, os.fill(), fdb); + } + else { + custom_date_facet* f = new custom_date_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(output_itr, os, os.fill(), fdb); + } + return os; + } + + //! input operator for first_day_of_the_week_before + template + inline + std::basic_istream& + operator>>(std::basic_istream& is, + first_day_of_the_week_before& fkb) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::date_input_facet date_input_facet; + + std::istreambuf_iterator sit(is), str_end; + if(std::has_facet(is.getloc())) { + std::use_facet(is.getloc()).get(sit, str_end, is, fkb); + } + else { + date_input_facet* f = new date_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, fkb); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + +} } // namespaces + +#endif // DATE_TIME_GREGORIAN_IO_HPP__ diff --git a/cpp/BoostParts/boost/date_time/period_formatter.hpp b/cpp/BoostParts/boost/date_time/period_formatter.hpp new file mode 100644 index 00000000..b6ddc821 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/period_formatter.hpp @@ -0,0 +1,196 @@ + +#ifndef DATETIME_PERIOD_FORMATTER_HPP___ +#define DATETIME_PERIOD_FORMATTER_HPP___ + +/* Copyright (c) 2002-2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2012-09-22 15:33:33 -0700 (Sat, 22 Sep 2012) $ + */ + + + +namespace boost { namespace date_time { + + + //! Not a facet, but a class used to specify and control period formats + /*! Provides settings for the following: + * - period_separator -- default '/' + * - period_open_start_delimeter -- default '[' + * - period_open_range_end_delimeter -- default ')' + * - period_closed_range_end_delimeter -- default ']' + * - display_as_open_range, display_as_closed_range -- default closed_range + * + * Thus the default formatting for a period is as follows: + *@code + * [period.start()/period.last()] + *@endcode + * So for a typical date_period this would be + *@code + * [2004-Jan-04/2004-Feb-01] + *@endcode + * where the date formatting is controlled by the date facet + */ + template > > + class period_formatter { + public: + typedef std::basic_string string_type; + typedef CharT char_type; + typedef typename std::basic_string::const_iterator const_itr_type; + typedef std::vector > collection_type; + + static const char_type default_period_separator[2]; + static const char_type default_period_start_delimeter[2]; + static const char_type default_period_open_range_end_delimeter[2]; + static const char_type default_period_closed_range_end_delimeter[2]; + + enum range_display_options { AS_OPEN_RANGE, AS_CLOSED_RANGE }; + + //! Constructor that sets up period formatter options -- default should suffice most cases. + period_formatter(range_display_options range_option_in = AS_CLOSED_RANGE, + const char_type* const period_separator = default_period_separator, + const char_type* const period_start_delimeter = default_period_start_delimeter, + const char_type* const period_open_range_end_delimeter = default_period_open_range_end_delimeter, + const char_type* const period_closed_range_end_delimeter = default_period_closed_range_end_delimeter) : + m_range_option(range_option_in), + m_period_separator(period_separator), + m_period_start_delimeter(period_start_delimeter), + m_open_range_end_delimeter(period_open_range_end_delimeter), + m_closed_range_end_delimeter(period_closed_range_end_delimeter) + {} + + //! Puts the characters between period elements into stream -- default is / + OutItrT put_period_separator(OutItrT& oitr) const + { + const_itr_type ci = m_period_separator.begin(); + while (ci != m_period_separator.end()) { + *oitr = *ci; + ci++; + } + return oitr; + } + + //! Puts the period start characters into stream -- default is [ + OutItrT put_period_start_delimeter(OutItrT& oitr) const + { + const_itr_type ci = m_period_start_delimeter.begin(); + while (ci != m_period_start_delimeter.end()) { + *oitr = *ci; + ci++; + } + return oitr; + } + + //! Puts the period end characters into stream as controled by open/closed range setting. + OutItrT put_period_end_delimeter(OutItrT& oitr) const + { + + const_itr_type ci, end; + if (m_range_option == AS_OPEN_RANGE) { + ci = m_open_range_end_delimeter.begin(); + end = m_open_range_end_delimeter.end(); + } + else { + ci = m_closed_range_end_delimeter.begin(); + end = m_closed_range_end_delimeter.end(); + } + while (ci != end) { + *oitr = *ci; + ci++; + } + return oitr; + } + + range_display_options range_option() const + { + return m_range_option; + } + + //! Reset the range_option control + void + range_option(range_display_options option) const + { + m_range_option = option; + } + void delimiter_strings(const string_type& , + const string_type& , + const string_type& , + const string_type& ) + { + m_period_separator; + m_period_start_delimeter; + m_open_range_end_delimeter; + m_closed_range_end_delimeter; + } + + + //! Generic code to output a period -- no matter the period type. + /*! This generic code will output any period using a facet to + * to output the 'elements'. For example, in the case of a date_period + * the elements will be instances of a date which will be formatted + * according the to setup in the passed facet parameter. + * + * The steps for formatting a period are always the same: + * - put the start delimiter + * - put start element + * - put the separator + * - put either last or end element depending on range settings + * - put end delimeter depending on range settings + * + * Thus for a typical date period the result might look like this: + *@code + * + * [March 01, 2004/June 07, 2004] <-- closed range + * [March 01, 2004/June 08, 2004) <-- open range + * + *@endcode + */ + template + OutItrT put_period(OutItrT next, + std::ios_base& a_ios, + char_type a_fill, + const period_type& p, + const facet_type& facet) const { + put_period_start_delimeter(next); + next = facet.put(next, a_ios, a_fill, p.begin()); + put_period_separator(next); + if (m_range_option == AS_CLOSED_RANGE) { + facet.put(next, a_ios, a_fill, p.last()); + } + else { + facet.put(next, a_ios, a_fill, p.end()); + } + put_period_end_delimeter(next); + return next; + } + + + private: + range_display_options m_range_option; + string_type m_period_separator; + string_type m_period_start_delimeter; + string_type m_open_range_end_delimeter; + string_type m_closed_range_end_delimeter; + }; + + template + const typename period_formatter::char_type + period_formatter::default_period_separator[2] = {'/'}; + + template + const typename period_formatter::char_type + period_formatter::default_period_start_delimeter[2] = {'['}; + + template + const typename period_formatter::char_type + period_formatter::default_period_open_range_end_delimeter[2] = {')'}; + + template + const typename period_formatter::char_type + period_formatter::default_period_closed_range_end_delimeter[2] = {']'}; + + } } //namespace boost::date_time + +#endif diff --git a/cpp/BoostParts/boost/date_time/period_parser.hpp b/cpp/BoostParts/boost/date_time/period_parser.hpp new file mode 100644 index 00000000..84b9d137 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/period_parser.hpp @@ -0,0 +1,198 @@ + +#ifndef DATETIME_PERIOD_PARSER_HPP___ +#define DATETIME_PERIOD_PARSER_HPP___ + +/* Copyright (c) 2002-2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-11-13 12:10:23 -0800 (Thu, 13 Nov 2008) $ + */ + +#include +#include +#include + + +namespace boost { namespace date_time { + + + //! Not a facet, but a class used to specify and control period parsing + /*! Provides settings for the following: + * - period_separator -- default '/' + * - period_open_start_delimeter -- default '[' + * - period_open_range_end_delimeter -- default ')' + * - period_closed_range_end_delimeter -- default ']' + * - display_as_open_range, display_as_closed_range -- default closed_range + * + * For a typical date_period, the contents of the input stream would be + *@code + * [2004-Jan-04/2004-Feb-01] + *@endcode + * where the date format is controlled by the date facet + */ + template + class period_parser { + public: + typedef std::basic_string string_type; + typedef CharT char_type; + //typedef typename std::basic_string::const_iterator const_itr_type; + typedef std::istreambuf_iterator stream_itr_type; + typedef string_parse_tree parse_tree_type; + typedef typename parse_tree_type::parse_match_result_type match_results; + typedef std::vector > collection_type; + + static const char_type default_period_separator[2]; + static const char_type default_period_start_delimeter[2]; + static const char_type default_period_open_range_end_delimeter[2]; + static const char_type default_period_closed_range_end_delimeter[2]; + + enum period_range_option { AS_OPEN_RANGE, AS_CLOSED_RANGE }; + + //! Constructor that sets up period parser options + period_parser(period_range_option range_opt = AS_CLOSED_RANGE, + const char_type* const period_separator = default_period_separator, + const char_type* const period_start_delimeter = default_period_start_delimeter, + const char_type* const period_open_range_end_delimeter = default_period_open_range_end_delimeter, + const char_type* const period_closed_range_end_delimeter = default_period_closed_range_end_delimeter) + : m_range_option(range_opt) + { + delimiters.push_back(string_type(period_separator)); + delimiters.push_back(string_type(period_start_delimeter)); + delimiters.push_back(string_type(period_open_range_end_delimeter)); + delimiters.push_back(string_type(period_closed_range_end_delimeter)); + } + + period_parser(const period_parser& p_parser) + { + this->delimiters = p_parser.delimiters; + this->m_range_option = p_parser.m_range_option; + } + + period_range_option range_option() const + { + return m_range_option; + } + void range_option(period_range_option option) + { + m_range_option = option; + } + collection_type delimiter_strings() const + { + return delimiters; + } + void delimiter_strings(const string_type& separator, + const string_type& start_delim, + const string_type& open_end_delim, + const string_type& closed_end_delim) + { + delimiters.clear(); + delimiters.push_back(separator); + delimiters.push_back(start_delim); + delimiters.push_back(open_end_delim); + delimiters.push_back(closed_end_delim); + } + + //! Generic code to parse a period -- no matter the period type. + /*! This generic code will parse any period using a facet to + * to get the 'elements'. For example, in the case of a date_period + * the elements will be instances of a date which will be parsed + * according the to setup in the passed facet parameter. + * + * The steps for parsing a period are always the same: + * - consume the start delimiter + * - get start element + * - consume the separator + * - get either last or end element depending on range settings + * - consume the end delimeter depending on range settings + * + * Thus for a typical date period the contents of the input stream + * might look like this: + *@code + * + * [March 01, 2004/June 07, 2004] <-- closed range + * [March 01, 2004/June 08, 2004) <-- open range + * + *@endcode + */ + template + period_type get_period(stream_itr_type& sitr, + stream_itr_type& stream_end, + std::ios_base& a_ios, + const period_type& /* p */, + const duration_type& dur_unit, + const facet_type& facet) const + { + // skip leading whitespace + while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } + + typedef typename period_type::point_type point_type; + point_type p1(not_a_date_time), p2(not_a_date_time); + + + consume_delim(sitr, stream_end, delimiters[START]); // start delim + facet.get(sitr, stream_end, a_ios, p1); // first point + consume_delim(sitr, stream_end, delimiters[SEPARATOR]); // separator + facet.get(sitr, stream_end, a_ios, p2); // second point + + // period construction parameters are always open range [begin, end) + if (m_range_option == AS_CLOSED_RANGE) { + consume_delim(sitr, stream_end, delimiters[CLOSED_END]);// end delim + // add 1 duration unit to p2 to make range open + p2 += dur_unit; + } + else { + consume_delim(sitr, stream_end, delimiters[OPEN_END]); // end delim + } + + return period_type(p1, p2); + } + + private: + collection_type delimiters; + period_range_option m_range_option; + + enum delim_ids { SEPARATOR, START, OPEN_END, CLOSED_END }; + + //! throws ios_base::failure if delimiter and parsed data do not match + void consume_delim(stream_itr_type& sitr, + stream_itr_type& stream_end, + const string_type& delim) const + { + /* string_parse_tree will not parse a string of punctuation characters + * without knowing exactly how many characters to process + * Ex [2000. Will not parse out the '[' string without knowing + * to process only one character. By using length of the delimiter + * string we can safely iterate past it. */ + string_type s; + for(unsigned int i = 0; i < delim.length() && sitr != stream_end; ++i) { + s += *sitr; + ++sitr; + } + if(s != delim) { + boost::throw_exception(std::ios_base::failure("Parse failed. Expected '" + + convert_string_type(delim) + "' but found '" + convert_string_type(s) + "'")); + } + } + }; + + template + const typename period_parser::char_type + period_parser::default_period_separator[2] = {'/'}; + + template + const typename period_parser::char_type + period_parser::default_period_start_delimeter[2] = {'['}; + + template + const typename period_parser::char_type + period_parser::default_period_open_range_end_delimeter[2] = {')'}; + + template + const typename period_parser::char_type + period_parser::default_period_closed_range_end_delimeter[2] = {']'}; + + } } //namespace boost::date_time + +#endif // DATETIME_PERIOD_PARSER_HPP___ diff --git a/cpp/BoostParts/boost/date_time/posix_time/time_formatters.hpp b/cpp/BoostParts/boost/date_time/posix_time/time_formatters.hpp new file mode 100644 index 00000000..534b9525 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/posix_time/time_formatters.hpp @@ -0,0 +1,289 @@ +#ifndef POSIXTIME_FORMATTERS_HPP___ +#define POSIXTIME_FORMATTERS_HPP___ + +/* Copyright (c) 2002-2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2010-01-10 11:17:23 -0800 (Sun, 10 Jan 2010) $ + */ + +#include +#include +#include +#include +#include +#include +#include // absolute_value +#include + +/* NOTE: The "to_*_string" code for older compilers, ones that define + * BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS, is located in + * formatters_limited.hpp + */ + +namespace boost { + +namespace posix_time { + + // template function called by wrapper functions: + // to_*_string(time_duration) & to_*_wstring(time_duration) + template + inline std::basic_string to_simple_string_type(time_duration td) { + std::basic_ostringstream ss; + if(td.is_special()) { + /* simply using 'ss << td.get_rep()' won't work on compilers + * that don't support locales. This way does. */ + // switch copied from date_names_put.hpp + switch(td.get_rep().as_special()) + { + case not_a_date_time: + //ss << "not-a-number"; + ss << "not-a-date-time"; + break; + case pos_infin: + ss << "+infinity"; + break; + case neg_infin: + ss << "-infinity"; + break; + default: + ss << ""; + } + } + else { + charT fill_char = '0'; + if(td.is_negative()) { + ss << '-'; + } + ss << std::setw(2) << std::setfill(fill_char) + << date_time::absolute_value(td.hours()) << ":"; + ss << std::setw(2) << std::setfill(fill_char) + << date_time::absolute_value(td.minutes()) << ":"; + ss << std::setw(2) << std::setfill(fill_char) + << date_time::absolute_value(td.seconds()); + //TODO the following is totally non-generic, yelling FIXME +#if (defined(BOOST_MSVC) && (_MSC_VER < 1300)) + boost::int64_t frac_sec = + date_time::absolute_value(td.fractional_seconds()); + // JDG [7/6/02 VC++ compatibility] + charT buff[32]; + _i64toa(frac_sec, buff, 10); +#else + time_duration::fractional_seconds_type frac_sec = + date_time::absolute_value(td.fractional_seconds()); +#endif + if (frac_sec != 0) { + ss << "." << std::setw(time_duration::num_fractional_digits()) + << std::setfill(fill_char) + + // JDG [7/6/02 VC++ compatibility] +#if (defined(BOOST_MSVC) && (_MSC_VER < 1300)) + << buff; +#else + << frac_sec; +#endif + } + }// else + return ss.str(); + } + //! Time duration to string -hh::mm::ss.fffffff. Example: 10:09:03.0123456 + /*!\ingroup time_format + */ + inline std::string to_simple_string(time_duration td) { + return to_simple_string_type(td); + } + + + // template function called by wrapper functions: + // to_*_string(time_duration) & to_*_wstring(time_duration) + template + inline std::basic_string to_iso_string_type(time_duration td) + { + std::basic_ostringstream ss; + if(td.is_special()) { + /* simply using 'ss << td.get_rep()' won't work on compilers + * that don't support locales. This way does. */ + // switch copied from date_names_put.hpp + switch(td.get_rep().as_special()) { + case not_a_date_time: + //ss << "not-a-number"; + ss << "not-a-date-time"; + break; + case pos_infin: + ss << "+infinity"; + break; + case neg_infin: + ss << "-infinity"; + break; + default: + ss << ""; + } + } + else { + charT fill_char = '0'; + if(td.is_negative()) { + ss << '-'; + } + ss << std::setw(2) << std::setfill(fill_char) + << date_time::absolute_value(td.hours()); + ss << std::setw(2) << std::setfill(fill_char) + << date_time::absolute_value(td.minutes()); + ss << std::setw(2) << std::setfill(fill_char) + << date_time::absolute_value(td.seconds()); + //TODO the following is totally non-generic, yelling FIXME +#if (defined(BOOST_MSVC) && (_MSC_VER < 1300)) + boost::int64_t frac_sec = + date_time::absolute_value(td.fractional_seconds()); + // JDG [7/6/02 VC++ compatibility] + charT buff[32]; + _i64toa(frac_sec, buff, 10); +#else + time_duration::fractional_seconds_type frac_sec = + date_time::absolute_value(td.fractional_seconds()); +#endif + if (frac_sec != 0) { + ss << "." << std::setw(time_duration::num_fractional_digits()) + << std::setfill(fill_char) + + // JDG [7/6/02 VC++ compatibility] +#if (defined(BOOST_MSVC) && (_MSC_VER < 1300)) + << buff; +#else + << frac_sec; +#endif + } + }// else + return ss.str(); + } + //! Time duration in iso format -hhmmss,fffffff Example: 10:09:03,0123456 + /*!\ingroup time_format + */ + inline std::string to_iso_string(time_duration td){ + return to_iso_string_type(td); + } + + //! Time to simple format CCYY-mmm-dd hh:mm:ss.fffffff + /*!\ingroup time_format + */ + template + inline std::basic_string to_simple_string_type(ptime t) + { + // can't use this w/gcc295, no to_simple_string_type<>(td) available + std::basic_string ts = gregorian::to_simple_string_type(t.date());// + " "; + if(!t.time_of_day().is_special()) { + charT space = ' '; + return ts + space + to_simple_string_type(t.time_of_day()); + } + else { + return ts; + } + } + inline std::string to_simple_string(ptime t){ + return to_simple_string_type(t); + } + + // function called by wrapper functions to_*_string(time_period) + // & to_*_wstring(time_period) + template + inline std::basic_string to_simple_string_type(time_period tp) + { + charT beg = '[', mid = '/', end = ']'; + std::basic_string d1(to_simple_string_type(tp.begin())); + std::basic_string d2(to_simple_string_type(tp.last())); + return std::basic_string(beg + d1 + mid + d2 + end); + } + //! Convert to string of form [YYYY-mmm-DD HH:MM::SS.ffffff/YYYY-mmm-DD HH:MM::SS.fffffff] + /*!\ingroup time_format + */ + inline std::string to_simple_string(time_period tp){ + return to_simple_string_type(tp); + } + + // function called by wrapper functions to_*_string(time_period) + // & to_*_wstring(time_period) + template + inline std::basic_string to_iso_string_type(ptime t) + { + std::basic_string ts = gregorian::to_iso_string_type(t.date());// + "T"; + if(!t.time_of_day().is_special()) { + charT sep = 'T'; + return ts + sep + to_iso_string_type(t.time_of_day()); + } + else { + return ts; + } + } + //! Convert iso short form YYYYMMDDTHHMMSS where T is the date-time separator + /*!\ingroup time_format + */ + inline std::string to_iso_string(ptime t){ + return to_iso_string_type(t); + } + + + // function called by wrapper functions to_*_string(time_period) + // & to_*_wstring(time_period) + template + inline std::basic_string to_iso_extended_string_type(ptime t) + { + std::basic_string ts = gregorian::to_iso_extended_string_type(t.date());// + "T"; + if(!t.time_of_day().is_special()) { + charT sep = 'T'; + return ts + sep + to_simple_string_type(t.time_of_day()); + } + else { + return ts; + } + } + //! Convert to form YYYY-MM-DDTHH:MM:SS where T is the date-time separator + /*!\ingroup time_format + */ + inline std::string to_iso_extended_string(ptime t){ + return to_iso_extended_string_type(t); + } + +#if !defined(BOOST_NO_STD_WSTRING) + //! Time duration to wstring -hh::mm::ss.fffffff. Example: 10:09:03.0123456 + /*!\ingroup time_format + */ + inline std::wstring to_simple_wstring(time_duration td) { + return to_simple_string_type(td); + } + //! Time duration in iso format -hhmmss,fffffff Example: 10:09:03,0123456 + /*!\ingroup time_format + */ + inline std::wstring to_iso_wstring(time_duration td){ + return to_iso_string_type(td); + } + inline std::wstring to_simple_wstring(ptime t){ + return to_simple_string_type(t); + } + //! Convert to wstring of form [YYYY-mmm-DD HH:MM::SS.ffffff/YYYY-mmm-DD HH:MM::SS.fffffff] + /*!\ingroup time_format + */ + inline std::wstring to_simple_wstring(time_period tp){ + return to_simple_string_type(tp); + } + //! Convert iso short form YYYYMMDDTHHMMSS where T is the date-time separator + /*!\ingroup time_format + */ + inline std::wstring to_iso_wstring(ptime t){ + return to_iso_string_type(t); + } + //! Convert to form YYYY-MM-DDTHH:MM:SS where T is the date-time separator + /*!\ingroup time_format + */ + inline std::wstring to_iso_extended_wstring(ptime t){ + return to_iso_extended_string_type(t); + } + +#endif // BOOST_NO_STD_WSTRING + + +} } //namespace posix_time + + +#endif + diff --git a/cpp/BoostParts/boost/date_time/special_values_formatter.hpp b/cpp/BoostParts/boost/date_time/special_values_formatter.hpp new file mode 100644 index 00000000..53fe9845 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/special_values_formatter.hpp @@ -0,0 +1,96 @@ + +#ifndef DATETIME_SPECIAL_VALUE_FORMATTER_HPP___ +#define DATETIME_SPECIAL_VALUE_FORMATTER_HPP___ + +/* Copyright (c) 2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland + * $Date: 2008-02-27 12:00:24 -0800 (Wed, 27 Feb 2008) $ + */ + +#include +#include +#include "boost/date_time/special_defs.hpp" + +namespace boost { namespace date_time { + + + //! Class that provides generic formmatting ostream formatting for special values + /*! This class provides for the formmating of special values to an output stream. + * In particular, it produces strings for the values of negative and positive + * infinity as well as not_a_date_time. + * + * While not a facet, this class is used by the date and time facets for formatting + * special value types. + * + */ + template > > + class special_values_formatter + { + public: + typedef std::basic_string string_type; + typedef CharT char_type; + typedef std::vector collection_type; + static const char_type default_special_value_names[3][17]; + + //! Construct special values formatter using default strings. + /*! Default strings are not-a-date-time -infinity +infinity + */ + special_values_formatter() + { + std::copy(&default_special_value_names[0], + &default_special_value_names[3], + std::back_inserter(m_special_value_names)); + } + + //! Construct special values formatter from array of strings + /*! This constructor will take pair of iterators from an array of strings + * that represent the special values and copy them for use in formatting + * special values. + *@code + * const char* const special_value_names[]={"nadt","-inf","+inf" }; + * + * special_value_formatter svf(&special_value_names[0], &special_value_names[3]); + *@endcode + */ + special_values_formatter(const char_type* const* begin, const char_type* const* end) + { + std::copy(begin, end, std::back_inserter(m_special_value_names)); + } + special_values_formatter(typename collection_type::iterator beg, typename collection_type::iterator end) + { + std::copy(beg, end, std::back_inserter(m_special_value_names)); + } + + OutItrT put_special(OutItrT next, + const boost::date_time::special_values& value) const + { + + unsigned int index = value; + if (index < m_special_value_names.size()) { + std::copy(m_special_value_names[index].begin(), + m_special_value_names[index].end(), + next); + } + return next; + } + protected: + collection_type m_special_value_names; + }; + + //! Storage for the strings used to indicate special values + /* using c_strings to initialize these worked fine in testing, however, + * a project that compiled its objects separately, then linked in a separate + * step wound up with redefinition errors for the values in this array. + * Initializing individual characters eliminated this problem */ + template + const typename special_values_formatter::char_type special_values_formatter::default_special_value_names[3][17] = { + {'n','o','t','-','a','-','d','a','t','e','-','t','i','m','e'}, + {'-','i','n','f','i','n','i','t','y'}, + {'+','i','n','f','i','n','i','t','y'} }; + + } } //namespace boost::date_time + +#endif diff --git a/cpp/BoostParts/boost/date_time/special_values_parser.hpp b/cpp/BoostParts/boost/date_time/special_values_parser.hpp new file mode 100644 index 00000000..e48ec5fd --- /dev/null +++ b/cpp/BoostParts/boost/date_time/special_values_parser.hpp @@ -0,0 +1,159 @@ + +#ifndef DATE_TIME_SPECIAL_VALUES_PARSER_HPP__ +#define DATE_TIME_SPECIAL_VALUES_PARSER_HPP__ + +/* Copyright (c) 2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: + */ + + +#include "boost/date_time/string_parse_tree.hpp" +#include "boost/date_time/special_defs.hpp" +#include +#include + +namespace boost { namespace date_time { + + //! Class for special_value parsing + /*! + * TODO: add doc-comments for which elements can be changed + * Parses input stream for strings representing special_values. + * Special values parsed are: + * - not_a_date_time + * - neg_infin + * - pod_infin + * - min_date_time + * - max_date_time + */ + template + class special_values_parser + { + public: + typedef std::basic_string string_type; + //typedef std::basic_stringstream stringstream_type; + typedef std::istreambuf_iterator stream_itr_type; + //typedef typename string_type::const_iterator const_itr; + //typedef typename date_type::year_type year_type; + //typedef typename date_type::month_type month_type; + typedef typename date_type::duration_type duration_type; + //typedef typename date_type::day_of_week_type day_of_week_type; + //typedef typename date_type::day_type day_type; + typedef string_parse_tree parse_tree_type; + typedef typename parse_tree_type::parse_match_result_type match_results; + typedef std::vector > collection_type; + + typedef charT char_type; + static const char_type nadt_string[16]; + static const char_type neg_inf_string[10]; + static const char_type pos_inf_string[10]; + static const char_type min_date_time_string[18]; + static const char_type max_date_time_string[18]; + + //! Creates a special_values_parser with the default set of "sv_strings" + special_values_parser() + { + sv_strings(string_type(nadt_string), + string_type(neg_inf_string), + string_type(pos_inf_string), + string_type(min_date_time_string), + string_type(max_date_time_string)); + } + + //! Creates a special_values_parser using a user defined set of element strings + special_values_parser(const string_type& nadt_str, + const string_type& neg_inf_str, + const string_type& pos_inf_str, + const string_type& min_dt_str, + const string_type& max_dt_str) + { + sv_strings(nadt_str, neg_inf_str, pos_inf_str, min_dt_str, max_dt_str); + } + + special_values_parser(typename collection_type::iterator beg, typename collection_type::iterator end) + { + collection_type phrases; + std::copy(beg, end, std::back_inserter(phrases)); + m_sv_strings = parse_tree_type(phrases, static_cast(not_a_date_time)); + } + + special_values_parser(const special_values_parser& svp) + { + this->m_sv_strings = svp.m_sv_strings; + } + + //! Replace special value strings + void sv_strings(const string_type& nadt_str, + const string_type& neg_inf_str, + const string_type& pos_inf_str, + const string_type& min_dt_str, + const string_type& max_dt_str) + { + collection_type phrases; + phrases.push_back(nadt_str); + phrases.push_back(neg_inf_str); + phrases.push_back(pos_inf_str); + phrases.push_back(min_dt_str); + phrases.push_back(max_dt_str); + m_sv_strings = parse_tree_type(phrases, static_cast(not_a_date_time)); + } + + /* Does not return a special_value because if the parsing fails, + * the return value will always be not_a_date_time + * (mr.current_match retains its default value of -1 on a failed + * parse and that casts to not_a_date_time). */ + //! Sets match_results.current_match to the corresponding special_value or -1 + bool match(stream_itr_type& sitr, + stream_itr_type& str_end, + match_results& mr) const + { + unsigned int level = 0; + m_sv_strings.match(sitr, str_end, mr, level); + return (mr.current_match != match_results::PARSE_ERROR); + } + /*special_values match(stream_itr_type& sitr, + stream_itr_type& str_end, + match_results& mr) const + { + unsigned int level = 0; + m_sv_strings.match(sitr, str_end, mr, level); + if(mr.current_match == match_results::PARSE_ERROR) { + throw std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'"); + } + return static_cast(mr.current_match); + }*/ + + + private: + parse_tree_type m_sv_strings; + + }; + + template + const typename special_values_parser::char_type + special_values_parser::nadt_string[16] = + {'n','o','t','-','a','-','d','a','t','e','-','t','i','m','e'}; + template + const typename special_values_parser::char_type + special_values_parser::neg_inf_string[10] = + {'-','i','n','f','i','n','i','t','y'}; + template + const typename special_values_parser::char_type + special_values_parser::pos_inf_string[10] = + {'+','i','n','f','i','n','i','t','y'}; + template + const typename special_values_parser::char_type + special_values_parser::min_date_time_string[18] = + {'m','i','n','i','m','u','m','-','d','a','t','e','-','t','i','m','e'}; + template + const typename special_values_parser::char_type + special_values_parser::max_date_time_string[18] = + {'m','a','x','i','m','u','m','-','d','a','t','e','-','t','i','m','e'}; + +} } //namespace + +#endif // DATE_TIME_SPECIAL_VALUES_PARSER_HPP__ + diff --git a/cpp/BoostParts/boost/date_time/string_convert.hpp b/cpp/BoostParts/boost/date_time/string_convert.hpp new file mode 100644 index 00000000..a3cc86c2 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/string_convert.hpp @@ -0,0 +1,33 @@ +#ifndef _STRING_CONVERT_HPP___ +#define _STRING_CONVERT_HPP___ + +/* Copyright (c) 2005 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 12:00:24 -0800 (Wed, 27 Feb 2008) $ + */ + +#include "boost/date_time/compiler_config.hpp" +#include + +namespace boost { +namespace date_time { + + //! Converts a string from one value_type to another + /*! Converts a wstring to a string (or a string to wstring). If both template parameters + * are of same type, a copy of the input string is returned. */ + template + inline + std::basic_string convert_string_type(const std::basic_string& inp_str) + { + typedef std::basic_string input_type; + typedef std::basic_string output_type; + output_type result; + result.insert(result.begin(), inp_str.begin(), inp_str.end()); + return result; + } + +}} // namespace boost::date_time + +#endif // _STRING_CONVERT_HPP___ diff --git a/cpp/BoostParts/boost/date_time/string_parse_tree.hpp b/cpp/BoostParts/boost/date_time/string_parse_tree.hpp new file mode 100644 index 00000000..d67bf6b7 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/string_parse_tree.hpp @@ -0,0 +1,278 @@ +#ifndef BOOST_DATE_TIME_STRING_PARSE_TREE___HPP__ +#define BOOST_DATE_TIME_STRING_PARSE_TREE___HPP__ + +/* Copyright (c) 2004-2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-11-12 11:37:53 -0800 (Wed, 12 Nov 2008) $ + */ + + +#include "boost/lexical_cast.hpp" //error without? +#include "boost/algorithm/string/case_conv.hpp" +#include +#include +#include +#include + +namespace boost { namespace date_time { + + +template +struct parse_match_result +{ + parse_match_result() : + match_depth(0), + current_match(-1)// -1 is match_not-found value + {} + typedef std::basic_string string_type; + string_type remaining() const + { + if (match_depth == cache.size()) { + return string_type(); + } + if (current_match == -1) { + return cache; + } + //some of the cache was used return the rest + return string_type(cache, match_depth); + } + charT last_char() const + { + return cache[cache.size()-1]; + } + //! Returns true if more characters were parsed than was necessary + /*! Should be used in conjunction with last_char() + * to get the remaining character. + */ + bool has_remaining() const + { + return (cache.size() > match_depth); + } + + // cache will hold characters that have been read from the stream + string_type cache; + unsigned short match_depth; + short current_match; + enum PARSE_STATE { PARSE_ERROR= -1 }; +}; + + //for debug -- really only char streams... +template +std::basic_ostream& +operator<<(std::basic_ostream& os, parse_match_result& mr) +{ + os << "cm: " << mr.current_match + << " C: '" << mr.cache + << "' md: " << mr.match_depth + << " R: " << mr.remaining(); + return os; +} + + + +//! Recursive data structure to allow efficient parsing of various strings +/*! This class provides a quick lookup by building what amounts to a + * tree data structure. It also features a match function which can + * can handle nasty input interators by caching values as it recurses + * the tree so that it can backtrack as needed. + */ +template +struct string_parse_tree +{ +#if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT(0x581) ) + typedef std::multimap > ptree_coll; +#else + typedef std::multimap ptree_coll; +#endif + typedef typename ptree_coll::value_type value_type; + typedef typename ptree_coll::iterator iterator; + typedef typename ptree_coll::const_iterator const_iterator; + typedef std::basic_string string_type; + typedef std::vector > collection_type; + typedef parse_match_result parse_match_result_type; + + /*! Parameter "starting_point" designates where the numbering begins. + * A starting_point of zero will start the numbering at zero + * (Sun=0, Mon=1, ...) were a starting_point of one starts the + * numbering at one (Jan=1, Feb=2, ...). The default is zero, + * negative vaules are not allowed */ + string_parse_tree(collection_type names, unsigned int starting_point=0) + { + // iterate thru all the elements and build the tree + unsigned short index = 0; + while (index != names.size() ) { + string_type s = boost::algorithm::to_lower_copy(names[index]); + insert(s, static_cast(index + starting_point)); + index++; + } + //set the last tree node = index+1 indicating a value + index++; + } + + + string_parse_tree(short value = -1) : + m_value(value) + {} + ptree_coll m_next_chars; + short m_value; + + void insert(const string_type& s, unsigned short value) + { + unsigned int i = 0; + iterator ti; + while(i < s.size()) { + if (i==0) { + if (i == (s.size()-1)) { + ti = m_next_chars.insert(value_type(s[i], + string_parse_tree(value))); + } + else { + ti = m_next_chars.insert(value_type(s[i], + string_parse_tree())); + } + } + else { + if (i == (s.size()-1)) { + ti = ti->second.m_next_chars.insert(value_type(s[i], + string_parse_tree(value))); + } + + else { + ti = ti->second.m_next_chars.insert(value_type(s[i], + string_parse_tree())); + } + + } + i++; + } + } + + + //! Recursive function that finds a matching string in the tree. + /*! Must check match_results::has_remaining() after match() is + * called. This is required so the user can determine if + * stream iterator is already pointing to the expected + * character or not (match() might advance sitr to next char in stream). + * + * A parse_match_result that has been returned from a failed match + * attempt can be sent in to the match function of a different + * string_parse_tree to attempt a match there. Use the iterators + * for the partially consumed stream, the parse_match_result object, + * and '0' for the level parameter. */ + short + match(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end, + parse_match_result_type& result, + unsigned int& level) const + { + + level++; + charT c; + // if we conditionally advance sitr, we won't have + // to consume the next character past the input + bool adv_itr = true; + if (level > result.cache.size()) { + if (sitr == stream_end) return 0; //bail - input exhausted + c = static_cast(std::tolower(*sitr)); + //result.cache += c; + //sitr++; + } + else { + // if we're looking for characters from the cache, + // we don't want to increment sitr + adv_itr = false; + c = static_cast(std::tolower(result.cache[level-1])); + } + const_iterator litr = m_next_chars.lower_bound(c); + const_iterator uitr = m_next_chars.upper_bound(c); + while (litr != uitr) { // equal if not found + if(adv_itr) { + sitr++; + result.cache += c; + } + if (litr->second.m_value != -1) { // -1 is default value + if (result.match_depth < level) { + result.current_match = litr->second.m_value; + result.match_depth = static_cast(level); + } + litr->second.match(sitr, stream_end, + result, level); + level--; + } + else { + litr->second.match(sitr, stream_end, + result, level); + level--; + } + + if(level <= result.cache.size()) { + adv_itr = false; + } + + litr++; + } + return result.current_match; + + } + + /*! Must check match_results::has_remaining() after match() is + * called. This is required so the user can determine if + * stream iterator is already pointing to the expected + * character or not (match() might advance sitr to next char in stream). + */ + parse_match_result_type + match(std::istreambuf_iterator& sitr, + std::istreambuf_iterator& stream_end) const + { + // lookup to_lower of char in tree. + unsigned int level = 0; + // string_type cache; + parse_match_result_type result; + match(sitr, stream_end, result, level); + return result; + } + + void printme(std::ostream& os, int& level) + { + level++; + iterator itr = m_next_chars.begin(); + iterator end = m_next_chars.end(); + // os << "starting level: " << level << std::endl; + while (itr != end) { + os << "level: " << level + << " node: " << itr->first + << " value: " << itr->second.m_value + << std::endl; + itr->second.printme(os, level); + itr++; + } + level--; + } + + void print(std::ostream& os) + { + int level = 0; + printme(os, level); + } + + void printmatch(std::ostream& os, charT c) + { + iterator litr = m_next_chars.lower_bound(c); + iterator uitr = m_next_chars.upper_bound(c); + os << "matches for: " << c << std::endl; + while (litr != uitr) { + os << " node: " << litr->first + << " value: " << litr->second.m_value + << std::endl; + litr++; + } + } + +}; + + +} } //namespace +#endif diff --git a/cpp/BoostParts/boost/date_time/strings_from_facet.hpp b/cpp/BoostParts/boost/date_time/strings_from_facet.hpp new file mode 100644 index 00000000..7c0765bf --- /dev/null +++ b/cpp/BoostParts/boost/date_time/strings_from_facet.hpp @@ -0,0 +1,125 @@ +#ifndef DATE_TIME_STRINGS_FROM_FACET__HPP___ +#define DATE_TIME_STRINGS_FROM_FACET__HPP___ + +/* Copyright (c) 2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland + * $Date: 2012-09-22 09:04:10 -0700 (Sat, 22 Sep 2012) $ + */ + +#include +#include +#include +#include + +namespace boost { namespace date_time { + +//! This function gathers up all the month strings from a std::locale +/*! Using the time_put facet, this function creates a collection of + * all the month strings from a locale. This is handy when building + * custom date parsers or formatters that need to be localized. + * + *@param charT The type of char to use when gathering typically char + * or wchar_t. + *@param locale The locale to use when gathering the strings + *@param short_strings True(default) to gather short strings, + * false for long strings. + *@return A vector of strings containing the strings in order. eg: + * Jan, Feb, Mar, etc. + */ +template +std::vector > +gather_month_strings(const std::locale& locale, bool short_strings=true) +{ + typedef std::basic_string string_type; + typedef std::vector collection_type; + typedef std::basic_ostringstream ostream_type; + typedef std::ostreambuf_iterator ostream_iter_type; + typedef std::basic_ostringstream stringstream_type; + typedef std::time_put time_put_facet_type; + charT short_fmt[3] = { '%', 'b' }; + charT long_fmt[3] = { '%', 'B' }; + collection_type months; + string_type outfmt(short_fmt); + if (!short_strings) { + outfmt = long_fmt; + } + { + //grab the needed strings by using the locale to + //output each month + const charT* p_outfmt = outfmt.c_str(), *p_outfmt_end = p_outfmt + outfmt.size(); + tm tm_value = {}; + for (int m=0; m < 12; m++) { + tm_value.tm_mon = m; + stringstream_type ss; + ostream_iter_type oitr(ss); + std::use_facet(locale).put(oitr, ss, ss.fill(), + &tm_value, + p_outfmt, + p_outfmt_end); + months.push_back(ss.str()); + } + } + return months; +} + +//! This function gathers up all the weekday strings from a std::locale +/*! Using the time_put facet, this function creates a collection of + * all the weekday strings from a locale starting with the string for + * 'Sunday'. This is handy when building custom date parsers or + * formatters that need to be localized. + * + *@param charT The type of char to use when gathering typically char + * or wchar_t. + *@param locale The locale to use when gathering the strings + *@param short_strings True(default) to gather short strings, + * false for long strings. + *@return A vector of strings containing the weekdays in order. eg: + * Sun, Mon, Tue, Wed, Thu, Fri, Sat + */ +template +std::vector > +gather_weekday_strings(const std::locale& locale, bool short_strings=true) +{ + typedef std::basic_string string_type; + typedef std::vector collection_type; + typedef std::basic_ostringstream ostream_type; + typedef std::ostreambuf_iterator ostream_iter_type; + typedef std::basic_ostringstream stringstream_type; + typedef std::time_put time_put_facet_type; + charT short_fmt[3] = { '%', 'a' }; + charT long_fmt[3] = { '%', 'A' }; + + collection_type weekdays; + + + string_type outfmt(short_fmt); + if (!short_strings) { + outfmt = long_fmt; + } + { + //grab the needed strings by using the locale to + //output each month / weekday + const charT* p_outfmt = outfmt.c_str(), *p_outfmt_end = p_outfmt + outfmt.size(); + tm tm_value = {}; + for (int i=0; i < 7; i++) { + tm_value.tm_wday = i; + stringstream_type ss; + ostream_iter_type oitr(ss); + std::use_facet(locale).put(oitr, ss, ss.fill(), + &tm_value, + p_outfmt, + p_outfmt_end); + + weekdays.push_back(ss.str()); + } + } + return weekdays; +} + +} } //namespace + + +#endif diff --git a/cpp/BoostParts/boost/date_time/time_formatting_streams.hpp b/cpp/BoostParts/boost/date_time/time_formatting_streams.hpp new file mode 100644 index 00000000..2d07d344 --- /dev/null +++ b/cpp/BoostParts/boost/date_time/time_formatting_streams.hpp @@ -0,0 +1,122 @@ +#ifndef DATE_TIME_TIME_FORMATTING_STREAMS_HPP___ +#define DATE_TIME_TIME_FORMATTING_STREAMS_HPP___ + +/* Copyright (c) 2002,2003 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-11-12 11:37:53 -0800 (Wed, 12 Nov 2008) $ + */ + +#include + +#ifndef BOOST_DATE_TIME_NO_LOCALE + +#include +#include +#include +#include +#include + +namespace boost { +namespace date_time { + + + //! Put a time type into a stream using appropriate facets + template + class ostream_time_duration_formatter + { + public: + typedef std::basic_ostream ostream_type; + typedef typename time_duration_type::fractional_seconds_type fractional_seconds_type; + + //! Put time into an ostream + static void duration_put(const time_duration_type& td, + ostream_type& os) + { + if(td.is_special()) { + os << td.get_rep(); + } + else { + charT fill_char = '0'; + if(td.is_negative()) { + os << '-'; + } + os << std::setw(2) << std::setfill(fill_char) + << absolute_value(td.hours()) << ":"; + os << std::setw(2) << std::setfill(fill_char) + << absolute_value(td.minutes()) << ":"; + os << std::setw(2) << std::setfill(fill_char) + << absolute_value(td.seconds()); + fractional_seconds_type frac_sec = + absolute_value(td.fractional_seconds()); + if (frac_sec != 0) { + os << "." + << std::setw(time_duration_type::num_fractional_digits()) + << std::setfill(fill_char) + << frac_sec; + } + } // else + } // duration_put + }; //class ostream_time_duration_formatter + + //! Put a time type into a stream using appropriate facets + template + class ostream_time_formatter + { + public: + typedef std::basic_ostream ostream_type; + typedef typename time_type::date_type date_type; + typedef typename time_type::time_duration_type time_duration_type; + typedef ostream_time_duration_formatter duration_formatter; + + //! Put time into an ostream + static void time_put(const time_type& t, + ostream_type& os) + { + date_type d = t.date(); + os << d; + if(!d.is_infinity() && !d.is_not_a_date()) + { + os << " "; //TODO: fix the separator here. + duration_formatter::duration_put(t.time_of_day(), os); + } + + } // time_to_ostream + }; //class ostream_time_formatter + + + //! Put a time period into a stream using appropriate facets + template + class ostream_time_period_formatter + { + public: + typedef std::basic_ostream ostream_type; + typedef typename time_period_type::point_type time_type; + typedef ostream_time_formatter time_formatter; + + //! Put time into an ostream + static void period_put(const time_period_type& tp, + ostream_type& os) + { + os << '['; //TODO: facet or manipulator for periods? + time_formatter::time_put(tp.begin(), os); + os << '/'; //TODO: facet or manipulator for periods? + time_formatter::time_put(tp.last(), os); + os << ']'; + + } // period_put + + }; //class ostream_time_period_formatter + + + +} } //namespace date_time + +#endif //BOOST_DATE_TIME_NO_LOCALE + +#endif diff --git a/cpp/BoostParts/boost/date_time/time_parsing.hpp b/cpp/BoostParts/boost/date_time/time_parsing.hpp new file mode 100644 index 00000000..7b71de0d --- /dev/null +++ b/cpp/BoostParts/boost/date_time/time_parsing.hpp @@ -0,0 +1,324 @@ +#ifndef _DATE_TIME_TIME_PARSING_HPP___ +#define _DATE_TIME_TIME_PARSING_HPP___ + +/* Copyright (c) 2002,2003,2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2012-10-10 12:05:03 -0700 (Wed, 10 Oct 2012) $ + */ + +#include "boost/tokenizer.hpp" +#include "boost/lexical_cast.hpp" +#include "boost/date_time/date_parsing.hpp" +#include "boost/cstdint.hpp" +#include + +namespace boost { +namespace date_time { + + //! computes exponential math like 2^8 => 256, only works with positive integers + //Not general purpose, but needed b/c std::pow is not available + //everywehere. Hasn't been tested with negatives and zeros + template + inline + int_type power(int_type base, int_type exponent) + { + int_type result = 1; + for(int i = 0; i < exponent; ++i){ + result *= base; + } + return result; + } + + //! Creates a time_duration object from a delimited string + /*! Expected format for string is "[-]h[h][:mm][:ss][.fff]". + * If the number of fractional digits provided is greater than the + * precision of the time duration type then the extra digits are + * truncated. + * + * A negative duration will be created if the first character in + * string is a '-', all other '-' will be treated as delimiters. + * Accepted delimiters are "-:,.". + */ + template + inline + time_duration + str_from_delimited_time_duration(const std::basic_string& s) + { + unsigned short min=0, sec =0; + int hour =0; + bool is_neg = (s.at(0) == '-'); + boost::int64_t fs=0; + int pos = 0; + + typedef typename std::basic_string::traits_type traits_type; + typedef boost::char_separator char_separator_type; + typedef boost::tokenizer::const_iterator, + std::basic_string > tokenizer; + typedef typename boost::tokenizer::const_iterator, + typename std::basic_string >::iterator tokenizer_iterator; + + char_type sep_chars[5] = {'-',':',',','.'}; + char_separator_type sep(sep_chars); + tokenizer tok(s,sep); + for(tokenizer_iterator beg=tok.begin(); beg!=tok.end();++beg){ + switch(pos) { + case 0: { + hour = boost::lexical_cast(*beg); + break; + } + case 1: { + min = boost::lexical_cast(*beg); + break; + } + case 2: { + sec = boost::lexical_cast(*beg); + break; + }; + case 3: { + int digits = static_cast(beg->length()); + //Works around a bug in MSVC 6 library that does not support + //operator>> thus meaning lexical_cast will fail to compile. +#if (defined(BOOST_MSVC) && (_MSC_VER < 1300)) + // msvc wouldn't compile 'time_duration::num_fractional_digits()' + // (required template argument list) as a workaround a temp + // time_duration object was used + time_duration td(hour,min,sec,fs); + int precision = td.num_fractional_digits(); + // _atoi64 is an MS specific function + if(digits >= precision) { + // drop excess digits + fs = _atoi64(beg->substr(0, precision).c_str()); + } + else { + fs = _atoi64(beg->c_str()); + } +#else + int precision = time_duration::num_fractional_digits(); + if(digits >= precision) { + // drop excess digits + fs = boost::lexical_cast(beg->substr(0, precision)); + } + else { + fs = boost::lexical_cast(*beg); + } +#endif + if(digits < precision){ + // trailing zeros get dropped from the string, + // "1:01:01.1" would yield .000001 instead of .100000 + // the power() compensates for the missing decimal places + fs *= power(10, precision - digits); + } + + break; + } + default: break; + }//switch + pos++; + } + if(is_neg) { + return -time_duration(hour, min, sec, fs); + } + else { + return time_duration(hour, min, sec, fs); + } + } + + //! Creates a time_duration object from a delimited string + /*! Expected format for string is "[-]h[h][:mm][:ss][.fff]". + * If the number of fractional digits provided is greater than the + * precision of the time duration type then the extra digits are + * truncated. + * + * A negative duration will be created if the first character in + * string is a '-', all other '-' will be treated as delimiters. + * Accepted delimiters are "-:,.". + */ + template + inline + time_duration + parse_delimited_time_duration(const std::string& s) + { + return str_from_delimited_time_duration(s); + } + + //! Utility function to split appart string + inline + bool + split(const std::string& s, + char sep, + std::string& first, + std::string& second) + { + std::string::size_type sep_pos = s.find(sep); + first = s.substr(0,sep_pos); + if (sep_pos!=std::string::npos) + second = s.substr(sep_pos+1); + return true; + } + + + template + inline + time_type + parse_delimited_time(const std::string& s, char sep) + { + typedef typename time_type::time_duration_type time_duration; + typedef typename time_type::date_type date_type; + + //split date/time on a unique delimiter char such as ' ' or 'T' + std::string date_string, tod_string; + split(s, sep, date_string, tod_string); + //call parse_date with first string + date_type d = parse_date(date_string); + //call parse_time_duration with remaining string + time_duration td = parse_delimited_time_duration(tod_string); + //construct a time + return time_type(d, td); + + } + + //! Parse time duration part of an iso time of form: [-]hhmmss[.fff...] (eg: 120259.123 is 12 hours, 2 min, 59 seconds, 123000 microseconds) + template + inline + time_duration + parse_undelimited_time_duration(const std::string& s) + { + int precision = 0; + { + // msvc wouldn't compile 'time_duration::num_fractional_digits()' + // (required template argument list) as a workaround, a temp + // time_duration object was used + time_duration tmp(0,0,0,1); + precision = tmp.num_fractional_digits(); + } + // 'precision+1' is so we grab all digits, plus the decimal + int offsets[] = {2,2,2, precision+1}; + int pos = 0, sign = 0; + int hours = 0; + short min=0, sec=0; + boost::int64_t fs=0; + // increment one position if the string was "signed" + if(s.at(sign) == '-') + { + ++sign; + } + // stlport choked when passing s.substr() to tokenizer + // using a new string fixed the error + std::string remain = s.substr(sign); + /* We do not want the offset_separator to wrap the offsets, we + * will never want to process more than: + * 2 char, 2 char, 2 char, frac_sec length. + * We *do* want the offset_separator to give us a partial for the + * last characters if there were not enough provided in the input string. */ + bool wrap_off = false; + bool ret_part = true; + boost::offset_separator osf(offsets, offsets+4, wrap_off, ret_part); + typedef boost::tokenizer::const_iterator, + std::basic_string > tokenizer; + typedef boost::tokenizer::const_iterator, + std::basic_string >::iterator tokenizer_iterator; + tokenizer tok(remain, osf); + for(tokenizer_iterator ti=tok.begin(); ti!=tok.end();++ti){ + switch(pos) { + case 0: + { + hours = boost::lexical_cast(*ti); + break; + } + case 1: + { + min = boost::lexical_cast(*ti); + break; + } + case 2: + { + sec = boost::lexical_cast(*ti); + break; + } + case 3: + { + std::string char_digits(ti->substr(1)); // digits w/no decimal + int digits = static_cast(char_digits.length()); + + //Works around a bug in MSVC 6 library that does not support + //operator>> thus meaning lexical_cast will fail to compile. +#if (defined(BOOST_MSVC) && (_MSC_VER <= 1200)) // 1200 == VC++ 6.0 + // _atoi64 is an MS specific function + if(digits >= precision) { + // drop excess digits + fs = _atoi64(char_digits.substr(0, precision).c_str()); + } + else if(digits == 0) { + fs = 0; // just in case _atoi64 doesn't like an empty string + } + else { + fs = _atoi64(char_digits.c_str()); + } +#else + if(digits >= precision) { + // drop excess digits + fs = boost::lexical_cast(char_digits.substr(0, precision)); + } + else if(digits == 0) { + fs = 0; // lexical_cast doesn't like empty strings + } + else { + fs = boost::lexical_cast(char_digits); + } +#endif + if(digits < precision){ + // trailing zeros get dropped from the string, + // "1:01:01.1" would yield .000001 instead of .100000 + // the power() compensates for the missing decimal places + fs *= power(10, precision - digits); + } + + break; + } + default: break; + }; + pos++; + } + if(sign) { + return -time_duration(hours, min, sec, fs); + } + else { + return time_duration(hours, min, sec, fs); + } + } + + //! Parse time string of form YYYYMMDDThhmmss where T is delimeter between date and time + template + inline + time_type + parse_iso_time(const std::string& s, char sep) + { + typedef typename time_type::time_duration_type time_duration; + typedef typename time_type::date_type date_type; + + //split date/time on a unique delimiter char such as ' ' or 'T' + std::string date_string, tod_string; + split(s, sep, date_string, tod_string); + //call parse_date with first string + date_type d = parse_undelimited_date(date_string); + //call parse_time_duration with remaining string + time_duration td = parse_undelimited_time_duration(tod_string); + //construct a time + return time_type(d, td); + } + + + +} }//namespace date_time + + + + +#endif diff --git a/cpp/BoostParts/boost/interprocess/allocators/allocator.hpp b/cpp/BoostParts/boost/interprocess/allocators/allocator.hpp new file mode 100644 index 00000000..497cbd44 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/allocators/allocator.hpp @@ -0,0 +1,306 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (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_ALLOCATOR_HPP +#define BOOST_INTERPROCESS_ALLOCATOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//!\file +//!Describes an allocator that allocates portions of fixed size +//!memory buffer (shared memory, mapped file...) + +namespace boost { +namespace interprocess { + + +//!An STL compatible allocator that uses a segment manager as +//!memory source. The internal pointer type will of the same type (raw, smart) as +//!"typename SegmentManager::void_pointer" type. This allows +//!placing the allocator in shared memory, memory mapped-files, etc... +template +class allocator +{ + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + + /// @cond + private: + + //Self type + typedef allocator self_t; + + //Pointer to void + typedef typename segment_manager::void_pointer aux_pointer_t; + + //Typedef to const void pointer + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type cvoid_ptr; + + //Pointer to the allocator + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type alloc_ptr_t; + + //Not assignable from related allocator + template + allocator& operator=(const allocator&); + + //Not assignable from other allocator + allocator& operator=(const allocator&); + + //Pointer to the allocator + alloc_ptr_t mp_mngr; + /// @endcond + + public: + typedef T value_type; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename segment_manager::size_type size_type; + typedef typename segment_manager::difference_type difference_type; + + typedef boost::interprocess::version_type version; + + /// @cond + + //Experimental. Don't use. + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + /// @endcond + + //!Obtains an allocator that allocates + //!objects of type T2 + template + struct rebind + { + typedef allocator other; + }; + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return ipcdetail::to_raw_pointer(mp_mngr); } + + //!Constructor from the segment manager. + //!Never throws + allocator(segment_manager *segment_mngr) + : mp_mngr(segment_mngr) { } + + //!Constructor from other allocator. + //!Never throws + allocator(const allocator &other) + : mp_mngr(other.get_segment_manager()){ } + + //!Constructor from related allocator. + //!Never throws + template + allocator(const allocator &other) + : mp_mngr(other.get_segment_manager()){} + + //!Allocates memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_ptr hint = 0) + { + (void)hint; + if(size_overflows(count)){ + throw bad_alloc(); + } + return pointer(static_cast(mp_mngr->allocate(count*sizeof(T)))); + } + + //!Deallocates memory previously allocated. + //!Never throws + void deallocate(const pointer &ptr, size_type) + { mp_mngr->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); } + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const + { return mp_mngr->get_size()/sizeof(T); } + + //!Swap segment manager. Does not throw. If each allocator is placed in + //!different memory segments, the result is undefined. + friend void swap(self_t &alloc1, self_t &alloc2) + { ipcdetail::do_swap(alloc1.mp_mngr, alloc2.mp_mngr); } + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const + { + return (size_type)mp_mngr->size(ipcdetail::to_raw_pointer(p))/sizeof(T); + } + + std::pair + allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0) + { + return mp_mngr->allocation_command + (command, limit_size, preferred_size, received_size, ipcdetail::to_raw_pointer(reuse)); + } + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain) + { + if(size_overflows(elem_size)){ + throw bad_alloc(); + } + mp_mngr->allocate_many(elem_size*sizeof(T), num_elements, chain); + } + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) + { + mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T), chain); + } + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain) + { mp_mngr->deallocate_many(chain); } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one() + { return this->allocate(1); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain) + { this->allocate_many(1, num_elements, chain); } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p) + { return this->deallocate(p, 1); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain) + { this->deallocate_many(chain); } + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const + { return pointer(boost::addressof(value)); } + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const + { return const_pointer(boost::addressof(value)); } + + //!Constructs an object + //!Throws if T's constructor throws + //!For backwards compatibility with libraries using C++03 allocators + template + void construct(const pointer &ptr, BOOST_FWD_REF(P) p) + { ::new((void*)ipcdetail::to_raw_pointer(ptr)) value_type(::boost::forward

(p)); } + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr) + { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } + +}; + +//!Equality test for same type +//!of allocator +template inline +bool operator==(const allocator &alloc1, + const allocator &alloc2) + { return alloc1.get_segment_manager() == alloc2.get_segment_manager(); } + +//!Inequality test for same type +//!of allocator +template inline +bool operator!=(const allocator &alloc1, + const allocator &alloc2) + { return alloc1.get_segment_manager() != alloc2.get_segment_manager(); } + +} //namespace interprocess { + +/// @cond + +template +struct has_trivial_destructor; + +template +struct has_trivial_destructor + > +{ + static const bool value = true; +}; +/// @endcond + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP + diff --git a/cpp/BoostParts/boost/interprocess/allocators/detail/allocator_common.hpp b/cpp/BoostParts/boost/interprocess/allocators/detail/allocator_common.hpp new file mode 100644 index 00000000..f2b54a8a --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/allocators/detail/allocator_common.hpp @@ -0,0 +1,850 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP +#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP + +#include +#include + +#include + +#include +#include //to_raw_pointer +#include //boost::addressof +#include //BOOST_ASSERT +#include //bad_alloc +#include //scoped_lock +#include //boost::interprocess::allocation_type +#include +#include +#include +#include +#include +#include +#include //std::swap +#include //std::pair +#include + +namespace boost { +namespace interprocess { + +template +struct sizeof_value +{ + static const std::size_t value = sizeof(T); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +namespace ipcdetail { + +//!Object function that creates the node allocator if it is not created and +//!increments reference count if it is already created +template +struct get_or_create_node_pool_func +{ + + //!This connects or constructs the unique instance of node_pool_t + //!Can throw boost::interprocess::bad_alloc + void operator()() + { + //Find or create the node_pool_t + mp_node_pool = mp_segment_manager->template find_or_construct + (boost::interprocess::unique_instance)(mp_segment_manager); + //If valid, increment link count + if(mp_node_pool != 0) + mp_node_pool->inc_ref_count(); + } + + //!Constructor. Initializes function + //!object parameters + get_or_create_node_pool_func(typename NodePool::segment_manager *mngr) + : mp_segment_manager(mngr){} + + NodePool *mp_node_pool; + typename NodePool::segment_manager *mp_segment_manager; +}; + +template +inline NodePool *get_or_create_node_pool(typename NodePool::segment_manager *mgnr) +{ + ipcdetail::get_or_create_node_pool_func func(mgnr); + mgnr->atomic_func(func); + return func.mp_node_pool; +} + +//!Object function that decrements the reference count. If the count +//!reaches to zero destroys the node allocator from memory. +//!Never throws +template +struct destroy_if_last_link_func +{ + //!Decrements reference count and destroys the object if there is no + //!more attached allocators. Never throws + void operator()() + { + //If not the last link return + if(mp_node_pool->dec_ref_count() != 0) return; + + //Last link, let's destroy the segment_manager + mp_node_pool->get_segment_manager()->template destroy(boost::interprocess::unique_instance); + } + + //!Constructor. Initializes function + //!object parameters + destroy_if_last_link_func(NodePool *pool) + : mp_node_pool(pool) + {} + + NodePool *mp_node_pool; +}; + +//!Destruction function, initializes and executes destruction function +//!object. Never throws +template +inline void destroy_node_pool_if_last_link(NodePool *pool) +{ + //Get segment manager + typename NodePool::segment_manager *mngr = pool->get_segment_manager(); + //Execute destruction functor atomically + destroy_if_last_link_funcfunc(pool); + mngr->atomic_func(func); +} + +template +class cache_impl +{ + typedef typename NodePool::segment_manager:: + void_pointer void_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type node_pool_ptr; + typedef typename NodePool::multiallocation_chain multiallocation_chain; + typedef typename NodePool::segment_manager::size_type size_type; + node_pool_ptr mp_node_pool; + multiallocation_chain m_cached_nodes; + size_type m_max_cached_nodes; + + public: + typedef typename NodePool::segment_manager segment_manager; + + cache_impl(segment_manager *segment_mngr, size_type max_cached_nodes) + : mp_node_pool(get_or_create_node_pool(segment_mngr)) + , m_max_cached_nodes(max_cached_nodes) + {} + + cache_impl(const cache_impl &other) + : mp_node_pool(other.get_node_pool()) + , m_max_cached_nodes(other.get_max_cached_nodes()) + { + mp_node_pool->inc_ref_count(); + } + + ~cache_impl() + { + this->deallocate_all_cached_nodes(); + ipcdetail::destroy_node_pool_if_last_link(ipcdetail::to_raw_pointer(mp_node_pool)); + } + + NodePool *get_node_pool() const + { return ipcdetail::to_raw_pointer(mp_node_pool); } + + segment_manager *get_segment_manager() const + { return mp_node_pool->get_segment_manager(); } + + size_type get_max_cached_nodes() const + { return m_max_cached_nodes; } + + void *cached_allocation() + { + //If don't have any cached node, we have to get a new list of free nodes from the pool + if(m_cached_nodes.empty()){ + mp_node_pool->allocate_nodes(m_max_cached_nodes/2, m_cached_nodes); + } + void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front()); + return ret; + } + + void cached_allocation(size_type n, multiallocation_chain &chain) + { + size_type count = n, allocated(0); + BOOST_TRY{ + //If don't have any cached node, we have to get a new list of free nodes from the pool + while(!m_cached_nodes.empty() && count--){ + void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front()); + chain.push_back(ret); + ++allocated; + } + + if(allocated != n){ + mp_node_pool->allocate_nodes(n - allocated, chain); + } + } + BOOST_CATCH(...){ + this->cached_deallocation(chain); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + void cached_deallocation(void *ptr) + { + //Check if cache is full + if(m_cached_nodes.size() >= m_max_cached_nodes){ + //This only occurs if this allocator deallocate memory allocated + //with other equal allocator. Since the cache is full, and more + //deallocations are probably coming, we'll make some room in cache + //in a single, efficient multi node deallocation. + this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2); + } + m_cached_nodes.push_front(ptr); + } + + void cached_deallocation(multiallocation_chain &chain) + { + m_cached_nodes.splice_after(m_cached_nodes.before_begin(), chain); + + //Check if cache is full + if(m_cached_nodes.size() >= m_max_cached_nodes){ + //This only occurs if this allocator deallocate memory allocated + //with other equal allocator. Since the cache is full, and more + //deallocations are probably coming, we'll make some room in cache + //in a single, efficient multi node deallocation. + this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2); + } + } + + //!Sets the new max cached nodes value. This can provoke deallocations + //!if "newmax" is less than current cached nodes. Never throws + void set_max_cached_nodes(size_type newmax) + { + m_max_cached_nodes = newmax; + this->priv_deallocate_remaining_nodes(); + } + + //!Frees all cached nodes. + //!Never throws + void deallocate_all_cached_nodes() + { + if(m_cached_nodes.empty()) return; + mp_node_pool->deallocate_nodes(m_cached_nodes); + } + + private: + //!Frees all cached nodes at once. + //!Never throws + void priv_deallocate_remaining_nodes() + { + if(m_cached_nodes.size() > m_max_cached_nodes){ + priv_deallocate_n_nodes(m_cached_nodes.size()-m_max_cached_nodes); + } + } + + //!Frees n cached nodes at once. Never throws + void priv_deallocate_n_nodes(size_type n) + { + //This only occurs if this allocator deallocate memory allocated + //with other equal allocator. Since the cache is full, and more + //deallocations are probably coming, we'll make some room in cache + //in a single, efficient multi node deallocation. + size_type count(n); + typename multiallocation_chain::iterator it(m_cached_nodes.before_begin()); + while(count--){ + ++it; + } + multiallocation_chain chain; + chain.splice_after(chain.before_begin(), m_cached_nodes, m_cached_nodes.before_begin(), it, n); + //Deallocate all new linked list at once + mp_node_pool->deallocate_nodes(chain); + } + + public: + void swap(cache_impl &other) + { + ipcdetail::do_swap(mp_node_pool, other.mp_node_pool); + m_cached_nodes.swap(other.m_cached_nodes); + ipcdetail::do_swap(m_max_cached_nodes, other.m_max_cached_nodes); + } +}; + +template +class array_allocation_impl +{ + const Derived *derived() const + { return static_cast(this); } + Derived *derived() + { return static_cast(this); } + + typedef typename SegmentManager::void_pointer void_pointer; + + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type difference_type; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + + public: + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. This size only works for memory allocated with + //!allocate, allocation_command and allocate_many. + size_type size(const pointer &p) const + { + return (size_type)this->derived()->get_segment_manager()->size(ipcdetail::to_raw_pointer(p))/sizeof(T); + } + + std::pair + allocation_command(boost::interprocess::allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0) + { + return this->derived()->get_segment_manager()->allocation_command + (command, limit_size, preferred_size, received_size, ipcdetail::to_raw_pointer(reuse)); + } + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain) + { + if(size_overflows(elem_size)){ + throw bad_alloc(); + } + this->derived()->get_segment_manager()->allocate_many(elem_size*sizeof(T), num_elements, chain); + } + + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous block + //!of memory. The elements must be deallocated + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) + { + this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T), chain); + } + + //!Allocates many elements of size elem_size in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. The elements must be deallocated + //!with deallocate(...) + void deallocate_many(multiallocation_chain &chain) + { this->derived()->get_segment_manager()->deallocate_many(chain); } + + //!Returns the number of elements that could be + //!allocated. Never throws + size_type max_size() const + { return this->derived()->get_segment_manager()->get_size()/sizeof(T); } + + //!Returns address of mutable object. + //!Never throws + pointer address(reference value) const + { return pointer(boost::addressof(value)); } + + //!Returns address of non mutable object. + //!Never throws + const_pointer address(const_reference value) const + { return const_pointer(boost::addressof(value)); } + + //!Constructs an object + //!Throws if T's constructor throws + //!For backwards compatibility with libraries using C++03 allocators + template + void construct(const pointer &ptr, BOOST_FWD_REF(P) p) + { ::new((void*)ipcdetail::to_raw_pointer(ptr)) value_type(::boost::forward

(p)); } + + //!Destroys object. Throws if object's + //!destructor throws + void destroy(const pointer &ptr) + { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } +}; + + +template +class node_pool_allocation_impl + : public array_allocation_impl + < Derived + , T + , SegmentManager> +{ + const Derived *derived() const + { return static_cast(this); } + Derived *derived() + { return static_cast(this); } + + typedef typename SegmentManager::void_pointer void_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type cvoid_pointer; + + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_pointer; + typedef T value_type; + typedef typename ipcdetail::add_reference + ::type reference; + typedef typename ipcdetail::add_reference + ::type const_reference; + typedef typename SegmentManager::size_type size_type; + typedef typename SegmentManager::difference_type difference_type; + typedef boost::container::container_detail::transform_multiallocation_chain + multiallocation_chain; + + + template + struct node_pool + { + typedef typename Derived::template node_pool<0>::type type; + static type *get(void *p) + { return static_cast(p); } + }; + + public: + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0) + { + (void)hint; + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + if(size_overflows(count)){ + throw bad_alloc(); + } + else if(Version == 1 && count == 1){ + return pointer(static_cast + (pool->allocate_node())); + } + else{ + return pointer(static_cast + (pool->get_segment_manager()->allocate(count*sizeof(T)))); + } + } + + //!Deallocate allocated memory. Never throws + void deallocate(const pointer &ptr, size_type count) + { + (void)count; + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + if(Version == 1 && count == 1) + pool->deallocate_node(ipcdetail::to_raw_pointer(ptr)); + else + pool->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); + } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one() + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + return pointer(static_cast(pool->allocate_node())); + } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain) + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + pool->allocate_nodes(num_elements, chain); + } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p) + { + typedef typename node_pool<0>::type node_pool_t; + node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool()); + pool->deallocate_node(ipcdetail::to_raw_pointer(p)); + } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain) + { + node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes + (chain); + } + + //!Deallocates all free blocks of the pool + void deallocate_free_blocks() + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } + + //!Deprecated, use deallocate_free_blocks. + //!Deallocates all free chunks of the pool. + void deallocate_free_chunks() + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } +}; + +template +class cached_allocator_impl + : public array_allocation_impl + , T, typename NodePool::segment_manager> +{ + cached_allocator_impl & operator=(const cached_allocator_impl& other); + typedef array_allocation_impl + < cached_allocator_impl + + , T + , typename NodePool::segment_manager> base_t; + + public: + typedef NodePool node_pool_t; + typedef typename NodePool::segment_manager segment_manager; + typedef typename segment_manager::void_pointer void_pointer; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type cvoid_pointer; + typedef typename base_t::pointer pointer; + typedef typename base_t::size_type size_type; + typedef typename base_t::multiallocation_chain multiallocation_chain; + typedef typename base_t::value_type value_type; + + public: + static const std::size_t DEFAULT_MAX_CACHED_NODES = 64; + + cached_allocator_impl(segment_manager *segment_mngr, size_type max_cached_nodes) + : m_cache(segment_mngr, max_cached_nodes) + {} + + cached_allocator_impl(const cached_allocator_impl &other) + : m_cache(other.m_cache) + {} + + //!Copy constructor from related cached_adaptive_pool_base. If not present, constructs + //!a node pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + template + cached_allocator_impl + (const cached_allocator_impl + &other) + : m_cache(other.get_segment_manager(), other.get_max_cached_nodes()) + {} + + //!Returns a pointer to the node pool. + //!Never throws + node_pool_t* get_node_pool() const + { return m_cache.get_node_pool(); } + + //!Returns the segment manager. + //!Never throws + segment_manager* get_segment_manager()const + { return m_cache.get_segment_manager(); } + + //!Sets the new max cached nodes value. This can provoke deallocations + //!if "newmax" is less than current cached nodes. Never throws + void set_max_cached_nodes(size_type newmax) + { m_cache.set_max_cached_nodes(newmax); } + + //!Returns the max cached nodes parameter. + //!Never throws + size_type get_max_cached_nodes() const + { return m_cache.get_max_cached_nodes(); } + + //!Allocate memory for an array of count elements. + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate(size_type count, cvoid_pointer hint = 0) + { + (void)hint; + void * ret; + if(size_overflows(count)){ + throw bad_alloc(); + } + else if(Version == 1 && count == 1){ + ret = m_cache.cached_allocation(); + } + else{ + ret = this->get_segment_manager()->allocate(count*sizeof(T)); + } + return pointer(static_cast(ret)); + } + + //!Deallocate allocated memory. Never throws + void deallocate(const pointer &ptr, size_type count) + { + (void)count; + if(Version == 1 && count == 1){ + m_cache.cached_deallocation(ipcdetail::to_raw_pointer(ptr)); + } + else{ + this->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); + } + } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws boost::interprocess::bad_alloc if there is no enough memory + pointer allocate_one() + { return pointer(static_cast(this->m_cache.cached_allocation())); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void allocate_individual(size_type num_elements, multiallocation_chain &chain) + { this->m_cache.cached_allocation(num_elements, chain); } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(const pointer &p) + { this->m_cache.cached_deallocation(ipcdetail::to_raw_pointer(p)); } + + //!Allocates many elements of size == 1 in a contiguous block + //!of memory. The minimum number to be allocated is min_elements, + //!the preferred and maximum number is + //!preferred_elements. The number of actually allocated elements is + //!will be assigned to received_size. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + void deallocate_individual(multiallocation_chain &chain) + { m_cache.cached_deallocation(chain); } + + //!Deallocates all free blocks of the pool + void deallocate_free_blocks() + { m_cache.get_node_pool()->deallocate_free_blocks(); } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different shared memory segments, the result is undefined. + friend void swap(cached_allocator_impl &alloc1, cached_allocator_impl &alloc2) + { alloc1.m_cache.swap(alloc2.m_cache); } + + void deallocate_cache() + { m_cache.deallocate_all_cached_nodes(); } + + //!Deprecated use deallocate_free_blocks. + void deallocate_free_chunks() + { m_cache.get_node_pool()->deallocate_free_blocks(); } + + /// @cond + private: + cache_impl m_cache; +}; + +//!Equality test for same type of +//!cached_allocator_impl +template inline +bool operator==(const cached_allocator_impl &alloc1, + const cached_allocator_impl &alloc2) + { return alloc1.get_node_pool() == alloc2.get_node_pool(); } + +//!Inequality test for same type of +//!cached_allocator_impl +template inline +bool operator!=(const cached_allocator_impl &alloc1, + const cached_allocator_impl &alloc2) + { return alloc1.get_node_pool() != alloc2.get_node_pool(); } + + +//!Pooled shared memory allocator using adaptive pool. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +template +class shared_pool_impl + : public private_node_allocator_t +{ + public: + //!Segment manager typedef + typedef typename private_node_allocator_t:: + segment_manager segment_manager; + typedef typename private_node_allocator_t:: + multiallocation_chain multiallocation_chain; + typedef typename private_node_allocator_t:: + size_type size_type; + + private: + typedef typename segment_manager::mutex_family::mutex_type mutex_type; + + public: + //!Constructor from a segment manager. Never throws + shared_pool_impl(segment_manager *segment_mngr) + : private_node_allocator_t(segment_mngr) + {} + + //!Destructor. Deallocates all allocated blocks. Never throws + ~shared_pool_impl() + {} + + //!Allocates array of count elements. Can throw boost::interprocess::bad_alloc + void *allocate_node() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return private_node_allocator_t::allocate_node(); + } + + //!Deallocates an array pointed by ptr. Never throws + void deallocate_node(void *ptr) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_node(ptr); + } + + //!Allocates n nodes. + //!Can throw boost::interprocess::bad_alloc + void allocate_nodes(const size_type n, multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::allocate_nodes(n, chain); + } + + //!Deallocates a linked list of nodes ending in null pointer. Never throws + void deallocate_nodes(multiallocation_chain &nodes, size_type num) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_nodes(nodes, num); + } + + //!Deallocates the nodes pointed by the multiallocation iterator. Never throws + void deallocate_nodes(multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_nodes(chain); + } + + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + //!Deallocates all used memory from the common pool. + //!Precondition: all nodes allocated from this pool should + //!already be deallocated. Otherwise, undefined behavior. Never throws + void purge_blocks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::purge_blocks(); + } + + //!Increments internal reference count and returns new count. Never throws + size_type inc_ref_count() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return ++m_header.m_usecount; + } + + //!Decrements internal reference count and returns new count. Never throws + size_type dec_ref_count() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + BOOST_ASSERT(m_header.m_usecount > 0); + return --m_header.m_usecount; + } + + //!Deprecated, use deallocate_free_blocks. + void deallocate_free_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + //!Deprecated, use purge_blocks. + void purge_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::purge_blocks(); + } + + private: + //!This struct includes needed data and derives from + //!the mutex type to allow EBO when using null_mutex + struct header_t : mutex_type + { + size_type m_usecount; //Number of attached allocators + + header_t() + : m_usecount(0) {} + } m_header; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP diff --git a/cpp/BoostParts/boost/interprocess/containers/allocation_type.hpp b/cpp/BoostParts/boost/interprocess/containers/allocation_type.hpp new file mode 100644 index 00000000..eea431b0 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/containers/allocation_type.hpp @@ -0,0 +1,40 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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_CONTAINERS_ALLOCATION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +/// @cond +typedef int allocation_type; +/// @endcond +static const allocation_type allocate_new = boost::container::allocate_new; +static const allocation_type expand_fwd = boost::container::expand_fwd; +static const allocation_type expand_bwd = boost::container::expand_bwd; +static const allocation_type shrink_in_place = boost::container::shrink_in_place; +static const allocation_type try_shrink_in_place= boost::container::try_shrink_in_place; +static const allocation_type nothrow_allocation = boost::container::nothrow_allocation; +static const allocation_type zero_memory = boost::container::zero_memory; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP diff --git a/cpp/BoostParts/boost/interprocess/containers/version_type.hpp b/cpp/BoostParts/boost/interprocess/containers/version_type.hpp new file mode 100644 index 00000000..4516e8c9 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/containers/version_type.hpp @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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_CONTAINERS_VERSION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::container::container_detail::version_type; +using boost::container::container_detail::version; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + diff --git a/cpp/BoostParts/boost/interprocess/creation_tags.hpp b/cpp/BoostParts/boost/interprocess/creation_tags.hpp new file mode 100644 index 00000000..459eb4df --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/creation_tags.hpp @@ -0,0 +1,77 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_CREATION_TAGS_HPP +#define BOOST_INTERPROCESS_CREATION_TAGS_HPP + +#include +#include + +namespace boost { +namespace interprocess { + +//!Tag to indicate that the resource must +//!be only created +struct create_only_t {}; + +//!Tag to indicate that the resource must +//!be only opened +struct open_only_t {}; + +//!Tag to indicate that the resource must +//!be only opened for reading +struct open_read_only_t {}; + +//!Tag to indicate that the resource must +//!be only opened privately for reading +struct open_read_private_t {}; + +//!Tag to indicate that the resource must +//!be only opened for reading +struct open_copy_on_write_t {}; + +//!Tag to indicate that the resource must +//!be created. If already created, it must be opened. +struct open_or_create_t {}; + +//!Value to indicate that the resource must +//!be only created +static const create_only_t create_only = create_only_t(); + +//!Value to indicate that the resource must +//!be only opened +static const open_only_t open_only = open_only_t(); + +//!Value to indicate that the resource must +//!be only opened for reading +static const open_read_only_t open_read_only = open_read_only_t(); + +//!Value to indicate that the resource must +//!be created. If already created, it must be opened. +static const open_or_create_t open_or_create = open_or_create_t(); + +//!Value to indicate that the resource must +//!be only opened for reading +static const open_copy_on_write_t open_copy_on_write = open_copy_on_write_t(); + +namespace ipcdetail { + +enum create_enum_t +{ DoCreate, DoOpen, DoOpenOrCreate }; + +} //namespace ipcdetail { + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/atomic.hpp b/cpp/BoostParts/boost/interprocess/detail/atomic.hpp new file mode 100644 index 00000000..08481a43 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/atomic.hpp @@ -0,0 +1,562 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012 +// (C) Copyright Markus Schoepflin 2007 +// (C) Copyright Bryce Lelbach 2010 +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP +#define BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP + +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +//! Atomically increment an boost::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); + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem); + +//! Atomically set an boost::uint32_t in memory +//! "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); + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with": what to swap it with +//! "cmp": the value to compare it to +//! 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); + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#if (defined BOOST_INTERPROCESS_WINDOWS) + +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +//! Atomically decrement an boost::uint32_t by 1 +//! "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(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(mem))-1; } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Atomically set an boost::uint32_t in memory +//! "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(mem), val); } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with": what to swap it with +//! "cmp": the value to compare it to +//! 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(mem), with, cmp); } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! 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) +{ + boost::uint32_t prev = cmp; + // This version by Mans Rullgard of Pathscale + __asm__ __volatile__ ( "lock\n\t" + "cmpxchg %2,%0" + : "+m"(*mem), "+a"(prev) + : "r"(with) + : "cc"); + + return prev; +} + +//! Atomically add 'val' to an boost::uint32_t +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32 + (volatile boost::uint32_t *mem, boost::uint32_t val) +{ + // int r = *pw; + // *mem += val; + // return r; + int r; + + asm volatile + ( + "lock\n\t" + "xadd %1, %0": + "+m"( *mem ), "=r"( r ): // outputs (%0, %1) + "1"( val ): // inputs (%2 == %1) + "memory", "cc" // clobbers + ); + + return r; +} + +//! 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 atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "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 atomic_add32(mem, (boost::uint32_t)-1); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Atomically set an boost::uint32_t in memory +//! "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) +{ *mem = val; } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__)) + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//! Atomically add 'val' to an boost::uint32_t +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ + 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"); + return prev; +} + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! 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) +{ + 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"(cmp), "r" (with) + : "cc", "memory"); + return prev; +} + +//! 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 atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "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 atomic_add32(mem, boost::uint32_t(-1u)); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Atomically set an boost::uint32_t in memory +//! "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) +{ *mem = val; } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif (defined(sun) || defined(__sun)) + +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +//! Atomically add 'val' to an boost::uint32_t +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ return atomic_add_32_nv(reinterpret_cast(mem), (int32_t)val) - val; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! 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 atomic_cas_32(reinterpret_cast(mem), cmp, with); } + +//! 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 atomic_add_32_nv(reinterpret_cast(mem), 1) - 1; } + +//! Atomically decrement an boost::uint32_t by 1 +//! "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 atomic_add_32_nv(reinterpret_cast(mem), (boost::uint32_t)-1) + 1; } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Atomically set an boost::uint32_t in memory +//! "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) +{ *mem = val; } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif defined(__osf__) && defined(__DECCXX) + +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +//! Atomically decrement a uint32_t by 1 +//! "mem": pointer to the atomic value +//! Returns the old value pointed to by mem +//! Acquire, memory barrier after decrement. +inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) +{ boost::uint32_t old_val = __ATOMIC_DECREMENT_LONG(mem); __MB(); return old_val; } + +//! Atomically increment a uint32_t by 1 +//! "mem": pointer to the object +//! Returns the old value pointed to by mem +//! Release, memory barrier before increment. +inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) +{ __MB(); return __ATOMIC_INCREMENT_LONG(mem); } + +// Rational for the implementation of the atomic read and write functions. +// +// 1. The Alpha Architecture Handbook requires that access to a byte, +// an aligned word, an aligned longword, or an aligned quadword is +// atomic. (See 'Alpha Architecture Handbook', version 4, chapter 5.2.2.) +// +// 2. The CXX User's Guide states that volatile quantities are accessed +// with single assembler instructions, and that a compilation error +// occurs when declaring a quantity as volatile which is not properly +// aligned. + +//! Atomically read an boost::uint32_t from memory +//! Acquire, memory barrier after load. +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ boost::uint32_t old_val = *mem; __MB(); return old_val; } + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +//! Release, memory barrier before store. +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ __MB(); *mem = val; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! Returns the old value of *mem +//! Memory barrier between load and store. +inline boost::uint32_t atomic_cas32( + volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) +{ + // Note: + // + // Branch prediction prefers backward branches, and the Alpha Architecture + // Handbook explicitely states that the loop should not be implemented like + // it is below. (See chapter 4.2.5.) Therefore the code should probably look + // like this: + // + // return asm( + // "10: ldl_l %v0,(%a0) ;" + // " cmpeq %v0,%a2,%t0 ;" + // " beq %t0,20f ;" + // " mb ;" + // " mov %a1,%t0 ;" + // " stl_c %t0,(%a0) ;" + // " beq %t0,30f ;" + // "20: ret ;" + // "30: br 10b;", + // mem, with, cmp); + // + // But as the compiler always transforms this into the form where a backward + // branch is taken on failure, we can as well implement it in the straight + // forward form, as this is what it will end up in anyway. + + return asm( + "10: ldl_l %v0,(%a0) ;" // load prev value from mem and lock mem + " cmpeq %v0,%a2,%t0 ;" // compare with given value + " beq %t0,20f ;" // if not equal, we're done + " mb ;" // memory barrier + " mov %a1,%t0 ;" // load new value into scratch register + " stl_c %t0,(%a0) ;" // store new value to locked mem (overwriting scratch) + " beq %t0,10b ;" // store failed because lock has been stolen, retry + "20: ", + mem, with, cmp); +} + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX) + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//first define boost::uint32_t versions of __lwarx and __stwcx to avoid poluting +//all the functions with casts + +//! From XLC documenation : +//! This function can be used with a subsequent stwcxu call to implement a +//! read-modify-write on a specified memory location. The two functions work +//! together to ensure that if the store is successfully performed, no other +//! processor or mechanism can modify the target doubleword between the time +//! lwarxu function is executed and the time the stwcxu functio ncompletes. +//! "mem" : pointer to the object +//! Returns the value at pointed to by mem +inline boost::uint32_t lwarxu(volatile boost::uint32_t *mem) +{ + return static_cast(__lwarx(reinterpret_cast(mem))); +} + +//! "mem" : pointer to the object +//! "val" : the value to store +//! Returns true if the update of mem is successful and false if it is +//!unsuccessful +inline bool stwcxu(volatile boost::uint32_t* mem, boost::uint32_t val) +{ + return (__stwcx(reinterpret_cast(mem), static_cast(val)) != 0); +} + +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32 + (volatile boost::uint32_t *mem, boost::uint32_t val) +{ + boost::uint32_t oldValue; + do + { + oldValue = lwarxu(mem); + }while (!stwcxu(mem, oldValue+val)); + return oldValue; +} + +//! 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 atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "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 atomic_add32(mem, (boost::uint32_t)-1); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! 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) +{ + boost::uint32_t oldValue; + boost::uint32_t valueToStore; + do + { + oldValue = lwarxu(mem); + } while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue)); + + return oldValue; +} + +//! Atomically set an boost::uint32_t in memory +//! "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) +{ *mem = val; } + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + +#elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +//! Atomically add 'val' to an boost::uint32_t +//! "mem": pointer to the object +//! "val": amount to add +//! Returns the old value pointed to by mem +inline boost::uint32_t atomic_add32 + (volatile boost::uint32_t *mem, boost::uint32_t val) +{ return __sync_fetch_and_add(const_cast(mem), val); } + +//! 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 atomic_add32(mem, 1); } + +//! Atomically decrement an boost::uint32_t by 1 +//! "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 atomic_add32(mem, (boost::uint32_t)-1); } + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "with" what to swap it with +//! "cmp": the value to compare it to +//! 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 __sync_val_compare_and_swap(const_cast(mem), cmp, with); } + +//! Atomically set an boost::uint32_t in memory +//! "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) +{ *mem = val; } + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#else + +#error No atomic operations implemented for this platform, sorry! + +#endif + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +inline bool atomic_add_unless32 + (volatile boost::uint32_t *mem, boost::uint32_t value, boost::uint32_t unless_this) +{ + boost::uint32_t old, c(atomic_read32(mem)); + while(c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c){ + c = old; + } + return c != unless_this; +} + +} //namespace ipcdetail +} //namespace interprocess +} //namespace boost + + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/cast_tags.hpp b/cpp/BoostParts/boost/interprocess/detail/cast_tags.hpp new file mode 100644 index 00000000..37dabd1f --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/cast_tags.hpp @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_CAST_TAGS_HPP +#define BOOST_INTERPROCESS_CAST_TAGS_HPP + +#include +#include + +namespace boost { namespace interprocess { namespace ipcdetail { + +struct static_cast_tag {}; +struct const_cast_tag {}; +struct dynamic_cast_tag {}; +struct reinterpret_cast_tag {}; + +}}} //namespace boost { namespace interprocess { namespace ipcdetail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_CAST_TAGS_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/config_begin.hpp b/cpp/BoostParts/boost/interprocess/detail/config_begin.hpp new file mode 100644 index 00000000..9224f7dd --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/config_begin.hpp @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_CONFIG_INCLUDED +#define BOOST_INTERPROCESS_CONFIG_INCLUDED +#include +#endif + +#ifdef BOOST_MSVC + #ifndef _CRT_SECURE_NO_DEPRECATE + #define BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE + #define _CRT_SECURE_NO_DEPRECATE + #endif + #pragma warning (push) + #pragma warning (disable : 4702) // unreachable code + #pragma warning (disable : 4706) // assignment within conditional expression + #pragma warning (disable : 4127) // conditional expression is constant + #pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned + #pragma warning (disable : 4284) // odd return type for operator-> + #pragma warning (disable : 4244) // possible loss of data + #pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2" + #pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data + #pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier" + #pragma warning (disable : 4355) // "this" : used in base member initializer list + #pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated + #pragma warning (disable : 4511) // copy constructor could not be generated + #pragma warning (disable : 4512) // assignment operator could not be generated + #pragma warning (disable : 4514) // unreferenced inline removed + #pragma warning (disable : 4521) // Disable "multiple copy constructors specified" + #pragma warning (disable : 4522) // "class" : multiple assignment operators specified + #pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter + #pragma warning (disable : 4710) // function not inlined + #pragma warning (disable : 4711) // function selected for automatic inline expansion + #pragma warning (disable : 4786) // identifier truncated in debug info + #pragma warning (disable : 4996) // "function": was declared deprecated + #pragma warning (disable : 4197) // top-level volatile in cast is ignored + #pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception' + // with /GR-; unpredictable behavior may result + #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site + #pragma warning (disable : 4671) // the copy constructor is inaccessible + #pragma warning (disable : 4250) // inherits 'x' via dominance +#endif diff --git a/cpp/BoostParts/boost/interprocess/detail/config_end.hpp b/cpp/BoostParts/boost/interprocess/detail/config_end.hpp new file mode 100644 index 00000000..f871ce75 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/config_end.hpp @@ -0,0 +1,17 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +#if defined BOOST_MSVC + #pragma warning (pop) + #ifdef BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE + #undef BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE + #undef _CRT_SECURE_NO_DEPRECATE + #endif +#endif + diff --git a/cpp/BoostParts/boost/interprocess/detail/config_external_begin.hpp b/cpp/BoostParts/boost/interprocess/detail/config_external_begin.hpp new file mode 100644 index 00000000..fb578ef0 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/config_external_begin.hpp @@ -0,0 +1,18 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-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_EXTERNAL_CONFIG_INCLUDED +#define BOOST_INTERPROCESS_EXTERNAL_CONFIG_INCLUDED +#include +#endif + +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wshadow" +#endif diff --git a/cpp/BoostParts/boost/interprocess/detail/config_external_end.hpp b/cpp/BoostParts/boost/interprocess/detail/config_external_end.hpp new file mode 100644 index 00000000..214558f5 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/config_external_end.hpp @@ -0,0 +1,12 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-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. +// +////////////////////////////////////////////////////////////////////////////// +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406) +# pragma GCC diagnostic pop +#endif diff --git a/cpp/BoostParts/boost/interprocess/detail/in_place_interface.hpp b/cpp/BoostParts/boost/interprocess/detail/in_place_interface.hpp new file mode 100644 index 00000000..7c0966c1 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/in_place_interface.hpp @@ -0,0 +1,73 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_IN_PLACE_INTERFACE_HPP +#define BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include //typeid + +//!\file +//!Describes an abstract interface for placement construction and destruction. + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +struct in_place_interface +{ + in_place_interface(std::size_t alignm, std::size_t sz, const char *tname) + : alignment(alignm), size(sz), type_name(tname) + {} + + std::size_t alignment; + std::size_t size; + const char *type_name; + + virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) = 0; + virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) = 0; + virtual ~in_place_interface(){} +}; + +template +struct placement_destroy : public in_place_interface +{ + placement_destroy() + : in_place_interface(::boost::alignment_of::value, sizeof(T), typeid(T).name()) + {} + + virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) + { + T* memory = static_cast(mem); + for(destroyed = 0; destroyed < num; ++destroyed) + (memory++)->~T(); + } + + virtual void construct_n(void *, std::size_t, std::size_t &) {} + + private: + void destroy(void *mem) + { static_cast(mem)->~T(); } +}; + +} +} +} //namespace boost { namespace interprocess { namespace ipcdetail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/intermodule_singleton_common.hpp b/cpp/BoostParts/boost/interprocess/detail/intermodule_singleton_common.hpp new file mode 100644 index 00000000..d03c5665 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/intermodule_singleton_common.hpp @@ -0,0 +1,496 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-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_INTERMODULE_SINGLETON_COMMON_HPP +#define BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +namespace intermodule_singleton_helpers { + +inline void get_pid_creation_time_str(std::string &s) +{ + std::stringstream stream; + stream << get_current_process_id() << '_'; + stream.precision(6); + stream << std::fixed << get_current_process_creation_time(); + s = stream.str(); +} + +inline const char *get_map_base_name() +{ return "bip.gmem.map."; } + +inline void get_map_name(std::string &map_name) +{ + get_pid_creation_time_str(map_name); + map_name.insert(0, get_map_base_name()); +} + +inline std::size_t get_map_size() +{ return 65536; } + +template +struct thread_safe_global_map_dependant; + +} //namespace intermodule_singleton_helpers { + +//This class contains common code for all singleton types, so that we instantiate this +//code just once per module. This class also holds a thread soafe global map +//to be used by all instances protected with a reference count +template +class intermodule_singleton_common +{ + public: + typedef void*(singleton_constructor_t)(ThreadSafeGlobalMap &); + typedef void (singleton_destructor_t)(void *, ThreadSafeGlobalMap &); + + static const ::boost::uint32_t Uninitialized = 0u; + static const ::boost::uint32_t Initializing = 1u; + static const ::boost::uint32_t Initialized = 2u; + static const ::boost::uint32_t Broken = 3u; + static const ::boost::uint32_t Destroyed = 4u; + + //Initialize this_module_singleton_ptr, creates the global map if needed and also creates an unique + //opaque type in global map through a singleton_constructor_t function call, + //initializing the passed pointer to that unique instance. + // + //We have two concurrency types here. a)the global map/singleton creation must + //be safe between threads of this process but in different modules/dlls. b) + //the pointer to the singleton is per-module, so we have to protect this + //initization between threads of the same module. + // + //All static variables declared here are shared between inside a module + //so atomic operations will synchronize only threads of the same module. + static void initialize_singleton_logic + (void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_constructor_t constructor, bool phoenix) + { + //If current module is not initialized enter to lock free logic + if(atomic_read32(&this_module_singleton_initialized) != Initialized){ + //Now a single thread of the module will succeed in this CAS. + //trying to pass from Uninitialized to Initializing + ::boost::uint32_t previous_module_singleton_initialized = atomic_cas32 + (&this_module_singleton_initialized, Initializing, Uninitialized); + //If the thread succeeded the CAS (winner) it will compete with other + //winner threads from other modules to create the global map + if(previous_module_singleton_initialized == Destroyed){ + //Trying to resurrect a dead Phoenix singleton. Just try to + //mark it as uninitialized and start again + if(phoenix){ + atomic_cas32(&this_module_singleton_initialized, Uninitialized, Destroyed); + previous_module_singleton_initialized = atomic_cas32 + (&this_module_singleton_initialized, Initializing, Uninitialized); + } + //Trying to resurrect a non-Phoenix dead singleton is an error + else{ + throw interprocess_exception("Boost.Interprocess: Dead reference on non-Phoenix singleton of type"); + } + } + if(previous_module_singleton_initialized == Uninitialized){ + try{ + //Now initialize the global map, this function must solve concurrency + //issues between threads of several modules + initialize_global_map_handle(); + //Now try to create the singleton in global map. + //This function solves concurrency issues + //between threads of several modules + void *tmp = constructor(get_map()); + //Increment the module reference count that reflects how many + //singletons this module holds, so that we can safely destroy + //module global map object when no singleton is left + atomic_inc32(&this_module_singleton_count); + //Insert a barrier before assigning the pointer to + //make sure this assignment comes after the initialization + atomic_write32(&this_module_singleton_initialized, Initializing); + //Assign the singleton address to the module-local pointer + ptr = tmp; + //Memory barrier inserted, all previous operations should complete + //before this one. Now marked as initialized + atomic_write32(&this_module_singleton_initialized, Initialized); + } + catch(...){ + //Mark singleton failed to initialize + atomic_write32(&this_module_singleton_initialized, Broken); + throw; + } + } + //If previous state was initializing, this means that another winner thread is + //trying to initialize the singleton. Just wait until completes its work. + else if(previous_module_singleton_initialized == Initializing){ + while(1){ + previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized); + if(previous_module_singleton_initialized >= Initialized){ + //Already initialized, or exception thrown by initializer thread + break; + } + else if(previous_module_singleton_initialized == Initializing){ + thread_yield(); + } + else{ + //This can't be happening! + BOOST_ASSERT(0); + } + } + } + else if(previous_module_singleton_initialized == Initialized){ + //Nothing to do here, the singleton is ready + } + //If previous state was greater than initialized, then memory is broken + //trying to initialize the singleton. + else{//(previous_module_singleton_initialized > Initialized) + throw interprocess_exception("boost::interprocess::intermodule_singleton initialization failed"); + } + } + BOOST_ASSERT(ptr != 0); + } + + static void finalize_singleton_logic(void *&ptr, volatile boost::uint32_t &this_module_singleton_initialized, singleton_destructor_t destructor) + { + //Protect destruction against lazy singletons not initialized in this execution + if(ptr){ + //Note: this destructor might provoke a Phoenix singleton + //resurrection. This means that this_module_singleton_count + //might change after this call. + destructor(ptr, get_map()); + ptr = 0; + + //Memory barrier to make sure pointer is nulled. + //Mark this singleton as destroyed. + atomic_write32(&this_module_singleton_initialized, Destroyed); + + //If this is the last singleton of this module + //apply map destruction. + //Note: singletons are destroyed when the module is unloaded + //so no threads should be executing or holding references + //to this module + if(1 == atomic_dec32(&this_module_singleton_count)){ + destroy_global_map_handle(); + } + } + } + + private: + static ThreadSafeGlobalMap &get_map() + { + return *static_cast(static_cast(&mem_holder.map_mem[0])); + } + + static void initialize_global_map_handle() + { + //Obtain unique map name and size + while(1){ + //Try to pass map state to initializing + ::boost::uint32_t tmp = atomic_cas32(&this_module_map_initialized, Initializing, Uninitialized); + if(tmp == Initialized || tmp == Broken){ + break; + } + else if(tmp == Destroyed){ + tmp = atomic_cas32(&this_module_map_initialized, Uninitialized, Destroyed); + continue; + } + //If some other thread is doing the work wait + else if(tmp == Initializing){ + thread_yield(); + } + else{ //(tmp == Uninitialized) + //If not initialized try it again? + try{ + //Remove old global map from the system + intermodule_singleton_helpers::thread_safe_global_map_dependant::remove_old_gmem(); + //in-place construction of the global map class + intermodule_singleton_helpers::thread_safe_global_map_dependant + ::construct_map(static_cast(&get_map())); + //Use global map's internal lock to initialize the lock file + //that will mark this gmem as "in use". + typename intermodule_singleton_helpers::thread_safe_global_map_dependant:: + lock_file_logic f(get_map()); + //If function failed (maybe a competing process has erased the shared + //memory between creation and file locking), retry with a new instance. + if(f.retry()){ + get_map().~ThreadSafeGlobalMap(); + atomic_write32(&this_module_map_initialized, Destroyed); + } + else{ + //Locking succeeded, so this global map module-instance is ready + atomic_write32(&this_module_map_initialized, Initialized); + break; + } + } + catch(...){ + // + throw; + } + } + } + } + + static void destroy_global_map_handle() + { + if(!atomic_read32(&this_module_singleton_count)){ + //This module is being unloaded, so destroy + //the global map object of this module + //and unlink the global map if it's the last + typename intermodule_singleton_helpers::thread_safe_global_map_dependant:: + unlink_map_logic f(get_map()); + (get_map()).~ThreadSafeGlobalMap(); + atomic_write32(&this_module_map_initialized, Destroyed); + //Do some cleanup for other processes old gmem instances + intermodule_singleton_helpers::thread_safe_global_map_dependant::remove_old_gmem(); + } + } + + //Static data, zero-initalized without any dependencies + //this_module_singleton_count is the number of singletons used by this module + static volatile boost::uint32_t this_module_singleton_count; + + //this_module_map_initialized is the state of this module's map class object. + //Values: Uninitialized, Initializing, Initialized, Broken + static volatile boost::uint32_t this_module_map_initialized; + + //Raw memory to construct the global map manager + static struct mem_holder_t + { + ::boost::detail::max_align aligner; + char map_mem [sizeof(ThreadSafeGlobalMap)]; + } mem_holder; +}; + +template +volatile boost::uint32_t intermodule_singleton_common::this_module_singleton_count; + +template +volatile boost::uint32_t intermodule_singleton_common::this_module_map_initialized; + +template +typename intermodule_singleton_common::mem_holder_t + intermodule_singleton_common::mem_holder; + +//A reference count to be stored in global map holding the number +//of singletons (one per module) attached to the instance pointed by +//the internal ptr. +struct ref_count_ptr +{ + ref_count_ptr(void *p, boost::uint32_t count) + : ptr(p), singleton_ref_count(count) + {} + void *ptr; + //This reference count serves to count the number of attached + //modules to this singleton + volatile boost::uint32_t singleton_ref_count; +}; + + +//Now this class is a singleton, initializing the singleton in +//the first get() function call if LazyInit is false. If true +//then the singleton will be initialized when loading the module. +template +class intermodule_singleton_impl +{ + public: + + static C& get() //Let's make inlining easy + { + if(!this_module_singleton_ptr){ + if(lifetime.dummy_function()){ //This forces lifetime instantiation, for reference counted destruction + atentry_work(); + } + } + return *static_cast(this_module_singleton_ptr); + } + + private: + + static void atentry_work() + { + intermodule_singleton_common::initialize_singleton_logic + (this_module_singleton_ptr, this_module_singleton_initialized, singleton_constructor, Phoenix); + } + + static void atexit_work() + { + intermodule_singleton_common::finalize_singleton_logic + (this_module_singleton_ptr, this_module_singleton_initialized, singleton_destructor); + } + + //These statics will be zero-initialized without any constructor call dependency + //this_module_singleton_ptr will be a module-local pointer to the singleton + static void* this_module_singleton_ptr; + + //this_module_singleton_count will be used to synchronize threads of the same module + //for access to a singleton instance, and to flag the state of the + //singleton. + static volatile boost::uint32_t this_module_singleton_initialized; + + //This class destructor will trigger singleton destruction + struct lifetime_type_lazy + { + bool dummy_function() + { return m_dummy == 0; } + + ~lifetime_type_lazy() + { + if(!Phoenix){ + atexit_work(); + } + } + + //Dummy volatile so that the compiler can't resolve its value at compile-time + //and can't avoid lifetime_type instantiation if dummy_function() is called. + static volatile int m_dummy; + }; + + struct lifetime_type_static + : public lifetime_type_lazy + { + lifetime_type_static() + { atentry_work(); } + }; + + typedef typename if_c + ::type lifetime_type; + + static lifetime_type lifetime; + + //A functor to be executed inside global map lock that just + //searches for the singleton in map and if not present creates a new one. + //If singleton constructor throws, the exception is propagated + struct init_atomic_func + { + init_atomic_func(ThreadSafeGlobalMap &m) + : m_map(m) + {} + + void operator()() + { + ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + ::find(m_map, typeid(C).name()); + if(!rcount){ + C *p = new C; + try{ + ref_count_ptr val(p, 0u); + rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + ::insert(m_map, typeid(C).name(), val); + } + catch(...){ + intermodule_singleton_helpers::thread_safe_global_map_dependant + ::erase(m_map, typeid(C).name()); + delete p; + throw; + } + } + if(Phoenix){ + std::atexit(&atexit_work); + } + atomic_inc32(&rcount->singleton_ref_count); + ret_ptr = rcount->ptr; + } + void *data() const + { return ret_ptr; } + + private: + ThreadSafeGlobalMap &m_map; + void *ret_ptr; + }; + + //A functor to be executed inside global map lock that just + //deletes the singleton in map if the attached count reaches to zero + struct fini_atomic_func + { + fini_atomic_func(ThreadSafeGlobalMap &m) + : m_map(m) + {} + + void operator()() + { + ref_count_ptr *rcount = intermodule_singleton_helpers::thread_safe_global_map_dependant + ::find(m_map, typeid(C).name()); + //The object must exist + BOOST_ASSERT(rcount); + BOOST_ASSERT(rcount->singleton_ref_count > 0); + //Check if last reference + if(atomic_dec32(&rcount->singleton_ref_count) == 1){ + //If last, destroy the object + BOOST_ASSERT(rcount->ptr != 0); + C *pc = static_cast(rcount->ptr); + //Now destroy map entry + bool destroyed = intermodule_singleton_helpers::thread_safe_global_map_dependant + ::erase(m_map, typeid(C).name()); + (void)destroyed; BOOST_ASSERT(destroyed == true); + delete pc; + } + } + void *data() const + { return ret_ptr; } + + private: + ThreadSafeGlobalMap &m_map; + void *ret_ptr; + }; + + //A wrapper to execute init_atomic_func + static void *singleton_constructor(ThreadSafeGlobalMap &map) + { + init_atomic_func f(map); + intermodule_singleton_helpers::thread_safe_global_map_dependant + ::atomic_func(map, f); + return f.data(); + } + + //A wrapper to execute fini_atomic_func + static void singleton_destructor(void *p, ThreadSafeGlobalMap &map) + { (void)p; + fini_atomic_func f(map); + intermodule_singleton_helpers::thread_safe_global_map_dependant + ::atomic_func(map, f); + } +}; + +template +volatile int intermodule_singleton_impl::lifetime_type_lazy::m_dummy = 0; + +//These will be zero-initialized by the loader +template +void *intermodule_singleton_impl::this_module_singleton_ptr = 0; + +template +volatile boost::uint32_t intermodule_singleton_impl::this_module_singleton_initialized = 0; + +template +typename intermodule_singleton_impl::lifetime_type + intermodule_singleton_impl::lifetime; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_INTERMODULE_SINGLETON_COMMON_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/interprocess_tester.hpp b/cpp/BoostParts/boost/interprocess/detail/interprocess_tester.hpp new file mode 100644 index 00000000..2fcc07bc --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/interprocess_tester.hpp @@ -0,0 +1,31 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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_INTERPROCESS_TESTER_HPP +#define BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +class interprocess_tester +{ + public: + template + static void dont_close_on_destruction(T &t) + { t.dont_close_on_destruction(); } +}; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/managed_memory_impl.hpp b/cpp/BoostParts/boost/interprocess/detail/managed_memory_impl.hpp new file mode 100644 index 00000000..2f97935d --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/managed_memory_impl.hpp @@ -0,0 +1,776 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_MANAGED_MEMORY_IMPL_HPP +#define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +// +#include +// +#include +#include +#include +#include + +//!\file +//!Describes a named shared memory allocation user class. +//! + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +class create_open_func; + +template< + class CharType, + class MemoryAlgorithm, + template class IndexType + > +struct segment_manager_type +{ + typedef segment_manager type; +}; + +//!This class is designed to be a base class to classes that manage +//!creation of objects in a fixed size memory buffer. Apart +//!from allocating raw memory, the user can construct named objects. To +//!achieve this, this class uses the reserved space provided by the allocation +//!algorithm to place a named_allocator_algo, who takes care of name mappings. +//!The class can be customized with the char type used for object names +//!and the memory allocation algorithm to be used.*/ +template < class CharType + , class MemoryAlgorithm + , template class IndexType + , std::size_t Offset = 0 + > +class basic_managed_memory_impl +{ + //Non-copyable + basic_managed_memory_impl(const basic_managed_memory_impl &); + basic_managed_memory_impl &operator=(const basic_managed_memory_impl &); + + template + friend class create_open_func; + + public: + typedef typename segment_manager_type + ::type segment_manager; + typedef CharType char_type; + typedef MemoryAlgorithm memory_algorithm; + typedef typename MemoryAlgorithm::mutex_family mutex_family; + typedef CharType char_t; + typedef typename MemoryAlgorithm::size_type size_type; + typedef typename MemoryAlgorithm::difference_type difference_type; + typedef difference_type handle_t; + typedef typename segment_manager:: + const_named_iterator const_named_iterator; + typedef typename segment_manager:: + const_unique_iterator const_unique_iterator; + + /// @cond + + typedef typename + segment_manager::char_ptr_holder_t char_ptr_holder_t; + //Experimental. Don't use. + + typedef typename segment_manager::multiallocation_chain multiallocation_chain; + + /// @endcond + + static const size_type PayloadPerAllocation = segment_manager::PayloadPerAllocation; + + private: + typedef basic_managed_memory_impl + self_t; + protected: + template + static bool grow(const char *filename, size_type extra_bytes) + { + typedef typename ManagedMemory::device_type device_type; + //Increase file size + try{ + offset_t old_size; + { + device_type f(open_or_create, filename, read_write); + if(!f.get_size(old_size)) + return false; + f.truncate(old_size + extra_bytes); + } + ManagedMemory managed_memory(open_only, filename); + //Grow always works + managed_memory.self_t::grow(extra_bytes); + } + catch(...){ + return false; + } + return true; + } + + template + static bool shrink_to_fit(const char *filename) + { + typedef typename ManagedMemory::device_type device_type; + size_type new_size; + try{ + ManagedMemory managed_memory(open_only, filename); + managed_memory.get_size(); + managed_memory.self_t::shrink_to_fit(); + new_size = managed_memory.get_size(); + } + catch(...){ + return false; + } + + //Decrease file size + { + device_type f(open_or_create, filename, read_write); + f.truncate(new_size); + } + return true; + } + + //!Constructor. Allocates basic resources. Never throws. + basic_managed_memory_impl() + : mp_header(0){} + + //!Destructor. Calls close. Never throws. + ~basic_managed_memory_impl() + { this->close_impl(); } + + //!Places segment manager in the reserved space. This can throw. + bool create_impl (void *addr, size_type size) + { + if(mp_header) return false; + + //Check if there is enough space + if(size < segment_manager::get_min_size()) + return false; + + //This function should not throw. The index construction can + //throw if constructor allocates memory. So we must catch it. + BOOST_TRY{ + //Let's construct the allocator in memory + mp_header = new(addr) segment_manager(size); + } + BOOST_CATCH(...){ + return false; + } + BOOST_CATCH_END + return true; + } + + //!Connects to a segment manager in the reserved buffer. Never throws. + bool open_impl (void *addr, size_type) + { + if(mp_header) return false; + mp_header = static_cast(addr); + return true; + } + + //!Frees resources. Never throws. + bool close_impl() + { + bool ret = mp_header != 0; + mp_header = 0; + return ret; + } + + //!Frees resources and destroys common resources. Never throws. + bool destroy_impl() + { + if(mp_header == 0) + return false; + mp_header->~segment_manager(); + this->close_impl(); + return true; + } + + //! + void grow(size_type extra_bytes) + { mp_header->grow(extra_bytes); } + + void shrink_to_fit() + { mp_header->shrink_to_fit(); } + + public: + + //!Returns segment manager. Never throws. + segment_manager *get_segment_manager() const + { return mp_header; } + + //!Returns the base address of the memory in this process. Never throws. + void * get_address () const + { return reinterpret_cast(mp_header) - Offset; } + + //!Returns the size of memory segment. Never throws. + size_type get_size () const + { return mp_header->get_size() + Offset; } + + //!Returns the number of free bytes of the memory + //!segment + size_type get_free_memory() const + { return mp_header->get_free_memory(); } + + //!Returns the result of "all_memory_deallocated()" function + //!of the used memory algorithm + bool all_memory_deallocated() + { return mp_header->all_memory_deallocated(); } + + //!Returns the result of "check_sanity()" function + //!of the used memory algorithm + bool check_sanity() + { return mp_header->check_sanity(); } + + //!Writes to zero free memory (memory not yet allocated) of + //!the memory algorithm + void zero_free_memory() + { mp_header->zero_free_memory(); } + + //!Transforms an absolute address into an offset from base address. + //!The address must belong to the memory segment. Never throws. + handle_t get_handle_from_address (const void *ptr) const + { + return (handle_t)(reinterpret_cast(ptr) - + reinterpret_cast(this->get_address())); + } + + //!Returns true if the address belongs to the managed memory segment + bool belongs_to_segment (const void *ptr) const + { + return ptr >= this->get_address() && + ptr < (reinterpret_cast(this->get_address()) + this->get_size()); + } + + //!Transforms previously obtained offset into an absolute address in the + //!process space of the current process. Never throws.*/ + void * get_address_from_handle (handle_t offset) const + { return reinterpret_cast(this->get_address()) + offset; } + + //!Searches for nbytes of free memory in the segment, marks the + //!memory as used and return the pointer to the memory. If no + //!memory is available throws a boost::interprocess::bad_alloc exception + void* allocate (size_type nbytes) + { return mp_header->allocate(nbytes); } + + //!Searches for nbytes of free memory in the segment, marks the + //!memory as used and return the pointer to the memory. If no memory + //!is available returns 0. Never throws. + void* allocate (size_type nbytes, std::nothrow_t nothrow) + { return mp_header->allocate(nbytes, nothrow); } + + //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" + //!must be power of two. If no memory + //!is available returns 0. Never throws. + void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t nothrow) + { return mp_header->allocate_aligned(nbytes, alignment, nothrow); } + + template + std::pair + allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type preferred_size,size_type &received_size, + T *reuse_ptr = 0) + { + return mp_header->allocation_command + (command, limit_size, preferred_size, received_size, reuse_ptr); + } + + //!Allocates nbytes bytes aligned to "alignment" bytes. "alignment" + //!must be power of two. If no + //!memory is available throws a boost::interprocess::bad_alloc exception + void * allocate_aligned(size_type nbytes, size_type alignment) + { return mp_header->allocate_aligned(nbytes, alignment); } + + /// @cond + + //Experimental. Don't use. + + //!Allocates n_elements of elem_bytes bytes. + //!Throws bad_alloc on failure. chain.size() is not increased on failure. + void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { mp_header->allocate_many(elem_bytes, n_elements, chain); } + + //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes. + //!Throws bad_alloc on failure. chain.size() is not increased on failure. + void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); } + + //!Allocates n_elements of elem_bytes bytes. + //!Non-throwing version. chain.size() is not increased on failure. + void allocate_many(std::nothrow_t, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { mp_header->allocate_many(std::nothrow_t(), elem_bytes, n_elements, chain); } + + //!Allocates n_elements, each one of + //!element_lengths[i]*sizeof_element bytes. + //!Non-throwing version. chain.size() is not increased on failure. + void allocate_many(std::nothrow_t, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { mp_header->allocate_many(std::nothrow_t(), elem_sizes, n_elements, sizeof_element, chain); } + + //!Deallocates all elements contained in chain. + //!Never throws. + void deallocate_many(multiallocation_chain &chain) + { mp_header->deallocate_many(chain); } + + /// @endcond + + //!Marks previously allocated memory as free. Never throws. + void deallocate (void *addr) + { if (mp_header) mp_header->deallocate(addr); } + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { return mp_header->template find(name); } + + //!Creates a named object or array in memory + //! + //!Allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + construct(char_ptr_holder_t name) + { return mp_header->template construct(name); } + + //!Finds or creates a named object or array in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + find_or_construct(char_ptr_holder_t name) + { return mp_header->template find_or_construct(name); } + + //!Creates a named object or array in memory + //! + //!Allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Returns 0 if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + construct(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->template construct(name, nothrow); } + + //!Finds or creates a named object or array in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs a T object or an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. If an array is being constructed all objects are + //!created using the same parameters given to this function. + //! + //!-> Returns 0 if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and if an + //!array was being constructed, destructors of created objects are called + //!before freeing the memory. + template + typename segment_manager::template construct_proxy::type + find_or_construct(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->template find_or_construct(name, nothrow); } + + //!Creates a named array from iterators in memory + //! + //!Allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory. + template + typename segment_manager::template construct_iter_proxy::type + construct_it(char_ptr_holder_t name) + { return mp_header->template construct_it(name); } + + //!Finds or creates a named array from iterators in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> Throws boost::interprocess::bad_alloc if there is no available memory + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory. + template + typename segment_manager::template construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name) + { return mp_header->template find_or_construct_it(name); } + + //!Creates a named array from iterators in memory + //! + //!Allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> If there is no available memory, returns 0. + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory.*/ + template + typename segment_manager::template construct_iter_proxy::type + construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->template construct_it(name, nothrow); } + + //!Finds or creates a named array from iterators in memory + //! + //!Tries to find an object with the given name in memory. If + //!found, returns the pointer to this pointer. If the object is not found, + //!allocates and constructs an array of T in memory, + //!associates this with the given name and returns a pointer to the + //!created object. Each element in the array is created using the + //!objects returned when dereferencing iterators as parameters + //!and incrementing all iterators for each element. + //! + //!-> If the name was previously used, returns 0. + //! + //!-> If there is no available memory, returns 0. + //! + //!-> If T's constructor throws, the function throws that exception. + //! + //!Memory is freed automatically if T's constructor throws and + //!destructors of created objects are called before freeing the memory.*/ + template + typename segment_manager::template construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->template find_or_construct_it(name, nothrow); } + + //!Calls a functor and guarantees that no new construction, search or + //!destruction will be executed by any process while executing the object + //!function call. If the functor throws, this function throws. + template + void atomic_func(Func &f) + { mp_header->atomic_func(f); } + + //!Tries to call a functor guaranteeing that no new construction, search or + //!destruction will be executed by any process while executing the object + //!function call. If the atomic function can't be immediatelly executed + //!because the internal mutex is already locked, returns false. + //!If the functor throws, this function throws. + template + bool try_atomic_func(Func &f) + { return mp_header->try_atomic_func(f); } + + //!Destroys a named memory object or array. + //! + //!Finds the object with the given name, calls its destructors, + //!frees used memory and returns true. + //! + //!-> If the object is not found, it returns false. + //! + //!Exception Handling: + //! + //!When deleting a dynamically object or array, the Standard + //!does not guarantee that dynamically allocated memory, will be released. + //!Also, when deleting arrays, the Standard doesn't require calling + //!destructors for the rest of the objects if for one of them the destructor + //!terminated with an exception. + //! + //!Destroying an object: + //! + //!If the destructor throws, the memory will be freed and that exception + //!will be thrown. + //! + //!Destroying an array: + //! + //!When destroying an array, if a destructor throws, the rest of + //!destructors are called. If any of these throws, the exceptions are + //!ignored. The name association will be erased, memory will be freed and + //!the first exception will be thrown. This guarantees the unlocking of + //!mutexes and other resources. + //! + //!For all theses reasons, classes with throwing destructors are not + //!recommended. + template + bool destroy(const CharType *name) + { return mp_header->template destroy(name); } + + //!Destroys the unique instance of type T + //! + //!Calls the destructor, frees used memory and returns true. + //! + //!Exception Handling: + //! + //!When deleting a dynamically object, the Standard does not + //!guarantee that dynamically allocated memory will be released. + //! + //!Destroying an object: + //! + //!If the destructor throws, the memory will be freed and that exception + //!will be thrown. + //! + //!For all theses reasons, classes with throwing destructors are not + //!recommended for memory. + template + bool destroy(const unique_instance_t *const ) + { return mp_header->template destroy(unique_instance); } + + //!Destroys the object (named, unique, or anonymous) + //! + //!Calls the destructor, frees used memory and returns true. + //! + //!Exception Handling: + //! + //!When deleting a dynamically object, the Standard does not + //!guarantee that dynamically allocated memory will be released. + //! + //!Destroying an object: + //! + //!If the destructor throws, the memory will be freed and that exception + //!will be thrown. + //! + //!For all theses reasons, classes with throwing destructors are not + //!recommended for memory. + template + void destroy_ptr(const T *ptr) + { mp_header->template destroy_ptr(ptr); } + + //!Returns the name of an object created with construct/find_or_construct + //!functions. Does not throw + template + static const char_type *get_instance_name(const T *ptr) + { return segment_manager::get_instance_name(ptr); } + + //!Returns is the type an object created with construct/find_or_construct + //!functions. Does not throw. + template + static instance_type get_instance_type(const T *ptr) + { return segment_manager::get_instance_type(ptr); } + + //!Returns the length of an object created with construct/find_or_construct + //!functions (1 if is a single element, >=1 if it's an array). Does not throw. + template + static size_type get_instance_length(const T *ptr) + { return segment_manager::get_instance_length(ptr); } + + //!Preallocates needed index resources to optimize the + //!creation of "num" named objects in the memory segment. + //!Can throw boost::interprocess::bad_alloc if there is no enough memory. + void reserve_named_objects(size_type num) + { mp_header->reserve_named_objects(num); } + + //!Preallocates needed index resources to optimize the + //!creation of "num" unique objects in the memory segment. + //!Can throw boost::interprocess::bad_alloc if there is no enough memory. + void reserve_unique_objects(size_type num) + { mp_header->reserve_unique_objects(num); } + + //!Calls shrink_to_fit in both named and unique object indexes + //to try to free unused memory from those indexes. + void shrink_to_fit_indexes() + { mp_header->shrink_to_fit_indexes(); } + + //!Returns the number of named objects stored + //!in the managed segment. + size_type get_num_named_objects() + { return mp_header->get_num_named_objects(); } + + //!Returns the number of unique objects stored + //!in the managed segment. + size_type get_num_unique_objects() + { return mp_header->get_num_unique_objects(); } + + //!Returns a constant iterator to the index storing the + //!named allocations. NOT thread-safe. Never throws. + const_named_iterator named_begin() const + { return mp_header->named_begin(); } + + //!Returns a constant iterator to the end of the index + //!storing the named allocations. NOT thread-safe. Never throws. + const_named_iterator named_end() const + { return mp_header->named_end(); } + + //!Returns a constant iterator to the index storing the + //!unique allocations. NOT thread-safe. Never throws. + const_unique_iterator unique_begin() const + { return mp_header->unique_begin(); } + + //!Returns a constant iterator to the end of the index + //!storing the unique allocations. NOT thread-safe. Never throws. + const_unique_iterator unique_end() const + { return mp_header->unique_end(); } + + //!This is the default allocator to allocate types T + //!from this managed segment + template + struct allocator + { + typedef typename segment_manager::template allocator::type type; + }; + + //!Returns an instance of the default allocator for type T + //!initialized that allocates memory from this segment manager. + template + typename allocator::type + get_allocator() + { return mp_header->template get_allocator(); } + + //!This is the default deleter to delete types T + //!from this managed segment. + template + struct deleter + { + typedef typename segment_manager::template deleter::type type; + }; + + //!Returns an instance of the default allocator for type T + //!initialized that allocates memory from this segment manager. + template + typename deleter::type + get_deleter() + { return mp_header->template get_deleter(); } + + /// @cond + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find_no_lock (char_ptr_holder_t name) + { return mp_header->template find_no_lock(name); } + /// @endcond + + protected: + //!Swaps the segment manager's managed by this managed memory segment. + //!NOT thread-safe. Never throws. + void swap(basic_managed_memory_impl &other) + { std::swap(mp_header, other.mp_header); } + + private: + segment_manager *mp_header; +}; + +template +class create_open_func +{ + typedef typename BasicManagedMemoryImpl::size_type size_type; + + public: + + create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type) + : m_frontend(frontend), m_type(type){} + + bool operator()(void *addr, std::size_t size, bool created) const + { + if( ((m_type == DoOpen) && created) || + ((m_type == DoCreate) && !created) || + //Check for overflow + size_type(-1) < size ){ + return false; + } + else if(created){ + return m_frontend->create_impl(addr, static_cast(size)); + } + else{ + return m_frontend->open_impl (addr, static_cast(size)); + } + } + + std::size_t get_min_size() const + { + const size_type sz = m_frontend->get_segment_manager()->get_min_size(); + if(sz > std::size_t(-1)){ + //The minimum size is not representable by std::size_t + BOOST_ASSERT(false); + return std::size_t(-1); + } + else{ + return static_cast(sz); + } + } + + private: + BasicManagedMemoryImpl *m_frontend; + create_enum_t m_type; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/managed_open_or_create_impl.hpp b/cpp/BoostParts/boost/interprocess/detail/managed_open_or_create_impl.hpp new file mode 100644 index 00000000..f8154d06 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -0,0 +1,489 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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_MANAGED_OPEN_OR_CREATE_IMPL +#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { + +/// @cond +namespace ipcdetail{ class interprocess_tester; } + + +template +struct managed_open_or_create_impl_device_id_t +{ + typedef const char *type; +}; + +#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + +class xsi_shared_memory_file_wrapper; +class xsi_key; + +template<> +struct managed_open_or_create_impl_device_id_t +{ + typedef xsi_key type; +}; + +#endif //BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + +/// @endcond + +namespace ipcdetail { + + +template +class managed_open_or_create_impl_device_holder +{ + public: + DeviceAbstraction &get_device() + { static DeviceAbstraction dev; return dev; } + + const DeviceAbstraction &get_device() const + { static DeviceAbstraction dev; return dev; } +}; + +template +class managed_open_or_create_impl_device_holder +{ + public: + DeviceAbstraction &get_device() + { return dev; } + + const DeviceAbstraction &get_device() const + { return dev; } + + private: + DeviceAbstraction dev; +}; + +template +class managed_open_or_create_impl + : public managed_open_or_create_impl_device_holder +{ + //Non-copyable + BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl) + + typedef typename managed_open_or_create_impl_device_id_t::type device_id_t; + typedef managed_open_or_create_impl_device_holder DevHolder; + enum + { + UninitializedSegment, + InitializingSegment, + InitializedSegment, + CorruptedSegment + }; + + public: + static const std::size_t + ManagedOpenOrCreateUserOffset = + ct_rounded_size + < sizeof(boost::uint32_t) + , MemAlignment ? (MemAlignment) : + (::boost::alignment_of< ::boost::detail::max_align >::value) + >::value; + + managed_open_or_create_impl() + {} + + managed_open_or_create_impl(create_only_t, + const device_id_t & id, + std::size_t size, + mode_t mode, + const void *addr, + const permissions &perm) + { + priv_open_or_create + ( DoCreate + , id + , size + , mode + , addr + , perm + , null_mapped_region_function()); + } + + managed_open_or_create_impl(open_only_t, + const device_id_t & id, + mode_t mode, + const void *addr) + { + priv_open_or_create + ( DoOpen + , id + , 0 + , mode + , addr + , permissions() + , null_mapped_region_function()); + } + + + managed_open_or_create_impl(open_or_create_t, + const device_id_t & id, + std::size_t size, + mode_t mode, + const void *addr, + const permissions &perm) + { + priv_open_or_create + ( DoOpenOrCreate + , id + , size + , mode + , addr + , perm + , null_mapped_region_function()); + } + + template + managed_open_or_create_impl(create_only_t, + const device_id_t & id, + std::size_t size, + mode_t mode, + const void *addr, + const ConstructFunc &construct_func, + const permissions &perm) + { + priv_open_or_create + (DoCreate + , id + , size + , mode + , addr + , perm + , construct_func); + } + + template + managed_open_or_create_impl(open_only_t, + const device_id_t & id, + mode_t mode, + const void *addr, + const ConstructFunc &construct_func) + { + priv_open_or_create + ( DoOpen + , id + , 0 + , mode + , addr + , permissions() + , construct_func); + } + + template + managed_open_or_create_impl(open_or_create_t, + const device_id_t & id, + std::size_t size, + mode_t mode, + const void *addr, + const ConstructFunc &construct_func, + const permissions &perm) + { + priv_open_or_create + ( DoOpenOrCreate + , id + , size + , mode + , addr + , perm + , construct_func); + } + + managed_open_or_create_impl(BOOST_RV_REF(managed_open_or_create_impl) moved) + { this->swap(moved); } + + managed_open_or_create_impl &operator=(BOOST_RV_REF(managed_open_or_create_impl) moved) + { + managed_open_or_create_impl tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + ~managed_open_or_create_impl() + {} + + std::size_t get_user_size() const + { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; } + + void *get_user_address() const + { return static_cast(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; } + + std::size_t get_real_size() const + { return m_mapped_region.get_size(); } + + void *get_real_address() const + { return m_mapped_region.get_address(); } + + void swap(managed_open_or_create_impl &other) + { + this->m_mapped_region.swap(other.m_mapped_region); + } + + bool flush() + { return m_mapped_region.flush(); } + + const mapped_region &get_mapped_region() const + { return m_mapped_region; } + + + DeviceAbstraction &get_device() + { return this->DevHolder::get_device(); } + + const DeviceAbstraction &get_device() const + { return this->DevHolder::get_device(); } + + private: + + //These are templatized to allow explicit instantiations + template + static void truncate_device(DeviceAbstraction &, offset_t, false_) + {} //Empty + + template + static void truncate_device(DeviceAbstraction &dev, offset_t size, true_) + { dev.truncate(size); } + + + template + static bool check_offset_t_size(std::size_t , false_) + { return true; } //Empty + + template + static bool check_offset_t_size(std::size_t size, true_) + { return size == std::size_t(offset_t(size)); } + + //These are templatized to allow explicit instantiations + template + static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t size, const permissions &perm, false_ file_like) + { + (void)file_like; + DeviceAbstraction tmp(create_only, id, read_write, size, perm); + tmp.swap(dev); + } + + template + static void create_device(DeviceAbstraction &dev, const device_id_t & id, std::size_t, const permissions &perm, true_ file_like) + { + (void)file_like; + DeviceAbstraction tmp(create_only, id, read_write, perm); + tmp.swap(dev); + } + + template inline + void priv_open_or_create + (create_enum_t type, + const device_id_t & id, + std::size_t size, + mode_t mode, const void *addr, + const permissions &perm, + ConstructFunc construct_func) + { + typedef bool_ file_like_t; + (void)mode; + error_info err; + bool created = false; + bool ronly = false; + bool cow = false; + DeviceAbstraction dev; + + if(type != DoOpen){ + //Check if the requested size is enough to build the managed metadata + const std::size_t func_min_size = construct_func.get_min_size(); + if( (std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size || + size < (func_min_size + ManagedOpenOrCreateUserOffset) ){ + throw interprocess_exception(error_info(size_error)); + } + } + //Check size can be represented by offset_t (used by truncate) + if(type != DoOpen && !check_offset_t_size(size, file_like_t())){ + throw interprocess_exception(error_info(size_error)); + } + if(type == DoOpen && mode == read_write){ + DeviceAbstraction tmp(open_only, id, read_write); + tmp.swap(dev); + created = false; + } + else if(type == DoOpen && mode == read_only){ + DeviceAbstraction tmp(open_only, id, read_only); + tmp.swap(dev); + created = false; + ronly = true; + } + else if(type == DoOpen && mode == copy_on_write){ + DeviceAbstraction tmp(open_only, id, read_only); + tmp.swap(dev); + created = false; + cow = true; + } + else if(type == DoCreate){ + create_device(dev, id, size, perm, file_like_t()); + created = true; + } + else if(type == DoOpenOrCreate){ + //This loop is very ugly, but brute force is sometimes better + //than diplomacy. If someone knows how to open or create a + //file and know if we have really created it or just open it + //drop me a e-mail! + bool completed = false; + while(!completed){ + try{ + create_device(dev, id, size, perm, file_like_t()); + created = true; + completed = true; + } + catch(interprocess_exception &ex){ + if(ex.get_error_code() != already_exists_error){ + throw; + } + else{ + try{ + DeviceAbstraction tmp(open_only, id, read_write); + dev.swap(tmp); + created = false; + completed = true; + } + catch(interprocess_exception &e){ + if(e.get_error_code() != not_found_error){ + throw; + } + } + catch(...){ + throw; + } + } + } + catch(...){ + throw; + } + thread_yield(); + } + } + + if(created){ + try{ + //If this throws, we are lost + truncate_device(dev, size, file_like_t()); + + //If the following throws, we will truncate the file to 1 + mapped_region region(dev, read_write, 0, 0, addr); + boost::uint32_t *patomic_word = 0; //avoid gcc warning + patomic_word = static_cast(region.get_address()); + boost::uint32_t previous = atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment); + + if(previous == UninitializedSegment){ + try{ + construct_func( static_cast(region.get_address()) + ManagedOpenOrCreateUserOffset + , size - ManagedOpenOrCreateUserOffset, true); + //All ok, just move resources to the external mapped region + m_mapped_region.swap(region); + } + catch(...){ + atomic_write32(patomic_word, CorruptedSegment); + throw; + } + atomic_write32(patomic_word, InitializedSegment); + } + else if(previous == InitializingSegment || previous == InitializedSegment){ + throw interprocess_exception(error_info(already_exists_error)); + } + else{ + throw interprocess_exception(error_info(corrupted_error)); + } + } + catch(...){ + try{ + truncate_device(dev, 1u, file_like_t()); + } + catch(...){ + } + throw; + } + } + else{ + if(FileBased){ + offset_t filesize = 0; + while(filesize == 0){ + if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){ + throw interprocess_exception(error_info(system_error_code())); + } + thread_yield(); + } + if(filesize == 1){ + throw interprocess_exception(error_info(corrupted_error)); + } + } + + mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr); + + boost::uint32_t *patomic_word = static_cast(region.get_address()); + boost::uint32_t value = atomic_read32(patomic_word); + + while(value == InitializingSegment || value == UninitializedSegment){ + thread_yield(); + value = atomic_read32(patomic_word); + } + + if(value != InitializedSegment) + throw interprocess_exception(error_info(corrupted_error)); + + construct_func( static_cast(region.get_address()) + ManagedOpenOrCreateUserOffset + , region.get_size() - ManagedOpenOrCreateUserOffset + , false); + //All ok, just move resources to the external mapped region + m_mapped_region.swap(region); + } + if(StoreDevice){ + this->DevHolder::get_device() = boost::move(dev); + } + } + + friend void swap(managed_open_or_create_impl &left, managed_open_or_create_impl &right) + { + left.swap(right); + } + + private: + friend class interprocess_tester; + void dont_close_on_destruction() + { interprocess_tester::dont_close_on_destruction(m_mapped_region); } + + mapped_region m_mapped_region; +}; + +} //namespace ipcdetail { + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL diff --git a/cpp/BoostParts/boost/interprocess/detail/math_functions.hpp b/cpp/BoostParts/boost/interprocess/detail/math_functions.hpp new file mode 100644 index 00000000..20922b39 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/math_functions.hpp @@ -0,0 +1,110 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Stephen Cleary 2000. +// (C) Copyright Ion Gaztanaga 2007-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. +// +// This file is a slightly modified file from Boost.Pool +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP + +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +// Greatest common divisor and least common multiple + +// +// gcd is an algorithm that calculates the greatest common divisor of two +// integers, using Euclid's algorithm. +// +// Pre: A > 0 && B > 0 +// Recommended: A > B +template +inline Integer gcd(Integer A, Integer B) +{ + do + { + const Integer tmp(B); + B = A % B; + A = tmp; + } while (B != 0); + + return A; +} + +// +// lcm is an algorithm that calculates the least common multiple of two +// integers. +// +// Pre: A > 0 && B > 0 +// Recommended: A > B +template +inline Integer lcm(const Integer & A, const Integer & B) +{ + Integer ret = A; + ret /= gcd(A, B); + ret *= B; + return ret; +} + +template +inline Integer log2_ceil(const Integer & A) +{ + Integer i = 0; + Integer power_of_2 = 1; + + while(power_of_2 < A){ + power_of_2 <<= 1; + ++i; + } + return i; +} + +template +inline Integer upper_power_of_2(const Integer & A) +{ + Integer power_of_2 = 1; + + while(power_of_2 < A){ + power_of_2 <<= 1; + } + return power_of_2; +} + +//This function uses binary search to discover the +//highest set bit of the integer +inline std::size_t floor_log2 (std::size_t x) +{ + const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; + const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); + BOOST_STATIC_ASSERT(((Size_t_Bits_Power_2)== true)); + + std::size_t n = x; + std::size_t log2 = 0; + + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ + std::size_t tmp = n >> shift; + if (tmp) + log2 += shift, n = tmp; + } + + return log2; +} + +} // namespace ipcdetail +} // namespace interprocess +} // namespace boost + +#endif diff --git a/cpp/BoostParts/boost/interprocess/detail/min_max.hpp b/cpp/BoostParts/boost/interprocess/detail/min_max.hpp new file mode 100644 index 00000000..63ce7efd --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/min_max.hpp @@ -0,0 +1,40 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_MIN_MAX_HPP +#define BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +template +const T &max_value(const T &a, const T &b) +{ return a > b ? a : b; } + +template +const T &min_value(const T &a, const T &b) +{ return a < b ? a : b; } + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/mpl.hpp b/cpp/BoostParts/boost/interprocess/detail/mpl.hpp new file mode 100644 index 00000000..4c5e1f1b --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/mpl.hpp @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_MPL_HPP +#define BOOST_INTERPROCESS_DETAIL_MPL_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +struct integral_constant +{ + static const T value = val; + typedef integral_constant type; +}; + +template< bool C_ > +struct bool_ : integral_constant +{ + static const bool value = C_; +}; + +typedef bool_ true_; +typedef bool_ false_; + +typedef true_ true_type; +typedef false_ false_type; + +typedef char yes_type; +struct no_type +{ + char padding[8]; +}; + +template +struct enable_if_c { + typedef T type; +}; + +template +struct enable_if_c {}; + +template +struct enable_if : public enable_if_c {}; + +template +struct disable_if : public enable_if_c {}; + +template +class is_convertible +{ + typedef char true_t; + class false_t { char dummy[2]; }; + static true_t dispatch(U); + static false_t dispatch(...); + static T trigger(); + public: + static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t); +}; + +template< + bool C + , typename T1 + , typename T2 + > +struct if_c +{ + typedef T1 type; +}; + +template< + typename T1 + , typename T2 + > +struct if_c +{ + typedef T2 type; +}; + +template< + typename T1 + , typename T2 + , typename T3 + > +struct if_ +{ + typedef typename if_c<0 != T1::value, T2, T3>::type type; +}; + + +template +struct select1st +// : public std::unary_function +{ + template + const typename Pair::first_type& operator()(const OtherPair& x) const + { return x.first; } + + const typename Pair::first_type& operator()(const typename Pair::first_type& x) const + { return x; } +}; + +// identity is an extension: it is not part of the standard. +template +struct identity +// : public std::unary_function +{ + typedef T type; + const T& operator()(const T& x) const + { return x; } +}; + +template +struct ls_zeros +{ + static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value); +}; + +template<> +struct ls_zeros<0> +{ + static const std::size_t value = 0; +}; + +template<> +struct ls_zeros<1> +{ + static const std::size_t value = 0; +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/named_proxy.hpp b/cpp/BoostParts/boost/interprocess/detail/named_proxy.hpp new file mode 100644 index 00000000..14a9aa0a --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/named_proxy.hpp @@ -0,0 +1,349 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_NAMED_PROXY_HPP +#define BOOST_INTERPROCESS_NAMED_PROXY_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include + +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +#include +#else +#include +#include +#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +//!\file +//!Describes a proxy class that implements named allocation syntax. + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +template +struct CtorNArg : public placement_destroy +{ + typedef bool_ IsIterator; + typedef CtorNArg self_t; + typedef typename build_number_seq::type index_tuple_t; + + self_t& operator++() + { + this->do_increment(IsIterator(), index_tuple_t()); + return *this; + } + + self_t operator++(int) { return ++*this; *this; } + + CtorNArg(Args && ...args) + : args_(args...) + {} + + virtual void construct_n(void *mem + , std::size_t num + , std::size_t &constructed) + { + T* memory = static_cast(mem); + for(constructed = 0; constructed < num; ++constructed){ + this->construct(memory++, IsIterator(), index_tuple_t()); + this->do_increment(IsIterator(), index_tuple_t()); + } + } + + private: + template + void construct(void *mem, true_, const index_tuple&) + { new((void*)mem)T(*boost::forward(get(args_))...); } + + template + void construct(void *mem, false_, const index_tuple&) + { new((void*)mem)T(boost::forward(get(args_))...); } + + template + void do_increment(true_, const index_tuple&) + { + this->expansion_helper(++get(args_)...); + } + + template + void expansion_helper(ExpansionArgs &&...) + {} + + template + void do_increment(false_, const index_tuple&) + {} + + tuple args_; +}; + +//!Describes a proxy class that implements named +//!allocation syntax. +template + < class SegmentManager //segment manager to construct the object + , class T //type of object to build + , bool is_iterator //passing parameters are normal object or iterators? + > +class named_proxy +{ + typedef typename SegmentManager::char_type char_type; + const char_type * mp_name; + SegmentManager * mp_mngr; + mutable std::size_t m_num; + const bool m_find; + const bool m_dothrow; + + public: + named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow) + : mp_name(name), mp_mngr(mngr), m_num(1) + , m_find(find), m_dothrow(dothrow) + {} + + template + T *operator()(Args &&...args) const + { + CtorNArg &&ctor_obj = CtorNArg + (boost::forward(args)...); + return mp_mngr->template + generic_construct(mp_name, m_num, m_find, m_dothrow, ctor_obj); + } + + //This operator allows --> named_new("Name")[3]; <-- syntax + const named_proxy &operator[](std::size_t num) const + { m_num *= num; return *this; } +}; + +#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +//!Function object that makes placement new +//!without arguments +template +struct Ctor0Arg : public placement_destroy +{ + typedef Ctor0Arg self_t; + + Ctor0Arg(){} + + self_t& operator++() { return *this; } + self_t operator++(int) { return *this; } + + void construct(void *mem) + { new((void*)mem)T; } + + virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) + { + T* memory = static_cast(mem); + for(constructed = 0; constructed < num; ++constructed) + new((void*)memory++)T; + } +}; + +//////////////////////////////////////////////////////////////// +// What the macro should generate (n == 2): +// +// template +// struct Ctor2Arg +// : public placement_destroy +// { +// typedef bool_ IsIterator; +// typedef Ctor2Arg self_t; +// +// void do_increment(false_) +// { ++m_p1; ++m_p2; } +// +// void do_increment(true_){} +// +// self_t& operator++() +// { +// this->do_increment(IsIterator()); +// return *this; +// } +// +// self_t operator++(int) { return ++*this; *this; } +// +// Ctor2Arg(const P1 &p1, const P2 &p2) +// : p1((P1 &)p_1), p2((P2 &)p_2) {} +// +// void construct(void *mem) +// { new((void*)object)T(m_p1, m_p2); } +// +// virtual void construct_n(void *mem +// , std::size_t num +// , std::size_t &constructed) +// { +// T* memory = static_cast(mem); +// for(constructed = 0; constructed < num; ++constructed){ +// this->construct(memory++, IsIterator()); +// this->do_increment(IsIterator()); +// } +// } +// +// private: +// void construct(void *mem, true_) +// { new((void*)mem)T(*m_p1, *m_p2); } +// +// void construct(void *mem, false_) +// { new((void*)mem)T(m_p1, m_p2); } +// +// P1 &m_p1; P2 &m_p2; +// }; +//////////////////////////////////////////////////////////////// + +//Note: +//We define template parameters as const references to +//be able to bind temporaries. After that we will un-const them. +//This cast is ugly but it is necessary until "perfect forwarding" +//is achieved in C++0x. Meanwhile, if we want to be able to +//bind lvalues with non-const references, we have to be ugly +#define BOOST_PP_LOCAL_MACRO(n) \ + template \ + struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ + : public placement_destroy \ + { \ + typedef bool_ IsIterator; \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) self_t; \ + \ + void do_increment(true_) \ + { BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_INC, _); } \ + \ + void do_increment(false_){} \ + \ + self_t& operator++() \ + { \ + this->do_increment(IsIterator()); \ + return *this; \ + } \ + \ + self_t operator++(int) { return ++*this; *this; } \ + \ + BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ + ( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _) ) \ + : BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_INIT, _) {} \ + \ + virtual void construct_n(void *mem \ + , std::size_t num \ + , std::size_t &constructed) \ + { \ + T* memory = static_cast(mem); \ + for(constructed = 0; constructed < num; ++constructed){ \ + this->construct(memory++, IsIterator()); \ + this->do_increment(IsIterator()); \ + } \ + } \ + \ + private: \ + void construct(void *mem, true_) \ + { \ + new((void*)mem) T \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD, _)); \ + } \ + \ + void construct(void *mem, false_) \ + { \ + new((void*)mem) T \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ + } \ + \ + BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_PP_PARAM_DEFINE, _) \ + }; \ +//! +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) +#include BOOST_PP_LOCAL_ITERATE() + +//!Describes a proxy class that implements named +//!allocation syntax. +template + < class SegmentManager //segment manager to construct the object + , class T //type of object to build + , bool is_iterator //passing parameters are normal object or iterators? + > +class named_proxy +{ + typedef typename SegmentManager::char_type char_type; + const char_type * mp_name; + SegmentManager * mp_mngr; + mutable std::size_t m_num; + const bool m_find; + const bool m_dothrow; + + public: + named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow) + : mp_name(name), mp_mngr(mngr), m_num(1) + , m_find(find), m_dothrow(dothrow) + {} + + //!makes a named allocation and calls the + //!default constructor + T *operator()() const + { + Ctor0Arg ctor_obj; + return mp_mngr->template + generic_construct(mp_name, m_num, m_find, m_dothrow, ctor_obj); + } + //! + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + T *operator()(BOOST_PP_ENUM (n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) const\ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ + \ + ctor_obj_t; \ + ctor_obj_t ctor_obj \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + return mp_mngr->template generic_construct \ + (mp_name, m_num, m_find, m_dothrow, ctor_obj); \ + } \ + //! + + #define BOOST_PP_LOCAL_LIMITS ( 1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS ) + #include BOOST_PP_LOCAL_ITERATE() + + //////////////////////////////////////////////////////////////////////// + // What the macro should generate (n == 2) + //////////////////////////////////////////////////////////////////////// + // + // template + // T *operator()(P1 &p1, P2 &p2) const + // { + // typedef Ctor2Arg + // + // ctor_obj_t; + // ctor_obj_t ctor_obj(p1, p2); + // + // return mp_mngr->template generic_construct + // (mp_name, m_num, m_find, m_dothrow, ctor_obj); + // } + // + ////////////////////////////////////////////////////////////////////////// + + //This operator allows --> named_new("Name")[3]; <-- syntax + const named_proxy &operator[](std::size_t num) const + { m_num *= num; return *this; } +}; + +#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +}}} //namespace boost { namespace interprocess { namespace ipcdetail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/os_file_functions.hpp b/cpp/BoostParts/boost/interprocess/detail/os_file_functions.hpp new file mode 100644 index 00000000..840079dc --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/os_file_functions.hpp @@ -0,0 +1,696 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_OS_FILE_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP + +#include +#include +#include +#include + +#include +#include +#include + +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include +# include +# include +# include +# include +# include +# if 0 +# include +# endif +# else +# error Unknown platform +# endif +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +#if (defined BOOST_INTERPROCESS_WINDOWS) + +typedef void * file_handle_t; +typedef long long offset_t; +typedef struct mapping_handle_impl_t{ + void * handle; + bool is_shm; +} mapping_handle_t; + +typedef enum { read_only = winapi::generic_read + , read_write = winapi::generic_read | winapi::generic_write + , copy_on_write + , read_private + , invalid_mode = 0xffff + } mode_t; + +typedef enum { file_begin = winapi::file_begin + , file_end = winapi::file_end + , file_current = winapi::file_current + } file_pos_t; + +namespace ipcdetail{ + +inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_shm = false; + return ret; +} + +inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_shm = true; + return ret; +} + +inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) +{ return hnd.handle; } + +inline bool create_directory(const char *path) +{ return winapi::create_directory(path); } + +inline const char *get_temporary_path() +{ return std::getenv("TMP"); } + + +inline file_handle_t create_new_file + (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) +{ + unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; + return winapi::create_file + ( name, (unsigned int)mode, winapi::create_new, attr + , (winapi::interprocess_security_attributes*)perm.get_permissions()); +} + +inline file_handle_t create_or_open_file + (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) +{ + unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; + return winapi::create_file + ( name, (unsigned int)mode, winapi::open_always, attr + , (winapi::interprocess_security_attributes*)perm.get_permissions()); +} + +inline file_handle_t open_existing_file + (const char *name, mode_t mode, bool temporary = false) +{ + unsigned long attr = temporary ? winapi::file_attribute_temporary : 0; + return winapi::create_file + (name, (unsigned int)mode, winapi::open_existing, attr, 0); +} + +inline bool delete_file(const char *name) +{ return winapi::unlink_file(name); } + +inline bool truncate_file (file_handle_t hnd, std::size_t size) +{ + offset_t filesize; + if(!winapi::get_file_size(hnd, filesize)) + return false; + + const offset_t max_filesize = (std::numeric_limits::max)(); + //Avoid unused variable warnings in 32 bit systems + (void)max_filesize; + if( sizeof(std::size_t) >= sizeof(offset_t) && size > std::size_t(max_filesize) ){ + winapi::set_last_error(winapi::error_file_too_large); + return false; + } + + if(offset_t(size) > filesize){ + if(!winapi::set_file_pointer_ex(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 + ;remaining > 0 + ;remaining -= write_size){ + const std::size_t DataSize = 512; + static char data [DataSize]; + write_size = DataSize < remaining ? DataSize : remaining; + unsigned long written; + winapi::write_file(hnd, data, (unsigned long)write_size, &written, 0); + if(written != write_size){ + return false; + } + } + } + else{ + if(!winapi::set_file_pointer_ex(hnd, size, 0, winapi::file_begin)){ + return false; + } + if(!winapi::set_end_of_file(hnd)){ + return false; + } + } + return true; +} + +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); } + +inline bool get_file_pointer(file_handle_t hnd, offset_t &off) +{ return winapi::set_file_pointer_ex(hnd, 0, &off, winapi::file_current); } + +inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata) +{ + unsigned long written; + return 0 != winapi::write_file(hnd, data, (unsigned long)numdata, &written, 0); +} + +inline file_handle_t invalid_file() +{ return winapi::invalid_handle_value; } + +inline bool close_file(file_handle_t hnd) +{ return 0 != winapi::close_handle(hnd); } + +inline bool acquire_file_lock(file_handle_t hnd) +{ + static winapi::interprocess_overlapped overlapped; + const unsigned long len = ((unsigned long)-1); +// winapi::interprocess_overlapped overlapped; +// std::memset(&overlapped, 0, sizeof(overlapped)); + return winapi::lock_file_ex + (hnd, winapi::lockfile_exclusive_lock, 0, len, len, &overlapped); +} + +inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) +{ + const unsigned long len = ((unsigned long)-1); + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + if(!winapi::lock_file_ex + (hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately, + 0, len, len, &overlapped)){ + return winapi::get_last_error() == winapi::error_lock_violation ? + acquired = false, true : false; + + } + return (acquired = true); +} + +inline bool release_file_lock(file_handle_t hnd) +{ + const unsigned long len = ((unsigned long)-1); + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + return winapi::unlock_file_ex(hnd, 0, len, len, &overlapped); +} + +inline bool acquire_file_lock_sharable(file_handle_t hnd) +{ + const unsigned long len = ((unsigned long)-1); + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + return winapi::lock_file_ex(hnd, 0, 0, len, len, &overlapped); +} + +inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) +{ + const unsigned long len = ((unsigned long)-1); + winapi::interprocess_overlapped overlapped; + std::memset(&overlapped, 0, sizeof(overlapped)); + if(!winapi::lock_file_ex + (hnd, winapi::lockfile_fail_immediately, 0, len, len, &overlapped)){ + return winapi::get_last_error() == winapi::error_lock_violation ? + acquired = false, true : false; + } + return (acquired = true); +} + +inline bool release_file_lock_sharable(file_handle_t hnd) +{ return release_file_lock(hnd); } + +inline bool delete_subdirectories_recursive + (const std::string &refcstrRootDirectory, const char *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_t FileInformation; // File information + + //Find all files and directories + strPattern = refcstrRootDirectory + "\\*.*"; + 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)){ + strFilePath.erase(); + strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName; + + //If it's a directory, go recursive + if(FileInformation.dwFileAttributes & winapi::file_attribute_directory){ + // Delete subdirectory + if(!delete_subdirectories_recursive(strFilePath, dont_delete_this, count+1)) + return false; + } + //If it's a file, just delete it + else{ + // Set file attributes + //if(::SetFileAttributes(strFilePath.c_str(), winapi::file_attribute_normal) == 0) + //return winapi::get_last_error(); + // Delete file + winapi::delete_file(strFilePath.c_str()); + } + } + //Go to the next file + } while(winapi::find_next_file(hFile, &FileInformation) == 1); + + // Close handle + winapi::find_close(hFile); + + //See if the loop has ended with an error or just because we've traversed all the files + if(winapi::get_last_error() != winapi::error_no_more_files){ + return false; + } + else + { + //Erase empty subdirectories or original refcstrRootDirectory + if(!bSubdirectory && count) + { + // Set directory attributes + //if(::SetFileAttributes(refcstrRootDirectory.c_str(), FILE_ATTRIBUTE_NORMAL) == 0) + //return ::GetLastError(); + // Delete directory + if(winapi::remove_directory(refcstrRootDirectory.c_str()) == 0) + return false; + } + } + } + return true; +} + +//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) +{ + return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this, 0u); +} + + +template +inline bool for_each_file_in_dir(const char *dir, Function f) +{ + void * hFile; // Handle to directory + winapi::win32_find_data_t FileInformation; // File information + + //Get base directory + std::string str(dir); + const std::size_t base_root_dir_len = str.size(); + + //Find all files and directories + str += "\\*.*"; + hFile = winapi::find_first_file(str.c_str(), &FileInformation); + if(hFile != winapi::invalid_handle_value){ + do{ //Now loop every file + str.erase(base_root_dir_len); + //If it's not "." or ".." skip it + if(FileInformation.cFileName[0] != '.'){ + str += "\\"; str += FileInformation.cFileName; + //If it's a file, apply erase logic + if(!(FileInformation.dwFileAttributes & winapi::file_attribute_directory)){ + f(str.c_str(), FileInformation.cFileName); + } + } + //Go to the next file + } while(winapi::find_next_file(hFile, &FileInformation) == 1); + + // Close handle and see if the loop has ended with an error + winapi::find_close(hFile); + if(winapi::get_last_error() != winapi::error_no_more_files){ + return false; + } + } + return true; +} + + +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) + +typedef int file_handle_t; +typedef off_t offset_t; + +typedef struct mapping_handle_impl_t +{ + file_handle_t handle; + bool is_xsi; +} mapping_handle_t; + +typedef enum { read_only = O_RDONLY + , read_write = O_RDWR + , copy_on_write + , read_private + , invalid_mode = 0xffff + } mode_t; + +typedef enum { file_begin = SEEK_SET + , file_end = SEEK_END + , file_current = SEEK_CUR + } file_pos_t; + +namespace ipcdetail{ + +inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_xsi = false; + return ret; +} + +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; } + +inline const char *get_temporary_path() +{ + const char *names[] = {"/tmp", "TMPDIR", "TMP", "TEMP" }; + const int names_size = sizeof(names)/sizeof(names[0]); + struct stat data; + for(int i = 0; i != names_size; ++i){ + if(::stat(names[i], &data) == 0){ + return names[i]; + } + } + return "/tmp"; +} + +inline file_handle_t create_new_file + (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) +{ + (void)temporary; + int ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions()); + if(ret >= 0){ + ::fchmod(ret, perm.get_permissions()); + } + return ret; +} + +inline file_handle_t create_or_open_file + (const char *name, mode_t mode, const permissions & perm = permissions(), bool temporary = false) +{ + (void)temporary; + 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){ + ret = ::open(name, ((int)mode) | O_EXCL | O_CREAT, perm.get_permissions()); + if(ret >= 0){ + ::fchmod(ret, perm.get_permissions()); + break; + } + else if(errno == EEXIST){ + if((ret = ::open(name, (int)mode)) >= 0 || errno != ENOENT){ + break; + } + } + } + return ret; +} + +inline file_handle_t open_existing_file + (const char *name, mode_t mode, bool temporary = false) +{ + (void)temporary; + return ::open(name, (int)mode); +} + +inline bool delete_file(const char *name) +{ return ::unlink(name) == 0; } + +inline bool truncate_file (file_handle_t hnd, std::size_t size) +{ + if(sizeof(off_t) == sizeof(std::size_t)){ + if(size > ((~std::size_t(0)) >> 1)){ + errno = EINVAL; + return false; + } + } + return 0 == ::ftruncate(hnd, off_t(size)); +} + +inline bool get_file_size(file_handle_t hnd, offset_t &size) +{ + struct stat data; + bool ret = 0 == ::fstat(hnd, &data); + if(ret){ + size = data.st_size; + } + return ret; +} + +inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos) +{ return ((off_t)(-1)) != ::lseek(hnd, off, (int)pos); } + +inline bool get_file_pointer(file_handle_t hnd, offset_t &off) +{ + off = ::lseek(hnd, 0, SEEK_CUR); + return off != ((off_t)-1); +} + +inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata) +{ return (ssize_t(numdata)) == ::write(hnd, data, numdata); } + +inline file_handle_t invalid_file() +{ return -1; } + +inline bool close_file(file_handle_t hnd) +{ return ::close(hnd) == 0; } + +inline bool acquire_file_lock(file_handle_t hnd) +{ + struct ::flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + return -1 != ::fcntl(hnd, F_SETLKW, &lock); +} + +inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) +{ + struct ::flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + int ret = ::fcntl(hnd, F_SETLK, &lock); + if(ret == -1){ + return (errno == EAGAIN || errno == EACCES) ? + acquired = false, true : false; + } + return (acquired = true); +} + +inline bool release_file_lock(file_handle_t hnd) +{ + struct ::flock lock; + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + return -1 != ::fcntl(hnd, F_SETLK, &lock); +} + +inline bool acquire_file_lock_sharable(file_handle_t hnd) +{ + struct ::flock lock; + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + return -1 != ::fcntl(hnd, F_SETLKW, &lock); +} + +inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) +{ + struct flock lock; + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + int ret = ::fcntl(hnd, F_SETLK, &lock); + if(ret == -1){ + return (errno == EAGAIN || errno == EACCES) ? + acquired = false, true : false; + } + return (acquired = true); +} + +inline bool release_file_lock_sharable(file_handle_t hnd) +{ return release_file_lock(hnd); } + +#if 0 +inline bool acquire_file_lock(file_handle_t hnd) +{ return 0 == ::flock(hnd, LOCK_EX); } + +inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) +{ + int ret = ::flock(hnd, LOCK_EX | LOCK_NB); + acquired = ret == 0; + return (acquired || errno == EWOULDBLOCK); +} + +inline bool release_file_lock(file_handle_t hnd) +{ return 0 == ::flock(hnd, LOCK_UN); } + +inline bool acquire_file_lock_sharable(file_handle_t hnd) +{ return 0 == ::flock(hnd, LOCK_SH); } + +inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) +{ + int ret = ::flock(hnd, LOCK_SH | LOCK_NB); + acquired = ret == 0; + return (acquired || errno == EWOULDBLOCK); +} + +inline bool release_file_lock_sharable(file_handle_t hnd) +{ return 0 == ::flock(hnd, LOCK_UN); } +#endif + +inline bool delete_subdirectories_recursive + (const std::string &refcstrRootDirectory, const char *dont_delete_this) +{ + DIR *d = opendir(refcstrRootDirectory.c_str()); + if(!d) { + return false; + } + + struct dir_close + { + DIR *d_; + dir_close(DIR *d) : d_(d) {} + ~dir_close() { ::closedir(d_); } + } dc(d); (void)dc; + + struct ::dirent *de; + struct ::stat st; + std::string fn; + + while((de=::readdir(d))) { + if( de->d_name[0] == '.' && ( de->d_name[1] == '\0' + || (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){ + continue; + } + if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){ + continue; + } + fn = refcstrRootDirectory; + fn += '/'; + fn += de->d_name; + + if(std::remove(fn.c_str())) { + if(::stat(fn.c_str(), & st)) { + return false; + } + if(S_ISDIR(st.st_mode)) { + if(!delete_subdirectories_recursive(fn, 0) ){ + return false; + } + } else { + return false; + } + } + } + return std::remove(refcstrRootDirectory.c_str()) ? false : true; +} + +template +inline bool for_each_file_in_dir(const char *dir, Function f) +{ + std::string refcstrRootDirectory(dir); + + DIR *d = opendir(refcstrRootDirectory.c_str()); + if(!d) { + return false; + } + + struct dir_close + { + DIR *d_; + dir_close(DIR *d) : d_(d) {} + ~dir_close() { ::closedir(d_); } + } dc(d); (void)dc; + + struct ::dirent *de; + struct ::stat st; + std::string fn; + + while((de=::readdir(d))) { + if( de->d_name[0] == '.' && ( de->d_name[1] == '\0' + || (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){ + continue; + } + fn = refcstrRootDirectory; + fn += '/'; + fn += de->d_name; + + if(::stat(fn.c_str(), & st)) { + return false; + } + //If it's a file, apply erase logic + if(!S_ISDIR(st.st_mode)) { + f(fn.c_str(), de->d_name); + } + } + return true; +} + + +//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) +{ + return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this ); +} + +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) + +inline bool open_or_create_directory(const char *dir_name) +{ + //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; + } + } + return true; +} + + +} //namespace ipcdetail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/os_thread_functions.hpp b/cpp/BoostParts/boost/interprocess/detail/os_thread_functions.hpp new file mode 100644 index 00000000..f881a1f4 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/os_thread_functions.hpp @@ -0,0 +1,211 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_OS_THREAD_FUNCTIONS_HPP +#define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP + +#include +#include +#include +#include + +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include +# include +# include +# else +# error Unknown platform +# endif +#endif + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + +#if (defined BOOST_INTERPROCESS_WINDOWS) + +typedef unsigned long OS_process_id_t; +typedef unsigned long OS_thread_id_t; +typedef OS_thread_id_t OS_systemwide_thread_id_t; + +//process +inline OS_process_id_t get_current_process_id() +{ return winapi::get_current_process_id(); } + +inline OS_process_id_t get_invalid_process_id() +{ return OS_process_id_t(0); } + +//thread +inline OS_thread_id_t get_current_thread_id() +{ return winapi::get_current_thread_id(); } + +inline OS_thread_id_t get_invalid_thread_id() +{ return OS_thread_id_t(0xffffffff); } + +inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) +{ return id1 == id2; } + +inline void thread_yield() +{ winapi::sched_yield(); } + +inline void thread_sleep(unsigned int ms) +{ winapi::Sleep(ms); } + +//systemwide thread +inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() +{ + return get_current_thread_id(); +} + +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to = from; +} + +inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) +{ + return equal_thread_id(id1, id2); +} + +inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() +{ + return get_invalid_thread_id(); +} + +inline long double get_current_process_creation_time() +{ + winapi::interprocess_filetime CreationTime, ExitTime, KernelTime, UserTime; + + get_process_times + ( winapi::get_current_process(), &CreationTime, &ExitTime, &KernelTime, &UserTime); + + typedef long double ldouble_t; + const ldouble_t resolution = (100.0l/1000000000.0l); + return CreationTime.dwHighDateTime*(ldouble_t(1u<<31u)*2.0l*resolution) + + CreationTime.dwLowDateTime*resolution; +} + + +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) + +typedef pthread_t OS_thread_id_t; +typedef pid_t OS_process_id_t; + +struct OS_systemwide_thread_id_t +{ + OS_systemwide_thread_id_t() + : pid(), tid() + {} + + OS_systemwide_thread_id_t(pid_t p, pthread_t t) + : pid(p), tid(t) + {} + + OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + void operator=(const OS_systemwide_thread_id_t &x) volatile + { pid = x.pid; tid = x.tid; } + + pid_t pid; + pthread_t tid; +}; + +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to.pid = from.pid; + to.tid = from.tid; +} + +//process +inline OS_process_id_t get_current_process_id() +{ return ::getpid(); } + +inline OS_process_id_t get_invalid_process_id() +{ return pid_t(0); } + +//thread +inline OS_thread_id_t get_current_thread_id() +{ return ::pthread_self(); } + +inline OS_thread_id_t get_invalid_thread_id() +{ + static pthread_t invalid_id; + return invalid_id; +} + +inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) +{ return 0 != pthread_equal(id1, id2); } + +inline void thread_yield() +{ ::sched_yield(); } + +inline void thread_sleep(unsigned int ms) +{ + const struct timespec rqt = { ms/1000u, (ms%1000u)*1000000u }; + ::nanosleep(&rqt, 0); +} + +//systemwide thread +inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() +{ + return OS_systemwide_thread_id_t(::getpid(), ::pthread_self()); +} + +inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) +{ + return (0 != pthread_equal(id1.tid, id2.tid)) && (id1.pid == id2.pid); +} + +inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() +{ + return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id()); +} + +inline long double get_current_process_creation_time() +{ return 0.0L; } + +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) + +typedef char pid_str_t[sizeof(OS_process_id_t)*3+1]; + +inline void get_pid_str(pid_str_t &pid_str, OS_process_id_t pid) +{ + bufferstream bstream(pid_str, sizeof(pid_str)); + bstream << pid << std::ends; +} + +inline void get_pid_str(pid_str_t &pid_str) +{ get_pid_str(pid_str, get_current_process_id()); } + +} //namespace ipcdetail{ +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/posix_time_types_wrk.hpp b/cpp/BoostParts/boost/interprocess/detail/posix_time_types_wrk.hpp new file mode 100644 index 00000000..fa167f57 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/posix_time_types_wrk.hpp @@ -0,0 +1,42 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 + +//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 +#include + +namespace boost { +namespace interprocess { + +typedef boost::date_time::microsec_clock 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/cpp/BoostParts/boost/interprocess/detail/preprocessor.hpp b/cpp/BoostParts/boost/interprocess/detail/preprocessor.hpp new file mode 100644 index 00000000..0eb419d6 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/preprocessor.hpp @@ -0,0 +1,203 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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_PREPROCESSOR_HPP +#define BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif + +#include +#include +#include +#include +#include + +#define BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS 10 + +//Note: +//We define template parameters as const references to +//be able to bind temporaries. After that we will un-const them. +//This cast is ugly but it is necessary until "perfect forwarding" +//is achieved in C++0x. Meanwhile, if we want to be able to +//bind rvalues with non-const references, we have to be ugly +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + #define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ + //! +#else + #define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \ + const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \ + //! +#endif + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + #define BOOST_INTERPROCESS_PP_PARAM(U, u) \ + U && u \ + //! +#else + #define BOOST_INTERPROCESS_PP_PARAM(U, u) \ + const U & u \ + //! +#endif + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + #define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) )) \ + //! + +#else //#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + #define BOOST_INTERPROCESS_PP_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (const_cast(BOOST_PP_CAT(p, n))) \ + //! +#endif + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + #if defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + + namespace boost { + namespace interprocess { + namespace ipcdetail { + template + struct ref_holder; + + template + struct ref_holder + { + ref_holder(T &t) + : t_(t) + {} + T &t_; + T & get() { return t_; } + T & get_lvalue() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(const T &t) + : t_(t) + {} + const T &t_; + const T & get() { return t_; } + const T & get_lvalue() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(const T &t) + : t_(t) + {} + const T &t_; + const T & get() { return t_; } + const T & get_lvalue() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(T &&t) + : t_(t) + {} + T &t_; + T && get() { return ::boost::move(t_); } + T & get_lvalue() { return t_; } + }; + + template + struct ref_holder + { + ref_holder(T &&t) + : t(t) + {} + T &t; + T && get() { return ::boost::move(t_); } + T & get_lvalue() { return t_; } + }; + + } //namespace ipcdetail { + } //namespace interprocess { + } //namespace boost { + + #define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \ + ::boost::interprocess::ipcdetail::ref_holder BOOST_PP_CAT(m_p, n); \ + //! + + #define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \ + BOOST_PP_CAT(++m_p, n).get_lvalue() \ + //! + + #else //BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG + + #define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data)\ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \ + //! + + #define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \ + BOOST_PP_CAT(++m_p, n) \ + //! + + #endif //defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + +#else + #define BOOST_INTERPROCESS_PP_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ + //! + + #define BOOST_INTERPROCESS_PP_PARAM_INC(z, n, data) \ + BOOST_PP_CAT(++m_p, n) \ + //! + +#endif + +#define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ +::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ +//! + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + + #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) BOOST_PP_CAT(this->m_p, n).get() \ + //! + + #define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \ + BOOST_PP_CAT(*m_p, n).get_lvalue() \ + //! + +#else + + #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ + ::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ + //! + + #define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \ + BOOST_PP_CAT(*m_p, n) \ + //! + + +#endif //!defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && defined(BOOST_MOVE_MSVC_10_MEMBER_RVALUE_REF_BUG) + +#include + +#else +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/segment_manager_helper.hpp b/cpp/BoostParts/boost/interprocess/detail/segment_manager_helper.hpp new file mode 100644 index 00000000..83e5a05e --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/segment_manager_helper.hpp @@ -0,0 +1,511 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_SEGMENT_MANAGER_BASE_HPP +#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include //std::size_t +#include //char_traits +#include //std::nothrow +#include //std::pair +#include //BOOST_ASSERT +#include //unary_function +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif + +//!\file +//!Describes the object placed in a memory segment that provides +//!named object allocation capabilities. + +namespace boost{ +namespace interprocess{ + +template +class segment_manager_base; + +//!An integer that describes the type of the +//!instance constructed in memory +enum instance_type { anonymous_type, named_type, unique_type, max_allocation_type }; + +namespace ipcdetail{ + +template +class mem_algo_deallocator +{ + void * m_ptr; + MemoryAlgorithm & m_algo; + + public: + mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo) + : m_ptr(ptr), m_algo(algo) + {} + + void release() + { m_ptr = 0; } + + ~mem_algo_deallocator() + { if(m_ptr) m_algo.deallocate(m_ptr); } +}; + +/// @cond +template +struct block_header +{ + size_type m_value_bytes; + unsigned short m_num_char; + unsigned char m_value_alignment; + unsigned char m_alloc_type_sizeof_char; + + block_header(size_type val_bytes + ,size_type val_alignment + ,unsigned char al_type + ,std::size_t szof_char + ,std::size_t num_char + ) + : 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) ) + {}; + + template + block_header &operator= (const T& ) + { return *this; } + + size_type total_size() const + { + if(alloc_type() != anonymous_type){ + return name_offset() + (m_num_char+1)*sizeof_char(); + } + else{ + return this->value_offset() + m_value_bytes; + } + } + + size_type value_bytes() const + { return m_value_bytes; } + + template + size_type total_size_with_header() const + { + return get_rounded_size + ( size_type(sizeof(Header)) + , size_type(::boost::alignment_of >::value)) + + total_size(); + } + + unsigned char alloc_type() const + { return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; } + + unsigned char sizeof_char() const + { return m_alloc_type_sizeof_char & (unsigned char)0x1F; } + + template + CharType *name() const + { + return const_cast(reinterpret_cast + (reinterpret_cast(this) + name_offset())); + } + + unsigned short name_length() const + { return m_num_char; } + + size_type name_offset() const + { + return this->value_offset() + get_rounded_size(size_type(m_value_bytes), size_type(sizeof_char())); + } + + void *value() const + { + return const_cast((reinterpret_cast(this) + this->value_offset())); + } + + size_type value_offset() const + { + return get_rounded_size(size_type(sizeof(block_header)), size_type(m_value_alignment)); + } + + template + bool less_comp(const block_header &b) const + { + return m_num_char < b.m_num_char || + (m_num_char < b.m_num_char && + std::char_traits::compare + (name(), b.name(), m_num_char) < 0); + } + + template + bool equal_comp(const block_header &b) const + { + return m_num_char == b.m_num_char && + std::char_traits::compare + (name(), b.name(), m_num_char) == 0; + } + + template + static block_header *block_header_from_value(T *value) + { return block_header_from_value(value, sizeof(T), ::boost::alignment_of::value); } + + static block_header *block_header_from_value(const void *value, std::size_t sz, std::size_t algn) + { + block_header * hdr = + const_cast + (reinterpret_cast(reinterpret_cast(value) - + get_rounded_size(sizeof(block_header), algn))); + (void)sz; + //Some sanity checks + BOOST_ASSERT(hdr->m_value_alignment == algn); + BOOST_ASSERT(hdr->m_value_bytes % sz == 0); + return hdr; + } + + template + static block_header *from_first_header(Header *header) + { + block_header * hdr = + reinterpret_cast*>(reinterpret_cast(header) + + get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of >::value))); + //Some sanity checks + return hdr; + } + + template + static Header *to_first_header(block_header *bheader) + { + Header * hdr = + reinterpret_cast(reinterpret_cast(bheader) - + get_rounded_size(size_type(sizeof(Header)), size_type(::boost::alignment_of >::value))); + //Some sanity checks + return hdr; + } +}; + +inline void array_construct(void *mem, std::size_t num, in_place_interface &table) +{ + //Try constructors + std::size_t constructed = 0; + BOOST_TRY{ + table.construct_n(mem, num, constructed); + } + //If there is an exception call destructors and erase index node + BOOST_CATCH(...){ + std::size_t destroyed = 0; + table.destroy_n(mem, constructed, destroyed); + BOOST_RETHROW + } + BOOST_CATCH_END +} + +template +struct intrusive_compare_key +{ + typedef CharT char_type; + + intrusive_compare_key(const CharT *str, std::size_t len) + : mp_str(str), m_len(len) + {} + + const CharT * mp_str; + std::size_t m_len; +}; + +//!This struct indicates an anonymous object creation +//!allocation +template +class instance_t +{ + instance_t(){} +}; + +template +struct char_if_void +{ + typedef T type; +}; + +template<> +struct char_if_void +{ + typedef char type; +}; + +typedef instance_t anonymous_instance_t; +typedef instance_t unique_instance_t; + + +template +struct intrusive_value_type_impl + : public Hook +{ + private: + //Non-copyable + intrusive_value_type_impl(const intrusive_value_type_impl &); + intrusive_value_type_impl& operator=(const intrusive_value_type_impl &); + + public: + typedef CharType char_type; + typedef SizeType size_type; + + intrusive_value_type_impl(){} + + enum { BlockHdrAlignment = ::boost::alignment_of >::value }; + + block_header *get_block_header() const + { + return const_cast*> + (reinterpret_cast *>(reinterpret_cast(this) + + get_rounded_size(size_type(sizeof(*this)), size_type(BlockHdrAlignment)))); + } + + bool operator <(const intrusive_value_type_impl & other) const + { return (this->get_block_header())->template less_comp(*other.get_block_header()); } + + bool operator ==(const intrusive_value_type_impl & other) const + { return (this->get_block_header())->template equal_comp(*other.get_block_header()); } + + static intrusive_value_type_impl *get_intrusive_value_type(block_header *hdr) + { + return reinterpret_cast(reinterpret_cast(hdr) - + get_rounded_size(size_type(sizeof(intrusive_value_type_impl)), size_type(BlockHdrAlignment))); + } + + CharType *name() const + { return get_block_header()->template name(); } + + unsigned short name_length() const + { return get_block_header()->name_length(); } + + void *value() const + { return get_block_header()->value(); } +}; + +template +class char_ptr_holder +{ + public: + char_ptr_holder(const CharType *name) + : m_name(name) + {} + + char_ptr_holder(const anonymous_instance_t *) + : m_name(static_cast(0)) + {} + + char_ptr_holder(const unique_instance_t *) + : m_name(reinterpret_cast(-1)) + {} + + operator const CharType *() + { return m_name; } + + private: + const CharType *m_name; +}; + +//!The key of the the named allocation information index. Stores an offset pointer +//!to a null terminated string and the length of the string to speed up sorting +template +struct index_key +{ + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type const_char_ptr_t; + typedef CharT char_type; + typedef typename boost::intrusive::pointer_traits::difference_type difference_type; + typedef typename boost::make_unsigned::type size_type; + + private: + //Offset pointer to the object's name + const_char_ptr_t mp_str; + //Length of the name buffer (null NOT included) + size_type m_len; + public: + + //!Constructor of the key + index_key (const char_type *nm, size_type length) + : mp_str(nm), m_len(length) + {} + + //!Less than function for index ordering + bool operator < (const index_key & right) const + { + return (m_len < right.m_len) || + (m_len == right.m_len && + std::char_traits::compare + (to_raw_pointer(mp_str) + ,to_raw_pointer(right.mp_str), m_len) < 0); + } + + //!Equal to function for index ordering + bool operator == (const index_key & right) const + { + return m_len == right.m_len && + std::char_traits::compare + (to_raw_pointer(mp_str), + to_raw_pointer(right.mp_str), m_len) == 0; + } + + void name(const CharT *nm) + { mp_str = nm; } + + void name_length(size_type len) + { m_len = len; } + + const CharT *name() const + { return to_raw_pointer(mp_str); } + + size_type name_length() const + { return m_len; } +}; + +//!The index_data stores a pointer to a buffer and the element count needed +//!to know how many destructors must be called when calling destroy +template +struct index_data +{ + typedef VoidPointer void_pointer; + void_pointer m_ptr; + index_data(void *ptr) : m_ptr(ptr){} + + void *value() const + { return static_cast(to_raw_pointer(m_ptr)); } +}; + +template +struct segment_manager_base_type +{ typedef segment_manager_base type; }; + +template +struct index_config +{ + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef CharT char_type; + typedef index_key key_type; + typedef index_data mapped_type; + typedef typename segment_manager_base_type + ::type segment_manager_base; + + template + struct intrusive_value_type + { typedef intrusive_value_type_impl type; }; + + typedef intrusive_compare_key intrusive_compare_key_type; +}; + +template +class segment_manager_iterator_value_adaptor +{ + typedef typename Iterator::value_type iterator_val_t; + typedef typename iterator_val_t::char_type char_type; + + public: + segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val) + : m_val(&val) + {} + + const char_type *name() const + { return m_val->name(); } + + unsigned short name_length() const + { return m_val->name_length(); } + + const void *value() const + { return m_val->value(); } + + const typename Iterator::value_type *m_val; +}; + + +template +class segment_manager_iterator_value_adaptor +{ + typedef typename Iterator::value_type iterator_val_t; + typedef typename iterator_val_t::first_type first_type; + typedef typename iterator_val_t::second_type second_type; + typedef typename first_type::char_type char_type; + typedef typename first_type::size_type size_type; + + public: + segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val) + : m_val(&val) + {} + + const char_type *name() const + { return m_val->first.name(); } + + size_type name_length() const + { return m_val->first.name_length(); } + + const void *value() const + { + return reinterpret_cast*> + (to_raw_pointer(m_val->second.m_ptr))->value(); + } + + const typename Iterator::value_type *m_val; +}; + +template +struct segment_manager_iterator_transform + : std::unary_function< typename Iterator::value_type + , segment_manager_iterator_value_adaptor > +{ + typedef segment_manager_iterator_value_adaptor result_type; + + result_type operator()(const typename Iterator::value_type &arg) const + { return result_type(arg); } +}; + +} //namespace ipcdetail { + +//These pointers are the ones the user will use to +//indicate previous allocation types +static const ipcdetail::anonymous_instance_t * anonymous_instance = 0; +static const ipcdetail::unique_instance_t * unique_instance = 0; + +namespace ipcdetail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)anonymous_instance; + (void)unique_instance; + } +}; + +} //detail_really_deep_namespace + +}} //namespace boost { namespace interprocess + +#include + +#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/tmp_dir_helpers.hpp b/cpp/BoostParts/boost/interprocess/detail/tmp_dir_helpers.hpp new file mode 100644 index 00000000..e4e867e3 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/tmp_dir_helpers.hpp @@ -0,0 +1,181 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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_TMP_DIR_HELPERS_HPP +#define BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP + +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) && defined(BOOST_INTERPROCESS_WINDOWS) + #include +#endif + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + #if defined(BOOST_INTERPROCESS_WINDOWS) + //This type will initialize the stamp + struct windows_bootstamp + { + windows_bootstamp() + { + winapi::get_last_bootup_time(stamp); + } + //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; + }; + + inline void get_bootstamp(std::string &s, bool add = false) + { + const windows_bootstamp &bootstamp = windows_intermodule_singleton::get(); + if(add){ + s += bootstamp.stamp; + } + else{ + s = bootstamp.stamp; + } + } + #elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME) + inline void get_bootstamp(std::string &s, bool add = false) + { + // FreeBSD specific: sysctl "kern.boottime" + int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct ::timeval result; + std::size_t result_len = sizeof result; + + if (::sysctl (request, 2, &result, &result_len, NULL, 0) < 0) + return; + + char bootstamp_str[256]; + + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + std::size_t char_counter = 0; + //32 bit values to allow 32 and 64 bit process IPC + boost::uint32_t fields[2] = { boost::uint32_t(result.tv_sec), boost::uint32_t(result.tv_usec) }; + for(std::size_t field = 0; field != 2; ++field){ + for(std::size_t i = 0; i != sizeof(fields[0]); ++i){ + const char *ptr = (const char *)&fields[field]; + bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4]; + bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)]; + } + } + bootstamp_str[char_counter] = 0; + if(add){ + s += bootstamp_str; + } + else{ + s = bootstamp_str; + } + } + #else + #error "BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME defined with no known implementation" + #endif +#endif //#if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + +inline void get_tmp_base_dir(std::string &tmp_name) +{ + #if defined (BOOST_INTERPROCESS_WINDOWS) + winapi::get_shared_documents_folder(tmp_name); + if(tmp_name.empty() || !winapi::is_directory(tmp_name.c_str())){ + tmp_name = get_temporary_path(); + } + #else + tmp_name = get_temporary_path(); + #endif + if(tmp_name.empty()){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + //Remove final null. + tmp_name += "/boost_interprocess"; +} + +inline void tmp_folder(std::string &tmp_name) +{ + get_tmp_base_dir(tmp_name); + #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + tmp_name += "/"; + get_bootstamp(tmp_name, true); + #endif +} + +inline void tmp_filename(const char *filename, std::string &tmp_name) +{ + tmp_folder(tmp_name); + tmp_name += "/"; + tmp_name += filename; +} + +inline void create_tmp_and_clean_old(std::string &tmp_name) +{ + //First get the temp directory + std::string root_tmp_name; + get_tmp_base_dir(root_tmp_name); + + //If fails, check that it's because already exists + if(!create_directory(root_tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + + #if defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) + tmp_folder(tmp_name); + + //If fails, check that it's because already exists + if(!create_directory(tmp_name.c_str())){ + error_info info(system_error_code()); + if(info.get_error_code() != already_exists_error){ + throw interprocess_exception(info); + } + } + //Now erase all old directories created in the previous boot sessions + std::string subdir = tmp_name; + subdir.erase(0, root_tmp_name.size()+1); + delete_subdirectories(root_tmp_name, subdir.c_str()); + #else + tmp_name = root_tmp_name; + #endif +} + +inline void create_tmp_and_clean_old_and_get_filename(const char *filename, std::string &tmp_name) +{ + create_tmp_and_clean_old(tmp_name); + tmp_name += "/"; + tmp_name += filename; +} + +inline void add_leading_slash(const char *name, std::string &new_name) +{ + if(name[0] != '/'){ + new_name = '/'; + } + new_name += name; +} + +} //namespace boost{ +} //namespace interprocess { +} //namespace ipcdetail { + +#include + +#endif //ifndef BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/transform_iterator.hpp b/cpp/BoostParts/boost/interprocess/detail/transform_iterator.hpp new file mode 100644 index 00000000..56bd0e56 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/transform_iterator.hpp @@ -0,0 +1,195 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include + +namespace boost { +namespace interprocess { + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(const PseudoReference &px) + : m_value(px) + {} + + PseudoReference* operator->() const { return &m_value; } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + mutable PseudoReference m_value; +}; + +template +struct operator_arrow_proxy +{ + operator_arrow_proxy(T &px) + : m_value(px) + {} + + T* operator->() const { return const_cast(&m_value); } + // This function is needed for MWCW and BCC, which won't call operator-> + // again automatically per 13.3.1.2 para 8 +// operator T*() const { return &m_value; } + T &m_value; +}; + +template +class transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename ipcdetail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , typename UnaryFunction::result_type> +{ + public: + explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) + : UnaryFunction(f), m_it(it) + {} + + explicit transform_iterator() + : UnaryFunction(), m_it() + {} + + //Constructors + transform_iterator& operator++() + { increment(); return *this; } + + transform_iterator operator++(int) + { + transform_iterator result (*this); + increment(); + return result; + } + + transform_iterator& operator--() + { decrement(); return *this; } + + transform_iterator operator--(int) + { + transform_iterator result (*this); + decrement(); + return result; + } + + friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + { return i.equal(i2); } + + friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + { return !(i == i2); } + + friend bool operator< (const transform_iterator& i, const transform_iterator& i2) + { return i < i2; } + + friend bool operator> (const transform_iterator& i, const transform_iterator& i2) + { return i2 < i; } + + friend bool operator<= (const transform_iterator& i, const transform_iterator& i2) + { return !(i > i2); } + + friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + { return !(i < i2); } + + friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + { return i2.distance_to(i); } + + //Arithmetic + transform_iterator& operator+=(typename Iterator::difference_type off) + { this->advance(off); return *this; } + + transform_iterator operator+(typename Iterator::difference_type off) const + { + transform_iterator other(*this); + other.advance(off); + return other; + } + + friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + { return right + off; } + + transform_iterator& operator-=(typename Iterator::difference_type off) + { this->advance(-off); return *this; } + + transform_iterator operator-(typename Iterator::difference_type off) const + { return *this + (-off); } + + typename UnaryFunction::result_type operator*() const + { return dereference(); } + + typename UnaryFunction::result_type operator[](typename Iterator::difference_type off) const + { return UnaryFunction::operator()(m_it[off]); } + + operator_arrow_proxy + operator->() const + { return operator_arrow_proxy(dereference()); } + + Iterator & base() + { return m_it; } + + const Iterator & base() const + { return m_it; } + + private: + Iterator m_it; + + void increment() + { ++m_it; } + + void decrement() + { --m_it; } + + bool equal(const transform_iterator &other) const + { return m_it == other.m_it; } + + bool less(const transform_iterator &other) const + { return other.m_it < m_it; } + + typename UnaryFunction::result_type dereference() const + { return UnaryFunction::operator()(*m_it); } + + void advance(typename Iterator::difference_type n) + { std::advance(m_it, n); } + + typename Iterator::difference_type distance_to(const transform_iterator &other)const + { return std::distance(other.m_it, m_it); } +}; + +template +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/type_traits.hpp b/cpp/BoostParts/boost/interprocess/detail/type_traits.hpp new file mode 100644 index 00000000..ade623f1 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/type_traits.hpp @@ -0,0 +1,158 @@ +////////////////////////////////////////////////////////////////////////////// +// (C) Copyright John Maddock 2000. +// (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_TYPE_TRAITS_HPP +#define BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +struct nat{}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct is_reference +{ + static const bool value = false; +}; + +template +struct is_reference +{ + static const bool value = true; +}; + +template +struct is_pointer +{ + static const bool value = false; +}; + +template +struct is_pointer +{ + static const bool value = true; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template<> +struct add_reference +{ + typedef nat &type; +}; + +template<> +struct add_reference +{ + typedef const nat &type; +}; + +template +struct add_const_reference +{ typedef const T &type; }; + +template +struct add_const_reference +{ typedef T& type; }; + +template +struct remove_const +{ + typedef T type; +}; + +template +struct remove_const +{ + typedef T type; +}; + +template +struct remove_volatile +{ + typedef T type; +}; + +template +struct remove_volatile +{ + typedef T type; +}; + +template +struct remove_const_volatile +{ + typedef typename remove_const::type>::type type; +}; + +template +struct is_same +{ + typedef char yes_type; + struct no_type + { + char padding[8]; + }; + + template + static yes_type is_same_tester(V*, V*); + static no_type is_same_tester(...); + + static T *t; + static U *u; + + static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u)); +}; + +template +struct is_cv_same +{ + static const bool value = is_same< typename remove_const_volatile::type + , typename remove_const_volatile::type >::value; +}; + +} // namespace ipcdetail +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/utilities.hpp b/cpp/BoostParts/boost/interprocess/detail/utilities.hpp new file mode 100644 index 00000000..3b486ddc --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/utilities.hpp @@ -0,0 +1,218 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2012. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP +#define BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +inline T* to_raw_pointer(T* p) +{ return p; } + +template +inline typename boost::intrusive::pointer_traits::element_type* +to_raw_pointer(const Pointer &p) +{ return boost::interprocess::ipcdetail::to_raw_pointer(p.operator->()); } + +//!To avoid ADL problems with swap +template +inline void do_swap(T& x, T& y) +{ + using std::swap; + swap(x, y); +} + +//Rounds "orig_size" by excess to round_to bytes +template +inline SizeType get_rounded_size(SizeType orig_size, SizeType round_to) +{ + return ((orig_size-1)/round_to+1)*round_to; +} + +//Truncates "orig_size" to a multiple of "multiple" bytes. +template +inline SizeType get_truncated_size(SizeType orig_size, SizeType multiple) +{ + return orig_size/multiple*multiple; +} + +//Rounds "orig_size" by excess to round_to bytes. round_to must be power of two +template +inline SizeType get_rounded_size_po2(SizeType orig_size, SizeType round_to) +{ + return ((orig_size-1)&(~(round_to-1))) + round_to; +} + +//Truncates "orig_size" to a multiple of "multiple" bytes. multiple must be power of two +template +inline SizeType get_truncated_size_po2(SizeType orig_size, SizeType multiple) +{ + return (orig_size & (~(multiple-1))); +} + +template +struct ct_rounded_size +{ + BOOST_STATIC_ASSERT((RoundTo != 0)); + static const std::size_t intermediate_value = (OrigSize-1)/RoundTo+1; + BOOST_STATIC_ASSERT(intermediate_value <= std::size_t(-1)/RoundTo); + static const std::size_t value = intermediate_value*RoundTo; +}; + +// Gennaro Prota wrote this. Thanks! +template +struct ct_max_pow2_less +{ + static const std::size_t c = 2*n < p; + + static const std::size_t value = + c ? (ct_max_pow2_less< c*p, 2*c*n>::value) : n; +}; + +template <> +struct ct_max_pow2_less<0, 0> +{ + static const std::size_t value = 0; +}; + +} //namespace ipcdetail { + +//!Trait class to detect if an index is a node +//!index. This allows more efficient operations +//!when deallocating named objects. +template +struct is_node_index +{ + static const bool value = false; +}; + +//!Trait class to detect if an index is an intrusive +//!index. This will embed the derivation hook in each +//!allocation header, to provide memory for the intrusive +//!container. +template +struct is_intrusive_index +{ + static const bool value = false; +}; + +template T* +addressof(T& v) +{ + return reinterpret_cast( + &const_cast(reinterpret_cast(v))); +} + +template +struct sqrt_size_type_max +{ + static const SizeType value = (SizeType(1) << (sizeof(SizeType)*(CHAR_BIT/2)))-1; +}; + +template +inline bool multiplication_overflows(SizeType a, SizeType b) +{ + const SizeType sqrt_size_max = sqrt_size_type_max::value; + return //Fast runtime check + ( (a | b) > sqrt_size_max && + //Slow division check + b && a > SizeType(-1)/b + ); +} + +template +inline bool size_overflows(SizeType count) +{ + //Compile time-check + BOOST_STATIC_ASSERT(SztSizeOfType <= SizeType(-1)); + //Runtime check + return multiplication_overflows(SizeType(SztSizeOfType), count); +} + +template +class pointer_size_t_caster +{ + public: + explicit pointer_size_t_caster(std::size_t sz) + : m_ptr(reinterpret_cast(sz)) + {} + + explicit pointer_size_t_caster(RawPointer p) + : m_ptr(p) + {} + + std::size_t size() const + { return reinterpret_cast(m_ptr); } + + RawPointer pointer() const + { return m_ptr; } + + private: + RawPointer m_ptr; +}; + + +template +inline bool sum_overflows(SizeType a, SizeType b) +{ return SizeType(-1) - a < b; } + +//Anti-exception node eraser +template +class value_eraser +{ + public: + value_eraser(Cont & cont, typename Cont::iterator it) + : m_cont(cont), m_index_it(it), m_erase(true){} + ~value_eraser() + { if(m_erase) m_cont.erase(m_index_it); } + + void release() { m_erase = false; } + + private: + Cont &m_cont; + typename Cont::iterator m_index_it; + bool m_erase; +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP + diff --git a/cpp/BoostParts/boost/interprocess/detail/variadic_templates_tools.hpp b/cpp/BoostParts/boost/interprocess/detail/variadic_templates_tools.hpp new file mode 100644 index 00000000..5f2a94a3 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/variadic_templates_tools.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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_VARIADIC_TEMPLATES_TOOLS_HPP +#define BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include //std::size_t + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +class tuple; + +template<> class tuple<> +{}; + +template +class tuple + : private tuple +{ + typedef tuple inherited; + + public: + tuple() { } + + // implicit copy-constructor is okay + // Construct tuple from separate arguments. + tuple(typename add_const_reference::type v, + typename add_const_reference::type... vtail) + : inherited(vtail...), m_head(v) + {} + + // Construct tuple from another tuple. + template + tuple(const tuple& other) + : m_head(other.head()), inherited(other.tail()) + {} + + template + tuple& operator=(const tuple& other) + { + m_head = other.head(); + tail() = other.tail(); + return this; + } + + typename add_reference::type head() { return m_head; } + typename add_reference::type head() const { return m_head; } + + inherited& tail() { return *this; } + const inherited& tail() const { return *this; } + + protected: + Head m_head; +}; + + +template +tuple tie_forward(Values&&... values) +{ return tuple(values...); } + +template +struct tuple_element; + +template +struct tuple_element > +{ + typedef typename tuple_element >::type type; +}; + +template +struct tuple_element<0, tuple > +{ + typedef Head type; +}; + +template +class get_impl; + +template +class get_impl > +{ + typedef typename tuple_element >::type Element; + typedef get_impl > Next; + + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return Next::get(t.tail()); } + static const_type get(const tuple& t) { return Next::get(t.tail()); } +}; + +template +class get_impl<0, tuple > +{ + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return t.head(); } + static const_type get(const tuple& t){ return t.head(); } +}; + +template +typename get_impl >::type get(tuple& t) +{ return get_impl >::get(t); } + +template +typename get_impl >::const_type get(const tuple& t) +{ return get_impl >::get(t); } + +//////////////////////////////////////////////////// +// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will +// be used to "unpack" into comma-separated values +// in a function call. +//////////////////////////////////////////////////// + +template +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + + +}}} //namespace boost { namespace interprocess { namespace ipcdetail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/win32_api.hpp b/cpp/BoostParts/boost/interprocess/detail/win32_api.hpp new file mode 100644 index 00000000..078eef10 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/win32_api.hpp @@ -0,0 +1,1852 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_WIN32_PRIMITIVES_HPP +#define BOOST_INTERPROCESS_WIN32_PRIMITIVES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +# pragma comment( lib, "advapi32.lib" ) +# pragma comment( lib, "oleaut32.lib" ) +# pragma comment( lib, "Ole32.lib" ) +# pragma comment( lib, "Psapi.lib" ) +#endif + +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +# include +#else +# error "This file can only be included in Windows OS" +#endif + + +//The structures used in Interprocess with the +//same binary interface as windows ones +namespace boost { +namespace interprocess { +namespace winapi { + +//Some used constants +static const unsigned long infinite_time = 0xFFFFFFFF; +static const unsigned long error_already_exists = 183L; +static const unsigned long error_invalid_handle = 6L; +static const unsigned long error_sharing_violation = 32L; +static const unsigned long error_file_not_found = 2u; +static const unsigned long error_no_more_files = 18u; +static const unsigned long error_not_locked = 158L; +//Retries in CreateFile, see http://support.microsoft.com/kb/316609 +static const unsigned int error_sharing_violation_tries = 3u; +static const unsigned int error_sharing_violation_sleep_ms = 250u; +static const unsigned int error_file_too_large = 223u; + +static const unsigned long semaphore_all_access = (0x000F0000L)|(0x00100000L)|0x3; +static const unsigned long mutex_all_access = (0x000F0000L)|(0x00100000L)|0x0001; + +static const unsigned long page_readonly = 0x02; +static const unsigned long page_readwrite = 0x04; +static const unsigned long page_writecopy = 0x08; +static const unsigned long page_noaccess = 0x01; + +static const unsigned long standard_rights_required = 0x000F0000L; +static const unsigned long section_query = 0x0001; +static const unsigned long section_map_write = 0x0002; +static const unsigned long section_map_read = 0x0004; +static const unsigned long section_map_execute = 0x0008; +static const unsigned long section_extend_size = 0x0010; +static const unsigned long section_all_access = standard_rights_required | + section_query | + section_map_write | + section_map_read | + section_map_execute | + section_extend_size; + +static const unsigned long file_map_copy = section_query; +static const unsigned long file_map_write = section_map_write; +static const unsigned long file_map_read = section_map_read; +static const unsigned long file_map_all_access = section_all_access; +static const unsigned long delete_access = 0x00010000L; +static const unsigned long file_flag_backup_semantics = 0x02000000; +static const long file_flag_delete_on_close = 0x04000000; + +//Native API constants +static const unsigned long file_open_for_backup_intent = 0x00004000; +static const int file_share_valid_flags = 0x00000007; +static const long file_delete_on_close = 0x00001000L; +static const long obj_case_insensitive = 0x00000040L; + +static const unsigned long movefile_copy_allowed = 0x02; +static const unsigned long movefile_delay_until_reboot = 0x04; +static const unsigned long movefile_replace_existing = 0x01; +static const unsigned long movefile_write_through = 0x08; +static const unsigned long movefile_create_hardlink = 0x10; +static const unsigned long movefile_fail_if_not_trackable = 0x20; + +static const unsigned long file_share_read = 0x00000001; +static const unsigned long file_share_write = 0x00000002; +static const unsigned long file_share_delete = 0x00000004; + +static const unsigned long file_attribute_readonly = 0x00000001; +static const unsigned long file_attribute_hidden = 0x00000002; +static const unsigned long file_attribute_system = 0x00000004; +static const unsigned long file_attribute_directory = 0x00000010; +static const unsigned long file_attribute_archive = 0x00000020; +static const unsigned long file_attribute_device = 0x00000040; +static const unsigned long file_attribute_normal = 0x00000080; +static const unsigned long file_attribute_temporary = 0x00000100; + +static const unsigned long generic_read = 0x80000000L; +static const unsigned long generic_write = 0x40000000L; + +static const unsigned long wait_object_0 = 0; +static const unsigned long wait_abandoned = 0x00000080L; +static const unsigned long wait_timeout = 258L; +static const unsigned long wait_failed = (unsigned long)0xFFFFFFFF; + +static const unsigned long duplicate_close_source = (unsigned long)0x00000001; +static const unsigned long duplicate_same_access = (unsigned long)0x00000002; + +static const unsigned long format_message_allocate_buffer + = (unsigned long)0x00000100; +static const unsigned long format_message_ignore_inserts + = (unsigned long)0x00000200; +static const unsigned long format_message_from_string + = (unsigned long)0x00000400; +static const unsigned long format_message_from_hmodule + = (unsigned long)0x00000800; +static const unsigned long format_message_from_system + = (unsigned long)0x00001000; +static const unsigned long format_message_argument_array + = (unsigned long)0x00002000; +static const unsigned long format_message_max_width_mask + = (unsigned long)0x000000FF; +static const unsigned long lang_neutral = (unsigned long)0x00; +static const unsigned long sublang_default = (unsigned long)0x01; +static const unsigned long invalid_file_size = (unsigned long)0xFFFFFFFF; +static const unsigned long invalid_file_attributes = ((unsigned long)-1); +static void * const invalid_handle_value = ((void*)(long)(-1)); + +static const unsigned long file_type_char = 0x0002L; +static const unsigned long file_type_disk = 0x0001L; +static const unsigned long file_type_pipe = 0x0003L; +static const unsigned long file_type_remote = 0x8000L; +static const unsigned long file_type_unknown = 0x0000L; + +static const unsigned long create_new = 1; +static const unsigned long create_always = 2; +static const unsigned long open_existing = 3; +static const unsigned long open_always = 4; +static const unsigned long truncate_existing = 5; + +static const unsigned long file_begin = 0; +static const unsigned long file_current = 1; +static const unsigned long file_end = 2; + +static const unsigned long lockfile_fail_immediately = 1; +static const unsigned long lockfile_exclusive_lock = 2; +static const unsigned long error_lock_violation = 33; +static const unsigned long security_descriptor_revision = 1; + +//Own defines +static const long SystemTimeOfDayInfoLength = 48; +static const long BootAndSystemstampLength = 16; +static const long BootstampLength = 8; +static const unsigned long MaxPath = 260; + +//Keys +static void * const hkey_local_machine = (void*)(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; + +//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 + +} //namespace winapi { +} //namespace interprocess { +} //namespace boost { + + +namespace boost { +namespace interprocess { +namespace winapi { + +struct GUID_BIPC +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +}; + +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}}; + +struct wchar_variant +{ + unsigned long long dummy; + union value_t{ + wchar_t *pbstrVal; + unsigned long long dummy; + } value; +}; + +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 wchar_t * 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 wchar_t * wszName, + /* [in] */ long lFlags, + /* [in] */ wchar_variant *pVal, + /* [in] */ long Type) = 0; + + virtual long __stdcall Delete( + /* [string][in] */ const wchar_t * wszName) = 0; + + virtual long __stdcall GetNames( + /* [string][in] */ const wchar_t * 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] */ wchar_t * *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 wchar_t * wszProperty, + /* [out] */ void **ppQualSet) = 0; + + virtual long __stdcall Clone( + /* [out] */ IWbemClassObject_BIPC **ppCopy) = 0; + + virtual long __stdcall GetObjectText( + /* [in] */ long lFlags, + /* [out] */ wchar_t * *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 wchar_t * wszName, + /* [out] */ wchar_t * *pstrClassName) = 0; + + virtual long __stdcall InheritsFrom( + /* [in] */ const wchar_t * strAncestor) = 0; + + virtual long __stdcall GetMethod( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [out] */ IWbemClassObject_BIPC **ppInSignature, + /* [out] */ IWbemClassObject_BIPC **ppOutSignature) = 0; + + virtual long __stdcall PutMethod( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [in] */ IWbemClassObject_BIPC *pInSignature, + /* [in] */ IWbemClassObject_BIPC *pOutSignature) = 0; + + virtual long __stdcall DeleteMethod( + /* [string][in] */ const wchar_t * wszName) = 0; + + virtual long __stdcall BeginMethodEnumeration( + /* [in] */ long lEnumFlags) = 0; + + virtual long __stdcall NextMethod( + /* [in] */ long lFlags, + /* [unique][in][out] */ wchar_t * *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 wchar_t * wszMethod, + /* [out] */ void **ppQualSet) = 0; + + virtual long __stdcall GetMethodOrigin( + /* [string][in] */ const wchar_t * wszMethodName, + /* [out] */ wchar_t * *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] */ wchar_t * *pstrName, + /* [out] */ wchar_variant *pValue) = 0; + + virtual long __stdcall EndEnumeration( void) = 0; + + virtual long __stdcall SetValue( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [in] */ wchar_variant *pValue) = 0; + + virtual long __stdcall GetValue( + /* [string][in] */ const wchar_t * wszName, + /* [in] */ long lFlags, + /* [out] */ wchar_variant *pValue) = 0; + + virtual long __stdcall DeleteValue( + /* [string][in] */ const wchar_t * 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 wchar_t * 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 wchar_t * strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppObject, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall GetObjectAsync( + /* [in] */ const wchar_t * 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 wchar_t * strClass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall DeleteClassAsync( + /* [in] */ const wchar_t * strClass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall CreateClassEnum( + /* [in] */ const wchar_t * strSuperclass, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall CreateClassEnumAsync( + /* [in] */ const wchar_t * 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 wchar_t * strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [unique][in][out] */ void **ppCallResult) = 0; + + virtual long __stdcall DeleteInstanceAsync( + /* [in] */ const wchar_t * strObjectPath, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall CreateInstanceEnum( + /* [in] */ const wchar_t * strFilter, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall CreateInstanceEnumAsync( + /* [in] */ const wchar_t * strFilter, + /* [in] */ long lFlags, + /* [in] */ void *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecQuery( + /* [in] */ const wchar_t * strQueryLanguage, + /* [in] */ const wchar_t * strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [out] */ IEnumWbemClassObject_BIPC **ppEnum) = 0; + + virtual long __stdcall ExecQueryAsync( + /* [in] */ const wchar_t * strQueryLanguage, + /* [in] */ const wchar_t * strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecNotificationQuery( + /* [in] */ const wchar_t * strQueryLanguage, + /* [in] */ const wchar_t * strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [out] */ void **ppEnum) = 0; + + virtual long __stdcall ExecNotificationQueryAsync( + /* [in] */ const wchar_t * strQueryLanguage, + /* [in] */ const wchar_t * strQuery, + /* [in] */ long lFlags, + /* [in] */ IWbemContext_BIPC *pCtx, + /* [in] */ void *pResponseHandler) = 0; + + virtual long __stdcall ExecMethod( + /* [in] */ const wchar_t * strObjectPath, + /* [in] */ const wchar_t * 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 wchar_t * strObjectPath, + /* [in] */ const wchar_t * 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 wchar_t * strNetworkResource, + /* [in] */ const wchar_t * strUser, + /* [in] */ const wchar_t * strPassword, + /* [in] */ const wchar_t * strLocale, + /* [in] */ long lSecurityFlags, + /* [in] */ const wchar_t * 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_semaphore_basic_information +{ + unsigned int count; // current semaphore count + unsigned int limit; // max semaphore count +}; + +struct interprocess_section_basic_information +{ + void * base_address; + unsigned long section_attributes; + __int64 section_size; +}; + +struct interprocess_filetime +{ + unsigned long dwLowDateTime; + unsigned long dwHighDateTime; +}; + +struct win32_find_data_t +{ + 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_memory_basic_information +{ + void * BaseAddress; + void * AllocationBase; + unsigned long AllocationProtect; + unsigned long RegionSize; + unsigned long State; + unsigned long Protect; + unsigned long Type; +}; + +struct interprocess_acl +{ + unsigned char AclRevision; + unsigned char Sbz1; + unsigned short AclSize; + unsigned short AceCount; + unsigned short Sbz2; +}; + +typedef struct _interprocess_security_descriptor +{ + unsigned char Revision; + unsigned char Sbz1; + unsigned short Control; + void *Owner; + void *Group; + interprocess_acl *Sacl; + interprocess_acl *Dacl; +} interprocess_security_descriptor; + +enum file_information_class_t { + file_directory_information = 1, + file_full_directory_information, + file_both_directory_information, + file_basic_information, + file_standard_information, + file_internal_information, + file_ea_information, + file_access_information, + file_name_information, + file_rename_information, + file_link_information, + file_names_information, + file_disposition_information, + file_position_information, + file_full_ea_information, + file_mode_information, + file_alignment_information, + file_all_information, + file_allocation_information, + file_end_of_file_information, + file_alternate_name_information, + file_stream_information, + file_pipe_information, + file_pipe_local_information, + file_pipe_remote_information, + file_mailslot_query_information, + file_mailslot_set_information, + file_compression_information, + file_copy_on_write_information, + file_completion_information, + file_move_cluster_information, + file_quota_information, + file_reparse_point_information, + file_network_open_information, + file_object_id_information, + file_tracking_information, + file_ole_directory_information, + file_content_index_information, + file_inherit_content_index_information, + file_ole_information, + file_maximum_information +}; + +enum semaphore_information_class { + semaphore_basic_information = 0 +}; + +struct file_name_information_t { + unsigned long FileNameLength; + wchar_t FileName[1]; +}; + +struct file_rename_information_t { + int Replace; + void *RootDir; + unsigned long FileNameLength; + wchar_t FileName[1]; +}; + +struct unicode_string_t { + unsigned short Length; + unsigned short MaximumLength; + wchar_t *Buffer; +}; + +struct object_attributes_t { + unsigned long Length; + void * RootDirectory; + unicode_string_t *ObjectName; + unsigned long Attributes; + void *SecurityDescriptor; + void *SecurityQualityOfService; +}; + +struct io_status_block_t { + union { + long Status; + void *Pointer; + }; + + unsigned long *Information; +}; + +union system_timeofday_information +{ + struct data_t + { + __int64 liKeBootTime; + __int64 liKeSystemTime; + __int64 liExpTimeZoneBias; + unsigned long uCurrentTimeZoneId; + unsigned long dwReserved; + } data; + unsigned char Reserved1[SystemTimeOfDayInfoLength]; +}; + +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; +}; + +enum system_information_class { + system_basic_information = 0, + system_performance_information = 2, + system_time_of_day_information = 3, + system_process_information = 5, + system_processor_performance_information = 8, + system_interrupt_information = 23, + system_exception_information = 33, + system_registry_quota_information = 37, + system_lookaside_information = 45 +}; + +enum object_information_class +{ + object_basic_information, + object_name_information, + object_type_information, + object_all_information, + object_data_information +}; + +enum section_information_class +{ + section_basic_information, + section_image_information +}; + +struct object_name_information_t +{ + unicode_string_t Name; + wchar_t NameBuffer[1]; +}; + +//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) 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_t *lpFindFileData); +extern "C" __declspec(dllimport) int __stdcall FindNextFileA(void *hFindFile, win32_find_data_t *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) int __stdcall DeleteFileA (const char *); +extern "C" __declspec(dllimport) int __stdcall MoveFileExA (const char *, const char *, unsigned long); +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 *, __int64 *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 *, __int64 distance, __int64 *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) void *__stdcall LoadLibraryA(const char *); +extern "C" __declspec(dllimport) int __stdcall FreeLibrary(void *); +extern "C" __declspec(dllimport) void *__stdcall GetProcAddress(void *, const char*); +extern "C" __declspec(dllimport) void *__stdcall GetModuleHandleA(const char*); +extern "C" __declspec(dllimport) void *__stdcall GetFileInformationByHandle(void *, interprocess_by_handle_file_information*); +extern "C" __declspec(dllimport) unsigned long __stdcall GetMappedFileNameW(void *, void *, wchar_t *, unsigned long); +extern "C" __declspec(dllimport) long __stdcall RegOpenKeyExA(void *, const char *, unsigned long, unsigned long, void **); +extern "C" __declspec(dllimport) long __stdcall RegQueryValueExA(void *, const char *, unsigned long*, unsigned long*, unsigned char *, unsigned long*); +extern "C" __declspec(dllimport) long __stdcall RegCloseKey(void *); +extern "C" __declspec(dllimport) int __stdcall QueryPerformanceCounter(__int64 *lpPerformanceCount); + +//COM API +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 VariantClear(wchar_variant * pvarg); +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); + + + +//API function typedefs +//Pointer to functions +typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes); +typedef long (__stdcall *NtSetInformationFile_t)(void *FileHandle, io_status_block_t *IoStatusBlock, void *FileInformation, unsigned long Length, int FileInformationClass ); +typedef long (__stdcall *NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *); +typedef long (__stdcall *NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *); +typedef long (__stdcall *NtQuerySemaphore_t)(void*, unsigned int info_class, interprocess_semaphore_basic_information *pinfo, unsigned int info_size, unsigned int *ret_len); +typedef long (__stdcall *NtQuerySection_t)(void*, section_information_class, interprocess_section_basic_information *pinfo, unsigned long info_size, unsigned long *ret_len); +typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int); +typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long); +typedef long (__stdcall *NtClose_t) (void*); +typedef long (__stdcall *RtlCreateUnicodeStringFromAsciiz_t)(unicode_string_t *, const char *); +typedef void (__stdcall *RtlFreeUnicodeString_t)(unicode_string_t *); +typedef void (__stdcall *RtlInitUnicodeString_t)( unicode_string_t *, const wchar_t * ); +typedef long (__stdcall *RtlAppendUnicodeToString_t)(unicode_string_t *Destination, const wchar_t *Source); +typedef unsigned long (__stdcall * GetMappedFileName_t)(void *, void *, wchar_t *, unsigned long); +typedef long (__stdcall * RegOpenKeyEx_t)(void *, const char *, unsigned long, unsigned long, void **); +typedef long (__stdcall * RegQueryValueEx_t)(void *, const char *, unsigned long*, unsigned long*, unsigned char *, unsigned long*); +typedef long (__stdcall * RegCloseKey_t)(void *); + +} //namespace winapi { +} //namespace interprocess { +} //namespace boost { + +namespace boost { +namespace interprocess { +namespace winapi { + +inline unsigned long get_last_error() +{ return GetLastError(); } + +inline void set_last_error(unsigned long err) +{ return SetLastError(err); } + +inline unsigned long format_message + (unsigned long dwFlags, const void *lpSource, + unsigned long dwMessageId, unsigned long dwLanguageId, + char *lpBuffer, unsigned long nSize, std::va_list *Arguments) +{ + return FormatMessageA + (dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); +} + +//And now, wrapper functions +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)); } + +inline void sched_yield() +{ + if(!SwitchToThread()){ + Sleep(1); + } +} + +inline void sleep(unsigned long ms) +{ Sleep(ms); } + +inline unsigned long get_current_thread_id() +{ return GetCurrentThreadId(); } + +inline bool get_process_times + ( void *hProcess, interprocess_filetime* lpCreationTime + , interprocess_filetime *lpExitTime, interprocess_filetime *lpKernelTime + , interprocess_filetime *lpUserTime ) +{ return 0 != GetProcessTimes(hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); } + +inline unsigned long get_current_process_id() +{ return GetCurrentProcessId(); } + +inline unsigned int close_handle(void* handle) +{ return CloseHandle(handle); } + +inline void * find_first_file(const char *lpFileName, win32_find_data_t *lpFindFileData) +{ return FindFirstFileA(lpFileName, lpFindFileData); } + +inline bool find_next_file(void *hFindFile, win32_find_data_t *lpFindFileData) +{ return FindNextFileA(hFindFile, lpFindFileData) != 0; } + +inline bool find_close(void *handle) +{ return FindClose(handle) != 0; } + +inline bool duplicate_current_process_handle + (void *hSourceHandle, void **lpTargetHandle) +{ + return 0 != DuplicateHandle + ( GetCurrentProcess(), hSourceHandle, GetCurrentProcess() + , lpTargetHandle, 0, 0 + , duplicate_same_access); +} + +inline unsigned long get_file_type(void *hFile) +{ + return GetFileType(hFile); +} + +/* +inline void get_system_time_as_file_time(interprocess_filetime *filetime) +{ GetSystemTimeAsFileTime(filetime); } + +inline bool file_time_to_local_file_time + (const interprocess_filetime *in, const interprocess_filetime *out) +{ return 0 != FileTimeToLocalFileTime(in, out); } +*/ +inline void *open_or_create_mutex(const char *name, bool initial_owner, interprocess_security_attributes *attr) +{ return CreateMutexA(attr, (int)initial_owner, name); } + +inline unsigned long wait_for_single_object(void *handle, unsigned long time) +{ return WaitForSingleObject(handle, time); } + +inline int release_mutex(void *handle) +{ return ReleaseMutex(handle); } + +inline int unmap_view_of_file(void *address) +{ return UnmapViewOfFile(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_semaphore(const char *name) +{ return OpenSemaphoreA(semaphore_all_access, 0, name); } + +inline int release_semaphore(void *handle, long release_count, long *prev_count) +{ return ReleaseSemaphore(handle, release_count, prev_count); } + +class interprocess_all_access_security +{ + interprocess_security_attributes sa; + interprocess_security_descriptor sd; + bool initialized; + + public: + interprocess_all_access_security() + : initialized(false) + { + if(!InitializeSecurityDescriptor(&sd, security_descriptor_revision)) + return; + if(!SetSecurityDescriptorDacl(&sd, true, 0, false)) + return; + sa.lpSecurityDescriptor = &sd; + sa.nLength = sizeof(interprocess_security_attributes); + sa.bInheritHandle = false; + initialized = false; + } + + interprocess_security_attributes *get_attributes() + { return &sa; } +}; + +inline void * create_file_mapping (void * handle, unsigned long access, unsigned __int64 file_offset, const char * name, interprocess_security_attributes *psec) +{ + const unsigned long high_size(file_offset >> 32), low_size((boost::uint32_t)file_offset); + return CreateFileMappingA (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 *map_view_of_file_ex(void *handle, unsigned long file_access, unsigned __int64 offset, std::size_t numbytes, void *base_addr) +{ + const unsigned long offset_low = (unsigned long)(offset & ((unsigned __int64)0xFFFFFFFF)); + const unsigned long offset_high = 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) +{ + for (unsigned int attempt(0); attempt < error_sharing_violation_tries; ++attempt){ + void * const handle = CreateFileA(name, access, + file_share_read | file_share_write | file_share_delete, + psec, creation_flags, attributes, 0); + bool const invalid(invalid_handle_value == handle); + if (!invalid){ + return handle; + } + if (error_sharing_violation != get_last_error()){ + return handle; + } + sleep(error_sharing_violation_sleep_ms); + } + return invalid_handle_value; +} + +inline bool delete_file(const char *name) +{ return 0 != DeleteFileA(name); } + +inline bool move_file_ex(const char *source_filename, const char *destination_filename, unsigned long flags) +{ return 0 != MoveFileExA(source_filename, destination_filename, flags); } + +inline void get_system_info(system_info *info) +{ GetSystemInfo(info); } + +inline bool flush_view_of_file(void *base_addr, std::size_t numbytes) +{ return 0 != FlushViewOfFile(base_addr, numbytes); } + +inline bool virtual_unlock(void *base_addr, std::size_t numbytes) +{ return 0 != 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); } + +inline bool flush_file_buffers(void *handle) +{ return 0 != FlushFileBuffers(handle); } + +inline bool get_file_size(void *handle, __int64 &size) +{ return 0 != GetFileSizeEx(handle, &size); } + +inline bool create_directory(const char *name) +{ + interprocess_all_access_security sec; + return 0 != CreateDirectoryA(name, sec.get_attributes()); +} + +inline bool remove_directory(const char *lpPathName) +{ return 0 != RemoveDirectoryA(lpPathName); } + +inline unsigned long get_temp_path(unsigned long length, char *buffer) +{ return GetTempPathA(length, buffer); } + +inline int set_end_of_file(void *handle) +{ return 0 != SetEndOfFile(handle); } + +inline bool set_file_pointer_ex(void *handle, __int64 distance, __int64 *new_file_pointer, unsigned long move_method) +{ return 0 != SetFilePointerEx(handle, distance, new_file_pointer, move_method); } + +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); } + +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); } + +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); } + +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); } + +inline bool get_file_information_by_handle(void *hnd, interprocess_by_handle_file_information *info) +{ return 0 != GetFileInformationByHandle(hnd, info); } + +inline long interlocked_increment(long volatile *addr) +{ return BOOST_INTERLOCKED_INCREMENT(addr); } + +inline long interlocked_decrement(long volatile *addr) +{ return BOOST_INTERLOCKED_DECREMENT(addr); } + +inline long interlocked_compare_exchange(long volatile *addr, long val1, long val2) +{ return BOOST_INTERLOCKED_COMPARE_EXCHANGE(addr, val1, val2); } + +inline long interlocked_exchange_add(long volatile* addend, long value) +{ return BOOST_INTERLOCKED_EXCHANGE_ADD(const_cast(addend), value); } + +inline long interlocked_exchange(long volatile* addend, long value) +{ return BOOST_INTERLOCKED_EXCHANGE(const_cast(addend), value); } + +//Forward functions +inline void *load_library(const char *name) +{ return LoadLibraryA(name); } + +inline bool free_library(void *module) +{ return 0 != FreeLibrary(module); } + +inline void *get_proc_address(void *module, const char *name) +{ return GetProcAddress(module, name); } + +inline void *get_current_process() +{ return GetCurrentProcess(); } + +inline void *get_module_handle(const char *name) +{ return GetModuleHandleA(name); } + +inline unsigned long get_mapped_file_name(void *process, void *lpv, wchar_t *lpfilename, unsigned long nSize) +{ return GetMappedFileNameW(process, lpv, lpfilename, nSize); } + +inline long reg_open_key_ex(void *hKey, const char *lpSubKey, unsigned long ulOptions, unsigned long samDesired, void **phkResult) +{ return RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult); } + +inline long reg_query_value_ex(void *hKey, const char *lpValueName, unsigned long*lpReserved, unsigned long*lpType, unsigned char *lpData, unsigned long*lpcbData) +{ return RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } + +inline long reg_close_key(void *hKey) +{ return RegCloseKey(hKey); } + +inline bool query_performance_counter(__int64 *lpPerformanceCount) +{ + return 0 != QueryPerformanceCounter(lpPerformanceCount); +} + +inline void initialize_object_attributes +( object_attributes_t *pobject_attr, unicode_string_t *name + , unsigned long attr, void *rootdir, void *security_descr) + +{ + pobject_attr->Length = sizeof(object_attributes_t); + pobject_attr->RootDirectory = rootdir; + pobject_attr->Attributes = attr; + pobject_attr->ObjectName = name; + pobject_attr->SecurityDescriptor = security_descr; + pobject_attr->SecurityQualityOfService = 0; +} + +inline void rtl_init_empty_unicode_string(unicode_string_t *ucStr, wchar_t *buf, unsigned short bufSize) +{ + ucStr->Buffer = buf; + ucStr->Length = 0; + ucStr->MaximumLength = bufSize; +} + +//A class that locates and caches loaded DLL function addresses. +template +struct function_address_holder +{ + enum { NtSetInformationFile, NtQuerySystemInformation, NtQueryObject, NtQuerySemaphore, NtQuerySection, NumFunction }; + enum { NtDll_dll, NumModule }; + + private: + static void *FunctionAddresses[NumFunction]; + static volatile long FunctionStates[NumFunction]; + static void *ModuleAddresses[NumModule]; + static volatile long ModuleStates[NumModule]; + + static void *get_module_from_id(unsigned int id) + { + assert(id < (unsigned int)NumModule); + const char *module[] = { "ntdll.dll" }; + bool compile_check[sizeof(module)/sizeof(module[0]) == NumModule]; + (void)compile_check; + return get_module_handle(module[id]); + } + + static void *get_module(const unsigned int id) + { + assert(id < (unsigned int)NumModule); + while(ModuleStates[id] < 2){ + if(interlocked_compare_exchange(&ModuleStates[id], 1, 0) == 0){ + ModuleAddresses[id] = get_module_from_id(id); + interlocked_increment(&ModuleStates[id]); + break; + } + else{ + sched_yield(); + } + } + return ModuleAddresses[id]; + } + + static void *get_address_from_dll(const unsigned int id) + { + assert(id < (unsigned int)NumFunction); + const char *function[] = { "NtSetInformationFile", "NtQuerySystemInformation", "NtQueryObject", "NtQuerySemaphore", "NtQuerySection" }; + bool compile_check[sizeof(function)/sizeof(function[0]) == NumFunction]; + (void)compile_check; + return get_proc_address(get_module(NtDll_dll), function[id]); + } + + public: + static void *get(const unsigned int id) + { + assert(id < (unsigned int)NumFunction); + while(FunctionStates[id] < 2){ + if(interlocked_compare_exchange(&FunctionStates[id], 1, 0) == 0){ + FunctionAddresses[id] = get_address_from_dll(id); + interlocked_increment(&FunctionStates[id]); + break; + } + else{ + sched_yield(); + } + } + return FunctionAddresses[id]; + } +}; + +template +void *function_address_holder::FunctionAddresses[function_address_holder::NumFunction]; + +template +volatile long function_address_holder::FunctionStates[function_address_holder::NumFunction]; + +template +void *function_address_holder::ModuleAddresses[function_address_holder::NumModule]; + +template +volatile long function_address_holder::ModuleStates[function_address_holder::NumModule]; + + +struct dll_func + : public function_address_holder<0> +{}; + +//Complex winapi based functions... +struct library_unloader +{ + void *lib_; + library_unloader(void *module) : lib_(module){} + ~library_unloader(){ free_library(lib_); } +}; + +//pszFilename must have room for at least MaxPath+1 characters +inline bool get_file_name_from_handle_function + (void * hFile, wchar_t *pszFilename, std::size_t length, std::size_t &out_length) +{ + if(length <= MaxPath){ + return false; + } + +// void *hiPSAPI = load_library("PSAPI.DLL"); +// if (0 == hiPSAPI) +// return 0; +// library_unloader unloader(hiPSAPI); + +// Pointer to function getMappedFileName() in PSAPI.DLL +// GetMappedFileName_t pfGMFN = +// (GetMappedFileName_t)get_proc_address(hiPSAPI, "GetMappedFileNameW"); +// if (! pfGMFN){ +// return 0; // Failed: unexpected error +// } + + bool bSuccess = false; + + // Create a file mapping object. + void * hFileMap = create_file_mapping(hFile, page_readonly, 1, 0, 0); + if(hFileMap){ + // Create a file mapping to get the file name. + void* pMem = map_view_of_file_ex(hFileMap, file_map_read, 0, 1, 0); + + if (pMem){ + //out_length = pfGMFN(get_current_process(), pMem, pszFilename, MaxPath); + out_length = get_mapped_file_name(get_current_process(), pMem, pszFilename, MaxPath); + if(out_length){ + bSuccess = true; + } + unmap_view_of_file(pMem); + } + close_handle(hFileMap); + } + + return(bSuccess); +} + +inline bool get_system_time_of_day_information(system_timeofday_information &info) +{ + NtQuerySystemInformation_t pNtQuerySystemInformation = (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){ + return false; + } + return true; +} + +inline bool get_boot_time(unsigned char (&bootstamp) [BootstampLength]) +{ + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + std::memcpy(&bootstamp[0], &info.Reserved1, sizeof(bootstamp)); + return true; +} + +inline bool get_boot_and_system_time(unsigned char (&bootsystemstamp) [BootAndSystemstampLength]) +{ + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + std::memcpy(&bootsystemstamp[0], &info.Reserved1, sizeof(bootsystemstamp)); + return true; +} + +inline bool get_boot_time_str(char *bootstamp_str, std::size_t &s) //will write BootstampLength chars +{ + if(s < (BootstampLength*2)) + return false; + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + return false; + } + const char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + std::size_t char_counter = 0; + for(std::size_t i = 0; i != static_cast(BootstampLength); ++i){ + bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootstampLength*2; + return true; +} + +inline bool get_boot_and_system_time_wstr(wchar_t *bootsystemstamp, std::size_t &s) //will write BootAndSystemstampLength chars +{ + if(s < (BootAndSystemstampLength*2)) + return false; + system_timeofday_information info; + bool ret = get_system_time_of_day_information(info); + if(!ret){ + 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; + for(std::size_t i = 0; i != static_cast(BootAndSystemstampLength); ++i){ + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootAndSystemstampLength*2; + return true; +} + +class handle_closer +{ + void *handle_; + handle_closer(const handle_closer &); + handle_closer& operator=(const handle_closer &); + public: + explicit handle_closer(void *handle) : handle_(handle){} + ~handle_closer() + { close_handle(handle_); } +}; + +union ntquery_mem_t +{ + object_name_information_t name; + struct ren_t + { + file_rename_information_t info; + wchar_t buf[32767]; + } ren; +}; + +inline bool unlink_file(const char *filename) +{ + //Don't try to optimize doing a DeleteFile first + //as there are interactions with permissions and + //in-use files. + // + //if(!delete_file(filename)){ + // (...) + // + + //This functions tries to emulate UNIX unlink semantics in windows. + // + //- Open the file and mark the handle as delete-on-close + //- Rename the file to an arbitrary name based on a random number + //- 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{ + NtSetInformationFile_t pNtSetInformationFile = + (NtSetInformationFile_t)dll_func::get(dll_func::NtSetInformationFile); + if(!pNtSetInformationFile){ + return false; + } + + NtQueryObject_t pNtQueryObject = + (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, + file_flag_backup_semantics | file_flag_delete_on_close, 0); + if(fh == invalid_handle_value){ + return false; + } + + handle_closer h_closer(fh); + + std::auto_ptr pmem(new ntquery_mem_t); + file_rename_information_t *pfri = &pmem->ren.info; + const std::size_t RenMaxNumChars = + ((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); + + //Obtain file name + unsigned long size; + if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(ntquery_mem_t), &size)){ + return false; + } + + //Copy filename to the rename member + std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); + std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t); + + //Second step: obtain the complete native-nt filename + //if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){ + //return 0; + //} + + //Add trailing mark + if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){ + return false; + } + + //Search '\\' character to replace it + for(std::size_t i = filename_string_length; i != 0; --filename_string_length){ + if(pmem->ren.info.FileName[--i] == L'\\') + break; + } + + //Add random number + std::size_t s = RenMaxNumChars - filename_string_length; + if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){ + return false; + } + filename_string_length += s; + + //Fill rename information (FileNameLength is in bytes) + pfri->FileNameLength = static_cast(sizeof(wchar_t)*(filename_string_length)); + pfri->Replace = 1; + pfri->RootDir = 0; + + //Final step: change the name of the in-use file: + io_status_block_t io; + if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(ntquery_mem_t::ren_t), file_rename_information)){ + return false; + } + return true; + } + catch(...){ + return false; + } + return true; +} + +struct reg_closer +{ + //reg_closer(RegCloseKey_t func, void *key) : func_(func), key_(key){} + //~reg_closer(){ (*func_)(key_); } + //RegCloseKey_t func_; + void *key_; + reg_closer(void *key) : key_(key){} + ~reg_closer(){ reg_close_key(key_); } +}; + +inline void get_shared_documents_folder(std::string &s) +{ + s.clear(); + void *key; + if (reg_open_key_ex( hkey_local_machine + , "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders" + , 0 + , key_query_value + , &key) == 0){ + reg_closer key_closer(key); + + //Obtain the value + unsigned long size; + unsigned long type; + const char *const reg_value = "Common AppData"; + //long err = (*pRegQueryValue)( key, reg_value, 0, &type, 0, &size); + long err = reg_query_value_ex( key, reg_value, 0, &type, 0, &size); + if(!err){ + //Size includes terminating NULL + s.resize(size); + //err = (*pRegQueryValue)( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + err = reg_query_value_ex( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + if(!err) + s.erase(s.end()-1); + (void)err; + } + } +} + +inline void get_registry_value(const char *folder, const char *value_key, std::vector &s) +{ + s.clear(); + void *key; + if (reg_open_key_ex( hkey_local_machine + , folder + , 0 + , key_query_value + , &key) == 0){ + reg_closer key_closer(key); + + //Obtain the value + unsigned long size; + unsigned long type; + const char *const reg_value = value_key; + //long err = (*pRegQueryValue)( key, reg_value, 0, &type, 0, &size); + long err = reg_query_value_ex( key, reg_value, 0, &type, 0, &size); + if(!err){ + //Size includes terminating NULL + s.resize(size); + //err = (*pRegQueryValue)( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + err = reg_query_value_ex( key, reg_value, 0, &type, (unsigned char*)(&s[0]), &size); + if(!err) + s.erase(s.end()-1); + (void)err; + } + } +} + +struct co_uninitializer +{ + co_uninitializer(bool b_uninitialize) + : m_b_uninitialize(b_uninitialize) + {} + + ~co_uninitializer() + { + if(m_b_uninitialize){ + CoUninitialize(); + } + } + + private: + const bool m_b_uninitialize; +}; + +template +struct com_releaser +{ + Object *&object_; + com_releaser(Object *&object) : object_(object) {} + ~com_releaser() { object_->Release(); object_ = 0; } +}; + +inline bool get_wmi_class_attribute( std::wstring& strValue, const wchar_t *wmi_class, const wchar_t *wmi_class_var) +{ + //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; + } + + com_releaser IWbemLocator_releaser(pIWbemLocator); + + IWbemServices_BIPC *pWbemServices = 0; + + if( 0 != pIWbemLocator->ConnectServer( + bstrNamespace, // Namespace + 0, // Userid + 0, // PW + 0, // Locale + 0, // flags + 0, // Authority + 0, // Context + &pWbemServices + ) + ){ + return false; + } + + 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_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( + L"WQL", + strValue.c_str(), + //WBEM_FLAG_RETURN_IMMEDIATELY_BIPC, + WBEM_FLAG_RETURN_WHEN_COMPLETE_BIPC | WBEM_FLAG_FORWARD_ONLY_BIPC, + 0, + &pEnumObject + ) + ){ + return false; + } + + com_releaser IEnumWbemClassObject_releaser(pEnumObject); + + //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 ) ) + { + com_releaser IWbemClassObject_releaser(pClassObject); + if ( 0 == pClassObject->Get( L"LastBootUpTime", 0, &vwchar, 0, 0 ) ){ + bRet = true; + strValue = vwchar.value.pbstrVal; + VariantClear(&vwchar ); + break; + } + } + } + return bRet; +} + +inline bool get_last_bootup_time( std::wstring& strValue ) +{ + 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; +} + +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'); + } + return ret; +} + +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); + if(ntstatus){ + return false; + } + size = info.section_size; + return true; +} + +inline bool get_semaphore_info(void *handle, long &count, long &limit) +{ + 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); + if(status){ + return false; + } + count = info.count; + limit = info.limit; + return true; +} + + +} //namespace winapi +} //namespace interprocess +} //namespace boost + +#include + +#endif //#ifdef BOOST_INTERPROCESS_WIN32_PRIMITIVES_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/windows_intermodule_singleton.hpp b/cpp/BoostParts/boost/interprocess/detail/windows_intermodule_singleton.hpp new file mode 100644 index 00000000..194e566a --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/windows_intermodule_singleton.hpp @@ -0,0 +1,306 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-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_WINDOWS_INTERMODULE_SINGLETON_HPP +#define BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#include +#include + +#if !defined(BOOST_INTERPROCESS_WINDOWS) + #error "This header can't be included from non-windows operating systems" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace ipcdetail{ + +namespace intermodule_singleton_helpers { + +//This global map will be implemented using 3 sync primitives: +// +//1) A named mutex that will implement global mutual exclusion between +// threads from different modules/dlls +// +//2) A semaphore that will act as a global counter for modules attached to the global map +// so that the global map can be destroyed when the last module is detached. +// +//3) A semaphore that will be hacked to hold the address of a heap-allocated map in the +// max and current semaphore count. +class windows_semaphore_based_map +{ + typedef std::map map_type; + + public: + windows_semaphore_based_map() + { + map_type *m = new map_type; + boost::uint32_t initial_count = 0; + boost::uint32_t max_count = 0; + + //Windows user address space sizes: + //32 bit windows: [32 bit processes] 2GB or 3GB (31/32 bits) + //64 bit windows: [32 bit processes] 2GB or 4GB (31/32 bits) + // [64 bit processes] 2GB or 8TB (31/43 bits) + // + //Windows semaphores use 'long' parameters (32 bits in LLP64 data model) and + //those values can't be negative, so we have 31 bits to store something + //in max_count and initial count parameters. + //Also, max count must be bigger than 0 and bigger or equal than initial count. + if(sizeof(void*) == sizeof(boost::uint32_t)){ + //This means that for 32 bit processes, a semaphore count (31 usable bits) is + //enough to store 4 byte aligned memory (4GB -> 32 bits - 2 bits = 30 bits). + //The max count will hold the pointer value and current semaphore count + //will be zero. + // + //Relying in UB with a cast through union, but all known windows compilers + //accept this (C11 also accepts this). + union caster_union + { + void *addr; + boost::uint32_t addr_uint32; + } caster; + caster.addr = m; + //memory is at least 4 byte aligned in windows + BOOST_ASSERT((caster.addr_uint32 & boost::uint32_t(3)) == 0); + max_count = caster.addr_uint32 >> 2; + } + else if(sizeof(void*) == sizeof(boost::uint64_t)){ + //Relying in UB with a cast through union, but all known windows compilers + //accept this (C11 accepts this). + union caster_union + { + void *addr; + boost::uint64_t addr_uint64; + } caster; + caster.addr = m; + //We'll encode the address using 30 bits in each 32 bit high and low parts. + //High part will be the sem max count, low part will be the sem initial count. + //(restrictions: max count > 0, initial count >= 0 and max count >= initial count): + // + // - Low part will be shifted two times (4 byte alignment) so that top + // two bits are cleared (the top one for sign, the next one to + // assure low part value is always less than the high part value. + // - The top bit of the high part will be cleared and the next bit will be 1 + // (so high part is always bigger than low part due to the quasi-top bit). + // + // This means that the addresses we can store must be 4 byte aligned + // and less than 1 ExbiBytes ( 2^60 bytes, ~1 ExaByte). User-level address space in Windows 64 + // is much less than this (8TB, 2^43 bytes): "1 EByte (or it was 640K?) ought to be enough for anybody" ;-). + caster.addr = m; + BOOST_ASSERT((caster.addr_uint64 & boost::uint64_t(3)) == 0); + max_count = boost::uint32_t(caster.addr_uint64 >> 32); + initial_count = boost::uint32_t(caster.addr_uint64); + initial_count = initial_count/4; + //Make sure top two bits are zero + BOOST_ASSERT((max_count & boost::uint32_t(0xC0000000)) == 0); + //Set quasi-top bit + max_count |= boost::uint32_t(0x40000000); + } + bool created = false; + const permissions & perm = permissions(); + std::string pid_creation_time, name; + get_pid_creation_time_str(pid_creation_time); + name = "bipc_gmap_sem_lock_"; + name += pid_creation_time; + bool success = m_mtx_lock.open_or_create(name.c_str(), perm); + name = "bipc_gmap_sem_count_"; + name += pid_creation_time; + scoped_lock lck(m_mtx_lock); + { + success = success && m_sem_count.open_or_create + ( name.c_str(), static_cast(0), winapi_semaphore_wrapper::MaxCount, perm, created); + 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); + if(!success){ + //winapi_xxx wrappers do the cleanup... + throw int(0); + } + if(!created){ + delete m; + } + else{ + BOOST_ASSERT(&get_map_unlocked() == m); + } + m_sem_count.post(); + } + } + + map_type &get_map_unlocked() + { + if(sizeof(void*) == sizeof(boost::uint32_t)){ + union caster_union + { + void *addr; + boost::uint32_t addr_uint32; + } caster; + caster.addr = 0; + caster.addr_uint32 = m_sem_map.limit(); + caster.addr_uint32 = caster.addr_uint32 << 2; + return *static_cast(caster.addr); + } + else{ + union caster_union + { + void *addr; + boost::uint64_t addr_uint64; + } caster; + boost::uint32_t max_count(m_sem_map.limit()), initial_count(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 |= boost::uint64_t(initial_count) << 2; + return *static_cast(caster.addr); + } + } + + ref_count_ptr *find(const char *name) + { + scoped_lock lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + map_type::iterator it = map.find(std::string(name)); + if(it != map.end()){ + return &it->second; + } + else{ + return 0; + } + } + + ref_count_ptr * insert(const char *name, const ref_count_ptr &ref) + { + scoped_lock lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + map_type::iterator it = map.insert(map_type::value_type(std::string(name), ref)).first; + return &it->second; + } + + bool erase(const char *name) + { + scoped_lock lck(m_mtx_lock); + map_type &map = this->get_map_unlocked(); + return map.erase(std::string(name)) != 0; + } + + template + void atomic_func(F &f) + { + scoped_lock lck(m_mtx_lock); + f(); + } + + ~windows_semaphore_based_map() + { + scoped_lock lck(m_mtx_lock); + m_sem_count.wait(); + if(0 == m_sem_count.value()){ + delete &this->get_map_unlocked(); + } + //First close sems to protect this with the external mutex + m_sem_map.close(); + m_sem_count.close(); + //Once scoped_lock unlocks the mutex, the destructor will close the handle... + } + + private: + winapi_mutex_wrapper m_mtx_lock; + winapi_semaphore_wrapper m_sem_map; + winapi_semaphore_wrapper m_sem_count; +}; + +template<> +struct thread_safe_global_map_dependant +{ + static void apply_gmem_erase_logic(const char *, const char *){} + + static bool remove_old_gmem() + { return true; } + + struct lock_file_logic + { + lock_file_logic(windows_semaphore_based_map &) + : retry_with_new_map(false) + {} + + void operator()(void){} + bool retry() const { return retry_with_new_map; } + private: + const bool retry_with_new_map; + }; + + static void construct_map(void *addr) + { + ::new (addr)windows_semaphore_based_map; + } + + struct unlink_map_logic + { + unlink_map_logic(windows_semaphore_based_map &) + {} + void operator()(){} + }; + + static ref_count_ptr *find(windows_semaphore_based_map &map, const char *name) + { + return map.find(name); + } + + static ref_count_ptr * insert(windows_semaphore_based_map &map, const char *name, const ref_count_ptr &ref) + { + return map.insert(name, ref); + } + + static bool erase(windows_semaphore_based_map &map, const char *name) + { + return map.erase(name); + } + + template + static void atomic_func(windows_semaphore_based_map &map, F &f) + { + map.atomic_func(f); + } +}; + +} //namespace intermodule_singleton_helpers { + +template +class windows_intermodule_singleton + : public intermodule_singleton_impl + < C + , LazyInit + , Phoenix + , intermodule_singleton_helpers::windows_semaphore_based_map + > +{}; + +} //namespace ipcdetail{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_WINDOWS_INTERMODULE_SINGLETON_HPP diff --git a/cpp/BoostParts/boost/interprocess/detail/workaround.hpp b/cpp/BoostParts/boost/interprocess/detail/workaround.hpp new file mode 100644 index 00000000..70af142b --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/detail/workaround.hpp @@ -0,0 +1,171 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_WORKAROUND_HPP +#define BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP + +#include + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define BOOST_INTERPROCESS_WINDOWS + #define BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION + #define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME +#else + #include + + #if defined(_POSIX_THREAD_PROCESS_SHARED) && ((_POSIX_THREAD_PROCESS_SHARED - 0) > 0) + //Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it. + //Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but does not seem to work. + #if !defined(__CYGWIN__) && !defined(__APPLE__) + #define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED + #endif + #endif + + #if defined(_POSIX_BARRIERS) && ((_POSIX_BARRIERS - 0) > 0) + #define BOOST_INTERPROCESS_POSIX_BARRIERS + #endif + + #if defined(_POSIX_SEMAPHORES) && ((_POSIX_SEMAPHORES - 0) > 0) + #define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + #if defined(__CYGWIN__) + #define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK + #endif + //Some platforms have a limited (name length) named semaphore support + #elif (defined(__FreeBSD__) && (__FreeBSD__ >= 4)) || defined(__APPLE__) + #define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + #endif + + #if ((defined _V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\ + ((defined _V6_LP64_OFF64) &&(_V6_LP64_OFF64 - 0 > 0)) ||\ + ((defined _V6_LPBIG_OFFBIG) &&(_V6_LPBIG_OFFBIG - 0 > 0)) ||\ + ((defined _XBS5_ILP32_OFFBIG)&&(_XBS5_ILP32_OFFBIG - 0 > 0)) ||\ + ((defined _XBS5_LP64_OFF64) &&(_XBS5_LP64_OFF64 - 0 > 0)) ||\ + ((defined _XBS5_LPBIG_OFFBIG)&&(_XBS5_LPBIG_OFFBIG - 0 > 0)) ||\ + ((defined _FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64))||\ + ((defined _FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64)) + #define BOOST_INTERPROCESS_UNIX_64_BIT_OR_BIGGER_OFF_T + #endif + + //Check for XSI shared memory objects. They are available in nearly all UNIX platforms + #if !defined(__QNXNTO__) + #define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + #endif + + #if defined(_POSIX_SHARED_MEMORY_OBJECTS) && ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0) + #define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + #else + //VMS and MACOS don't define it but they have shm_open/close interface + #if defined(__vms) + #if __CRTL_VER >= 70200000 + #define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + #endif + //Mac OS has some non-conformant features like names limited to SHM_NAME_MAX + #elif defined (__APPLE__) + //#define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + //#define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS_NO_GROW + #endif + #endif + + //Now check if we have only XSI shared memory + #if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) &&\ + !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) + //#define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY + #endif + + #if defined(_POSIX_TIMEOUTS) && ((_POSIX_TIMEOUTS - 0) > 0) + #define BOOST_INTERPROCESS_POSIX_TIMEOUTS + #endif + + #ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS + //Some systems have filesystem-based resources, so the + //portable "/shmname" format does not work due to permission issues + //For those systems we need to form a path to a temporary directory: + // hp-ux tru64 vms freebsd + #if defined(__hpux) || defined(__osf__) || defined(__vms) || (defined(__FreeBSD__) && (__FreeBSD__ < 7)) + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + //Some systems have "jailed" environments where shm usage is restricted at runtime + //and temporary file file based shm is possible in those executions. + #elif defined(__FreeBSD__) + #define BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + #endif + #endif + + #ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES + #if defined(__osf__) || defined(__vms) + #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES + #endif + #endif + + #if defined(_POSIX_VERSION) && defined(_XOPEN_VERSION) && \ + (((_POSIX_VERSION + 0)>= 200112L || (_XOPEN_VERSION + 0)>= 500)) + #define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES + #endif + + #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) + #define BOOST_INTERPROCESS_BSD_DERIVATIVE + #include + #if defined(CTL_KERN) && defined (KERN_BOOTTIME) + //#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME + #endif + #endif +#endif //!defined(BOOST_INTERPROCESS_WINDOWS) + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + #define BOOST_INTERPROCESS_PERFECT_FORWARDING +#endif + +//Now declare some Boost.Interprocess features depending on the implementation +#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) + #define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES + #define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES +#endif + +// Timeout duration use if BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING is set +#ifndef BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS + #define BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS 10000 +#endif + +//Other switches +//BOOST_INTERPROCESS_MSG_QUEUE_USES_CIRC_INDEX +//message queue uses a circular queue as index instead of an array (better performance) +//Boost version < 1.52 uses an array, so undef this if you want to communicate +//with processes compiled with those versions. +#define BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX + +//Inline attributes +#if defined(_MSC_VER) + #define BOOST_INTERPROCESS_ALWAYS_INLINE __forceinline +#elif defined (__GNUC__) + #define BOOST_INTERPROCESS_ALWAYS_INLINE __attribute__((__always_inline__)) +#else + #define BOOST_INTERPROCESS_ALWAYS_INLINE inline +#endif + +#if defined(_MSC_VER) + #define BOOST_INTERPROCESS_NEVER_INLINE __declspec(noinline) +#elif defined (__GNUC__) + #define BOOST_INTERPROCESS_NEVER_INLINE __attribute__((__noinline__)) +#endif + +#if defined(BOOST_NO_CXX11_NOEXCEPT) + #if defined(BOOST_MSVC) + #define BOOST_INTERPROCESS_NOEXCEPT throw() + #else + #define BOOST_INTERPROCESS_NOEXCEPT + #endif + #define BOOST_INTERPROCESS_NOEXCEPT_IF(x) +#else + #define BOOST_INTERPROCESS_NOEXCEPT noexcept + #define BOOST_INTERPROCESS_NOEXCEPT_IF(x) noexcept(x) +#endif + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP diff --git a/cpp/BoostParts/boost/interprocess/errors.hpp b/cpp/BoostParts/boost/interprocess/errors.hpp new file mode 100644 index 00000000..345ca311 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/errors.hpp @@ -0,0 +1,236 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +// Parts of this code are taken from boost::filesystem library +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 Beman Dawes +// Copyright (C) 2001 Dietmar Kuehl +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy +// at http://www.boost.org/LICENSE_1_0.txt) +// +// See library home page at http://www.boost.org/libs/filesystem +// +////////////////////////////////////////////////////////////////////////////// + + +#ifndef BOOST_INTERPROCESS_ERRORS_HPP +#define BOOST_INTERPROCESS_ERRORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include //Errors +# include //strerror +# else //ifdef BOOST_HAS_UNISTD_H +# error Unknown platform +# endif //ifdef BOOST_HAS_UNISTD_H +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) + +//!\file +//!Describes the error numbering of interprocess classes + +namespace boost { +namespace interprocess { +/// @cond +inline int system_error_code() // artifact of POSIX and WINDOWS error reporting +{ + #if (defined BOOST_INTERPROCESS_WINDOWS) + return winapi::get_last_error(); + #else + return errno; // GCC 3.1 won't accept ::errno + #endif +} + + +#if (defined BOOST_INTERPROCESS_WINDOWS) +inline void fill_system_message(int sys_err_code, std::string &str) +{ + void *lpMsgBuf; + winapi::format_message( + winapi::format_message_allocate_buffer | + winapi::format_message_from_system | + winapi::format_message_ignore_inserts, + 0, + sys_err_code, + winapi::make_lang_id(winapi::lang_neutral, winapi::sublang_default), // Default language + reinterpret_cast(&lpMsgBuf), + 0, + 0 + ); + str += static_cast(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 +inline void fill_system_message( int system_error, std::string &str) +{ str = std::strerror(system_error); } +# endif +/// @endcond + +enum error_code_t +{ + no_error = 0, + system_error, // system generated error; if possible, is translated + // to one of the more specific errors below. + other_error, // library generated error + security_error, // includes access rights, permissions failures + read_only_error, + io_error, + path_error, + not_found_error, +// not_directory_error, + busy_error, // implies trying again might succeed + already_exists_error, + not_empty_error, + is_directory_error, + out_of_space_error, + out_of_memory_error, + out_of_resource_error, + lock_error, + sem_error, + mode_error, + size_error, + corrupted_error, + not_such_file_or_directory, + invalid_argument, + timeout_when_locking_error, + timeout_when_waiting_error, +}; + +typedef int native_error_t; + +/// @cond +struct ec_xlate +{ + native_error_t sys_ec; + error_code_t ec; +}; + +static const ec_xlate ec_table[] = +{ + #if (defined BOOST_INTERPROCESS_WINDOWS) + { /*ERROR_ACCESS_DENIED*/5L, security_error }, + { /*ERROR_INVALID_ACCESS*/12L, security_error }, + { /*ERROR_SHARING_VIOLATION*/32L, security_error }, + { /*ERROR_LOCK_VIOLATION*/33L, security_error }, + { /*ERROR_LOCKED*/212L, security_error }, + { /*ERROR_NOACCESS*/998L, security_error }, + { /*ERROR_WRITE_PROTECT*/19L, read_only_error }, + { /*ERROR_NOT_READY*/21L, io_error }, + { /*ERROR_SEEK*/25L, io_error }, + { /*ERROR_READ_FAULT*/30L, io_error }, + { /*ERROR_WRITE_FAULT*/29L, io_error }, + { /*ERROR_CANTOPEN*/1011L, io_error }, + { /*ERROR_CANTREAD*/1012L, io_error }, + { /*ERROR_CANTWRITE*/1013L, io_error }, + { /*ERROR_DIRECTORY*/267L, path_error }, + { /*ERROR_INVALID_NAME*/123L, path_error }, + { /*ERROR_FILE_NOT_FOUND*/2L, not_found_error }, + { /*ERROR_PATH_NOT_FOUND*/3L, not_found_error }, + { /*ERROR_DEV_NOT_EXIST*/55L, not_found_error }, + { /*ERROR_DEVICE_IN_USE*/2404L, busy_error }, + { /*ERROR_OPEN_FILES*/2401L, busy_error }, + { /*ERROR_BUSY_DRIVE*/142L, busy_error }, + { /*ERROR_BUSY*/170L, busy_error }, + { /*ERROR_FILE_EXISTS*/80L, already_exists_error }, + { /*ERROR_ALREADY_EXISTS*/183L, already_exists_error }, + { /*ERROR_DIR_NOT_EMPTY*/145L, not_empty_error }, + { /*ERROR_HANDLE_DISK_FULL*/39L, out_of_space_error }, + { /*ERROR_DISK_FULL*/112L, out_of_space_error }, + { /*ERROR_OUTOFMEMORY*/14L, out_of_memory_error }, + { /*ERROR_NOT_ENOUGH_MEMORY*/8L, out_of_memory_error }, + { /*ERROR_TOO_MANY_OPEN_FILES*/4L, out_of_resource_error }, + { /*ERROR_INVALID_ADDRESS*/487L, busy_error } + #else //#if (defined BOOST_INTERPROCESS_WINDOWS) + { EACCES, security_error }, + { EROFS, read_only_error }, + { EIO, io_error }, + { ENAMETOOLONG, path_error }, + { ENOENT, not_found_error }, + // { ENOTDIR, not_directory_error }, + { EAGAIN, busy_error }, + { EBUSY, busy_error }, + { ETXTBSY, busy_error }, + { EEXIST, already_exists_error }, + { ENOTEMPTY, not_empty_error }, + { EISDIR, is_directory_error }, + { ENOSPC, out_of_space_error }, + { ENOMEM, out_of_memory_error }, + { EMFILE, out_of_resource_error }, + { ENOENT, not_such_file_or_directory }, + { EINVAL, invalid_argument } + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) +}; + +inline error_code_t lookup_error(native_error_t err) +{ + const ec_xlate *cur = &ec_table[0], + *end = cur + sizeof(ec_table)/sizeof(ec_xlate); + for (;cur != end; ++cur ){ + if ( err == cur->sys_ec ) return cur->ec; + } + return system_error; // general system error code +} + +struct error_info +{ + error_info(error_code_t ec = other_error ) + : m_nat(0), m_ec(ec) + {} + + error_info(native_error_t sys_err_code) + : m_nat(sys_err_code), m_ec(lookup_error(sys_err_code)) + {} + + error_info & operator =(error_code_t ec) + { + m_nat = 0; + m_ec = ec; + return *this; + } + + error_info & operator =(native_error_t sys_err_code) + { + m_nat = sys_err_code; + m_ec = lookup_error(sys_err_code); + return *this; + } + + native_error_t get_native_error()const + { return m_nat; } + + error_code_t get_error_code()const + { return m_ec; } + + private: + native_error_t m_nat; + error_code_t m_ec; +}; +/// @endcond + +} // namespace interprocess { +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_ERRORS_HPP diff --git a/cpp/BoostParts/boost/interprocess/exceptions.hpp b/cpp/BoostParts/boost/interprocess/exceptions.hpp new file mode 100644 index 00000000..b9ab45be --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/exceptions.hpp @@ -0,0 +1,150 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_EXCEPTIONS_HPP +#define BOOST_INTERPROCESS_EXCEPTIONS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include + +//!\file +//!Describes exceptions thrown by interprocess classes + +namespace boost { + +namespace interprocess { + +//!This class is the base class of all exceptions +//!thrown by boost::interprocess +class interprocess_exception : public std::exception +{ + public: + interprocess_exception(const char *err/*error_code_t ec = other_error*/) + : m_err(other_error) + { +// try { m_str = "boost::interprocess_exception::library_error"; } + try { m_str = err; } + catch (...) {} + } +/* + interprocess_exception(native_error_t sys_err_code) + : m_err(sys_err_code) + { + try { fill_system_message(m_err.get_native_error(), m_str); } + catch (...) {} + }*/ + + interprocess_exception(const error_info &err_info, const char *str = 0) + : m_err(err_info) + { + try{ + if(m_err.get_native_error() != 0){ + fill_system_message(m_err.get_native_error(), m_str); + } + else if(str){ + m_str = str; + } + else{ + m_str = "boost::interprocess_exception::library_error"; + } + } + catch(...){} + } + + virtual ~interprocess_exception() throw(){} + + virtual const char * what() const throw() + { return m_str.c_str(); } + + native_error_t get_native_error()const { 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(); } + + /// @cond + private: + error_info m_err; + std::string m_str; + /// @endcond +}; + +//!This is the exception thrown by shared interprocess_mutex family when a deadlock situation +//!is detected or when using a interprocess_condition the interprocess_mutex is not locked +class lock_exception : public interprocess_exception +{ + public: + lock_exception() + : interprocess_exception(lock_error) + {} + + virtual const char* what() const throw() + { return "boost::interprocess::lock_exception"; } +}; + +//!This is the exception thrown by named interprocess_semaphore when a deadlock situation +//!is detected or when an error is detected in the post/wait operation +/* +class sem_exception : public interprocess_exception +{ + public: + sem_exception() + : interprocess_exception(lock_error) + {} + + virtual const char* what() const throw() + { return "boost::interprocess::sem_exception"; } +}; +*/ +//!This is the exception thrown by synchronization objects when there is +//!an error in a wait() function +/* +class wait_exception : public interprocess_exception +{ + public: + virtual const char* what() const throw() + { return "boost::interprocess::wait_exception"; } +}; +*/ + +//!This exception is thrown when a named object is created +//!in "open_only" mode and the resource was not already created +/* +class not_previously_created : public interprocess_exception +{ + public: + virtual const char* what() const throw() + { return "boost::interprocess::not_previously_created"; } +}; +*/ + +//!This exception is thrown when a memory request can't be +//!fulfilled. +class bad_alloc : public interprocess_exception +{ + public: + bad_alloc() : interprocess_exception("::boost::interprocess::bad_alloc"){} + virtual const char* what() const throw() + { return "boost::interprocess::bad_alloc"; } +}; + +} // namespace interprocess { + +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_EXCEPTIONS_HPP diff --git a/cpp/BoostParts/boost/interprocess/indexes/iset_index.hpp b/cpp/BoostParts/boost/interprocess/indexes/iset_index.hpp new file mode 100644 index 00000000..b1abeded --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/indexes/iset_index.hpp @@ -0,0 +1,150 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_ISET_INDEX_HPP +#define BOOST_INTERPROCESS_ISET_INDEX_HPP + +#include +#include + +#include +#include +#include +#include +#include + + +//!\file +//!Describes index adaptor of boost::intrusive::set container, to use it +//!as name/shared memory index + +namespace boost { +namespace interprocess { + +/// @cond + +//!Helper class to define typedefs from IndexTraits +template +struct iset_index_aux +{ + typedef typename + MapConfig::segment_manager_base segment_manager_base; + + typedef typename + segment_manager_base::void_pointer void_pointer; + typedef typename bi::make_set_base_hook + < bi::void_pointer + , bi::optimize_size + >::type derivation_hook; + + typedef typename MapConfig::template + intrusive_value_type::type value_type; + typedef std::less value_compare; + typedef typename bi::make_set + < value_type + , bi::base_hook + >::type index_t; +}; +/// @endcond + +//!Index type based in boost::intrusive::set. +//!Just derives from boost::intrusive::set +//!and defines the interface needed by managed memory segments*/ +template +class iset_index + //Derive class from map specialization + : public iset_index_aux::index_t +{ + /// @cond + typedef iset_index_aux index_aux; + typedef typename index_aux::index_t index_type; + typedef typename MapConfig:: + intrusive_compare_key_type intrusive_compare_key_type; + typedef typename MapConfig::char_type char_type; + /// @endcond + + public: + typedef typename index_type::iterator iterator; + typedef typename index_type::const_iterator const_iterator; + typedef typename index_type::insert_commit_data insert_commit_data; + typedef typename index_type::value_type value_type; + + /// @cond + private: + + struct intrusive_key_value_less + { + bool operator()(const intrusive_compare_key_type &i, const value_type &b) const + { + std::size_t blen = b.name_length(); + return (i.m_len < blen) || + (i.m_len == blen && + std::char_traits::compare + (i.mp_str, b.name(), i.m_len) < 0); + } + + bool operator()(const value_type &b, const intrusive_compare_key_type &i) const + { + std::size_t blen = b.name_length(); + return (blen < i.m_len) || + (blen == i.m_len && + std::char_traits::compare + (b.name(), i.mp_str, i.m_len) < 0); + } + }; + + /// @endcond + + public: + + //!Constructor. Takes a pointer to the + //!segment manager. Can throw + iset_index(typename MapConfig::segment_manager_base *) + : index_type(/*typename index_aux::value_compare()*/) + {} + + //!This reserves memory to optimize the insertion of n + //!elements in the index + void reserve(typename MapConfig::segment_manager_base::size_type) + { /*Does nothing, map has not reserve or rehash*/ } + + //!This frees all unnecessary memory + void shrink_to_fit() + { /*Does nothing, this intrusive index does not allocate memory;*/ } + + iterator find(const intrusive_compare_key_type &key) + { return index_type::find(key, intrusive_key_value_less()); } + + const_iterator find(const intrusive_compare_key_type &key) const + { return index_type::find(key, intrusive_key_value_less()); } + + std::pairinsert_check + (const intrusive_compare_key_type &key, insert_commit_data &commit_data) + { return index_type::insert_check(key, intrusive_key_value_less(), commit_data); } +}; + +/// @cond + +//!Trait class to detect if an index is an intrusive +//!index. +template +struct is_intrusive_index + > +{ + static const bool value = true; +}; +/// @endcond + +} //namespace interprocess { +} //namespace boost + +#include + +#endif //#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/interprocess_fwd.hpp b/cpp/BoostParts/boost/interprocess/interprocess_fwd.hpp new file mode 100644 index 00000000..42f170a6 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/interprocess_fwd.hpp @@ -0,0 +1,418 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_FWD_HPP +#define BOOST_INTERPROCESS_FWD_HPP + +#if defined (_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +/// @cond + +namespace boost{ +namespace intrusive{ +}} + +namespace boost{ +namespace interprocess{ +namespace bi = boost::intrusive; +}} + +#include +#include +#include +#include +#include + +/// @endcond + +namespace boost { namespace interprocess { + +////////////////////////////////////////////////////////////////////////////// +// permissions +////////////////////////////////////////////////////////////////////////////// + +class permissions; + +////////////////////////////////////////////////////////////////////////////// +// shared_memory +////////////////////////////////////////////////////////////////////////////// + +class shared_memory_object; + +#if defined (BOOST_INTERPROCESS_WINDOWS) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +class windows_shared_memory; +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +////////////////////////////////////////////////////////////////////////////// +// mapped file/mapped region/mapped_file +////////////////////////////////////////////////////////////////////////////// + +class file_mapping; +class mapped_region; +class mapped_file; + +////////////////////////////////////////////////////////////////////////////// +// Mutexes +////////////////////////////////////////////////////////////////////////////// + +class null_mutex; + +class interprocess_mutex; +class interprocess_recursive_mutex; + +class named_mutex; +class named_recursive_mutex; + +class interprocess_semaphore; +class named_semaphore; + +////////////////////////////////////////////////////////////////////////////// +// Mutex families +////////////////////////////////////////////////////////////////////////////// + +struct mutex_family; +struct null_mutex_family; + +////////////////////////////////////////////////////////////////////////////// +// Other synchronization classes +////////////////////////////////////////////////////////////////////////////// + +class barrier; +class interprocess_sharable_mutex; +class interprocess_condition; + +////////////////////////////////////////////////////////////////////////////// +// Locks +////////////////////////////////////////////////////////////////////////////// + +template +class scoped_lock; + +template +class sharable_lock; + +template +class upgradable_lock; + +////////////////////////////////////////////////////////////////////////////// +// STL compatible allocators +////////////////////////////////////////////////////////////////////////////// + +template +class allocator; + +template +class node_allocator; + +template +class private_node_allocator; + +template +class cached_node_allocator; + +template +class adaptive_pool; + +template +class private_adaptive_pool; + +template +class cached_adaptive_pool; + + +////////////////////////////////////////////////////////////////////////////// +// offset_ptr +////////////////////////////////////////////////////////////////////////////// + +static const std::size_t offset_type_alignment = 0; + +template +class offset_ptr; + +////////////////////////////////////////////////////////////////////////////// +// Memory allocation algorithms +////////////////////////////////////////////////////////////////////////////// + +//Single segment memory allocation algorithms +template > +class simple_seq_fit; + +template, std::size_t MemAlignment = 0> +class rbtree_best_fit; + +////////////////////////////////////////////////////////////////////////////// +// Index Types +////////////////////////////////////////////////////////////////////////////// + +template class flat_map_index; +template class iset_index; +template class iunordered_set_index; +template class map_index; +template class null_index; +template class unordered_map_index; + +////////////////////////////////////////////////////////////////////////////// +// Segment manager +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class segment_manager; + +////////////////////////////////////////////////////////////////////////////// +// External buffer managed memory classes +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class basic_managed_external_buffer; + +typedef basic_managed_external_buffer + + ,iset_index> +managed_external_buffer; + +typedef basic_managed_external_buffer + + ,iset_index> +wmanaged_external_buffer; + +////////////////////////////////////////////////////////////////////////////// +// managed memory classes +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class basic_managed_shared_memory; + +typedef basic_managed_shared_memory + + ,iset_index> +managed_shared_memory; + +typedef basic_managed_shared_memory + + ,iset_index> +wmanaged_shared_memory; + + +////////////////////////////////////////////////////////////////////////////// +// Windows shared memory managed memory classes +////////////////////////////////////////////////////////////////////////////// + +#if defined (BOOST_INTERPROCESS_WINDOWS) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +template class IndexType> +class basic_managed_windows_shared_memory; + +typedef basic_managed_windows_shared_memory + + ,iset_index> +managed_windows_shared_memory; + +typedef basic_managed_windows_shared_memory + + ,iset_index> +wmanaged_windows_shared_memory; + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) + +#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +template class IndexType> +class basic_managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +wmanaged_xsi_shared_memory; + +#endif //#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) + +////////////////////////////////////////////////////////////////////////////// +// Fixed address shared memory +////////////////////////////////////////////////////////////////////////////// + +typedef basic_managed_shared_memory + + ,iset_index> +fixed_managed_shared_memory; + +typedef basic_managed_shared_memory + + ,iset_index> +wfixed_managed_shared_memory; + +////////////////////////////////////////////////////////////////////////////// +// Heap memory managed memory classes +////////////////////////////////////////////////////////////////////////////// + +template + class IndexType> +class basic_managed_heap_memory; + +typedef basic_managed_heap_memory + + ,iset_index> +managed_heap_memory; + +typedef basic_managed_heap_memory + + ,iset_index> +wmanaged_heap_memory; + +////////////////////////////////////////////////////////////////////////////// +// Mapped file managed memory classes +////////////////////////////////////////////////////////////////////////////// + +template + class IndexType> +class basic_managed_mapped_file; + +typedef basic_managed_mapped_file + + ,iset_index> +managed_mapped_file; + +typedef basic_managed_mapped_file + + ,iset_index> +wmanaged_mapped_file; + +////////////////////////////////////////////////////////////////////////////// +// Exceptions +////////////////////////////////////////////////////////////////////////////// + +class interprocess_exception; +class lock_exception; +class bad_alloc; + +////////////////////////////////////////////////////////////////////////////// +// Bufferstream +////////////////////////////////////////////////////////////////////////////// + +//bufferstream +template > +class basic_bufferbuf; + +template > +class basic_ibufferstream; + +template > +class basic_obufferstream; + +template > +class basic_bufferstream; + +////////////////////////////////////////////////////////////////////////////// +// Vectorstream +////////////////////////////////////////////////////////////////////////////// + +template > +class basic_vectorbuf; + +template > +class basic_ivectorstream; + +template > +class basic_ovectorstream; + +template > +class basic_vectorstream; + +////////////////////////////////////////////////////////////////////////////// +// Smart pointers +////////////////////////////////////////////////////////////////////////////// + +template +class scoped_ptr; + +template +class intrusive_ptr; + +template +class shared_ptr; + +template +class weak_ptr; + +////////////////////////////////////////////////////////////////////////////// +// IPC +////////////////////////////////////////////////////////////////////////////// + +template +class message_queue_t; + +typedef message_queue_t > message_queue; + +}} //namespace boost { namespace interprocess { + +////////////////////////////////////////////////////////////////////////////// +// CONTAINERS +////////////////////////////////////////////////////////////////////////////// + +#include + +#endif //#ifndef BOOST_INTERPROCESS_FWD_HPP diff --git a/cpp/BoostParts/boost/interprocess/managed_shared_memory.hpp b/cpp/BoostParts/boost/interprocess/managed_shared_memory.hpp new file mode 100644 index 00000000..c20f39ca --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/managed_shared_memory.hpp @@ -0,0 +1,221 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_MANAGED_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +//These includes needed to fulfill default template parameters of +//predeclarations in interprocess_fwd.hpp +#include +#include + +namespace boost { +namespace interprocess { + +namespace ipcdetail { + +template +struct shmem_open_or_create +{ + typedef ipcdetail::managed_open_or_create_impl + < shared_memory_object, AllocationAlgorithm::Alignment, true, false> type; +}; + +} //namespace ipcdetail { + +//!A basic shared memory named object creation class. Initializes the +//!shared memory segment. Inherits all basic functionality from +//!basic_managed_memory_impl*/ +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_shared_memory + : public ipcdetail::basic_managed_memory_impl + ::type::ManagedOpenOrCreateUserOffset> + , private ipcdetail::shmem_open_or_create::type +{ + /// @cond + typedef ipcdetail::basic_managed_memory_impl + ::type::ManagedOpenOrCreateUserOffset> base_t; + typedef typename ipcdetail::shmem_open_or_create::type base2_t; + + typedef ipcdetail::create_open_func create_open_func_t; + + basic_managed_shared_memory *get_this_pointer() + { return this; } + + public: + typedef shared_memory_object device_type; + typedef typename base_t::size_type size_type; + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_shared_memory) + /// @endcond + + public: //functions + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~basic_managed_shared_memory() + {} + + //!Default constructor. Does nothing. + //!Useful in combination with move semantics + basic_managed_shared_memory() + {} + + //!Creates shared memory and creates and places the segment manager. + //!This can throw. + basic_managed_shared_memory(create_only_t, const char *name, + size_type size, const void *addr = 0, const permissions& perm = permissions()) + : base_t() + , base2_t(create_only, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm) + {} + + //!Creates shared memory and creates and places the segment manager if + //!segment was not created. If segment was created it connects to the + //!segment. + //!This can throw. + basic_managed_shared_memory (open_or_create_t, + const char *name, size_type size, + const void *addr = 0, const permissions& perm = permissions()) + : base_t() + , base2_t(open_or_create, name, size, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpenOrCreate), perm) + {} + + //!Connects to a created shared memory and its segment manager. + //!in copy_on_write mode. + //!This can throw. + basic_managed_shared_memory (open_copy_on_write_t, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, copy_on_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager. + //!in read-only mode. + //!This can throw. + basic_managed_shared_memory (open_read_only_t, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, read_only, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Connects to a created shared memory and its segment manager. + //!This can throw. + basic_managed_shared_memory (open_only_t, const char* name, + const void *addr = 0) + : base_t() + , base2_t(open_only, name, read_write, addr, + create_open_func_t(get_this_pointer(), + ipcdetail::DoOpen)) + {} + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_shared_memory(BOOST_RV_REF(basic_managed_shared_memory) moved) + { + basic_managed_shared_memory tmp; + this->swap(moved); + tmp.swap(moved); + } + + //!Moves the ownership of "moved"'s managed memory to *this. + //!Does not throw + basic_managed_shared_memory &operator=(BOOST_RV_REF(basic_managed_shared_memory) moved) + { + basic_managed_shared_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps the ownership of the managed shared memories managed by *this and other. + //!Never throws. + void swap(basic_managed_shared_memory &other) + { + base_t::swap(other); + base2_t::swap(other); + } + + //!Tries to resize the managed shared memory object so that we have + //!room for more objects. + //! + //!This function is not synchronized so no other thread or process should + //!be reading or writing the file + static bool grow(const char *shmname, size_type extra_bytes) + { + return base_t::template grow + (shmname, extra_bytes); + } + + //!Tries to resize the managed shared memory to minimized the size of the file. + //! + //!This function is not synchronized so no other thread or process should + //!be reading or writing the file + static bool shrink_to_fit(const char *shmname) + { + return base_t::template shrink_to_fit + (shmname); + } + /// @cond + + //!Tries to find a previous named allocation address. Returns a memory + //!buffer and the object count. If not found returned pointer is 0. + //!Never throws. + template + std::pair find (char_ptr_holder_t name) + { + if(base2_t::get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + + /// @endcond +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP + diff --git a/cpp/BoostParts/boost/interprocess/mapped_region.hpp b/cpp/BoostParts/boost/interprocess/mapped_region.hpp new file mode 100644 index 00000000..6a3366f4 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/mapped_region.hpp @@ -0,0 +1,886 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_MAPPED_REGION_HPP +#define BOOST_INTERPROCESS_MAPPED_REGION_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +//Some Unixes use caddr_t instead of void * in madvise +// SunOS Tru64 HP-UX AIX +#if defined(sun) || defined(__sun) || defined(__osf__) || defined(__osf) || defined(_hpux) || defined(hpux) || defined(_AIX) +#define BOOST_INTERPROCESS_MADVISE_USES_CADDR_T +#include +#endif + +//A lot of UNIXes have destructive semantics for MADV_DONTNEED, so +//we need to be careful to allow it. +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +#define BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS +#endif + +#if defined (BOOST_INTERPROCESS_WINDOWS) +# include +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include //mmap +# include +# include +# include +# if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS) +# include //System V shared memory... +# endif +# include +# else +# error Unknown platform +# endif + +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) + +//!\file +//!Describes mapped region class + +namespace boost { +namespace interprocess { + +/// @cond + +//Solaris declares madvise only in some configurations but defines MADV_XXX, a bit confusing. +//Predeclare it here to avoid any compilation error +#if (defined(sun) || defined(__sun)) && defined(MADV_NORMAL) +extern "C" int madvise(caddr_t, size_t, int); +#endif + +namespace ipcdetail{ class interprocess_tester; } +namespace ipcdetail{ class raw_mapped_region_creator; } + +/// @endcond + +//!The mapped_region class represents a portion or region created from a +//!memory_mappable object. +//! +//!The OS can map a region bigger than the requested one, as region must +//!be multiple of the page size, but mapped_region will always refer to +//!the region specified by the user. +class mapped_region +{ + /// @cond + //Non-copyable + BOOST_MOVABLE_BUT_NOT_COPYABLE(mapped_region) + /// @endcond + + public: + + //!Creates a mapping region of the mapped memory "mapping", starting in + //!offset "offset", and the mapping's size will be "size". The mapping + //!can be opened for read only, read-write or copy-on-write. + //! + //!If an address is specified, both the offset and the address must be + //!multiples of the page size. + //! + //!The OS could allocate more pages than size/page_size(), but get_address() + //!will always return the address passed in this function (if not null) and + //!get_size() will return the specified size. + template + mapped_region(const MemoryMappable& mapping + ,mode_t mode + ,offset_t offset = 0 + ,std::size_t size = 0 + ,const void *address = 0); + + //!Default constructor. Address will be 0 (nullptr). + //!Size will be 0. + //!Does not throw + mapped_region(); + + //!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) + #if defined (BOOST_INTERPROCESS_WINDOWS) + : m_base(0), m_size(0) + , m_page_offset(0) + , m_mode(read_only) + , m_file_or_mapping_hnd(ipcdetail::invalid_file()) + #else + : m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false) + #endif + { this->swap(other); } + + //!Destroys the mapped region. + //!Does not throw + ~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 tmp(boost::move(other)); + this->swap(tmp); + return *this; + } + + //!Swaps the mapped_region with another + //!mapped region + void swap(mapped_region &other); + + //!Returns the size of the mapping. Never throws. + std::size_t get_size() const; + + //!Returns the base address of the mapping. + //!Never throws. + void* get_address() const; + + //!Returns the mode of the mapping used to construct the mapped region. + //!Never throws. + mode_t get_mode() const; + + //!Flushes to the disk a byte range within the mapped memory. + //!If 'async' is true, the function will return before flushing operation is completed + //!If 'async' is false, function will return once data has been written into the underlying + //!device (i.e., in mapped files OS cached information is written to disk). + //!Never throws. Returns false if operation could not be performed. + bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0, bool async = true); + + //!Shrinks current mapped region. If after shrinking there is no longer need for a previously + //!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). + //!Returns true on success. Never throws. + bool shrink_by(std::size_t bytes, bool from_back = true); + + //!This enum specifies region usage behaviors that an application can specify + //!to the mapped region implementation. + enum advice_types{ + //!Specifies that the application has no advice to give on its behavior with respect to + //!the region. It is the default characteristic if no advice is given for a range of memory. + advice_normal, + //!Specifies that the application expects to access the region sequentially from + //!lower addresses to higher addresses. The implementation can lower the priority of + //!preceding pages within the region once a page have been accessed. + advice_sequential, + //!Specifies that the application expects to access the region in a random order, + //!and prefetching is likely not advantageous. + advice_random, + //!Specifies that the application expects to access the region in the near future. + //!The implementation can prefetch pages of the region. + advice_willneed, + //!Specifies that the application expects that it will not access the region in the near future. + //!The implementation can unload pages within the range to save system resources. + advice_dontneed + }; + + //!Advises the implementation on the expected behavior of the application with respect to the data + //!in the region. The implementation may use this information to optimize handling of the region data. + //!This function has no effect on the semantics of access to memory in the region, although it may affect + //!the performance of access. + //!If the advise type is not known to the implementation, the function returns false. True otherwise. + bool advise(advice_types advise); + + //!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(); + + /// @cond + private: + //!Closes a previously opened memory mapping. Never throws + void priv_close(); + + void* priv_map_address() const; + std::size_t priv_map_size() const; + bool priv_flush_param_check(std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const; + bool priv_shrink_param_check(std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes); + static void priv_size_from_mapping_size + (offset_t mapping_size, offset_t offset, offset_t page_offset, std::size_t &size); + static offset_t priv_page_offset_addr_fixup(offset_t page_offset, const void *&addr); + + template + struct page_size_holder + { + static const std::size_t PageSize; + static std::size_t get_page_size(); + }; + + void* m_base; + std::size_t m_size; + std::size_t m_page_offset; + mode_t m_mode; + #if defined(BOOST_INTERPROCESS_WINDOWS) + file_handle_t m_file_or_mapping_hnd; + #else + bool m_is_xsi; + #endif + + friend class ipcdetail::interprocess_tester; + friend class ipcdetail::raw_mapped_region_creator; + void dont_close_on_destruction(); + #if defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) + template + static void destroy_syncs_in_range(const void *addr, std::size_t size); + #endif + /// @endcond +}; + +///@cond + +inline void swap(mapped_region &x, mapped_region &y) +{ x.swap(y); } + +inline mapped_region::~mapped_region() +{ this->priv_close(); } + +inline std::size_t mapped_region::get_size() const +{ return m_size; } + +inline mode_t mapped_region::get_mode() const +{ return m_mode; } + +inline void* mapped_region::get_address() const +{ return m_base; } + +inline void* mapped_region::priv_map_address() const +{ return static_cast(m_base) - m_page_offset; } + +inline std::size_t mapped_region::priv_map_size() const +{ return m_size + m_page_offset; } + +inline bool mapped_region::priv_flush_param_check + (std::size_t mapping_offset, void *&addr, std::size_t &numbytes) const +{ + //Check some errors + if(m_base == 0) + return false; + + if(mapping_offset >= m_size || (mapping_offset + numbytes) > m_size){ + return false; + } + + //Update flush size if the user does not provide it + if(numbytes == 0){ + numbytes = m_size - mapping_offset; + } + addr = (char*)this->priv_map_address() + mapping_offset; + numbytes += m_page_offset; + return true; +} + +inline bool mapped_region::priv_shrink_param_check + (std::size_t bytes, bool from_back, void *&shrink_page_start, std::size_t &shrink_page_bytes) +{ + //Check some errors + if(m_base == 0 || bytes > m_size){ + return false; + } + else if(bytes == m_size){ + this->priv_close(); + return true; + } + else{ + const std::size_t page_size = mapped_region::get_page_size(); + if(from_back){ + const std::size_t new_pages = (m_size + m_page_offset - bytes - 1)/page_size + 1; + shrink_page_start = static_cast(this->priv_map_address()) + new_pages*page_size; + shrink_page_bytes = m_page_offset + m_size - new_pages*page_size; + m_size -= bytes; + } + else{ + shrink_page_start = this->priv_map_address(); + m_page_offset += bytes; + shrink_page_bytes = (m_page_offset/page_size)*page_size; + m_page_offset = m_page_offset % page_size; + m_size -= bytes; + m_base = static_cast(m_base) + bytes; + assert(shrink_page_bytes%page_size == 0); + } + return true; + } +} + +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. + 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(mapping_size - (offset - page_offset)); +} + +inline offset_t mapped_region::priv_page_offset_addr_fixup(offset_t offset, const void *&address) +{ + //We can't map any offset so we have to obtain system's + //memory granularity + const std::size_t page_size = mapped_region::get_page_size(); + + //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(offset - (offset / page_size) * page_size); + //Update the mapping address + if(address){ + address = static_cast(address) - page_offset; + } + return page_offset; +} + +#if defined (BOOST_INTERPROCESS_WINDOWS) + +inline mapped_region::mapped_region() + : m_base(0), m_size(0), m_page_offset(0), m_mode(read_only) + , m_file_or_mapping_hnd(ipcdetail::invalid_file()) +{} + +template +inline std::size_t mapped_region::page_size_holder::get_page_size() +{ + winapi::system_info info; + get_system_info(&info); + return std::size_t(info.dwAllocationGranularity); +} + +template +inline mapped_region::mapped_region + (const MemoryMappable &mapping + ,mode_t mode + ,offset_t offset + ,std::size_t size + ,const void *address) + : m_base(0), m_size(0), m_page_offset(0), m_mode(mode) + , m_file_or_mapping_hnd(ipcdetail::invalid_file()) +{ + mapping_handle_t mhandle = mapping.get_mapping_handle(); + { + file_handle_t native_mapping_handle = 0; + + //Set accesses + //For "create_file_mapping" + unsigned long protection = 0; + //For "mapviewoffile" + unsigned long map_access = 0; + + switch(mode) + { + case read_only: + case read_private: + protection |= winapi::page_readonly; + map_access |= winapi::file_map_read; + break; + case read_write: + protection |= winapi::page_readwrite; + map_access |= winapi::file_map_write; + break; + case copy_on_write: + protection |= winapi::page_writecopy; + map_access |= winapi::file_map_copy; + break; + default: + { + error_info err(mode_error); + throw interprocess_exception(err); + } + break; + } + + //For file mapping (including emulated shared memory through temporary files), + //the device is a file handle so we need to obtain file's size and call create_file_mapping + //to obtain the mapping handle. + //For files we don't need the file mapping after mapping the memory, as the file is there + //so we'll program the handle close + void * handle_to_close = winapi::invalid_handle_value; + if(!mhandle.is_shm){ + //Create mapping handle + native_mapping_handle = winapi::create_file_mapping + ( ipcdetail::file_handle_from_mapping_handle(mapping.get_mapping_handle()) + , protection, 0, 0, 0); + + //Check if all is correct + if(!native_mapping_handle){ + error_info err = winapi::get_last_error(); + throw interprocess_exception(err); + } + handle_to_close = native_mapping_handle; + } + else{ + //For windows_shared_memory the device handle is already a mapping handle + //and we need to maintain it + native_mapping_handle = mhandle.handle; + } + //RAII handle close on scope exit + const winapi::handle_closer close_handle(handle_to_close); + (void)close_handle; + + const offset_t page_offset = priv_page_offset_addr_fixup(offset, address); + + //Obtain mapping size if user provides 0 size + 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(); + throw interprocess_exception(err); + } + //This can throw + priv_size_from_mapping_size(mapping_size, offset, page_offset, size); + } + + + //Map with new offsets and size + void *base = winapi::map_view_of_file_ex + (native_mapping_handle, + map_access, + offset - page_offset, + static_cast(page_offset + size), + const_cast(address)); + //Check error + if(!base){ + error_info err = winapi::get_last_error(); + throw interprocess_exception(err); + } + + //Calculate new base for the user + m_base = static_cast(base) + page_offset; + m_page_offset = page_offset; + m_size = size; + } + //Windows shared memory needs the duplication of the handle if we want to + //make mapped_region independent from the mappable device + // + //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(); + this->priv_close(); + throw interprocess_exception(err); + } +} + +inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async) +{ + void *addr; + if(!this->priv_flush_param_check(mapping_offset, addr, numbytes)){ + return false; + } + //Flush it all + if(!winapi::flush_view_of_file(addr, numbytes)){ + return false; + } + //m_file_or_mapping_hnd can be a file handle or a mapping handle. + //so flushing file buffers has only sense for files... + else if(async && m_file_or_mapping_hnd != winapi::invalid_handle_value && + winapi::get_file_type(m_file_or_mapping_hnd) == winapi::file_type_disk){ + return winapi::flush_file_buffers(m_file_or_mapping_hnd); + } + return true; +} + +inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back) +{ + void *shrink_page_start; + std::size_t shrink_page_bytes; + if(!this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){ + return false; + } + else if(shrink_page_bytes){ + //In Windows, we can't decommit the storage or release the virtual address space, + //the best we can do is try to remove some memory from the process working set. + //With a bit of luck we can free some physical memory. + unsigned long old_protect_ignored; + bool b_ret = winapi::virtual_unlock(shrink_page_start, shrink_page_bytes) + || (winapi::get_last_error() == winapi::error_not_locked); + (void)old_protect_ignored; + //Change page protection to forbid any further access + b_ret = b_ret && winapi::virtual_protect + (shrink_page_start, shrink_page_bytes, winapi::page_noaccess, old_protect_ignored); + return b_ret; + } + else{ + return true; + } +} + +inline bool mapped_region::advise(advice_types) +{ + //Windows has no madvise/posix_madvise equivalent + return false; +} + +inline void mapped_region::priv_close() +{ + if(m_base){ + void *addr = this->priv_map_address(); + #if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) + mapped_region::destroy_syncs_in_range<0>(addr, m_size); + #endif + winapi::unmap_view_of_file(addr); + m_base = 0; + } + if(m_file_or_mapping_hnd != ipcdetail::invalid_file()){ + winapi::close_handle(m_file_or_mapping_hnd); + m_file_or_mapping_hnd = ipcdetail::invalid_file(); + } +} + +inline void mapped_region::dont_close_on_destruction() +{} + +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) + +inline mapped_region::mapped_region() + : m_base(0), m_size(0), m_page_offset(0), m_mode(read_only), m_is_xsi(false) +{} + +template +inline std::size_t mapped_region::page_size_holder::get_page_size() +{ return std::size_t(sysconf(_SC_PAGESIZE)); } + +template +inline mapped_region::mapped_region + ( const MemoryMappable &mapping + , mode_t mode + , offset_t offset + , std::size_t size + , const void *address) + : m_base(0), m_size(0), m_page_offset(0), m_mode(mode), m_is_xsi(false) +{ + mapping_handle_t map_hnd = mapping.get_mapping_handle(); + + //Some systems dont' support XSI shared memory + #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + if(map_hnd.is_xsi){ + //Get the size + ::shmid_ds xsi_ds; + int ret = ::shmctl(map_hnd.handle, IPC_STAT, &xsi_ds); + if(ret == -1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Compare sizess + if(size == 0){ + size = (std::size_t)xsi_ds.shm_segsz; + } + else if(size != (std::size_t)xsi_ds.shm_segsz){ + error_info err(size_error); + throw interprocess_exception(err); + } + //Calculate flag + int flag = 0; + if(m_mode == read_only){ + flag |= SHM_RDONLY; + } + else if(m_mode != read_write){ + error_info err(mode_error); + throw interprocess_exception(err); + } + //Attach memory + void *base = ::shmat(map_hnd.handle, (void*)address, flag); + if(base == (void*)-1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Update members + m_base = base; + m_size = size; + m_mode = mode; + m_page_offset = 0; + m_is_xsi = true; + return; + } + #endif //ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + + //We calculate the difference between demanded and valid offset + const offset_t page_offset = priv_page_offset_addr_fixup(offset, address); + + if(size == 0){ + struct ::stat buf; + if(0 != fstat(map_hnd.handle, &buf)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //This can throw + priv_size_from_mapping_size(buf.st_size, offset, page_offset, size); + } + + //Create new mapping + int prot = 0; + int flags = + #ifdef MAP_NOSYNC + //Avoid excessive syncing in BSD systems + MAP_NOSYNC; + #else + 0; + #endif + + switch(mode) + { + case read_only: + prot |= PROT_READ; + flags |= MAP_SHARED; + break; + + case read_private: + prot |= (PROT_READ); + flags |= MAP_PRIVATE; + break; + + case read_write: + prot |= (PROT_WRITE | PROT_READ); + flags |= MAP_SHARED; + break; + + case copy_on_write: + prot |= (PROT_WRITE | PROT_READ); + flags |= MAP_PRIVATE; + break; + + default: + { + error_info err(mode_error); + throw interprocess_exception(err); + } + break; + } + + //Map it to the address space + void* base = mmap ( const_cast(address) + , static_cast(page_offset + size) + , prot + , flags + , mapping.get_mapping_handle().handle + , offset - page_offset); + + //Check if mapping was successful + if(base == MAP_FAILED){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + + //Calculate new base for the user + m_base = static_cast(base) + page_offset; + m_page_offset = page_offset; + m_size = size; + + //Check for fixed mapping error + if(address && (base != address)){ + error_info err(busy_error); + this->priv_close(); + throw interprocess_exception(err); + } +} + +inline bool mapped_region::shrink_by(std::size_t bytes, bool from_back) +{ + void *shrink_page_start = 0; + std::size_t shrink_page_bytes = 0; + if(m_is_xsi || !this->priv_shrink_param_check(bytes, from_back, shrink_page_start, shrink_page_bytes)){ + return false; + } + else if(shrink_page_bytes){ + //In UNIX we can decommit and free virtual address space. + return 0 == munmap(shrink_page_start, shrink_page_bytes); + } + else{ + return true; + } +} + +inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes, bool async) +{ + void *addr; + if(m_is_xsi || !this->priv_flush_param_check(mapping_offset, addr, numbytes)){ + return false; + } + //Flush it all + return msync(addr, numbytes, async ? MS_ASYNC : MS_SYNC) == 0; +} + +inline bool mapped_region::advise(advice_types advice) +{ + int unix_advice = 0; + //Modes; 0: none, 2: posix, 1: madvise + const unsigned int mode_none = 0; + const unsigned int mode_padv = 1; + const unsigned int mode_madv = 2; + unsigned int mode = mode_none; + //Choose advice either from POSIX (preferred) or native Unix + switch(advice){ + case advice_normal: + #if defined(POSIX_MADV_NORMAL) + unix_advice = POSIX_MADV_NORMAL; + mode = mode_padv; + #elif defined(MADV_NORMAL) + unix_advice = MADV_NORMAL; + mode = mode_madv; + #endif + break; + case advice_sequential: + #if defined(POSIX_MADV_SEQUENTIAL) + unix_advice = POSIX_MADV_SEQUENTIAL; + mode = mode_padv; + #elif defined(MADV_SEQUENTIAL) + unix_advice = MADV_SEQUENTIAL; + mode = mode_madv; + #endif + break; + case advice_random: + #if defined(POSIX_MADV_RANDOM) + unix_advice = POSIX_MADV_RANDOM; + mode = mode_padv; + #elif defined(MADV_RANDOM) + unix_advice = MADV_RANDOM; + mode = mode_madv; + #endif + break; + case advice_willneed: + #if defined(POSIX_MADV_WILLNEED) + unix_advice = POSIX_MADV_WILLNEED; + mode = mode_padv; + #elif defined(MADV_WILLNEED) + unix_advice = MADV_WILLNEED; + mode = mode_madv; + #endif + break; + case advice_dontneed: + #if defined(POSIX_MADV_DONTNEED) + unix_advice = POSIX_MADV_DONTNEED; + mode = mode_padv; + #elif defined(MADV_DONTNEED) && defined(BOOST_INTERPROCESS_MADV_DONTNEED_HAS_NONDESTRUCTIVE_SEMANTICS) + unix_advice = MADV_DONTNEED; + mode = mode_madv; + #endif + break; + default: + return false; + } + switch(mode){ + #if defined(POSIX_MADV_NORMAL) + case mode_padv: + return 0 == posix_madvise(this->priv_map_address(), this->priv_map_size(), unix_advice); + #endif + #if defined(MADV_NORMAL) + case mode_madv: + return 0 == madvise( + #if defined(BOOST_INTERPROCESS_MADVISE_USES_CADDR_T) + (caddr_t) + #endif + this->priv_map_address(), this->priv_map_size(), unix_advice); + #endif + default: + return false; + + } +} + +inline void mapped_region::priv_close() +{ + if(m_base != 0){ + #ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + if(m_is_xsi){ + int ret = ::shmdt(m_base); + BOOST_ASSERT(ret == 0); + (void)ret; + return; + } + #endif //#ifdef BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS + munmap(this->priv_map_address(), this->priv_map_size()); + m_base = 0; + } +} + +inline void mapped_region::dont_close_on_destruction() +{ m_base = 0; } + +#endif //##if (defined BOOST_INTERPROCESS_WINDOWS) + +template +const std::size_t mapped_region::page_size_holder::PageSize + = mapped_region::page_size_holder::get_page_size(); + +inline std::size_t mapped_region::get_page_size() +{ + if(!page_size_holder<0>::PageSize) + return page_size_holder<0>::get_page_size(); + else + return page_size_holder<0>::PageSize; +} + +inline void mapped_region::swap(mapped_region &other) +{ + ipcdetail::do_swap(this->m_base, other.m_base); + ipcdetail::do_swap(this->m_size, other.m_size); + ipcdetail::do_swap(this->m_page_offset, other.m_page_offset); + ipcdetail::do_swap(this->m_mode, other.m_mode); + #if (defined BOOST_INTERPROCESS_WINDOWS) + ipcdetail::do_swap(this->m_file_or_mapping_hnd, other.m_file_or_mapping_hnd); + #else + ipcdetail::do_swap(this->m_is_xsi, other.m_is_xsi); + #endif +} + +//!No-op functor +struct null_mapped_region_function +{ + bool operator()(void *, std::size_t , bool) const + { return true; } + + std::size_t get_min_size() const + { return 0; } +}; + +/// @endcond + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MAPPED_REGION_HPP + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +#ifndef BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP +#define BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP + +#if defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) +# include +# include + +namespace boost { +namespace interprocess { + +template +inline void mapped_region::destroy_syncs_in_range(const void *addr, std::size_t size) +{ + ipcdetail::sync_handles &handles = + ipcdetail::windows_intermodule_singleton::get(); + handles.destroy_syncs_in_range(addr, size); +} + +} //namespace interprocess { +} //namespace boost { + +#endif //defined(BOOST_INTERPROCESS_WINDOWS) && !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) + +#endif //#ifdef BOOST_INTERPROCESS_MAPPED_REGION_EXT_HPP + +#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + diff --git a/cpp/BoostParts/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/cpp/BoostParts/boost/interprocess/mem_algo/detail/mem_algo_common.hpp new file mode 100644 index 00000000..a6936ec3 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -0,0 +1,591 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_MEM_ALGO_COMMON_HPP +#define BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Implements common operations for memory algorithms. + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +template +class basic_multiallocation_chain + : public boost::container::container_detail:: + basic_multiallocation_chain +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain) + typedef boost::container::container_detail:: + basic_multiallocation_chain base_t; + public: + + basic_multiallocation_chain() + : base_t() + {} + + basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other) + : base_t(::boost::move(static_cast(other))) + {} + + basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other) + { + this->base_t::operator=(::boost::move(static_cast(other))); + return *this; + } + + void *pop_front() + { + return boost::interprocess::ipcdetail::to_raw_pointer(this->base_t::pop_front()); + } +}; + + +//!This class implements several allocation functions shared by different algorithms +//!(aligned allocation, multiple allocation...). +template +class memory_algorithm_common +{ + public: + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef typename MemoryAlgorithm::block_ctrl block_ctrl; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; + typedef memory_algorithm_common this_type; + typedef typename MemoryAlgorithm::size_type size_type; + + static const size_type Alignment = MemoryAlgorithm::Alignment; + static const size_type MinBlockUnits = MemoryAlgorithm::MinBlockUnits; + static const size_type AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes; + static const size_type AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits; + static const size_type BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes; + static const size_type BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits; + static const size_type UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk; + + static void assert_alignment(const void *ptr) + { assert_alignment((std::size_t)ptr); } + + static void assert_alignment(size_type uint_ptr) + { + (void)uint_ptr; + BOOST_ASSERT(uint_ptr % Alignment == 0); + } + + static bool check_alignment(const void *ptr) + { return (((std::size_t)ptr) % Alignment == 0); } + + static size_type ceil_units(size_type size) + { return get_rounded_size(size, Alignment)/Alignment; } + + static size_type floor_units(size_type size) + { return size/Alignment; } + + static size_type multiple_of_units(size_type size) + { return get_rounded_size(size, Alignment); } + + static void allocate_many + (MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { + return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain); + } + + static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain) + { + return this_type::priv_deallocate_many(memory_algo, chain); + } + + static bool calculate_lcm_and_needs_backwards_lcmed + (size_type backwards_multiple, size_type received_size, size_type size_to_achieve, + size_type &lcm_out, size_type &needs_backwards_lcmed_out) + { + // Now calculate lcm_val + size_type max = backwards_multiple; + size_type min = Alignment; + size_type needs_backwards; + size_type needs_backwards_lcmed; + size_type lcm_val; + size_type current_forward; + //Swap if necessary + if(max < min){ + size_type tmp = min; + min = max; + max = tmp; + } + //Check if it's power of two + if((backwards_multiple & (backwards_multiple-1)) == 0){ + if(0 != (size_to_achieve & ((backwards_multiple-1)))){ + return false; + } + + lcm_val = max; + //If we want to use minbytes data to get a buffer between maxbytes + //and minbytes if maxbytes can't be achieved, calculate the + //biggest of all possibilities + current_forward = get_truncated_size_po2(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + BOOST_ASSERT((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = get_rounded_size_po2(needs_backwards, lcm_val); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of alignment + else if((backwards_multiple & (Alignment - 1u)) == 0){ + lcm_val = backwards_multiple; + current_forward = get_truncated_size(received_size, backwards_multiple); + //No need to round needs_backwards because backwards_multiple == lcm_val + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + BOOST_ASSERT((needs_backwards_lcmed & (Alignment - 1u)) == 0); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of the half of the alignmment + else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){ + lcm_val = backwards_multiple*2u; + current_forward = get_truncated_size(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + if(0 != (needs_backwards_lcmed & (Alignment-1))) + //while(0 != (needs_backwards_lcmed & (Alignment-1))) + needs_backwards_lcmed += backwards_multiple; + BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + //Check if it's multiple of the quarter of the alignmment + else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){ + size_type remainder; + lcm_val = backwards_multiple*4u; + current_forward = get_truncated_size(received_size, backwards_multiple); + needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward; + //while(0 != (needs_backwards_lcmed & (Alignment-1))) + //needs_backwards_lcmed += backwards_multiple; + if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){ + if(backwards_multiple & Alignment/2u){ + needs_backwards_lcmed += (remainder)*backwards_multiple; + } + else{ + needs_backwards_lcmed += (4-remainder)*backwards_multiple; + } + } + BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + else{ + lcm_val = lcm(max, min); + } + //If we want to use minbytes data to get a buffer between maxbytes + //and minbytes if maxbytes can't be achieved, calculate the + //biggest of all possibilities + current_forward = get_truncated_size(received_size, backwards_multiple); + needs_backwards = size_to_achieve - current_forward; + BOOST_ASSERT((needs_backwards % backwards_multiple) == 0); + needs_backwards_lcmed = get_rounded_size(needs_backwards, lcm_val); + lcm_out = lcm_val; + needs_backwards_lcmed_out = needs_backwards_lcmed; + return true; + } + + static void allocate_many + ( MemoryAlgorithm *memory_algo + , const size_type *elem_sizes + , size_type n_elements + , size_type sizeof_element + , multiallocation_chain &chain) + { + this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain); + } + + static void* allocate_aligned + (MemoryAlgorithm *memory_algo, size_type nbytes, size_type alignment) + { + + //Ensure power of 2 + if ((alignment & (alignment - size_type(1u))) != 0){ + //Alignment is not power of two + BOOST_ASSERT((alignment & (alignment - size_type(1u))) == 0); + return 0; + } + + size_type real_size; + if(alignment <= Alignment){ + return memory_algo->priv_allocate + (boost::interprocess::allocate_new, nbytes, nbytes, real_size).first; + } + + if(nbytes > UsableByPreviousChunk) + nbytes -= UsableByPreviousChunk; + + //We can find a aligned portion if we allocate a block that has alignment + //nbytes + alignment bytes or more. + size_type minimum_allocation = max_value + (nbytes + alignment, size_type(MinBlockUnits*Alignment)); + //Since we will split that block, we must request a bit more memory + //if the alignment is near the beginning of the buffer, because otherwise, + //there is no space for a new block before the alignment. + // + // ____ Aligned here + // | + // ----------------------------------------------------- + // | MBU | + // ----------------------------------------------------- + size_type request = + minimum_allocation + (2*MinBlockUnits*Alignment - AllocatedCtrlBytes + //prevsize - UsableByPreviousChunk + ); + + //Now allocate the buffer + void *buffer = memory_algo->priv_allocate + (boost::interprocess::allocate_new, request, request, real_size).first; + if(!buffer){ + return 0; + } + else if ((((std::size_t)(buffer)) % alignment) == 0){ + //If we are lucky and the buffer is aligned, just split it and + //return the high part + block_ctrl *first = memory_algo->priv_get_block(buffer); + size_type old_size = first->m_size; + const size_type first_min_units = + 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 + (reinterpret_cast(first) + Alignment*first_min_units); + first->m_size = first_min_units; + second->m_size = old_size - first->m_size; + BOOST_ASSERT(second->m_size >= MinBlockUnits); + memory_algo->priv_mark_new_allocated_block(first); + //memory_algo->priv_tail_size(first, first->m_size); + memory_algo->priv_mark_new_allocated_block(second); + memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(second)); + } + return buffer; + } + + //Buffer not aligned, find the aligned part. + // + // ____ Aligned here + // | + // ----------------------------------------------------- + // | MBU +more | ACB | + // ----------------------------------------------------- + char *pos = reinterpret_cast + (reinterpret_cast(static_cast(buffer) + + //This is the minimum size of (2) + (MinBlockUnits*Alignment - AllocatedCtrlBytes) + + //This is the next MBU for the aligned memory + AllocatedCtrlBytes + + //This is the alignment trick + alignment - 1) & -alignment); + + //Now obtain the address of the blocks + block_ctrl *first = memory_algo->priv_get_block(buffer); + block_ctrl *second = memory_algo->priv_get_block(pos); + BOOST_ASSERT(pos <= (reinterpret_cast(first) + first->m_size*Alignment)); + BOOST_ASSERT(first->m_size >= 2*MinBlockUnits); + BOOST_ASSERT((pos + MinBlockUnits*Alignment - AllocatedCtrlBytes + nbytes*Alignment/Alignment) <= + (reinterpret_cast(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(second) - reinterpret_cast(first))/Alignment; + memory_algo->priv_mark_new_allocated_block(first); + + //Now check if we can create a new buffer in the end + // + // __"second" block + // | __Aligned here + // | | __"third" block + // -----------|-----|-----|------------------------------ + // | MBU +more | ACB | (3) | BCU | + // ----------------------------------------------------- + //This size will be the minimum size to be able to create a + //new block in the end. + const size_type second_min_units = max_value(size_type(MinBlockUnits), + ceil_units(nbytes) + AllocatedCtrlUnits ); + + //Check if we can create a new block (of size MinBlockUnits) in the end of the segment + if((old_size - first->m_size) >= (second_min_units + MinBlockUnits)){ + //Now obtain the address of the end block + block_ctrl *third = new (reinterpret_cast(second) + Alignment*second_min_units)block_ctrl; + second->m_size = second_min_units; + third->m_size = old_size - first->m_size - second->m_size; + 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; + BOOST_ASSERT(second->m_size >= MinBlockUnits); + memory_algo->priv_mark_new_allocated_block(second); + } + + memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(first)); + return memory_algo->priv_get_user_buffer(second); + } + + static bool try_shrink + (MemoryAlgorithm *memory_algo, void *ptr + ,const size_type max_size, const size_type preferred_size + ,size_type &received_size) + { + (void)memory_algo; + //Obtain the real block + block_ctrl *block = memory_algo->priv_get_block(ptr); + size_type old_block_units = (size_type)block->m_size; + + //The block must be marked as allocated + BOOST_ASSERT(memory_algo->priv_is_allocated_block(block)); + + //Check if alignment and block size are right + assert_alignment(ptr); + + //Put this to a safe value + received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; + + //Now translate it to Alignment units + const size_type max_user_units = floor_units(max_size - UsableByPreviousChunk); + const size_type preferred_user_units = ceil_units(preferred_size - UsableByPreviousChunk); + + //Check if rounded max and preferred are possible correct + if(max_user_units < preferred_user_units) + return false; + + //Check if the block is smaller than the requested minimum + size_type old_user_units = old_block_units - AllocatedCtrlUnits; + + if(old_user_units < preferred_user_units) + return false; + + //If the block is smaller than the requested minimum + if(old_user_units == preferred_user_units) + return true; + + size_type shrunk_user_units = + ((BlockCtrlUnits - AllocatedCtrlUnits) >= preferred_user_units) + ? (BlockCtrlUnits - AllocatedCtrlUnits) + : preferred_user_units; + + //Some parameter checks + if(max_user_units < shrunk_user_units) + return false; + + //We must be able to create at least a new empty block + if((old_user_units - shrunk_user_units) < BlockCtrlUnits ){ + return false; + } + + //Update new size + received_size = shrunk_user_units*Alignment + UsableByPreviousChunk; + return true; + } + + static bool shrink + (MemoryAlgorithm *memory_algo, void *ptr + ,const size_type max_size, const size_type preferred_size + ,size_type &received_size) + { + //Obtain the real block + block_ctrl *block = memory_algo->priv_get_block(ptr); + size_type old_block_units = (size_type)block->m_size; + + if(!try_shrink + (memory_algo, ptr, max_size, preferred_size, received_size)){ + return false; + } + + //Check if the old size was just the shrunk size (no splitting) + if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size - UsableByPreviousChunk)) + return true; + + //Now we can just rewrite the size of the old buffer + block->m_size = (received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits; + BOOST_ASSERT(block->m_size >= BlockCtrlUnits); + + //We create the new block + block_ctrl *new_block = reinterpret_cast + (reinterpret_cast(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; + BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits); + memory_algo->priv_mark_new_allocated_block(block); + memory_algo->priv_mark_new_allocated_block(new_block); + memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(new_block)); + return true; + } + + private: + static void priv_allocate_many + ( MemoryAlgorithm *memory_algo + , const size_type *elem_sizes + , size_type n_elements + , size_type sizeof_element + , multiallocation_chain &chain) + { + //Note: sizeof_element == 0 indicates that we want to + //allocate n_elements of the same size "*elem_sizes" + + //Calculate the total size of all requests + size_type total_request_units = 0; + size_type elem_units = 0; + const size_type ptr_size_units = memory_algo->priv_get_total_units(sizeof(void_pointer)); + if(!sizeof_element){ + elem_units = memory_algo->priv_get_total_units(*elem_sizes); + elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; + total_request_units = n_elements*elem_units; + } + else{ + for(size_type i = 0; i < n_elements; ++i){ + if(multiplication_overflows(elem_sizes[i], sizeof_element)){ + total_request_units = 0; + break; + } + elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element); + elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; + if(sum_overflows(total_request_units, elem_units)){ + total_request_units = 0; + break; + } + total_request_units += elem_units; + } + } + + if(total_request_units && !multiplication_overflows(total_request_units, Alignment)){ + size_type low_idx = 0; + while(low_idx < n_elements){ + size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + size_type min_allocation = (!sizeof_element) + ? elem_units + : memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element); + min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + + size_type received_size; + std::pair ret = memory_algo->priv_allocate + (boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0); + if(!ret.first){ + break; + } + + block_ctrl *block = memory_algo->priv_get_block(ret.first); + size_type received_units = (size_type)block->m_size; + char *block_address = reinterpret_cast(block); + + size_type total_used_units = 0; + while(total_used_units < received_units){ + if(sizeof_element){ + elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element); + elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units; + } + if(total_used_units + elem_units > received_units) + break; + total_request_units -= elem_units; + //This is the position where the new block must be created + block_ctrl *new_block = reinterpret_cast(block_address); + assert_alignment(new_block); + + //The last block should take all the remaining space + if((low_idx + 1) == n_elements || + (total_used_units + elem_units + + ((!sizeof_element) + ? elem_units + : std::max(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; + memory_algo->priv_mark_new_allocated_block(new_block); + + //If the remaining units are bigger than needed and we can + //split it obtaining a new free memory block do it. + if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){ + size_type shrunk_received; + size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; + bool shrink_ok = shrink + (memory_algo + ,memory_algo->priv_get_user_buffer(new_block) + ,shrunk_request + ,shrunk_request + ,shrunk_received); + (void)shrink_ok; + //Shrink must always succeed with passed parameters + BOOST_ASSERT(shrink_ok); + //Some sanity checks + BOOST_ASSERT(shrunk_request == shrunk_received); + BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits)); + //"new_block->m_size" must have been reduced to elem_units by "shrink" + BOOST_ASSERT(new_block->m_size == elem_units); + //Now update the total received units with the reduction + received_units = elem_units + total_used_units; + } + } + else{ + new_block->m_size = elem_units; + memory_algo->priv_mark_new_allocated_block(new_block); + } + + block_address += new_block->m_size*Alignment; + total_used_units += (size_type)new_block->m_size; + //Check we have enough room to overwrite the intrusive pointer + BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer)); + void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0); + chain.push_back(p); + ++low_idx; + } + //Sanity check + BOOST_ASSERT(total_used_units == received_units); + } + + if(low_idx != n_elements){ + priv_deallocate_many(memory_algo, chain); + } + } + } + + static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain) + { + while(!chain.empty()){ + memory_algo->priv_deallocate(to_raw_pointer(chain.pop_front())); + } + } +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP diff --git a/cpp/BoostParts/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/cpp/BoostParts/boost/interprocess/mem_algo/rbtree_best_fit.hpp new file mode 100644 index 00000000..7853ede8 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -0,0 +1,1413 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_MEM_ALGO_RBTREE_BEST_FIT_HPP +#define BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +//#define BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP +//to maintain ABI compatible with the original version +//ABI had to be updated to fix compatibility issues when +//sharing shared memory between 32 adn 64 bit processes. + +//!\file +//!Describes a best-fit algorithm based in an intrusive red-black tree used to allocate +//!objects in shared memory. This class is intended as a base class for single segment +//!and multi-segment implementations. + +namespace boost { +namespace interprocess { + +//!This class implements an algorithm that stores the free nodes in a red-black tree +//!to have logarithmic search/insert times. +template +class rbtree_best_fit +{ + /// @cond + //Non-copyable + rbtree_best_fit(); + rbtree_best_fit(const rbtree_best_fit &); + rbtree_best_fit &operator=(const rbtree_best_fit &); + + private: + struct block_ctrl; + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type block_ctrl_ptr; + + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type char_ptr; + + /// @endcond + + public: + //!Shared mutex family used for the rest of the Interprocess framework + typedef MutexFamily mutex_family; + //!Pointer type to be used with the rest of the Interprocess framework + typedef VoidPointer void_pointer; + typedef ipcdetail::basic_multiallocation_chain multiallocation_chain; + + typedef typename boost::intrusive::pointer_traits::difference_type difference_type; + typedef typename boost::make_unsigned::type size_type; + + /// @cond + + private: + + typedef typename bi::make_set_base_hook + < bi::void_pointer + , bi::optimize_size + , bi::link_mode >::type TreeHook; + + struct SizeHolder + { + //!This block's memory size (including block_ctrl + //!header) in Alignment units + size_type m_prev_size : sizeof(size_type)*CHAR_BIT; + size_type m_size : sizeof(size_type)*CHAR_BIT - 2; + size_type m_prev_allocated : 1; + size_type m_allocated : 1; + }; + + //!Block control structure + struct block_ctrl + : public SizeHolder, public TreeHook + { + block_ctrl() + { this->m_size = 0; this->m_allocated = 0, this->m_prev_allocated = 0; } + + friend bool operator<(const block_ctrl &a, const block_ctrl &b) + { return a.m_size < b.m_size; } + friend bool operator==(const block_ctrl &a, const block_ctrl &b) + { return a.m_size == b.m_size; } + }; + + struct size_block_ctrl_compare + { + bool operator()(size_type size, const block_ctrl &block) const + { return size < block.m_size; } + + bool operator()(const block_ctrl &block, size_type size) const + { return block.m_size < size; } + }; + + //!Shared mutex to protect memory allocate/deallocate + typedef typename MutexFamily::mutex_type mutex_type; + typedef typename bi::make_multiset + >::type Imultiset; + + typedef typename Imultiset::iterator imultiset_iterator; + + //!This struct includes needed data and derives from + //!mutex_type to allow EBO when using null mutex_type + struct header_t : public mutex_type + { + Imultiset m_imultiset; + + //!The extra size required by the segment + size_type m_extra_hdr_bytes; + //!Allocated bytes for internal checking + size_type m_allocated; + //!The size of the memory segment + size_type m_size; + } m_header; + + friend class ipcdetail::memory_algorithm_common; + + typedef ipcdetail::memory_algorithm_common algo_impl_t; + + public: + /// @endcond + + //!Constructor. "size" is the total size of the managed memory segment, + //!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(rbtree_best_fit) + //!offset that the allocator should not use at all. + rbtree_best_fit (size_type size, size_type extra_hdr_bytes); + + //!Destructor. + ~rbtree_best_fit(); + + //!Obtains the minimum size needed by the algorithm + static size_type get_min_size (size_type extra_hdr_bytes); + + //Functions for single segment management + + //!Allocates bytes, returns 0 if there is not more memory + void* allocate (size_type nbytes); + + /// @cond + + //Experimental. Dont' use + + //!Multiple element allocation, same size + void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain); + } + + //!Multiple element allocation, different size + void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain); + } + + //!Multiple element allocation, different size + void deallocate_many(multiallocation_chain &chain); + + /// @endcond + + //!Deallocates previously allocated bytes + void deallocate (void *addr); + + //!Returns the size of the memory segment + size_type get_size() const; + + //!Returns the number of free bytes of the segment + size_type get_free_memory() const; + + //!Initializes to zero all the memory that's not in use. + //!This function is normally used for security reasons. + void zero_free_memory(); + + //!Increases managed memory in + //!extra_size bytes more + void grow(size_type extra_size); + + //!Decreases managed memory as much as possible + void shrink_to_fit(); + + //!Returns true if all allocated memory has been deallocated + bool all_memory_deallocated(); + + //!Makes an internal sanity check + //!and returns true if success + bool check_sanity(); + + template + std::pair + allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type preferred_size,size_type &received_size, + T *reuse_ptr = 0); + + std::pair + raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_object, + size_type preferred_object,size_type &received_object, + void *reuse_ptr = 0, size_type sizeof_object = 1); + + //!Returns the size of the buffer previously allocated pointed by ptr + size_type size(const void *ptr) const; + + //!Allocates aligned bytes, returns 0 if there is not more memory. + //!Alignment must be power of 2 + void* allocate_aligned (size_type nbytes, size_type alignment); + + /// @cond + private: + static size_type priv_first_block_offset_from_this(const void *this_ptr, size_type extra_hdr_bytes); + + block_ctrl *priv_first_block(); + + block_ctrl *priv_end_block(); + + std::pair + priv_allocation_command(boost::interprocess::allocation_type command, size_type limit_size, + size_type preferred_size,size_type &received_size, + void *reuse_ptr, size_type sizeof_object); + + + //!Real allocation algorithm with min allocation option + std::pair priv_allocate(boost::interprocess::allocation_type command + ,size_type limit_size + ,size_type preferred_size + ,size_type &received_size + ,void *reuse_ptr = 0 + ,size_type backwards_multiple = 1); + + //!Obtains the block control structure of the user buffer + static block_ctrl *priv_get_block(const void *ptr); + + //!Obtains the pointer returned to the user from the block control + static void *priv_get_user_buffer(const block_ctrl *block); + + //!Returns the number of total units that a user buffer + //!of "userbytes" bytes really occupies (including header) + static size_type priv_get_total_units(size_type userbytes); + + //!Real expand function implementation + bool priv_expand(void *ptr + ,const size_type min_size, const size_type preferred_size + ,size_type &received_size); + + //!Real expand to both sides implementation + void* priv_expand_both_sides(boost::interprocess::allocation_type command + ,size_type min_size + ,size_type preferred_size + ,size_type &received_size + ,void *reuse_ptr + ,bool only_preferred_backwards + ,size_type backwards_multiple); + + //!Returns true if the previous block is allocated + bool priv_is_prev_allocated(block_ctrl *ptr); + + //!Get a pointer of the "end" block from the first block of the segment + static block_ctrl * priv_end_block(block_ctrl *first_segment_block); + + //!Get a pointer of the "first" block from the end block of the segment + static block_ctrl * priv_first_block(block_ctrl *end_segment_block); + + //!Get poitner of the previous block (previous block must be free) + static block_ctrl * priv_prev_block(block_ctrl *ptr); + + //!Get the size in the tail of the previous block + static block_ctrl * priv_next_block(block_ctrl *ptr); + + //!Check if this block is free (not allocated) + bool priv_is_allocated_block(block_ctrl *ptr); + + //!Marks the block as allocated + void priv_mark_as_allocated_block(block_ctrl *ptr); + + //!Marks the block as allocated + void priv_mark_new_allocated_block(block_ctrl *ptr) + { return priv_mark_as_allocated_block(ptr); } + + //!Marks the block as allocated + void priv_mark_as_free_block(block_ctrl *ptr); + + //!Checks if block has enough memory and splits/unlinks the block + //!returning the address to the users + void* priv_check_and_allocate(size_type units + ,block_ctrl* block + ,size_type &received_size); + //!Real deallocation algorithm + void priv_deallocate(void *addr); + + //!Makes a new memory portion available for allocation + void priv_add_segment(void *addr, size_type size); + + public: + + static const size_type Alignment = !MemAlignment + ? size_type(::boost::alignment_of< ::boost::detail::max_align>::value) + : size_type(MemAlignment) + ; + + private: + //Due to embedded bits in size, Alignment must be at least 4 + BOOST_STATIC_ASSERT((Alignment >= 4)); + //Due to rbtree size optimizations, Alignment must have at least pointer alignment + BOOST_STATIC_ASSERT((Alignment >= ::boost::alignment_of::value)); + static const size_type AlignmentMask = (Alignment - 1); + static const size_type BlockCtrlBytes = ipcdetail::ct_rounded_size::value; + static const size_type BlockCtrlUnits = BlockCtrlBytes/Alignment; + static const size_type AllocatedCtrlBytes = ipcdetail::ct_rounded_size::value; + static const size_type AllocatedCtrlUnits = AllocatedCtrlBytes/Alignment; + static const size_type EndCtrlBlockBytes = ipcdetail::ct_rounded_size::value; + static const size_type EndCtrlBlockUnits = EndCtrlBlockBytes/Alignment; + static const size_type MinBlockUnits = BlockCtrlUnits; + static const size_type UsableByPreviousChunk = sizeof(size_type); + + //Make sure the maximum alignment is power of two + BOOST_STATIC_ASSERT((0 == (Alignment & (Alignment - size_type(1u))))); + /// @endcond + public: + static const size_type PayloadPerAllocation = AllocatedCtrlBytes - UsableByPreviousChunk; +}; + +/// @cond + +template +inline typename rbtree_best_fit::size_type + rbtree_best_fit + ::priv_first_block_offset_from_this(const void *this_ptr, size_type extra_hdr_bytes) +{ + size_type uint_this = (std::size_t)this_ptr; + size_type main_hdr_end = uint_this + sizeof(rbtree_best_fit) + extra_hdr_bytes; + size_type aligned_main_hdr_end = ipcdetail::get_rounded_size(main_hdr_end, Alignment); + size_type block1_off = aligned_main_hdr_end - uint_this; + algo_impl_t::assert_alignment(aligned_main_hdr_end); + algo_impl_t::assert_alignment(uint_this + block1_off); + return block1_off; +} + +template +void rbtree_best_fit:: + priv_add_segment(void *addr, size_type segment_size) +{ + //Check alignment + algo_impl_t::check_alignment(addr); + //Check size + BOOST_ASSERT(segment_size >= (BlockCtrlBytes + EndCtrlBlockBytes)); + + //Initialize the first big block and the "end" node + block_ctrl *first_big_block = new(addr)block_ctrl; + first_big_block->m_size = segment_size/Alignment - EndCtrlBlockUnits; + BOOST_ASSERT(first_big_block->m_size >= BlockCtrlUnits); + + //The "end" node is just a node of size 0 with the "end" bit set + block_ctrl *end_block = static_cast + (new (reinterpret_cast(addr) + first_big_block->m_size*Alignment)SizeHolder); + + //This will overwrite the prev part of the "end" node + priv_mark_as_free_block (first_big_block); + #ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP + first_big_block->m_prev_size = end_block->m_size = + (reinterpret_cast(first_big_block) - reinterpret_cast(end_block))/Alignment; + #else + first_big_block->m_prev_size = end_block->m_size = + (reinterpret_cast(end_block) - reinterpret_cast(first_big_block))/Alignment; + #endif + end_block->m_allocated = 1; + first_big_block->m_prev_allocated = 1; + + BOOST_ASSERT(priv_next_block(first_big_block) == end_block); + BOOST_ASSERT(priv_prev_block(end_block) == first_big_block); + BOOST_ASSERT(priv_first_block() == first_big_block); + BOOST_ASSERT(priv_end_block() == end_block); + + //Some check to validate the algorithm, since it makes some assumptions + //to optimize the space wasted in bookkeeping: + + //Check that the sizes of the header are placed before the rbtree + BOOST_ASSERT(static_cast(static_cast(first_big_block)) + < static_cast(static_cast(first_big_block))); + //Insert it in the intrusive containers + m_header.m_imultiset.insert(*first_big_block); +} + +template +inline typename rbtree_best_fit::block_ctrl * + rbtree_best_fit + ::priv_first_block() +{ + size_type block1_off = priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); + return reinterpret_cast(reinterpret_cast(this) + block1_off); +} + +template +inline typename rbtree_best_fit::block_ctrl * + rbtree_best_fit + ::priv_end_block() +{ + size_type block1_off = priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); + const size_type original_first_block_size = m_header.m_size/Alignment*Alignment - block1_off/Alignment*Alignment - EndCtrlBlockBytes; + block_ctrl *end_block = reinterpret_cast + (reinterpret_cast(this) + block1_off + original_first_block_size); + return end_block; +} + +template +inline rbtree_best_fit:: + rbtree_best_fit(size_type segment_size, size_type extra_hdr_bytes) +{ + //Initialize the header + m_header.m_allocated = 0; + m_header.m_size = segment_size; + m_header.m_extra_hdr_bytes = extra_hdr_bytes; + + //Now write calculate the offset of the first big block that will + //cover the whole segment + BOOST_ASSERT(get_min_size(extra_hdr_bytes) <= segment_size); + size_type block1_off = priv_first_block_offset_from_this(this, extra_hdr_bytes); + priv_add_segment(reinterpret_cast(this) + block1_off, segment_size - block1_off); +} + +template +inline rbtree_best_fit::~rbtree_best_fit() +{ + //There is a memory leak! +// BOOST_ASSERT(m_header.m_allocated == 0); +// BOOST_ASSERT(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root)); +} + +template +void rbtree_best_fit::grow(size_type extra_size) +{ + //Get the address of the first block + block_ctrl *first_block = priv_first_block(); + block_ctrl *old_end_block = priv_end_block(); + size_type old_border_offset = (size_type)(reinterpret_cast(old_end_block) - + reinterpret_cast(this)) + EndCtrlBlockBytes; + + //Update managed buffer's size + m_header.m_size += extra_size; + + //We need at least MinBlockUnits blocks to create a new block + if((m_header.m_size - old_border_offset) < MinBlockUnits){ + return; + } + + //Now create a new block between the old end and the new end + size_type align_offset = (m_header.m_size - old_border_offset)/Alignment; + block_ctrl *new_end_block = reinterpret_cast + (reinterpret_cast(old_end_block) + align_offset*Alignment); + + //the last and first block are special: + //new_end_block->m_size & first_block->m_prev_size store the absolute value + //between them + new_end_block->m_allocated = 1; + #ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP + new_end_block->m_size = (reinterpret_cast(first_block) - + reinterpret_cast(new_end_block))/Alignment; + #else + new_end_block->m_size = (reinterpret_cast(new_end_block) - + reinterpret_cast(first_block))/Alignment; + #endif + first_block->m_prev_size = new_end_block->m_size; + first_block->m_prev_allocated = 1; + BOOST_ASSERT(new_end_block == priv_end_block()); + + //The old end block is the new block + block_ctrl *new_block = old_end_block; + new_block->m_size = (reinterpret_cast(new_end_block) - + reinterpret_cast(new_block))/Alignment; + BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits); + priv_mark_as_allocated_block(new_block); + BOOST_ASSERT(priv_next_block(new_block) == new_end_block); + + m_header.m_allocated += (size_type)new_block->m_size*Alignment; + + //Now deallocate the newly created block + this->priv_deallocate(priv_get_user_buffer(new_block)); +} + +template +void rbtree_best_fit::shrink_to_fit() +{ + //Get the address of the first block + block_ctrl *first_block = priv_first_block(); + algo_impl_t::assert_alignment(first_block); + + //block_ctrl *old_end_block = priv_end_block(first_block); + block_ctrl *old_end_block = priv_end_block(); + algo_impl_t::assert_alignment(old_end_block); + size_type old_end_block_size = old_end_block->m_size; + + void *unique_buffer = 0; + block_ctrl *last_block; + //Check if no memory is allocated between the first and last block + if(priv_next_block(first_block) == old_end_block){ + //If so check if we can allocate memory + size_type ignore; + unique_buffer = priv_allocate(boost::interprocess::allocate_new, 0, 0, ignore).first; + //If not, return, we can't shrink + if(!unique_buffer) + return; + //If we can, mark the position just after the new allocation as the new end + algo_impl_t::assert_alignment(unique_buffer); + block_ctrl *unique_block = priv_get_block(unique_buffer); + BOOST_ASSERT(priv_is_allocated_block(unique_block)); + algo_impl_t::assert_alignment(unique_block); + last_block = priv_next_block(unique_block); + BOOST_ASSERT(!priv_is_allocated_block(last_block)); + algo_impl_t::assert_alignment(last_block); + } + else{ + //If memory is allocated, check if the last block is allocated + if(priv_is_prev_allocated(old_end_block)) + return; + //If not, mark last block after the free block + last_block = priv_prev_block(old_end_block); + } + + size_type last_block_size = last_block->m_size; + + //Erase block from the free tree, since we will erase it + m_header.m_imultiset.erase(Imultiset::s_iterator_to(*last_block)); + + size_type shrunk_border_offset = (size_type)(reinterpret_cast(last_block) - + reinterpret_cast(this)) + EndCtrlBlockBytes; + + block_ctrl *new_end_block = last_block; + algo_impl_t::assert_alignment(new_end_block); + + //Write new end block attributes + #ifdef BOOST_INTERPROCESS_RBTREE_BEST_FIT_ABI_V1_HPP + new_end_block->m_size = first_block->m_prev_size = + (reinterpret_cast(first_block) - reinterpret_cast(new_end_block))/Alignment; + #else + new_end_block->m_size = first_block->m_prev_size = + (reinterpret_cast(new_end_block) - reinterpret_cast(first_block))/Alignment; + #endif + + new_end_block->m_allocated = 1; + (void)last_block_size; + (void)old_end_block_size; + BOOST_ASSERT(new_end_block->m_size == (old_end_block_size - last_block_size)); + + //Update managed buffer's size + m_header.m_size = shrunk_border_offset; + BOOST_ASSERT(priv_end_block() == new_end_block); + if(unique_buffer) + priv_deallocate(unique_buffer); +} + +template +inline typename rbtree_best_fit::size_type +rbtree_best_fit::get_size() const +{ return m_header.m_size; } + +template +typename rbtree_best_fit::size_type +rbtree_best_fit::get_free_memory() const +{ + return m_header.m_size - m_header.m_allocated - + priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); +} + +template +typename rbtree_best_fit::size_type +rbtree_best_fit:: + get_min_size (size_type extra_hdr_bytes) +{ + return (algo_impl_t::ceil_units(sizeof(rbtree_best_fit)) + + algo_impl_t::ceil_units(extra_hdr_bytes) + + MinBlockUnits + EndCtrlBlockUnits)*Alignment; +} + +template +inline bool rbtree_best_fit:: + all_memory_deallocated() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + size_type block1_off = + priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); + + return m_header.m_allocated == 0 && + m_header.m_imultiset.begin() != m_header.m_imultiset.end() && + (++m_header.m_imultiset.begin()) == m_header.m_imultiset.end() + && m_header.m_imultiset.begin()->m_size == + (m_header.m_size - block1_off - EndCtrlBlockBytes)/Alignment; +} + +template +bool rbtree_best_fit:: + check_sanity() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + imultiset_iterator ib(m_header.m_imultiset.begin()), ie(m_header.m_imultiset.end()); + + size_type free_memory = 0; + + //Iterate through all blocks obtaining their size + for(; ib != ie; ++ib){ + free_memory += (size_type)ib->m_size*Alignment; + algo_impl_t::assert_alignment(&*ib); + if(!algo_impl_t::check_alignment(&*ib)) + return false; + } + + //Check allocated bytes are less than size + if(m_header.m_allocated > m_header.m_size){ + return false; + } + + size_type block1_off = + priv_first_block_offset_from_this(this, m_header.m_extra_hdr_bytes); + + //Check free bytes are less than size + if(free_memory > (m_header.m_size - block1_off)){ + return false; + } + return true; +} + +template +inline void* rbtree_best_fit:: + allocate(size_type nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + size_type ignore; + void * ret = priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; + return ret; +} + +template +inline void* rbtree_best_fit:: + allocate_aligned(size_type nbytes, size_type alignment) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_aligned(this, nbytes, alignment); +} + +template +template +inline std::pair rbtree_best_fit:: + allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type preferred_size,size_type &received_size, + T *reuse_ptr) +{ + std::pair ret = priv_allocation_command + (command, limit_size, preferred_size, received_size, static_cast(reuse_ptr), sizeof(T)); + + BOOST_ASSERT(0 == ((std::size_t)ret.first % ::boost::alignment_of::value)); + return std::pair(static_cast(ret.first), ret.second); +} + +template +inline std::pair rbtree_best_fit:: + raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects, + size_type preferred_objects,size_type &received_objects, + void *reuse_ptr, size_type sizeof_object) +{ + if(!sizeof_object) + return std::pair(static_cast(0), false); + if(command & boost::interprocess::try_shrink_in_place){ + bool success = algo_impl_t::try_shrink + ( this, reuse_ptr, limit_objects*sizeof_object + , preferred_objects*sizeof_object, received_objects); + received_objects /= sizeof_object; + return std::pair ((success ? reuse_ptr : 0), true); + } + return priv_allocation_command + (command, limit_objects, preferred_objects, received_objects, reuse_ptr, sizeof_object); +} + + +template +inline std::pair rbtree_best_fit:: + priv_allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type preferred_size,size_type &received_size, + void *reuse_ptr, size_type sizeof_object) +{ + std::pair ret; + size_type max_count = m_header.m_size/sizeof_object; + if(limit_size > max_count || preferred_size > max_count){ + ret.first = 0; return ret; + } + size_type l_size = limit_size*sizeof_object; + size_type p_size = preferred_size*sizeof_object; + size_type r_size; + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + ret = priv_allocate(command, l_size, p_size, r_size, reuse_ptr, sizeof_object); + } + received_size = r_size/sizeof_object; + return ret; +} + +template +typename rbtree_best_fit::size_type +rbtree_best_fit:: + size(const void *ptr) const +{ + //We need no synchronization since this block's size is not going + //to be modified by anyone else + //Obtain the real size of the block + return ((size_type)priv_get_block(ptr)->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; +} + +template +inline void rbtree_best_fit::zero_free_memory() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + imultiset_iterator ib(m_header.m_imultiset.begin()), ie(m_header.m_imultiset.end()); + + //Iterate through all blocks obtaining their size + while(ib != ie){ + //Just clear user the memory part reserved for the user + volatile char *ptr = reinterpret_cast(&*ib) + BlockCtrlBytes; + size_type s = (size_type)ib->m_size*Alignment - BlockCtrlBytes; + while(s--){ + *ptr++ = 0; + } + + //This surprisingly is optimized out by Visual C++ 7.1 in release mode! + //std::memset( reinterpret_cast(&*ib) + BlockCtrlBytes + // , 0 + // , ib->m_size*Alignment - BlockCtrlBytes); + ++ib; + } +} + +template +void* rbtree_best_fit:: + priv_expand_both_sides(boost::interprocess::allocation_type command + ,size_type min_size + ,size_type preferred_size + ,size_type &received_size + ,void *reuse_ptr + ,bool only_preferred_backwards + ,size_type backwards_multiple) +{ + algo_impl_t::assert_alignment(reuse_ptr); + if(command & boost::interprocess::expand_fwd){ + if(priv_expand(reuse_ptr, min_size, preferred_size, received_size)) + return reuse_ptr; + } + else{ + received_size = this->size(reuse_ptr); + if(received_size >= preferred_size || received_size >= min_size) + return reuse_ptr; + } + + if(backwards_multiple){ + BOOST_ASSERT(0 == (min_size % backwards_multiple)); + BOOST_ASSERT(0 == (preferred_size % backwards_multiple)); + } + + if(command & boost::interprocess::expand_bwd){ + //Obtain the real size of the block + block_ctrl *reuse = priv_get_block(reuse_ptr); + + //Sanity check + //BOOST_ASSERT(reuse->m_size == priv_tail_size(reuse)); + algo_impl_t::assert_alignment(reuse); + + block_ctrl *prev_block; + + //If the previous block is not free, there is nothing to do + if(priv_is_prev_allocated(reuse)){ + return 0; + } + + prev_block = priv_prev_block(reuse); + BOOST_ASSERT(!priv_is_allocated_block(prev_block)); + + //Some sanity checks + BOOST_ASSERT(prev_block->m_size == reuse->m_prev_size); + algo_impl_t::assert_alignment(prev_block); + + size_type needs_backwards_aligned; + size_type lcm; + if(!algo_impl_t::calculate_lcm_and_needs_backwards_lcmed + ( backwards_multiple + , received_size + , only_preferred_backwards ? preferred_size : min_size + , lcm, needs_backwards_aligned)){ + return 0; + } + + //Check if previous block has enough size + if(size_type(prev_block->m_size*Alignment) >= needs_backwards_aligned){ + //Now take all next space. This will succeed + if(command & boost::interprocess::expand_fwd){ + size_type received_size2; + if(!priv_expand(reuse_ptr, received_size, received_size, received_size2)){ + BOOST_ASSERT(0); + } + BOOST_ASSERT(received_size = received_size2); + } + //We need a minimum size to split the previous one + if(prev_block->m_size >= (needs_backwards_aligned/Alignment + BlockCtrlUnits)){ + block_ctrl *new_block = reinterpret_cast + (reinterpret_cast(reuse) - needs_backwards_aligned); + + //Free old previous buffer + new_block->m_size = + AllocatedCtrlUnits + (needs_backwards_aligned + (received_size - UsableByPreviousChunk))/Alignment; + BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits); + priv_mark_as_allocated_block(new_block); + + prev_block->m_size = (reinterpret_cast(new_block) - + reinterpret_cast(prev_block))/Alignment; + BOOST_ASSERT(prev_block->m_size >= BlockCtrlUnits); + priv_mark_as_free_block(prev_block); + + //Update the old previous block in the free blocks tree + //If the new size fulfills tree invariants do nothing, + //otherwise erase() + insert() + { + imultiset_iterator prev_block_it(Imultiset::s_iterator_to(*prev_block)); + imultiset_iterator was_smaller_it(prev_block_it); + if(prev_block_it != m_header.m_imultiset.begin() && + (--(was_smaller_it = prev_block_it))->m_size > prev_block->m_size){ + m_header.m_imultiset.erase(prev_block_it); + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *prev_block); + } + } + + received_size = needs_backwards_aligned + received_size; + m_header.m_allocated += needs_backwards_aligned; + + //Check alignment + algo_impl_t::assert_alignment(new_block); + + //If the backwards expansion has remaining bytes in the + //first bytes, fill them with a pattern + void *p = priv_get_user_buffer(new_block); + void *user_ptr = reinterpret_cast(p); + BOOST_ASSERT((static_cast(reuse_ptr) - static_cast(user_ptr)) % backwards_multiple == 0); + algo_impl_t::assert_alignment(user_ptr); + return user_ptr; + } + //Check if there is no place to create a new block and + //the whole new block is multiple of the backwards expansion multiple + else if(prev_block->m_size >= needs_backwards_aligned/Alignment && + 0 == ((prev_block->m_size*Alignment) % lcm)) { + //Erase old previous block, since we will change it + m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block)); + + //Just merge the whole previous block + //prev_block->m_size*Alignment is multiple of lcm (and backwards_multiple) + received_size = received_size + (size_type)prev_block->m_size*Alignment; + + m_header.m_allocated += (size_type)prev_block->m_size*Alignment; + //Now update sizes + prev_block->m_size = prev_block->m_size + reuse->m_size; + BOOST_ASSERT(prev_block->m_size >= BlockCtrlUnits); + priv_mark_as_allocated_block(prev_block); + + //If the backwards expansion has remaining bytes in the + //first bytes, fill them with a pattern + void *user_ptr = priv_get_user_buffer(prev_block); + BOOST_ASSERT((static_cast(reuse_ptr) - static_cast(user_ptr)) % backwards_multiple == 0); + algo_impl_t::assert_alignment(user_ptr); + return user_ptr; + } + else{ + //Alignment issues + } + } + } + return 0; +} + +template +inline void rbtree_best_fit:: + deallocate_many(typename rbtree_best_fit::multiallocation_chain &chain) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + algo_impl_t::deallocate_many(this, chain); +} + +template +std::pair rbtree_best_fit:: + priv_allocate(boost::interprocess::allocation_type command + ,size_type limit_size + ,size_type preferred_size + ,size_type &received_size + ,void *reuse_ptr + ,size_type backwards_multiple) +{ + //Remove me. Forbid backwards allocation + //command &= (~boost::interprocess::expand_bwd); + + if(command & boost::interprocess::shrink_in_place){ + bool success = + algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size); + return std::pair ((success ? reuse_ptr : 0), true); + } + + typedef std::pair return_type; + received_size = 0; + + if(limit_size > preferred_size) + return return_type(static_cast(0), false); + + //Number of units to request (including block_ctrl header) + size_type preferred_units = priv_get_total_units(preferred_size); + + //Number of units to request (including block_ctrl header) + size_type limit_units = priv_get_total_units(limit_size); + + //Expand in place + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ + void *ret = priv_expand_both_sides + (command, limit_size, preferred_size, received_size, reuse_ptr, true, backwards_multiple); + if(ret) + return return_type(ret, true); + } + + if(command & boost::interprocess::allocate_new){ + size_block_ctrl_compare comp; + imultiset_iterator it(m_header.m_imultiset.lower_bound(preferred_units, comp)); + + if(it != m_header.m_imultiset.end()){ + return return_type(this->priv_check_and_allocate + (preferred_units, ipcdetail::to_raw_pointer(&*it), received_size), false); + } + + if(it != m_header.m_imultiset.begin()&& + (--it)->m_size >= limit_units){ + return return_type(this->priv_check_and_allocate + (it->m_size, ipcdetail::to_raw_pointer(&*it), received_size), false); + } + } + + + //Now try to expand both sides with min size + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ + return return_type(priv_expand_both_sides + (command, limit_size, preferred_size, received_size, reuse_ptr, false, backwards_multiple), true); + } + + return return_type(static_cast(0), false); +} + +template +inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_get_block(const void *ptr) +{ + return const_cast + (reinterpret_cast + (reinterpret_cast(ptr) - AllocatedCtrlBytes)); +} + +template +inline +void *rbtree_best_fit:: + priv_get_user_buffer(const typename rbtree_best_fit::block_ctrl *block) +{ return const_cast(reinterpret_cast(block) + AllocatedCtrlBytes); } + +template +inline typename rbtree_best_fit::size_type +rbtree_best_fit:: + priv_get_total_units(size_type userbytes) +{ + if(userbytes < UsableByPreviousChunk) + userbytes = UsableByPreviousChunk; + size_type units = ipcdetail::get_rounded_size(userbytes - UsableByPreviousChunk, Alignment)/Alignment + AllocatedCtrlUnits; + if(units < BlockCtrlUnits) units = BlockCtrlUnits; + return units; +} + +template +bool rbtree_best_fit:: + priv_expand (void *ptr + ,const size_type min_size + ,const size_type preferred_size + ,size_type &received_size) +{ + //Obtain the real size of the block + block_ctrl *block = priv_get_block(ptr); + size_type old_block_units = block->m_size; + + //The block must be marked as allocated and the sizes must be equal + BOOST_ASSERT(priv_is_allocated_block(block)); + //BOOST_ASSERT(old_block_units == priv_tail_size(block)); + + //Put this to a safe value + received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; + if(received_size >= preferred_size || received_size >= min_size) + return true; + + //Now translate it to Alignment units + const size_type min_user_units = algo_impl_t::ceil_units(min_size - UsableByPreviousChunk); + const size_type preferred_user_units = algo_impl_t::ceil_units(preferred_size - UsableByPreviousChunk); + + //Some parameter checks + BOOST_ASSERT(min_user_units <= preferred_user_units); + + block_ctrl *next_block; + + if(priv_is_allocated_block(next_block = priv_next_block(block))){ + return received_size >= min_size ? true : false; + } + algo_impl_t::assert_alignment(next_block); + + //Is "block" + "next_block" big enough? + const size_type merged_units = old_block_units + (size_type)next_block->m_size; + + //Now get the expansion size + const size_type merged_user_units = merged_units - AllocatedCtrlUnits; + + if(merged_user_units < min_user_units){ + received_size = merged_units*Alignment - UsableByPreviousChunk; + return false; + } + + //Now get the maximum size the user can allocate + size_type intended_user_units = (merged_user_units < preferred_user_units) ? + merged_user_units : preferred_user_units; + + //These are total units of the merged block (supposing the next block can be split) + const size_type intended_units = AllocatedCtrlUnits + intended_user_units; + + //Check if we can split the next one in two parts + if((merged_units - intended_units) >= BlockCtrlUnits){ + //This block is bigger than needed, split it in + //two blocks, the first one will be merged and + //the second's size will be the remaining space + BOOST_ASSERT(next_block->m_size == priv_next_block(next_block)->m_prev_size); + const size_type rem_units = merged_units - intended_units; + + //Check if we we need to update the old next block in the free blocks tree + //If the new size fulfills tree invariants, we just need to replace the node + //(the block start has been displaced), otherwise erase() + insert(). + // + //This fixup must be done in two parts, because the new next block might + //overwrite the tree hook of the old next block. So we first erase the + //old if needed and we'll insert the new one after creating the new next + imultiset_iterator old_next_block_it(Imultiset::s_iterator_to(*next_block)); + const bool size_invariants_broken = + (next_block->m_size - rem_units ) < BlockCtrlUnits || + (old_next_block_it != m_header.m_imultiset.begin() && + (--imultiset_iterator(old_next_block_it))->m_size > rem_units); + if(size_invariants_broken){ + m_header.m_imultiset.erase(old_next_block_it); + } + //This is the remaining block + block_ctrl *rem_block = new(reinterpret_cast + (reinterpret_cast(block) + intended_units*Alignment))block_ctrl; + rem_block->m_size = rem_units; + algo_impl_t::assert_alignment(rem_block); + BOOST_ASSERT(rem_block->m_size >= BlockCtrlUnits); + priv_mark_as_free_block(rem_block); + + //Now the second part of the fixup + if(size_invariants_broken) + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block); + else + m_header.m_imultiset.replace_node(old_next_block_it, *rem_block); + + //Write the new length + block->m_size = intended_user_units + AllocatedCtrlUnits; + BOOST_ASSERT(block->m_size >= BlockCtrlUnits); + m_header.m_allocated += (intended_units - old_block_units)*Alignment; + } + //There is no free space to create a new node: just merge both blocks + else{ + //Now we have to update the data in the tree + m_header.m_imultiset.erase(Imultiset::s_iterator_to(*next_block)); + + //Write the new length + block->m_size = merged_units; + BOOST_ASSERT(block->m_size >= BlockCtrlUnits); + m_header.m_allocated += (merged_units - old_block_units)*Alignment; + } + priv_mark_as_allocated_block(block); + received_size = ((size_type)block->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; + return true; +} + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_prev_block + (typename rbtree_best_fit::block_ctrl *ptr) +{ + BOOST_ASSERT(!ptr->m_prev_allocated); + return reinterpret_cast + (reinterpret_cast(ptr) - ptr->m_prev_size*Alignment); +} + + + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_end_block + (typename rbtree_best_fit::block_ctrl *first_segment_block) +{ + //The first block's logic is different from the rest of blocks: stores in m_prev_size the absolute + //distance with the end block + BOOST_ASSERT(first_segment_block->m_prev_allocated); + block_ctrl *end_block = reinterpret_cast + (reinterpret_cast(first_segment_block) + first_segment_block->m_prev_size*Alignment); + (void)end_block; + BOOST_ASSERT(end_block->m_allocated == 1); + BOOST_ASSERT(end_block->m_size == first_segment_block->m_prev_size); + BOOST_ASSERT(end_block > first_segment_block); + return end_block; +} + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_first_block + (typename rbtree_best_fit::block_ctrl *end_segment_block) +{ + //The first block's logic is different from the rest of blocks: stores in m_prev_size the absolute + //distance with the end block + BOOST_ASSERT(end_segment_block->m_allocated); + block_ctrl *first_block = reinterpret_cast + (reinterpret_cast(end_segment_block) - end_segment_block->m_size*Alignment); + (void)first_block; + BOOST_ASSERT(first_block->m_prev_allocated == 1); + BOOST_ASSERT(first_block->m_prev_size == end_segment_block->m_size); + BOOST_ASSERT(end_segment_block > first_block); + return first_block; +} + + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_next_block + (typename rbtree_best_fit::block_ctrl *ptr) +{ + return reinterpret_cast + (reinterpret_cast(ptr) + ptr->m_size*Alignment); +} + +template inline +bool rbtree_best_fit::priv_is_allocated_block + (typename rbtree_best_fit::block_ctrl *block) +{ + bool allocated = block->m_allocated != 0; + #ifndef NDEBUG + if(block != priv_end_block()){ + block_ctrl *next_block = reinterpret_cast + (reinterpret_cast(block) + block->m_size*Alignment); + bool next_block_prev_allocated = next_block->m_prev_allocated != 0; + (void)next_block_prev_allocated; + BOOST_ASSERT(allocated == next_block_prev_allocated); + } + else{ + block = block; + } + #endif + return allocated; +} + +template inline +bool rbtree_best_fit::priv_is_prev_allocated + (typename rbtree_best_fit::block_ctrl *block) +{ + if(block->m_prev_allocated){ + return true; + } + else{ + #ifndef NDEBUG + if(block != priv_first_block()){ + block_ctrl *prev = priv_prev_block(block); + (void)prev; + BOOST_ASSERT(!prev->m_allocated); + } + else{ + block = block; + } + #endif + return false; + } +} + +template inline +void rbtree_best_fit::priv_mark_as_allocated_block + (typename rbtree_best_fit::block_ctrl *block) +{ + block->m_allocated = 1; + reinterpret_cast + (reinterpret_cast(block)+ block->m_size*Alignment)->m_prev_allocated = 1; +} + +template inline +void rbtree_best_fit::priv_mark_as_free_block + (typename rbtree_best_fit::block_ctrl *block) +{ + block->m_allocated = 0; + block_ctrl *next_block = priv_next_block(block); + next_block->m_prev_allocated = 0; + next_block->m_prev_size = block->m_size; +} + +template inline +void* rbtree_best_fit::priv_check_and_allocate + (size_type nunits + ,typename rbtree_best_fit::block_ctrl* block + ,size_type &received_size) +{ + size_type upper_nunits = nunits + BlockCtrlUnits; + imultiset_iterator it_old = Imultiset::s_iterator_to(*block); + algo_impl_t::assert_alignment(block); + + if (block->m_size >= upper_nunits){ + //This block is bigger than needed, split it in + //two blocks, the first's size will be "units" and + //the second's size "block->m_size-units" + size_type block_old_size = block->m_size; + block->m_size = nunits; + BOOST_ASSERT(block->m_size >= BlockCtrlUnits); + + //This is the remaining block + block_ctrl *rem_block = new(reinterpret_cast + (reinterpret_cast(block) + Alignment*nunits))block_ctrl; + algo_impl_t::assert_alignment(rem_block); + rem_block->m_size = block_old_size - nunits; + BOOST_ASSERT(rem_block->m_size >= BlockCtrlUnits); + priv_mark_as_free_block(rem_block); + + imultiset_iterator it_hint; + if(it_old == m_header.m_imultiset.begin() + || (--imultiset_iterator(it_old))->m_size < rem_block->m_size){ + //option a: slow but secure + //m_header.m_imultiset.insert(m_header.m_imultiset.erase(it_old), *rem_block); + //option b: Construct an empty node and swap + //Imultiset::init_node(*rem_block); + //block->swap_nodes(*rem_block); + //option c: replace the node directly + m_header.m_imultiset.replace_node(Imultiset::s_iterator_to(*it_old), *rem_block); + } + else{ + //Now we have to update the data in the tree + m_header.m_imultiset.erase(it_old); + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block); + } + + } + else if (block->m_size >= nunits){ + m_header.m_imultiset.erase(it_old); + } + else{ + BOOST_ASSERT(0); + return 0; + } + //We need block_ctrl for deallocation stuff, so + //return memory user can overwrite + m_header.m_allocated += (size_type)block->m_size*Alignment; + received_size = ((size_type)block->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; + + //Mark the block as allocated + priv_mark_as_allocated_block(block); + + //Clear the memory occupied by the tree hook, since this won't be + //cleared with zero_free_memory + TreeHook *t = static_cast(block); + //Just clear the memory part reserved for the user + std::size_t tree_hook_offset_in_block = (char*)t - (char*)block; + //volatile char *ptr = + char *ptr = reinterpret_cast(block)+tree_hook_offset_in_block; + const std::size_t s = BlockCtrlBytes - tree_hook_offset_in_block; + std::memset(ptr, 0, s); + this->priv_next_block(block)->m_prev_size = 0; + return priv_get_user_buffer(block); +} + +template +void rbtree_best_fit::deallocate(void* addr) +{ + if(!addr) return; + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return this->priv_deallocate(addr); +} + +template +void rbtree_best_fit::priv_deallocate(void* addr) +{ + if(!addr) return; + + block_ctrl *block = priv_get_block(addr); + + //The blocks must be marked as allocated and the sizes must be equal + BOOST_ASSERT(priv_is_allocated_block(block)); +// BOOST_ASSERT(block->m_size == priv_tail_size(block)); + + //Check if alignment and block size are right + algo_impl_t::assert_alignment(addr); + + size_type block_old_size = Alignment*(size_type)block->m_size; + BOOST_ASSERT(m_header.m_allocated >= block_old_size); + + //Update used memory count + m_header.m_allocated -= block_old_size; + + //The block to insert in the tree + block_ctrl *block_to_insert = block; + + //Get the next block + block_ctrl *next_block = priv_next_block(block); + bool merge_with_prev = !priv_is_prev_allocated(block); + bool merge_with_next = !priv_is_allocated_block(next_block); + + //Merge logic. First just update block sizes, then fix free blocks tree + if(merge_with_prev || merge_with_next){ + //Merge if the previous is free + if(merge_with_prev){ + //Get the previous block + block_ctrl *prev_block = priv_prev_block(block); + prev_block->m_size += block->m_size; + BOOST_ASSERT(prev_block->m_size >= BlockCtrlUnits); + block_to_insert = prev_block; + } + //Merge if the next is free + if(merge_with_next){ + block_to_insert->m_size += next_block->m_size; + BOOST_ASSERT(block_to_insert->m_size >= BlockCtrlUnits); + if(merge_with_prev) + m_header.m_imultiset.erase(Imultiset::s_iterator_to(*next_block)); + } + + bool only_merge_next = !merge_with_prev && merge_with_next; + imultiset_iterator free_block_to_check_it + (Imultiset::s_iterator_to(only_merge_next ? *next_block : *block_to_insert)); + imultiset_iterator was_bigger_it(free_block_to_check_it); + + //Now try to shortcut erasure + insertion (O(log(N))) with + //a O(1) operation if merging does not alter tree positions + if(++was_bigger_it != m_header.m_imultiset.end() && + block_to_insert->m_size > was_bigger_it->m_size ){ + m_header.m_imultiset.erase(free_block_to_check_it); + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *block_to_insert); + } + else if(only_merge_next){ + m_header.m_imultiset.replace_node(free_block_to_check_it, *block_to_insert); + } + } + else{ + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *block_to_insert); + } + priv_mark_as_free_block(block_to_insert); +} + +/// @endcond + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP diff --git a/cpp/BoostParts/boost/interprocess/offset_ptr.hpp b/cpp/BoostParts/boost/interprocess/offset_ptr.hpp new file mode 100644 index 00000000..752c4358 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/offset_ptr.hpp @@ -0,0 +1,730 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_OFFSET_PTR_HPP +#define BOOST_INTERPROCESS_OFFSET_PTR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes a smart pointer that stores the offset between this pointer and +//!target pointee, called offset_ptr. + +namespace boost { + +//Predeclarations +template +struct has_trivial_constructor; + +template +struct has_trivial_destructor; + +namespace interprocess { + +/// @cond +namespace ipcdetail { + + template + union offset_ptr_internal + { + explicit offset_ptr_internal(OffsetType off) + : m_offset(off) + {} + OffsetType m_offset; //Distance between this object and pointee address + typename ::boost::aligned_storage + < sizeof(OffsetType) + , (OffsetAlignment == offset_type_alignment) ? + ::boost::alignment_of::value : OffsetAlignment + >::type alignment_helper; + }; + + //Note: using the address of a local variable to point to another address + //is not standard conforming and this can be optimized-away by the compiler. + //Non-inlining is a method to remain illegal but correct + + //Undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_XXX if your compiler can inline + //this code without breaking the library + + //////////////////////////////////////////////////////////////////////// + // + // offset_ptr_to_raw_pointer + // + //////////////////////////////////////////////////////////////////////// + #define BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_PTR + #define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR + + template + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_PTR + BOOST_INTERPROCESS_NEVER_INLINE + #elif defined(NDEBUG) + inline + #endif + void * offset_ptr_to_raw_pointer(const volatile void *this_ptr, std::size_t offset) + { + typedef pointer_size_t_caster caster_t; + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR + if(offset == 1){ + return 0; + } + else{ + caster_t caster((void*)this_ptr); + return caster_t(caster.size() + offset).pointer(); + } + #else + caster_t caster((void*)this_ptr); + return caster_t((caster.size() + offset) & -std::size_t(offset != 1)).pointer(); + #endif + } + + #ifdef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_PTR + #undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_PTR + #endif + #ifdef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR + #undef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR + #endif + + //////////////////////////////////////////////////////////////////////// + // + // offset_ptr_to_offset + // + //////////////////////////////////////////////////////////////////////// + #define BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF + //Branchless seems slower in x86 + //#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF + + template + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF + BOOST_INTERPROCESS_NEVER_INLINE + #elif defined(NDEBUG) + inline + #endif + std::size_t offset_ptr_to_offset(const volatile void *ptr, const volatile void *this_ptr) + { + typedef pointer_size_t_caster caster_t; + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF + //offset == 1 && ptr != 0 is not legal for this pointer + if(!ptr){ + return 1; + } + else{ + caster_t this_caster((void*)this_ptr); + caster_t ptr_caster((void*)ptr); + std::size_t offset = ptr_caster.size() - this_caster.size(); + BOOST_ASSERT(offset != 1); + return offset; + } + #else + caster_t this_caster((void*)this_ptr); + caster_t ptr_caster((void*)ptr); + std::size_t offset = (ptr_caster.size() - this_caster.size() - 1) & -std::size_t(ptr != 0); + ++offset; + return offset; + #endif + } + + #ifdef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF + #undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF + #endif + #ifdef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF + #undef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF + #endif + + //////////////////////////////////////////////////////////////////////// + // + // offset_ptr_to_offset_from_other + // + //////////////////////////////////////////////////////////////////////// + #define BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF_FROM_OTHER + //Branchless seems slower in x86 + //#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER + + template + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF_FROM_OTHER + BOOST_INTERPROCESS_NEVER_INLINE + #elif defined(NDEBUG) + inline + #endif + std::size_t offset_ptr_to_offset_from_other + (const volatile void *this_ptr, const volatile void *other_ptr, std::size_t other_offset) + { + typedef pointer_size_t_caster caster_t; + #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER + if(other_offset == 1){ + return 1; + } + else{ + caster_t this_caster((void*)this_ptr); + caster_t other_caster((void*)other_ptr); + std::size_t offset = other_caster.size() - this_caster.size() + other_offset; + BOOST_ASSERT(offset != 1); + return offset; + } + #else + caster_t this_caster((void*)this_ptr); + caster_t other_caster((void*)other_ptr); + std::size_t offset = (other_caster.size() - this_caster.size()) & -std::size_t(other_offset != 1); + offset += other_offset; + return offset; + #endif + } + + #ifdef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF_FROM_OTHER + #undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_TO_OFF_FROM_OTHER + #endif + #ifdef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER + #undef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER + #endif + + //////////////////////////////////////////////////////////////////////// + // + // Let's assume cast to void and cv cast don't change any target address + // + //////////////////////////////////////////////////////////////////////// + template + struct offset_ptr_maintains_address + { + static const bool value = ipcdetail::is_cv_same::value + || ipcdetail::is_cv_same::value; + }; + +} //namespace ipcdetail { +/// @endcond + +//!A smart pointer that stores the offset between between the pointer and the +//!the object it points. This allows offset allows special properties, since +//!the pointer is independent from the address address of the pointee, if the +//!pointer and the pointee are still separated by the same offset. This feature +//!converts offset_ptr in a smart pointer that can be placed in shared memory and +//!memory mapped files mapped in different addresses in every process. +template +class offset_ptr +{ + /// @cond + typedef offset_ptr self_t; + void unspecified_bool_type_func() const {} + typedef void (self_t::*unspecified_bool_type)() const; + /// @endcond + + public: + typedef PointedType element_type; + typedef PointedType * pointer; + typedef typename ipcdetail:: + add_reference::type reference; + typedef typename ipcdetail:: + remove_volatile::type + >::type value_type; + typedef DifferenceType difference_type; + typedef std::random_access_iterator_tag iterator_category; + typedef OffsetType offset_type; + + public: //Public Functions + + //!Default constructor (null pointer). + //!Never throws. + offset_ptr() + : internal(1) + {} + + //!Constructor from raw pointer (allows "0" pointer conversion). + //!Never throws. + offset_ptr(pointer ptr) + : internal(static_cast(ipcdetail::offset_ptr_to_offset<0>(ptr, this))) + {} + + //!Constructor from other pointer. + //!Never throws. + template + offset_ptr( T *ptr + , typename ipcdetail::enable_if< ipcdetail::is_convertible >::type * = 0) + : internal(static_cast + (ipcdetail::offset_ptr_to_offset<0>(static_cast(ptr), this))) + {} + + //!Constructor from other offset_ptr + //!Never throws. + offset_ptr(const offset_ptr& ptr) + : internal(static_cast + (ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.internal.m_offset))) + {} + + //!Constructor from other offset_ptr. If pointers of pointee types are + //!convertible, offset_ptrs will be convertibles. Never throws. + template + offset_ptr( const offset_ptr &ptr + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + , typename ipcdetail::enable_if_c< ipcdetail::is_convertible::value + && ipcdetail::offset_ptr_maintains_address::value + >::type * = 0 + #endif + ) + : internal(static_cast + (ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.get_offset()))) + {} + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + //!Constructor from other offset_ptr. If pointers of pointee types are + //!convertible, offset_ptrs will be convertibles. Never throws. + template + offset_ptr( const offset_ptr &ptr + , typename ipcdetail::enable_if_c< ipcdetail::is_convertible::value + && !ipcdetail::offset_ptr_maintains_address::value + >::type * = 0) + : internal(static_cast + (ipcdetail::offset_ptr_to_offset<0>(static_cast(ptr.get()), this))) + {} + + #endif + + //!Emulates static_cast operator. + //!Never throws. + template + offset_ptr(const offset_ptr & r, ipcdetail::static_cast_tag) + : internal(static_cast + (ipcdetail::offset_ptr_to_offset<0>(static_cast(r.get()), this))) + {} + + //!Emulates const_cast operator. + //!Never throws. + template + offset_ptr(const offset_ptr & r, ipcdetail::const_cast_tag) + : internal(static_cast + (ipcdetail::offset_ptr_to_offset<0>(const_cast(r.get()), this))) + {} + + //!Emulates dynamic_cast operator. + //!Never throws. + template + offset_ptr(const offset_ptr & r, ipcdetail::dynamic_cast_tag) + : internal(static_cast + (ipcdetail::offset_ptr_to_offset<0>(dynamic_cast(r.get()), this))) + {} + + //!Emulates reinterpret_cast operator. + //!Never throws. + template + offset_ptr(const offset_ptr & r, ipcdetail::reinterpret_cast_tag) + : internal(static_cast + (ipcdetail::offset_ptr_to_offset<0>(reinterpret_cast(r.get()), this))) + {} + + //!Obtains raw pointer from offset. + //!Never throws. + pointer get() const + { return (pointer)ipcdetail::offset_ptr_to_raw_pointer<0>(this, this->internal.m_offset); } + + offset_type get_offset() const + { return this->internal.m_offset; } + + //!Pointer-like -> operator. It can return 0 pointer. + //!Never throws. + pointer operator->() const + { return this->get(); } + + //!Dereferencing operator, if it is a null offset_ptr behavior + //! is undefined. Never throws. + reference operator* () const + { + pointer p = this->get(); + reference r = *p; + return r; + } + + //!Indexing operator. + //!Never throws. + reference operator[](difference_type idx) const + { return this->get()[idx]; } + + //!Assignment from pointer (saves extra conversion). + //!Never throws. + offset_ptr& operator= (pointer from) + { + this->internal.m_offset = + static_cast(ipcdetail::offset_ptr_to_offset<0>(from, this)); + return *this; + } + + //!Assignment from other offset_ptr. + //!Never throws. + offset_ptr& operator= (const offset_ptr & ptr) + { + this->internal.m_offset = + static_cast(ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.internal.m_offset)); + return *this; + } + + //!Assignment from related offset_ptr. If pointers of pointee types + //! are assignable, offset_ptrs will be assignable. Never throws. + template + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typename ipcdetail::enable_if_c< ipcdetail::is_convertible::value + && ipcdetail::offset_ptr_maintains_address::value + , offset_ptr&>::type + #else + offset_ptr& + #endif + operator= (const offset_ptr &ptr) + { + this->internal.m_offset = + static_cast(ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.get_offset())); + return *this; + } + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + template + typename ipcdetail::enable_if_c::value + && !ipcdetail::offset_ptr_maintains_address::value + , offset_ptr&>::type + operator= (const offset_ptr &ptr) + { + this->internal.m_offset = + static_cast(ipcdetail::offset_ptr_to_offset<0>(static_cast(ptr.get()), this)); + return *this; + } + #endif + + //!offset_ptr += difference_type. + //!Never throws. + offset_ptr &operator+= (difference_type offset) + { this->inc_offset(offset * sizeof (PointedType)); return *this; } + + //!offset_ptr -= difference_type. + //!Never throws. + offset_ptr &operator-= (difference_type offset) + { this->dec_offset(offset * sizeof (PointedType)); return *this; } + + //!++offset_ptr. + //!Never throws. + offset_ptr& operator++ (void) + { this->inc_offset(sizeof (PointedType)); return *this; } + + //!offset_ptr++. + //!Never throws. + offset_ptr operator++ (int) + { + offset_ptr tmp(*this); + this->inc_offset(sizeof (PointedType)); + return tmp; + } + + //!--offset_ptr. + //!Never throws. + offset_ptr& operator-- (void) + { this->dec_offset(sizeof (PointedType)); return *this; } + + //!offset_ptr--. + //!Never throws. + offset_ptr operator-- (int) + { + offset_ptr tmp(*this); + this->dec_offset(sizeof (PointedType)); + return tmp; + } + + //!safe bool conversion operator. + //!Never throws. + operator unspecified_bool_type() const + { return this->internal.m_offset != 1? &self_t::unspecified_bool_type_func : 0; } + + //!Not operator. Not needed in theory, but improves portability. + //!Never throws + bool operator! () const + { return this->internal.m_offset == 1; } + + //!Compatibility with pointer_traits + //! + template + struct rebind + { typedef offset_ptr other; }; + + //!Compatibility with pointer_traits + //! + static offset_ptr pointer_to(reference r) + { return offset_ptr(&r); } + + //!difference_type + offset_ptr + //!operation + friend offset_ptr operator+(difference_type diff, offset_ptr right) + { right += diff; return right; } + + //!offset_ptr + difference_type + //!operation + friend offset_ptr operator+(offset_ptr left, difference_type diff) + { left += diff; return left; } + + //!offset_ptr - diff + //!operation + friend offset_ptr operator-(offset_ptr left, difference_type diff) + { left -= diff; return left; } + + //!offset_ptr - diff + //!operation + friend offset_ptr operator-(difference_type diff, offset_ptr right) + { right -= diff; return right; } + + //!offset_ptr - offset_ptr + //!operation + friend difference_type operator-(const offset_ptr &pt, const offset_ptr &pt2) + { return difference_type(pt.get()- pt2.get()); } + + //Comparison + friend bool operator== (const offset_ptr &pt1, const offset_ptr &pt2) + { return pt1.get() == pt2.get(); } + + friend bool operator!= (const offset_ptr &pt1, const offset_ptr &pt2) + { return pt1.get() != pt2.get(); } + + friend bool operator<(const offset_ptr &pt1, const offset_ptr &pt2) + { return pt1.get() < pt2.get(); } + + friend bool operator<=(const offset_ptr &pt1, const offset_ptr &pt2) + { return pt1.get() <= pt2.get(); } + + friend bool operator>(const offset_ptr &pt1, const offset_ptr &pt2) + { return pt1.get() > pt2.get(); } + + friend bool operator>=(const offset_ptr &pt1, const offset_ptr &pt2) + { return pt1.get() >= pt2.get(); } + + //Comparison to raw ptr to support literal 0 + friend bool operator== (pointer pt1, const offset_ptr &pt2) + { return pt1 == pt2.get(); } + + friend bool operator!= (pointer pt1, const offset_ptr &pt2) + { return pt1 != pt2.get(); } + + friend bool operator<(pointer pt1, const offset_ptr &pt2) + { return pt1 < pt2.get(); } + + friend bool operator<=(pointer pt1, const offset_ptr &pt2) + { return pt1 <= pt2.get(); } + + friend bool operator>(pointer pt1, const offset_ptr &pt2) + { return pt1 > pt2.get(); } + + friend bool operator>=(pointer pt1, const offset_ptr &pt2) + { return pt1 >= pt2.get(); } + + //Comparison + friend bool operator== (const offset_ptr &pt1, pointer pt2) + { return pt1.get() == pt2; } + + friend bool operator!= (const offset_ptr &pt1, pointer pt2) + { return pt1.get() != pt2; } + + friend bool operator<(const offset_ptr &pt1, pointer pt2) + { return pt1.get() < pt2; } + + friend bool operator<=(const offset_ptr &pt1, pointer pt2) + { return pt1.get() <= pt2; } + + friend bool operator>(const offset_ptr &pt1, pointer pt2) + { return pt1.get() > pt2; } + + friend bool operator>=(const offset_ptr &pt1, pointer pt2) + { return pt1.get() >= pt2; } + + friend void swap(offset_ptr &left, offset_ptr &right) + { + pointer ptr = right.get(); + right = left; + left = ptr; + } + + private: + /// @cond + void inc_offset(DifferenceType bytes) + { internal.m_offset += bytes; } + + void dec_offset(DifferenceType bytes) + { internal.m_offset -= bytes; } + + ipcdetail::offset_ptr_internal internal; + /// @endcond +}; + +//!operator<< +//!for offset ptr +template +inline std::basic_ostream & operator<< + (std::basic_ostream & os, offset_ptr const & p) +{ return os << p.get_offset(); } + +//!operator>> +//!for offset ptr +template +inline std::basic_istream & operator>> + (std::basic_istream & is, offset_ptr & p) +{ return is >> p.get_offset(); } + +//!Simulation of static_cast between pointers. Never throws. +template +inline boost::interprocess::offset_ptr + static_pointer_cast(const boost::interprocess::offset_ptr & r) +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::ipcdetail::static_cast_tag()); +} + +//!Simulation of const_cast between pointers. Never throws. +template +inline boost::interprocess::offset_ptr + const_pointer_cast(const boost::interprocess::offset_ptr & r) +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::ipcdetail::const_cast_tag()); +} + +//!Simulation of dynamic_cast between pointers. Never throws. +template +inline boost::interprocess::offset_ptr + dynamic_pointer_cast(const boost::interprocess::offset_ptr & r) +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::ipcdetail::dynamic_cast_tag()); +} + +//!Simulation of reinterpret_cast between pointers. Never throws. +template +inline boost::interprocess::offset_ptr + reinterpret_pointer_cast(const boost::interprocess::offset_ptr & r) +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::ipcdetail::reinterpret_cast_tag()); +} + +} //namespace interprocess { + +/// @cond + +//!has_trivial_constructor<> == true_type specialization for optimizations +template +struct has_trivial_constructor< boost::interprocess::offset_ptr > +{ + static const bool value = true; +}; + +///has_trivial_destructor<> == true_type specialization for optimizations +template +struct has_trivial_destructor< boost::interprocess::offset_ptr > +{ + static const bool value = true; +}; + + +namespace interprocess { + +//!to_raw_pointer() enables boost::mem_fn to recognize offset_ptr. +//!Never throws. +template +inline T * to_raw_pointer(boost::interprocess::offset_ptr const & p) +{ return ipcdetail::to_raw_pointer(p); } + +} //namespace interprocess + + +/// @endcond +} //namespace boost { + +/// @cond + +namespace boost{ + +//This is to support embedding a bit in the pointer +//for intrusive containers, saving space +namespace intrusive { + +//Predeclaration to avoid including header +template +struct max_pointer_plus_bits; + +template +struct max_pointer_plus_bits, OffsetAlignment> +{ + //The offset ptr can embed one bit less than the alignment since it + //uses offset == 1 to store the null pointer. + static const std::size_t value = ::boost::interprocess::ipcdetail::ls_zeros::value - 1; +}; + +//Predeclaration +template +struct pointer_plus_bits; + +template +struct pointer_plus_bits, NumBits> +{ + typedef boost::interprocess::offset_ptr pointer; + typedef ::boost::interprocess::pointer_size_t_caster caster_t; + //Bits are stored in the lower bits of the pointer except the LSB, + //because this bit is used to represent the null pointer. + static const std::size_t Mask = ((std::size_t(1) << NumBits) - 1) << 1u; + + static pointer get_pointer(const pointer &n) + { + caster_t caster(n.get()); + return pointer(caster_t(caster.size() & ~Mask).pointer()); + } + + static void set_pointer(pointer &n, const pointer &p) + { + caster_t n_caster(n.get()); + caster_t p_caster(p.get()); + BOOST_ASSERT(0 == (p_caster.size() & Mask)); + n = caster_t(p_caster.size() | (n_caster.size() & Mask)).pointer(); + } + + static std::size_t get_bits(const pointer &n) + { return (caster_t(n.get()).size() & Mask) >> 1u; } + + static void set_bits(pointer &n, std::size_t b) + { + BOOST_ASSERT(b < (std::size_t(1) << NumBits)); + caster_t n_caster(n.get()); + n = caster_t((n_caster.size() & ~Mask) | (b << 1u)).pointer(); + } +}; + +} //namespace intrusive + +//Predeclaration +template +struct pointer_to_other; + +//Backwards compatibility with pointer_to_other +template +struct pointer_to_other + < ::boost::interprocess::offset_ptr, U > +{ + typedef ::boost::interprocess::offset_ptr type; +}; + +} //namespace boost{ +/// @endcond + +#include + +#endif //#ifndef BOOST_INTERPROCESS_OFFSET_PTR_HPP diff --git a/cpp/BoostParts/boost/interprocess/permissions.hpp b/cpp/BoostParts/boost/interprocess/permissions.hpp new file mode 100644 index 00000000..4266b24a --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/permissions.hpp @@ -0,0 +1,132 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PERMISSIONS_HPP +#define BOOST_INTERPROCESS_PERMISSIONS_HPP + +/// @cond + +#if defined (_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +#include + +#endif + +/// @endcond + +//!\file +//!Describes permissions class + +namespace boost { +namespace interprocess { + +/// @cond + +#if defined(BOOST_INTERPROCESS_WINDOWS) + +namespace ipcdetail { + +template +struct unrestricted_permissions_holder +{ + static winapi::interprocess_all_access_security unrestricted; +}; + +template +winapi::interprocess_all_access_security unrestricted_permissions_holder::unrestricted; + +} //namespace ipcdetail { + +#endif //defined BOOST_INTERPROCESS_WINDOWS + +/// @endcond + +//!The permissions class represents permissions to be set to shared memory or +//!files, that can be constructed form usual permission representations: +//!a SECURITY_ATTRIBUTES pointer in windows or ORed rwx chmod integer in UNIX. +class permissions +{ + /// @cond + + #if defined(BOOST_INTERPROCESS_WINDOWS) + typedef void* os_permissions_type; + #else + typedef int os_permissions_type; + #endif + os_permissions_type m_perm; + + /// @endcond + + public: + //!Constructs a permissions object from a user provided os-dependent + //!permissions. + permissions(os_permissions_type type) + : m_perm(type) + {} + + //!Constructs a default permissions object: + //!A null security attributes pointer for windows or 0644 + //!for UNIX. + permissions() + { set_default(); } + + //!Sets permissions to default values: + //!A null security attributes pointer for windows or 0644 + //!for UNIX. + void set_default() + { + /// @cond + #if defined (BOOST_INTERPROCESS_WINDOWS) + m_perm = 0; + #else + m_perm = 0644; + #endif + /// @endcond + } + + //!Sets permissions to unrestricted access: + //!A null DACL for windows or 0666 for UNIX. + void set_unrestricted() + { + /// @cond + #if defined (BOOST_INTERPROCESS_WINDOWS) + m_perm = &ipcdetail::unrestricted_permissions_holder<0>::unrestricted; + #else + m_perm = 0666; + #endif + /// @endcond + } + + //!Sets permissions from a user provided os-dependent + //!permissions. + void set_permissions(os_permissions_type perm) + { m_perm = perm; } + + //!Returns stored os-dependent + //!permissions + os_permissions_type get_permissions() const + { return m_perm; } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_PERMISSIONS_HPP + diff --git a/cpp/BoostParts/boost/interprocess/segment_manager.hpp b/cpp/BoostParts/boost/interprocess/segment_manager.hpp new file mode 100644 index 00000000..a0f948f6 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/segment_manager.hpp @@ -0,0 +1,1366 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_SEGMENT_MANAGER_HPP +#define BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //std::size_t +#include //char_traits +#include //std::nothrow +#include //std::pair +#include +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif + +//!\file +//!Describes the object placed in a memory segment that provides +//!named object allocation capabilities for single-segment and +//!multi-segment allocations. + +namespace boost{ +namespace interprocess{ + +//!This object is the public base class of segment manager. +//!This class only depends on the memory allocation algorithm +//!and implements all the allocation features not related +//!to named or unique objects. +//! +//!Storing a reference to segment_manager forces +//!the holder class to be dependent on index types and character types. +//!When such dependence is not desirable and only anonymous and raw +//!allocations are needed, segment_manager_base is the correct answer. +template +class segment_manager_base + : private MemoryAlgorithm +{ + public: + typedef segment_manager_base segment_manager_base_type; + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef typename MemoryAlgorithm::mutex_family mutex_family; + typedef MemoryAlgorithm memory_algorithm; + + /// @cond + + //Experimental. Don't use + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; + typedef typename MemoryAlgorithm::difference_type difference_type; + typedef typename MemoryAlgorithm::size_type size_type; + + /// @endcond + + //!This constant indicates the payload size + //!associated with each allocation of the memory algorithm + static const size_type PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation; + + //!Constructor of the segment_manager_base + //! + //!"size" is the size of the memory segment where + //!the basic segment manager is being constructed. + //! + //!"reserved_bytes" is the number of bytes + //!after the end of the memory algorithm object itself + //!that the memory algorithm will exclude from + //!dynamic allocation + //! + //!Can throw + segment_manager_base(size_type sz, size_type reserved_bytes) + : MemoryAlgorithm(sz, reserved_bytes) + { + BOOST_ASSERT((sizeof(segment_manager_base) == sizeof(MemoryAlgorithm))); + } + + //!Returns the size of the memory + //!segment + size_type get_size() const + { return MemoryAlgorithm::get_size(); } + + //!Returns the number of free bytes of the memory + //!segment + size_type get_free_memory() const + { return MemoryAlgorithm::get_free_memory(); } + + //!Obtains the minimum size needed by + //!the segment manager + static size_type get_min_size (size_type size) + { return MemoryAlgorithm::get_min_size(size); } + + //!Allocates nbytes bytes. This function is only used in + //!single-segment management. Never throws + void * allocate (size_type nbytes, std::nothrow_t) + { return MemoryAlgorithm::allocate(nbytes); } + + /// @cond + + //Experimental. Dont' use. + //!Allocates n_elements of elem_bytes bytes. + //!Throws bad_alloc on failure. chain.size() is not increased on failure. + void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { + size_type prev_size = chain.size(); + MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); + if(!elem_bytes || chain.size() == prev_size){ + throw bad_alloc(); + } + } + + //!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes. + //!Throws bad_alloc on failure. chain.size() is not increased on failure. + void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { + size_type prev_size = chain.size(); + MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain); + if(!sizeof_element || chain.size() == prev_size){ + throw bad_alloc(); + } + } + + //!Allocates n_elements of elem_bytes bytes. + //!Non-throwing version. chain.size() is not increased on failure. + void allocate_many(std::nothrow_t, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain) + { MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); } + + //!Allocates n_elements, each one of + //!element_lengths[i]*sizeof_element bytes. + //!Non-throwing version. chain.size() is not increased on failure. + void allocate_many(std::nothrow_t, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain) + { MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); } + + //!Deallocates all elements contained in chain. + //!Never throws. + void deallocate_many(multiallocation_chain &chain) + { MemoryAlgorithm::deallocate_many(chain); } + + /// @endcond + + //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc + //!on failure + void * allocate(size_type nbytes) + { + void * ret = MemoryAlgorithm::allocate(nbytes); + if(!ret) + throw bad_alloc(); + return ret; + } + + //!Allocates nbytes bytes. This function is only used in + //!single-segment management. Never throws + void * allocate_aligned (size_type nbytes, size_type alignment, std::nothrow_t) + { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); } + + //!Allocates nbytes bytes. This function is only used in + //!single-segment management. Throws bad_alloc when fails + void * allocate_aligned(size_type nbytes, size_type alignment) + { + void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment); + if(!ret) + throw bad_alloc(); + return ret; + } + + template + std::pair + allocation_command (boost::interprocess::allocation_type command, size_type limit_size, + size_type preferred_size,size_type &received_size, + T *reuse_ptr = 0) + { + std::pair ret = MemoryAlgorithm::allocation_command + ( command | boost::interprocess::nothrow_allocation, limit_size, preferred_size, received_size + , reuse_ptr); + if(!(command & boost::interprocess::nothrow_allocation) && !ret.first) + throw bad_alloc(); + return ret; + } + + std::pair + raw_allocation_command (boost::interprocess::allocation_type command, size_type limit_objects, + size_type preferred_objects,size_type &received_objects, + void *reuse_ptr = 0, size_type sizeof_object = 1) + { + std::pair ret = MemoryAlgorithm::raw_allocation_command + ( command | boost::interprocess::nothrow_allocation, limit_objects, preferred_objects, received_objects + , reuse_ptr, sizeof_object); + if(!(command & boost::interprocess::nothrow_allocation) && !ret.first) + throw bad_alloc(); + return ret; + } + + //!Deallocates the bytes allocated with allocate/allocate_many() + //!pointed by addr + void deallocate (void *addr) + { MemoryAlgorithm::deallocate(addr); } + + //!Increases managed memory in extra_size bytes more. This only works + //!with single-segment management. + void grow(size_type extra_size) + { MemoryAlgorithm::grow(extra_size); } + + //!Decreases managed memory to the minimum. This only works + //!with single-segment management. + void shrink_to_fit() + { MemoryAlgorithm::shrink_to_fit(); } + + //!Returns the result of "all_memory_deallocated()" function + //!of the used memory algorithm + bool all_memory_deallocated() + { return MemoryAlgorithm::all_memory_deallocated(); } + + //!Returns the result of "check_sanity()" function + //!of the used memory algorithm + bool check_sanity() + { return MemoryAlgorithm::check_sanity(); } + + //!Writes to zero free memory (memory not yet allocated) + //!of the memory algorithm + void zero_free_memory() + { MemoryAlgorithm::zero_free_memory(); } + + //!Returns the size of the buffer previously allocated pointed by ptr + size_type size(const void *ptr) const + { return MemoryAlgorithm::size(ptr); } + + /// @cond + protected: + void * prot_anonymous_construct + (size_type num, bool dothrow, ipcdetail::in_place_interface &table) + { + typedef ipcdetail::block_header block_header_t; + block_header_t block_info ( size_type(table.size*num) + , size_type(table.alignment) + , anonymous_type + , 1 + , 0); + + //Allocate memory + void *ptr_struct = this->allocate(block_info.total_size(), std::nothrow_t()); + + //Check if there is enough memory + if(!ptr_struct){ + if(dothrow){ + throw bad_alloc(); + } + else{ + return 0; + } + } + + //Build scoped ptr to avoid leaks with constructor exception + ipcdetail::mem_algo_deallocator mem(ptr_struct, *this); + + //Now construct the header + block_header_t * hdr = new(ptr_struct) block_header_t(block_info); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); + + //Now call constructors + ipcdetail::array_construct(ptr, num, table); + + //All constructors successful, we don't want erase memory + mem.release(); + return ptr; + } + + //!Calls the destructor and makes an anonymous deallocate + void prot_anonymous_destroy(const void *object, ipcdetail::in_place_interface &table) + { + + //Get control data from associated with this object + typedef ipcdetail::block_header block_header_t; + block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment); + + //------------------------------- + //scoped_lock guard(m_header); + //------------------------------- + + if(ctrl_data->alloc_type() != anonymous_type){ + //This is not an anonymous object, the pointer is wrong! + BOOST_ASSERT(0); + } + + //Call destructors and free memory + //Build scoped ptr to avoid leaks with destructor exception + std::size_t destroyed = 0; + table.destroy_n(const_cast(object), ctrl_data->m_value_bytes/table.size, destroyed); + this->deallocate(ctrl_data); + } + /// @endcond +}; + +//!This object is placed in the beginning of memory segment and +//!implements the allocation (named or anonymous) of portions +//!of the segment. This object contains two indexes that +//!maintain an association between a name and a portion of the segment. +//! +//!The first index contains the mappings for normal named objects using the +//!char type specified in the template parameter. +//! +//!The second index contains the association for unique instances. The key will +//!be the const char * returned from type_info.name() function for the unique +//!type to be constructed. +//! +//!segment_manager inherits publicly +//!from segment_manager_base and inherits from it +//!many public functions related to anonymous object and raw memory allocation. +//!See segment_manager_base reference to know about those functions. +template class IndexType> +class segment_manager + : public segment_manager_base +{ + /// @cond + //Non-copyable + segment_manager(); + segment_manager(const segment_manager &); + segment_manager &operator=(const segment_manager &); + typedef segment_manager_base Base; + /// @endcond + + public: + typedef MemoryAlgorithm memory_algorithm; + typedef typename Base::void_pointer void_pointer; + typedef typename Base::size_type size_type; + typedef typename Base::difference_type difference_type; + typedef CharType char_type; + + typedef segment_manager_base segment_manager_base_type; + + static const size_type PayloadPerAllocation = Base::PayloadPerAllocation; + + /// @cond + private: + typedef ipcdetail::block_header block_header_t; + typedef ipcdetail::index_config index_config_named; + typedef ipcdetail::index_config index_config_unique; + typedef IndexType index_type; + typedef ipcdetail::bool_::value > is_intrusive_t; + typedef ipcdetail::bool_::value> is_node_index_t; + + public: + typedef IndexType named_index_t; + typedef IndexType unique_index_t; + typedef ipcdetail::char_ptr_holder char_ptr_holder_t; + typedef ipcdetail::segment_manager_iterator_transform + ::value> named_transform; + + typedef ipcdetail::segment_manager_iterator_transform + ::value> unique_transform; + /// @endcond + + typedef typename Base::mutex_family mutex_family; + + typedef transform_iterator + const_named_iterator; + typedef transform_iterator + const_unique_iterator; + + /// @cond + + //!Constructor proxy object definition helper class + template + struct construct_proxy + { + typedef ipcdetail::named_proxy type; + }; + + //!Constructor proxy object definition helper class + template + struct construct_iter_proxy + { + typedef ipcdetail::named_proxy type; + }; + + /// @endcond + + //!Constructor of the segment manager + //!"size" is the size of the memory segment where + //!the segment manager is being constructed. + //!Can throw + explicit segment_manager(size_type segment_size) + : Base(segment_size, priv_get_reserved_bytes()) + , m_header(static_cast(get_this_pointer())) + { + (void) anonymous_instance; (void) unique_instance; + BOOST_ASSERT(static_cast(this) == static_cast(static_cast(this))); + } + + //!Tries to find a previous named allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair find (const CharType* name) + { return this->priv_find_impl(name, true); } + + //!Tries to find a previous unique allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair find (const ipcdetail::unique_instance_t* name) + { return this->priv_find_impl(name, true); } + + //!Tries to find a previous named allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. This search is not mutex-protected! + template + std::pair find_no_lock (const CharType* name) + { return this->priv_find_impl(name, false); } + + //!Tries to find a previous unique allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. This search is not mutex-protected! + template + std::pair find_no_lock (const ipcdetail::unique_instance_t* name) + { return this->priv_find_impl(name, false); } + + //!Returns throwing "construct" proxy + //!object + template + typename construct_proxy::type + construct(char_ptr_holder_t name) + { return typename construct_proxy::type (this, name, false, true); } + + //!Returns throwing "search or construct" proxy + //!object + template + typename construct_proxy::type find_or_construct(char_ptr_holder_t name) + { return typename construct_proxy::type (this, name, true, true); } + + //!Returns no throwing "construct" proxy + //!object + template + typename construct_proxy::type + construct(char_ptr_holder_t name, std::nothrow_t) + { return typename construct_proxy::type (this, name, false, false); } + + //!Returns no throwing "search or construct" + //!proxy object + template + typename construct_proxy::type + find_or_construct(char_ptr_holder_t name, std::nothrow_t) + { return typename construct_proxy::type (this, name, true, false); } + + //!Returns throwing "construct from iterators" proxy object + template + typename construct_iter_proxy::type + construct_it(char_ptr_holder_t name) + { return typename construct_iter_proxy::type (this, name, false, true); } + + //!Returns throwing "search or construct from iterators" + //!proxy object + template + typename construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name) + { return typename construct_iter_proxy::type (this, name, true, true); } + + //!Returns no throwing "construct from iterators" + //!proxy object + template + typename construct_iter_proxy::type + construct_it(char_ptr_holder_t name, std::nothrow_t) + { return typename construct_iter_proxy::type (this, name, false, false); } + + //!Returns no throwing "search or construct from iterators" + //!proxy object + template + typename construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name, std::nothrow_t) + { return typename construct_iter_proxy::type (this, name, true, false); } + + //!Calls object function blocking recursive interprocess_mutex and guarantees that + //!no new named_alloc or destroy will be executed by any process while + //!executing the object function call*/ + template + void atomic_func(Func &f) + { scoped_lock guard(m_header); f(); } + + //!Tries to calls a functor guaranteeing that no new construction, search or + //!destruction will be executed by any process while executing the object + //!function call. If the atomic function can't be immediatelly executed + //!because the internal mutex is already locked, returns false. + //!If the functor throws, this function throws. + template + bool try_atomic_func(Func &f) + { + scoped_lock guard(m_header, try_to_lock); + if(guard){ + f(); + return true; + } + else{ + return false; + } + } + + //!Destroys a previously created unique instance. + //!Returns false if the object was not present. + template + bool destroy(const ipcdetail::unique_instance_t *) + { + ipcdetail::placement_destroy dtor; + return this->priv_generic_named_destroy + (typeid(T).name(), m_header.m_unique_index, dtor, is_intrusive_t()); + } + + //!Destroys the named object with + //!the given name. Returns false if that object can't be found. + template + bool destroy(const CharType *name) + { + ipcdetail::placement_destroy dtor; + return this->priv_generic_named_destroy + (name, m_header.m_named_index, dtor, is_intrusive_t()); + } + + //!Destroys an anonymous, unique or named object + //!using it's address + template + void destroy_ptr(const T *p) + { + //If T is void transform it to char + typedef typename ipcdetail::char_if_void::type data_t; + ipcdetail::placement_destroy dtor; + priv_destroy_ptr(p, dtor); + } + + //!Returns the name of an object created with construct/find_or_construct + //!functions. Does not throw + template + static const CharType *get_instance_name(const T *ptr) + { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); } + + //!Returns the length of an object created with construct/find_or_construct + //!functions. Does not throw. + template + static size_type get_instance_length(const T *ptr) + { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); } + + //!Returns is the the name of an object created with construct/find_or_construct + //!functions. Does not throw + template + static instance_type get_instance_type(const T *ptr) + { return priv_get_instance_type(block_header_t::block_header_from_value(ptr)); } + + //!Preallocates needed index resources to optimize the + //!creation of "num" named objects in the managed memory segment. + //!Can throw boost::interprocess::bad_alloc if there is no enough memory. + void reserve_named_objects(size_type num) + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + m_header.m_named_index.reserve(num); + } + + //!Preallocates needed index resources to optimize the + //!creation of "num" unique objects in the managed memory segment. + //!Can throw boost::interprocess::bad_alloc if there is no enough memory. + void reserve_unique_objects(size_type num) + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + m_header.m_unique_index.reserve(num); + } + + //!Calls shrink_to_fit in both named and unique object indexes + //!to try to free unused memory from those indexes. + void shrink_to_fit_indexes() + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + m_header.m_named_index.shrink_to_fit(); + m_header.m_unique_index.shrink_to_fit(); + } + + //!Returns the number of named objects stored in + //!the segment. + size_type get_num_named_objects() + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + return m_header.m_named_index.size(); + } + + //!Returns the number of unique objects stored in + //!the segment. + size_type get_num_unique_objects() + { + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + return m_header.m_unique_index.size(); + } + + //!Obtains the minimum size needed by the + //!segment manager + static size_type get_min_size() + { return Base::get_min_size(priv_get_reserved_bytes()); } + + //!Returns a constant iterator to the beginning of the information about + //!the named allocations performed in this segment manager + const_named_iterator named_begin() const + { + return make_transform_iterator + (m_header.m_named_index.begin(), named_transform()); + } + + //!Returns a constant iterator to the end of the information about + //!the named allocations performed in this segment manager + const_named_iterator named_end() const + { + return make_transform_iterator + (m_header.m_named_index.end(), named_transform()); + } + + //!Returns a constant iterator to the beginning of the information about + //!the unique allocations performed in this segment manager + const_unique_iterator unique_begin() const + { + return make_transform_iterator + (m_header.m_unique_index.begin(), unique_transform()); + } + + //!Returns a constant iterator to the end of the information about + //!the unique allocations performed in this segment manager + const_unique_iterator unique_end() const + { + return make_transform_iterator + (m_header.m_unique_index.end(), unique_transform()); + } + + //!This is the default allocator to allocate types T + //!from this managed segment + template + struct allocator + { + typedef boost::interprocess::allocator type; + }; + + //!Returns an instance of the default allocator for type T + //!initialized that allocates memory from this segment manager. + template + typename allocator::type + get_allocator() + { return typename allocator::type(this); } + + //!This is the default deleter to delete types T + //!from this managed segment. + template + struct deleter + { + typedef boost::interprocess::deleter type; + }; + + //!Returns an instance of the default allocator for type T + //!initialized that allocates memory from this segment manager. + template + typename deleter::type + get_deleter() + { return typename deleter::type(this); } + + /// @cond + + //!Generic named/anonymous new function. Offers all the possibilities, + //!such as throwing, search before creating, and the constructor is + //!encapsulated in an object function. + template + T *generic_construct(const CharType *name, + size_type num, + bool try2find, + bool dothrow, + ipcdetail::in_place_interface &table) + { + return static_cast + (priv_generic_construct(name, num, try2find, dothrow, table)); + } + + private: + //!Tries to find a previous named allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair priv_find_impl (const CharType* name, bool lock) + { + //The name can't be null, no anonymous object can be found by name + BOOST_ASSERT(name != 0); + ipcdetail::placement_destroy table; + size_type sz; + void *ret; + + if(name == reinterpret_cast(-1)){ + ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, sz, is_intrusive_t(), lock); + } + else{ + ret = priv_generic_find (name, m_header.m_named_index, table, sz, is_intrusive_t(), lock); + } + return std::pair(static_cast(ret), sz); + } + + //!Tries to find a previous unique allocation. Returns the address + //!and the object count. On failure the first member of the + //!returned pair is 0. + template + std::pair priv_find__impl (const ipcdetail::unique_instance_t* name, bool lock) + { + ipcdetail::placement_destroy table; + size_type size; + void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock); + return std::pair(static_cast(ret), size); + } + + void *priv_generic_construct(const CharType *name, + size_type num, + bool try2find, + bool dothrow, + ipcdetail::in_place_interface &table) + { + void *ret; + //Security overflow check + if(num > ((std::size_t)-1)/table.size){ + if(dothrow) + throw bad_alloc(); + else + return 0; + } + if(name == 0){ + ret = this->prot_anonymous_construct(num, dothrow, table); + } + else if(name == reinterpret_cast(-1)){ + ret = this->priv_generic_named_construct + (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t()); + } + else{ + ret = this->priv_generic_named_construct + (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t()); + } + return ret; + } + + void priv_destroy_ptr(const void *ptr, ipcdetail::in_place_interface &dtor) + { + block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment); + switch(ctrl_data->alloc_type()){ + case anonymous_type: + this->prot_anonymous_destroy(ptr, dtor); + break; + + case named_type: + this->priv_generic_named_destroy + (ctrl_data, m_header.m_named_index, dtor, is_node_index_t()); + break; + + case unique_type: + this->priv_generic_named_destroy + (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t()); + break; + + default: + //This type is unknown, bad pointer passed to this function! + BOOST_ASSERT(0); + break; + } + } + + //!Returns the name of an object created with construct/find_or_construct + //!functions. Does not throw + static const CharType *priv_get_instance_name(block_header_t *ctrl_data) + { + boost::interprocess::allocation_type type = ctrl_data->alloc_type(); + if(type != named_type){ + BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) || + (type == unique_type && ctrl_data->m_num_char != 0) ); + return 0; + } + CharType *name = static_cast(ctrl_data->template name()); + + //Sanity checks + BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharType)); + BOOST_ASSERT(ctrl_data->m_num_char == std::char_traits::length(name)); + return name; + } + + static size_type priv_get_instance_length(block_header_t *ctrl_data, size_type sizeofvalue) + { + //Get header + BOOST_ASSERT((ctrl_data->value_bytes() %sizeofvalue) == 0); + return ctrl_data->value_bytes()/sizeofvalue; + } + + //!Returns is the the name of an object created with construct/find_or_construct + //!functions. Does not throw + static instance_type priv_get_instance_type(block_header_t *ctrl_data) + { + //Get header + BOOST_ASSERT((instance_type)ctrl_data->alloc_type() < max_allocation_type); + return (instance_type)ctrl_data->alloc_type(); + } + + static size_type priv_get_reserved_bytes() + { + //Get the number of bytes until the end of (*this) + //beginning in the end of the Base base. + return sizeof(segment_manager) - sizeof(Base); + } + + template + void *priv_generic_find + (const CharT* name, + IndexType > &index, + ipcdetail::in_place_interface &table, + size_type &length, + ipcdetail::true_ is_intrusive, + bool use_lock) + { + (void)is_intrusive; + typedef IndexType > index_type; + typedef ipcdetail::index_key index_key_t; + typedef typename index_type::iterator index_it; + + //------------------------------- + scoped_lock guard(priv_get_lock(use_lock)); + //------------------------------- + //Find name in index + ipcdetail::intrusive_compare_key key + (name, std::char_traits::length(name)); + index_it it = index.find(key); + + //Initialize return values + void *ret_ptr = 0; + length = 0; + + //If found, assign values + if(it != index.end()){ + //Get header + block_header_t *ctrl_data = it->get_block_header(); + + //Sanity check + BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); + BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT)); + ret_ptr = ctrl_data->value(); + length = ctrl_data->m_value_bytes/table.size; + } + return ret_ptr; + } + + template + void *priv_generic_find + (const CharT* name, + IndexType > &index, + ipcdetail::in_place_interface &table, + size_type &length, + ipcdetail::false_ is_intrusive, + bool use_lock) + { + (void)is_intrusive; + typedef IndexType > index_type; + typedef typename index_type::key_type key_type; + typedef typename index_type::iterator index_it; + + //------------------------------- + scoped_lock guard(priv_get_lock(use_lock)); + //------------------------------- + //Find name in index + index_it it = index.find(key_type(name, std::char_traits::length(name))); + + //Initialize return values + void *ret_ptr = 0; + length = 0; + + //If found, assign values + if(it != index.end()){ + //Get header + block_header_t *ctrl_data = reinterpret_cast + (ipcdetail::to_raw_pointer(it->second.m_ptr)); + + //Sanity check + BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); + BOOST_ASSERT(ctrl_data->sizeof_char() == sizeof(CharT)); + ret_ptr = ctrl_data->value(); + length = ctrl_data->m_value_bytes/table.size; + } + return ret_ptr; + } + + template + bool priv_generic_named_destroy + (block_header_t *block_header, + IndexType > &index, + ipcdetail::in_place_interface &table, + ipcdetail::true_ is_node_index) + { + (void)is_node_index; + typedef typename IndexType >::iterator index_it; + + index_it *ihdr = block_header_t::template to_first_header(block_header); + return this->priv_generic_named_destroy_impl(*ihdr, index, table); + } + + template + bool priv_generic_named_destroy + (block_header_t *block_header, + IndexType > &index, + ipcdetail::in_place_interface &table, + ipcdetail::false_ is_node_index) + { + (void)is_node_index; + CharT *name = static_cast(block_header->template name()); + return this->priv_generic_named_destroy(name, index, table, is_intrusive_t()); + } + + template + bool priv_generic_named_destroy(const CharT *name, + IndexType > &index, + ipcdetail::in_place_interface &table, + ipcdetail::true_ is_intrusive_index) + { + (void)is_intrusive_index; + typedef IndexType > index_type; + typedef ipcdetail::index_key index_key_t; + typedef typename index_type::iterator index_it; + typedef typename index_type::value_type intrusive_value_type; + + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + //Find name in index + ipcdetail::intrusive_compare_key key + (name, std::char_traits::length(name)); + index_it it = index.find(key); + + //If not found, return false + if(it == index.end()){ + //This name is not present in the index, wrong pointer or name! + //BOOST_ASSERT(0); + return false; + } + + block_header_t *ctrl_data = it->get_block_header(); + intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data); + void *memory = iv; + void *values = ctrl_data->value(); + std::size_t num = ctrl_data->m_value_bytes/table.size; + + //Sanity check + BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); + BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char()); + + //Erase node from index + index.erase(it); + + //Destroy the headers + ctrl_data->~block_header_t(); + iv->~intrusive_value_type(); + + //Call destructors and free memory + std::size_t destroyed; + table.destroy_n(values, num, destroyed); + this->deallocate(memory); + return true; + } + + template + bool priv_generic_named_destroy(const CharT *name, + IndexType > &index, + ipcdetail::in_place_interface &table, + ipcdetail::false_ is_intrusive_index) + { + (void)is_intrusive_index; + typedef IndexType > index_type; + typedef typename index_type::iterator index_it; + typedef typename index_type::key_type key_type; + + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + //Try to find the name in the index + index_it it = index.find(key_type (name, + std::char_traits::length(name))); + + //If not found, return false + if(it == index.end()){ + //This name is not present in the index, wrong pointer or name! + //BOOST_ASSERT(0); + return false; + } + return this->priv_generic_named_destroy_impl(it, index, table); + } + + template + bool priv_generic_named_destroy_impl + (const typename IndexType >::iterator &it, + IndexType > &index, + ipcdetail::in_place_interface &table) + { + typedef IndexType > index_type; + typedef typename index_type::iterator index_it; + + //Get allocation parameters + block_header_t *ctrl_data = reinterpret_cast + (ipcdetail::to_raw_pointer(it->second.m_ptr)); + char *stored_name = static_cast(static_cast(const_cast(it->first.name()))); + (void)stored_name; + + //Check if the distance between the name pointer and the memory pointer + //is correct (this can detect incorrect type in destruction) + std::size_t num = ctrl_data->m_value_bytes/table.size; + void *values = ctrl_data->value(); + + //Sanity check + BOOST_ASSERT((ctrl_data->m_value_bytes % table.size) == 0); + BOOST_ASSERT(static_cast(stored_name) == static_cast(ctrl_data->template name())); + BOOST_ASSERT(sizeof(CharT) == ctrl_data->sizeof_char()); + + //Erase node from index + index.erase(it); + + //Destroy the header + ctrl_data->~block_header_t(); + + void *memory; + if(is_node_index_t::value){ + index_it *ihdr = block_header_t::template + to_first_header(ctrl_data); + ihdr->~index_it(); + memory = ihdr; + } + else{ + memory = ctrl_data; + } + + //Call destructors and free memory + std::size_t destroyed; + table.destroy_n(values, num, destroyed); + this->deallocate(memory); + return true; + } + + template + void * priv_generic_named_construct(unsigned char type, + const CharT *name, + size_type num, + bool try2find, + bool dothrow, + ipcdetail::in_place_interface &table, + IndexType > &index, + ipcdetail::true_ is_intrusive) + { + (void)is_intrusive; + std::size_t namelen = std::char_traits::length(name); + + block_header_t block_info ( size_type(table.size*num) + , size_type(table.alignment) + , type + , sizeof(CharT) + , namelen); + + typedef IndexType > index_type; + typedef typename index_type::iterator index_it; + typedef std::pair index_ib; + + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + //Insert the node. This can throw. + //First, we want to know if the key is already present before + //we allocate any memory, and if the key is not present, we + //want to allocate all memory in a single buffer that will + //contain the name and the user buffer. + // + //Since equal_range(key) + insert(hint, value) approach is + //quite inefficient in container implementations + //(they re-test if the position is correct), I've chosen + //to insert the node, do an ugly un-const cast and modify + //the key (which is a smart pointer) to an equivalent one + index_ib insert_ret; + + typename index_type::insert_commit_data commit_data; + typedef typename index_type::value_type intrusive_value_type; + + BOOST_TRY{ + ipcdetail::intrusive_compare_key key(name, namelen); + insert_ret = index.insert_check(key, commit_data); + } + //Ignore exceptions + BOOST_CATCH(...){ + if(dothrow) + BOOST_RETHROW + return 0; + } + BOOST_CATCH_END + + index_it it = insert_ret.first; + + //If found and this is find or construct, return data + //else return null + if(!insert_ret.second){ + if(try2find){ + return it->get_block_header()->value(); + } + if(dothrow){ + throw interprocess_exception(already_exists_error); + } + else{ + return 0; + } + } + + //Allocates buffer for name + data, this can throw (it hurts) + void *buffer_ptr; + + //Check if there is enough memory + if(dothrow){ + buffer_ptr = this->allocate + (block_info.template total_size_with_header()); + } + else{ + buffer_ptr = this->allocate + (block_info.template total_size_with_header(), std::nothrow_t()); + if(!buffer_ptr) + return 0; + } + + //Now construct the intrusive hook plus the header + intrusive_value_type * intrusive_hdr = new(buffer_ptr) intrusive_value_type(); + block_header_t * hdr = new(intrusive_hdr->get_block_header())block_header_t(block_info); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); + + //Copy name to memory segment and insert data + CharT *name_ptr = static_cast(hdr->template name()); + std::char_traits::copy(name_ptr, name, namelen+1); + + BOOST_TRY{ + //Now commit the insertion using previous context data + it = index.insert_commit(*intrusive_hdr, commit_data); + } + //Ignore exceptions + BOOST_CATCH(...){ + if(dothrow) + BOOST_RETHROW + return 0; + } + BOOST_CATCH_END + + //Avoid constructions if constructor is trivial + //Build scoped ptr to avoid leaks with constructor exception + ipcdetail::mem_algo_deallocator mem + (buffer_ptr, *static_cast(this)); + + //Initialize the node value_eraser to erase inserted node + //if something goes wrong. This will be executed *before* + //the memory allocation as the intrusive value is built in that + //memory + value_eraser v_eraser(index, it); + + //Construct array, this can throw + ipcdetail::array_construct(ptr, num, table); + + //Release rollbacks since construction was successful + v_eraser.release(); + mem.release(); + return ptr; + } + + //!Generic named new function for + //!named functions + template + void * priv_generic_named_construct(unsigned char type, + const CharT *name, + size_type num, + bool try2find, + bool dothrow, + ipcdetail::in_place_interface &table, + IndexType > &index, + ipcdetail::false_ is_intrusive) + { + (void)is_intrusive; + std::size_t namelen = std::char_traits::length(name); + + block_header_t block_info ( size_type(table.size*num) + , size_type(table.alignment) + , type + , sizeof(CharT) + , namelen); + + typedef IndexType > index_type; + typedef typename index_type::key_type key_type; + typedef typename index_type::mapped_type mapped_type; + typedef typename index_type::value_type value_type; + typedef typename index_type::iterator index_it; + typedef std::pair index_ib; + + //------------------------------- + scoped_lock guard(m_header); + //------------------------------- + //Insert the node. This can throw. + //First, we want to know if the key is already present before + //we allocate any memory, and if the key is not present, we + //want to allocate all memory in a single buffer that will + //contain the name and the user buffer. + // + //Since equal_range(key) + insert(hint, value) approach is + //quite inefficient in container implementations + //(they re-test if the position is correct), I've chosen + //to insert the node, do an ugly un-const cast and modify + //the key (which is a smart pointer) to an equivalent one + index_ib insert_ret; + BOOST_TRY{ + insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0))); + } + //Ignore exceptions + BOOST_CATCH(...){ + if(dothrow) + BOOST_RETHROW; + return 0; + } + BOOST_CATCH_END + + index_it it = insert_ret.first; + + //If found and this is find or construct, return data + //else return null + if(!insert_ret.second){ + if(try2find){ + block_header_t *hdr = static_cast + (ipcdetail::to_raw_pointer(it->second.m_ptr)); + return hdr->value(); + } + return 0; + } + //Initialize the node value_eraser to erase inserted node + //if something goes wrong + value_eraser v_eraser(index, it); + + //Allocates buffer for name + data, this can throw (it hurts) + void *buffer_ptr; + block_header_t * hdr; + + //Allocate and construct the headers + if(is_node_index_t::value){ + size_type total_size = block_info.template total_size_with_header(); + if(dothrow){ + buffer_ptr = this->allocate(total_size); + } + else{ + buffer_ptr = this->allocate(total_size, std::nothrow_t()); + if(!buffer_ptr) + return 0; + } + index_it *idr = new(buffer_ptr) index_it(it); + hdr = block_header_t::template from_first_header(idr); + } + else{ + if(dothrow){ + buffer_ptr = this->allocate(block_info.total_size()); + } + else{ + buffer_ptr = this->allocate(block_info.total_size(), std::nothrow_t()); + if(!buffer_ptr) + return 0; + } + hdr = static_cast(buffer_ptr); + } + + hdr = new(hdr)block_header_t(block_info); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); + + //Copy name to memory segment and insert data + CharT *name_ptr = static_cast(hdr->template name()); + std::char_traits::copy(name_ptr, name, namelen+1); + + //Do the ugly cast, please mama, forgive me! + //This new key points to an identical string, so it must have the + //same position than the overwritten key according to the predicate + const_cast(it->first).name(name_ptr); + it->second.m_ptr = hdr; + + //Build scoped ptr to avoid leaks with constructor exception + ipcdetail::mem_algo_deallocator mem + (buffer_ptr, *static_cast(this)); + + //Construct array, this can throw + ipcdetail::array_construct(ptr, num, table); + + //All constructors successful, we don't want to release memory + mem.release(); + + //Release node v_eraser since construction was successful + v_eraser.release(); + return ptr; + } + + private: + //!Returns the this pointer + segment_manager *get_this_pointer() + { return this; } + + typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex; + + scoped_lock priv_get_lock(bool use_lock) + { + scoped_lock local(m_header, defer_lock); + if(use_lock){ + local.lock(); + } + return scoped_lock(boost::move(local)); + } + + //!This struct includes needed data and derives from + //!rmutex to allow EBO when using null interprocess_mutex + struct header_t + : public rmutex + { + named_index_t m_named_index; + unique_index_t m_unique_index; + + header_t(Base *restricted_segment_mngr) + : m_named_index (restricted_segment_mngr) + , m_unique_index(restricted_segment_mngr) + {} + } m_header; + + /// @endcond +}; + + +}} //namespace boost { namespace interprocess + +#include + +#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP + diff --git a/cpp/BoostParts/boost/interprocess/shared_memory_object.hpp b/cpp/BoostParts/boost/interprocess/shared_memory_object.hpp new file mode 100644 index 00000000..c501ee1a --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/shared_memory_object.hpp @@ -0,0 +1,422 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_SHARED_MEMORY_OBJECT_HPP +#define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS_ONLY) +# include //System V shared memory... +#elif defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) +# include //O_CREAT, O_*... +# include //shm_xxx +# include //ftruncate, close +# include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +# if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) +# if defined(__FreeBSD__) +# include +# endif +# endif +#else +// +#endif + +//!\file +//!Describes a shared memory object management class. + +namespace boost { +namespace interprocess { + +//!A class that wraps a shared memory mapping that can be used to +//!create mapped regions from the mapped files +class shared_memory_object +{ + /// @cond + //Non-copyable and non-assignable + BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object) + /// @endcond + + public: + //!Default constructor. Represents an empty shared_memory_object. + shared_memory_object(); + + //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode" + //!If the file previously exists, throws an error.*/ + shared_memory_object(create_only_t, const char *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. + shared_memory_object(open_or_create_t, const char *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. + shared_memory_object(open_only_t, const char *name, mode_t mode) + { this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); } + + //!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) + : m_handle(file_handle_t(ipcdetail::invalid_file())) + { this->swap(moved); } + + //!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 tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //!Swaps the shared_memory_objects. Does not throw + void swap(shared_memory_object &moved); + + //!Erases a shared memory object from the system. + //!Returns false on error. Never throws + static bool remove(const char *name); + + //!Sets the size of the shared memory mapping + void truncate(offset_t length); + + //!Destroys *this and indicates that the calling process is finished using + //!the resource. All mapped regions are still + //!valid after destruction. The destructor function will deallocate + //!any system resources allocated by the system for use by this process for + //!this resource. The resource can still be opened again calling + //!the open constructor overload. To erase the resource from the system + //!use remove(). + ~shared_memory_object(); + + //!Returns the name of the shared memory object. + const char *get_name() const; + + //!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; + + //!Returns access mode + mode_t get_mode() const; + + //!Returns mapping handle. Never throws. + mapping_handle_t get_mapping_handle() const; + + /// @cond + private: + + //!Closes a previously opened file mapping. Never throws. + void priv_close(); + + //!Closes a previously opened file mapping. Never throws. + bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm); + + file_handle_t m_handle; + mode_t m_mode; + std::string m_filename; + /// @endcond +}; + +/// @cond + +inline shared_memory_object::shared_memory_object() + : m_handle(file_handle_t(ipcdetail::invalid_file())) +{} + +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 bool shared_memory_object::get_size(offset_t &size) const +{ return ipcdetail::get_file_size((file_handle_t)m_handle, size); } + +inline void shared_memory_object::swap(shared_memory_object &other) +{ + std::swap(m_handle, other.m_handle); + std::swap(m_mode, other.m_mode); + m_filename.swap(other.m_filename); +} + +inline mapping_handle_t shared_memory_object::get_mapping_handle() const +{ + return ipcdetail::mapping_handle_from_file_handle(m_handle); +} + +inline mode_t shared_memory_object::get_mode() const +{ return m_mode; } + +#if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) + +inline bool shared_memory_object::priv_open_or_create + (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm) +{ + m_filename = filename; + std::string shmfile; + ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, shmfile); + + //Set accesses + if (mode != read_write && mode != read_only){ + error_info err = other_error; + throw interprocess_exception(err); + } + + switch(type){ + case ipcdetail::DoOpen: + m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true); + break; + case ipcdetail::DoCreate: + m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true); + break; + case ipcdetail::DoOpenOrCreate: + m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true); + break; + default: + { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + //Check for error + if(m_handle == ipcdetail::invalid_file()){ + error_info err = system_error_code(); + this->priv_close(); + throw interprocess_exception(err); + } + + m_mode = mode; + return true; +} + +inline bool shared_memory_object::remove(const char *filename) +{ + try{ + //Make sure a temporary path is created for shared memory + std::string shmfile; + ipcdetail::tmp_filename(filename, shmfile); + return ipcdetail::delete_file(shmfile.c_str()); + } + catch(...){ + return false; + } +} + +inline void shared_memory_object::truncate(offset_t length) +{ + if(!ipcdetail::truncate_file(m_handle, length)){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } +} + +inline void shared_memory_object::priv_close() +{ + if(m_handle != ipcdetail::invalid_file()){ + ipcdetail::close_file(m_handle); + m_handle = ipcdetail::invalid_file(); + } +} + +#else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) + +namespace shared_memory_object_detail { + +#ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY + +#if defined(__FreeBSD__) + +inline bool use_filesystem_based_posix() +{ + int jailed = 0; + std::size_t len = sizeof(jailed); + ::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0); + return jailed != 0; +} + +#else +#error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY" +#endif + +#endif + +} //shared_memory_object_detail + +inline bool shared_memory_object::priv_open_or_create + (ipcdetail::create_enum_t type, + const char *filename, + mode_t mode, const permissions &perm) +{ + #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) + const bool add_leading_slash = false; + #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) + const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix(); + #else + const bool add_leading_slash = true; + #endif + if(add_leading_slash){ + ipcdetail::add_leading_slash(filename, m_filename); + } + else{ + ipcdetail::create_tmp_and_clean_old_and_get_filename(filename, m_filename); + } + + //Create new mapping + int oflag = 0; + if(mode == read_only){ + oflag |= O_RDONLY; + } + else if(mode == read_write){ + oflag |= O_RDWR; + } + else{ + error_info err(mode_error); + throw interprocess_exception(err); + } + int unix_perm = perm.get_permissions(); + + switch(type){ + case ipcdetail::DoOpen: + { + //No oflag addition + m_handle = shm_open(m_filename.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); + if(m_handle >= 0){ + ::fchmod(m_handle, unix_perm); + } + } + break; + case ipcdetail::DoOpenOrCreate: + { + oflag |= O_CREAT; + //We need a loop to change permissions correctly using fchmod, since + //with "O_CREAT only" shm_open we don't know if we've created or opened the file. + while(1){ + m_handle = shm_open(m_filename.c_str(), oflag, unix_perm); + if(m_handle >= 0){ + ::fchmod(m_handle, unix_perm); + break; + } + else if(errno == EEXIST){ + if((m_handle = shm_open(m_filename.c_str(), oflag, unix_perm)) >= 0 || errno != ENOENT){ + break; + } + } + } + } + break; + default: + { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + //Check for error + if(m_handle == -1){ + error_info err = errno; + this->priv_close(); + throw interprocess_exception(err); + } + + m_filename = filename; + m_mode = mode; + return true; +} + +inline bool shared_memory_object::remove(const char *filename) +{ + try{ + std::string file_str; + #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) + const bool add_leading_slash = false; + #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY) + const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix(); + #else + const bool add_leading_slash = true; + #endif + if(add_leading_slash){ + ipcdetail::add_leading_slash(filename, file_str); + } + else{ + ipcdetail::tmp_filename(filename, file_str); + } + return 0 == shm_unlink(file_str.c_str()); + } + catch(...){ + return false; + } +} + +inline void shared_memory_object::truncate(offset_t length) +{ + if(0 != ftruncate(m_handle, length)){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline void shared_memory_object::priv_close() +{ + if(m_handle != -1){ + ::close(m_handle); + m_handle = -1; + } +} + +#endif + +///@endcond + +//!A class that stores the name of a shared memory +//!and calls shared_memory_object::remove(name) in its destructor +//!Useful to remove temporary shared memory objects in the presence +//!of exceptions +class remove_shared_memory_on_destroy +{ + const char * m_name; + public: + remove_shared_memory_on_destroy(const char *name) + : m_name(name) + {} + + ~remove_shared_memory_on_destroy() + { shared_memory_object::remove(m_name); } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP diff --git a/cpp/BoostParts/boost/interprocess/smart_ptr/deleter.hpp b/cpp/BoostParts/boost/interprocess/smart_ptr/deleter.hpp new file mode 100644 index 00000000..8447bf1b --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/smart_ptr/deleter.hpp @@ -0,0 +1,64 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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_DELETER_HPP +#define BOOST_INTERPROCESS_DELETER_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +//!\file +//!Describes the functor to delete objects from the segment. + +namespace boost { +namespace interprocess { + +//!A deleter that uses the segment manager's destroy_ptr +//!function to destroy the passed pointer resource. +//! +//!This deleter is used +template +class deleter +{ + public: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type pointer; + + private: + typedef typename boost::intrusive:: + pointer_traits::template + rebind_pointer::type segment_manager_pointer; + + segment_manager_pointer mp_mngr; + + public: + deleter(segment_manager_pointer pmngr) + : mp_mngr(pmngr) + {} + + void operator()(const pointer &p) + { mp_mngr->destroy_ptr(ipcdetail::to_raw_pointer(p)); } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DELETER_HPP diff --git a/cpp/BoostParts/boost/interprocess/streams/bufferstream.hpp b/cpp/BoostParts/boost/interprocess/streams/bufferstream.hpp new file mode 100644 index 00000000..9a2681ab --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/streams/bufferstream.hpp @@ -0,0 +1,444 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's sstream file. Modified by Ion Gaztanaga 2005-2012. +// Changed internal SGI string to a buffer. Added efficient +// internal buffer get/set/swap functions, so that we can obtain/establish the +// internal buffer without any reallocation or copy. Kill those temporaries! +/////////////////////////////////////////////////////////////////////////////// +/* + * Copyright (c) 1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +//!\file +//!This file defines basic_bufferbuf, basic_ibufferstream, +//!basic_obufferstream, and basic_bufferstream classes. These classes +//!represent streamsbufs and streams whose sources or destinations +//!are fixed size character buffers. + +#ifndef BOOST_INTERPROCESS_BUFFERSTREAM_HPP +#define BOOST_INTERPROCESS_BUFFERSTREAM_HPP + +#include +#include + +#include +#include +#include +#include +#include // char traits +#include // ptrdiff_t +#include +#include + +namespace boost { namespace interprocess { + +//!A streambuf class that controls the transmission of elements to and from +//!a basic_xbufferstream. The elements are transmitted from a to a fixed +//!size buffer +template +class basic_bufferbuf + : public std::basic_streambuf +{ + public: + typedef CharT char_type; + typedef typename CharTraits::int_type int_type; + typedef typename CharTraits::pos_type pos_type; + typedef typename CharTraits::off_type off_type; + typedef CharTraits traits_type; + typedef std::basic_streambuf base_t; + + public: + //!Constructor. + //!Does not throw. + explicit basic_bufferbuf(std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : base_t(), m_mode(mode), m_buffer(0), m_length(0) + {} + + //!Constructor. Assigns formatting buffer. + //!Does not throw. + explicit basic_bufferbuf(CharT *buf, std::size_t length, + std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : base_t(), m_mode(mode), m_buffer(buf), m_length(length) + { this->set_pointers(); } + + virtual ~basic_bufferbuf(){} + + public: + //!Returns the pointer and size of the internal buffer. + //!Does not throw. + std::pair buffer() const + { return std::pair(m_buffer, m_length); } + + //!Sets the underlying buffer to a new value + //!Does not throw. + void buffer(CharT *buf, std::size_t length) + { m_buffer = buf; m_length = length; this->set_pointers(); } + + /// @cond + private: + void set_pointers() + { + // The initial read position is the beginning of the buffer. + if(m_mode & std::ios_base::in) + this->setg(m_buffer, m_buffer, m_buffer + m_length); + + // The initial write position is the beginning of the buffer. + if(m_mode & std::ios_base::out) + this->setp(m_buffer, m_buffer + m_length); + } + + protected: + virtual int_type underflow() + { + // 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()) + { + if(this->gptr() != this->eback()) { + if(!CharTraits::eq_int_type(c, CharTraits::eof())) { + if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) { + this->gbump(-1); + return c; + } + else if(m_mode & std::ios_base::out) { + this->gbump(-1); + *this->gptr() = c; + return c; + } + else + return CharTraits::eof(); + } + else { + this->gbump(-1); + return CharTraits::not_eof(c); + } + } + else + return CharTraits::eof(); + } + + virtual int_type overflow(int_type c = CharTraits::eof()) + { + if(m_mode & std::ios_base::out) { + if(!CharTraits::eq_int_type(c, CharTraits::eof())) { +// if(!(m_mode & std::ios_base::in)) { +// if(this->pptr() != this->epptr()) { +// *this->pptr() = CharTraits::to_char_type(c); +// this->pbump(1); +// return c; +// } +// else +// return CharTraits::eof(); +// } +// else { + if(this->pptr() == this->epptr()) { + //We can't append to a static buffer + return CharTraits::eof(); + } + else { + *this->pptr() = CharTraits::to_char_type(c); + this->pbump(1); + return c; + } +// } + } + else // c is EOF, so we don't have to do anything + return CharTraits::not_eof(c); + } + else // Overflow always fails if it's read-only. + return CharTraits::eof(); + } + + 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) + { + bool in = false; + bool out = false; + + const std::ios_base::openmode inout = + std::ios_base::in | std::ios_base::out; + + if((mode & inout) == inout) { + if(dir == std::ios_base::beg || dir == std::ios_base::end) + in = out = true; + } + else if(mode & std::ios_base::in) + in = true; + else if(mode & std::ios_base::out) + out = true; + + if(!in && !out) + return pos_type(off_type(-1)); + else if((in && (!(m_mode & std::ios_base::in) || this->gptr() == 0)) || + (out && (!(m_mode & std::ios_base::out) || this->pptr() == 0))) + return pos_type(off_type(-1)); + + std::streamoff newoff; + switch(dir) { + case std::ios_base::beg: + newoff = 0; + break; + case std::ios_base::end: + newoff = static_cast(m_length); + break; + case std::ios_base::cur: + newoff = in ? static_cast(this->gptr() - this->eback()) + : static_cast(this->pptr() - this->pbase()); + break; + default: + return pos_type(off_type(-1)); + } + + off += newoff; + + if(in) { + std::ptrdiff_t n = this->egptr() - this->eback(); + + if(off < 0 || off > n) + return pos_type(off_type(-1)); + else + this->setg(this->eback(), this->eback() + off, this->eback() + n); + } + + if(out) { + std::ptrdiff_t n = this->epptr() - this->pbase(); + + if(off < 0 || off > n) + return pos_type(off_type(-1)); + else { + this->setp(this->pbase(), this->pbase() + n); + this->pbump(off); + } + } + + return pos_type(off); + } + + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + { return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); } + + private: + std::ios_base::openmode m_mode; + CharT * m_buffer; + std::size_t m_length; + /// @endcond +}; + +//!A basic_istream class that uses a fixed size character buffer +//!as its formatting buffer. +template +class basic_ibufferstream + : public std::basic_istream +{ + public: // Typedefs + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_istream base_t; + + public: + //!Constructor. + //!Does not throw. + basic_ibufferstream(std::ios_base::openmode mode = std::ios_base::in) + : basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::in) + { basic_ios_t::init(&m_buf); } + + //!Constructor. Assigns formatting buffer. + //!Does not throw. + basic_ibufferstream(const CharT *buf, std::size_t length, + std::ios_base::openmode mode = std::ios_base::in) + : basic_ios_t(), base_t(0), + m_buf(const_cast(buf), length, mode | std::ios_base::in) + { basic_ios_t::init(&m_buf); } + + ~basic_ibufferstream(){}; + + public: + //!Returns the address of the stored + //!stream buffer. + basic_bufferbuf* rdbuf() const + { return const_cast*>(&m_buf); } + + //!Returns the pointer and size of the internal buffer. + //!Does not throw. + std::pair buffer() const + { return m_buf.buffer(); } + + //!Sets the underlying buffer to a new value. Resets + //!stream position. Does not throw. + void buffer(const CharT *buf, std::size_t length) + { m_buf.buffer(const_cast(buf), length); } + + /// @cond + private: + basic_bufferbuf m_buf; + /// @endcond +}; + +//!A basic_ostream class that uses a fixed size character buffer +//!as its formatting buffer. +template +class basic_obufferstream + : public std::basic_ostream +{ + public: + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + /// @cond + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_ostream base_t; + /// @endcond + public: + //!Constructor. + //!Does not throw. + basic_obufferstream(std::ios_base::openmode mode = std::ios_base::out) + : basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::out) + { basic_ios_t::init(&m_buf); } + + //!Constructor. Assigns formatting buffer. + //!Does not throw. + basic_obufferstream(CharT *buf, std::size_t length, + std::ios_base::openmode mode = std::ios_base::out) + : basic_ios_t(), base_t(0), + m_buf(buf, length, mode | std::ios_base::out) + { basic_ios_t::init(&m_buf); } + + ~basic_obufferstream(){} + + public: + //!Returns the address of the stored + //!stream buffer. + basic_bufferbuf* rdbuf() const + { return const_cast*>(&m_buf); } + + //!Returns the pointer and size of the internal buffer. + //!Does not throw. + std::pair buffer() const + { return m_buf.buffer(); } + + //!Sets the underlying buffer to a new value. Resets + //!stream position. Does not throw. + void buffer(CharT *buf, std::size_t length) + { m_buf.buffer(buf, length); } + + /// @cond + private: + basic_bufferbuf m_buf; + /// @endcond +}; + + +//!A basic_iostream class that uses a fixed size character buffer +//!as its formatting buffer. +template +class basic_bufferstream + : public std::basic_iostream + +{ + public: // Typedefs + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + /// @cond + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_iostream base_t; + /// @endcond + + public: + //!Constructor. + //!Does not throw. + basic_bufferstream(std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : basic_ios_t(), base_t(0), m_buf(mode) + { basic_ios_t::init(&m_buf); } + + //!Constructor. Assigns formatting buffer. + //!Does not throw. + basic_bufferstream(CharT *buf, std::size_t length, + std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::out) + : basic_ios_t(), base_t(0), m_buf(buf, length, mode) + { basic_ios_t::init(&m_buf); } + + ~basic_bufferstream(){} + + public: + //!Returns the address of the stored + //!stream buffer. + basic_bufferbuf* rdbuf() const + { return const_cast*>(&m_buf); } + + //!Returns the pointer and size of the internal buffer. + //!Does not throw. + std::pair buffer() const + { return m_buf.buffer(); } + + //!Sets the underlying buffer to a new value. Resets + //!stream position. Does not throw. + void buffer(CharT *buf, std::size_t length) + { m_buf.buffer(buf, length); } + + /// @cond + private: + basic_bufferbuf m_buf; + /// @endcond +}; + +//Some typedefs to simplify usage +typedef basic_bufferbuf bufferbuf; +typedef basic_bufferstream bufferstream; +typedef basic_ibufferstream ibufferstream; +typedef basic_obufferstream obufferstream; + +typedef basic_bufferbuf wbufferbuf; +typedef basic_bufferstream wbufferstream; +typedef basic_ibufferstream wibufferstream; +typedef basic_obufferstream wobufferstream; + + +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_BUFFERSTREAM_HPP */ diff --git a/cpp/BoostParts/boost/interprocess/sync/interprocess_mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/interprocess_mutex.hpp new file mode 100644 index 00000000..5615e8b9 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/interprocess_mutex.hpp @@ -0,0 +1,184 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MUTEX_HPP +#define BOOST_INTERPROCESS_MUTEX_HPP + +/// @cond + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include + +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) + #include + #define BOOST_INTERPROCESS_USE_POSIX +//Experimental... +#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + #include + #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION + +namespace boost { +namespace interprocess { +namespace ipcdetail{ +namespace robust_emulation_helpers { + +template +class mutex_traits; + +}}}} + +#endif + +/// @endcond + +//!\file +//!Describes a mutex class that can be placed in memory shared by +//!several processes. + +namespace boost { +namespace interprocess { + +class interprocess_condition; + +//!Wraps a interprocess_mutex that can be placed in shared memory and can be +//!shared between processes. Allows timed lock tries +class interprocess_mutex +{ + /// @cond + //Non-copyable + interprocess_mutex(const interprocess_mutex &); + interprocess_mutex &operator=(const interprocess_mutex &); + friend class interprocess_condition; + + public: + #if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION) + #undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION + typedef ipcdetail::spin_mutex internal_mutex_type; + private: + friend class ipcdetail::robust_emulation_helpers::mutex_traits; + 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 + + /// @endcond + public: + + //!Constructor. + //!Throws interprocess_exception on error. + interprocess_mutex(); + + //!Destructor. If any process uses the mutex after the destructor is called + //!the result is undefined. Does not throw. + ~interprocess_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. + void lock(); + + //!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. + bool try_lock(); + + //!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 + //! number of times it is locked. + //!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); + + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //!Throws: interprocess_exception on error. + void unlock(); + + /// @cond + internal_mutex_type &internal_mutex() + { return m_mutex; } + + const internal_mutex_type &internal_mutex() const + { return m_mutex; } + + private: + internal_mutex_type m_mutex; + /// @endcond +}; + +} //namespace interprocess { +} //namespace boost { + + +namespace boost { +namespace interprocess { + +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 + = boost::posix_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 +} + +inline bool interprocess_mutex::try_lock() +{ return m_mutex.try_lock(); } + +inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return m_mutex.timed_lock(abs_time); } + +inline void interprocess_mutex::unlock() +{ m_mutex.unlock(); } + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/interprocess_recursive_mutex.hpp new file mode 100644 index 00000000..1c5dad37 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -0,0 +1,177 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code: +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP + +/// @cond + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ + (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined (BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES)) + #include + #define BOOST_INTERPROCESS_USE_POSIX +//Experimental... +#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS) + #include + #define BOOST_INTERPROCESS_USE_WINDOWS +#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + #include + #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION +#endif + +#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) +namespace boost { +namespace interprocess { +namespace ipcdetail{ +namespace robust_emulation_helpers { + +template +class mutex_traits; + +}}}} + +#endif + +/// @endcond + +//!\file +//!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes + +namespace boost { +namespace interprocess { + +//!Wraps a interprocess_mutex that can be placed in shared memory and can be +//!shared between processes. Allows several locking calls by the same +//!process. Allows timed lock tries +class interprocess_recursive_mutex +{ + /// @cond + //Non-copyable + interprocess_recursive_mutex(const interprocess_recursive_mutex &); + interprocess_recursive_mutex &operator=(const interprocess_recursive_mutex &); + /// @endcond + public: + //!Constructor. + //!Throws interprocess_exception on error. + interprocess_recursive_mutex(); + + //!Destructor. If any process uses the mutex after the destructor is called + //!the result is undefined. Does not throw. + ~interprocess_recursive_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. The mutex must be unlocked + //! the same number of times it is locked. + //!Throws: interprocess_exception on error. + void lock(); + + //!Tries to lock the interprocess_mutex, returns false when interprocess_mutex + //!is already locked, returns true when success. The mutex must be unlocked + //!the same number of times it is locked. + //!Throws: interprocess_exception if a severe error is found + bool try_lock(); + + //!Tries to lock the interprocess_mutex, if interprocess_mutex can't be locked before + //!abs_time time, returns false. The mutex must be unlocked + //! the same number of times it is locked. + //!Throws: interprocess_exception if a severe error is found + bool timed_lock(const boost::posix_time::ptime &abs_time); + + //!Effects: The calling thread releases the exclusive ownership of the mutex. + //! If the mutex supports recursive locking, the mutex must be unlocked the + //! same number of times it is locked. + //!Throws: interprocess_exception on error. + void unlock(); + /// @cond + private: + + #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) + #undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION + void take_ownership(){ mutex.take_ownership(); } + friend class ipcdetail::robust_emulation_helpers::mutex_traits; + ipcdetail::spin_recursive_mutex mutex; + #elif defined(BOOST_INTERPROCESS_USE_POSIX) + #undef BOOST_INTERPROCESS_USE_POSIX + ipcdetail::posix_recursive_mutex mutex; + #elif defined(BOOST_INTERPROCESS_USE_WINDOWS) + #undef BOOST_INTERPROCESS_USE_WINDOWS + ipcdetail::windows_recursive_mutex mutex; + #else + #error "Unknown platform for interprocess_mutex" + #endif + /// @endcond +}; + +} //namespace interprocess { +} //namespace boost { + +namespace boost { +namespace interprocess { + +inline interprocess_recursive_mutex::interprocess_recursive_mutex(){} + +inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){} + +inline void interprocess_recursive_mutex::lock() +{ + #ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING + boost::posix_time::ptime wait_time + = boost::posix_time::microsec_clock::universal_time() + + boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS); + if (!mutex.timed_lock(wait_time)){ + throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?"); + } + #else + mutex.lock(); + #endif +} + +inline bool interprocess_recursive_mutex::try_lock() +{ return mutex.try_lock(); } + +inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return mutex.timed_lock(abs_time); } + +inline void interprocess_recursive_mutex::unlock() +{ mutex.unlock(); } + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/lock_options.hpp b/cpp/BoostParts/boost/interprocess/sync/lock_options.hpp new file mode 100644 index 00000000..1139d83a --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/lock_options.hpp @@ -0,0 +1,55 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_LOCK_OPTIONS_HPP +#define BOOST_INTERPROCESS_LOCK_OPTIONS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +//!\file +//!Describes the lock options with associated with interprocess_mutex lock constructors. + +namespace boost { + +namespace posix_time +{ class ptime; } + +namespace interprocess { + +//!Type to indicate to a mutex lock constructor that must not lock the mutex. +struct defer_lock_type{}; +//!Type to indicate to a mutex lock constructor that must try to lock the mutex. +struct try_to_lock_type {}; +//!Type to indicate to a mutex lock constructor that the mutex is already locked. +struct accept_ownership_type{}; + +//!An object indicating that the locking +//!must be deferred. +static const defer_lock_type defer_lock = defer_lock_type(); + +//!An object indicating that a try_lock() +//!operation must be executed. +static const try_to_lock_type try_to_lock = try_to_lock_type(); + +//!An object indicating that the ownership of lockable +//!object must be accepted by the new owner. +static const accept_ownership_type accept_ownership = accept_ownership_type(); + +} // namespace interprocess { +} // namespace boost{ + +#include + +#endif // BOOST_INTERPROCESS_LOCK_OPTIONS_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/mutex_family.hpp b/cpp/BoostParts/boost/interprocess/sync/mutex_family.hpp new file mode 100644 index 00000000..0636de0d --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/mutex_family.hpp @@ -0,0 +1,56 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_MUTEX_FAMILY_HPP +#define BOOST_INTERPROCESS_MUTEX_FAMILY_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +//!\file +//!Describes a shared interprocess_mutex family fit algorithm used to allocate objects in shared memory. + +namespace boost { + +namespace interprocess { + +//!Describes interprocess_mutex family to use with Interprocess framework +//!based on boost::interprocess synchronization objects. +struct mutex_family +{ + typedef boost::interprocess::interprocess_mutex mutex_type; + typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex_type; +}; + +//!Describes interprocess_mutex family to use with Interprocess frameworks +//!based on null operation synchronization objects. +struct null_mutex_family +{ + typedef boost::interprocess::null_mutex mutex_type; + typedef boost::interprocess::null_mutex recursive_mutex_type; +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP + + diff --git a/cpp/BoostParts/boost/interprocess/sync/null_mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/null_mutex.hpp new file mode 100644 index 00000000..d9f69a69 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/null_mutex.hpp @@ -0,0 +1,147 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_NULL_MUTEX_HPP +#define BOOST_INTERPROCESS_NULL_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + + +//!\file +//!Describes null_mutex classes + +namespace boost { + +namespace posix_time +{ class ptime; } + +namespace interprocess { + +//!Implements a mutex that simulates a mutex without doing any operation and +//!simulates a successful operation. +class null_mutex +{ + /// @cond + null_mutex(const null_mutex&); + null_mutex &operator= (const null_mutex&); + /// @endcond + public: + + //!Constructor. + //!Empty. + null_mutex(){} + + //!Destructor. + //!Empty. + ~null_mutex(){} + + //!Simulates a mutex lock() operation. Empty function. + void lock(){} + + //!Simulates a mutex try_lock() operation. + //!Equivalent to "return true;" + bool try_lock() + { return true; } + + //!Simulates a mutex timed_lock() operation. + //!Equivalent to "return true;" + bool timed_lock(const boost::posix_time::ptime &) + { return true; } + + //!Simulates a mutex unlock() operation. + //!Empty function. + void unlock(){} + + //!Simulates a mutex lock_sharable() operation. + //!Empty function. + void lock_sharable(){} + + //!Simulates a mutex try_lock_sharable() operation. + //!Equivalent to "return true;" + bool try_lock_sharable() + { return true; } + + //!Simulates a mutex timed_lock_sharable() operation. + //!Equivalent to "return true;" + bool timed_lock_sharable(const boost::posix_time::ptime &) + { return true; } + + //!Simulates a mutex unlock_sharable() operation. + //!Empty function. + void unlock_sharable(){} + + //!Simulates a mutex lock_upgradable() operation. + //!Empty function. + void lock_upgradable(){} + + //!Simulates a mutex try_lock_upgradable() operation. + //!Equivalent to "return true;" + bool try_lock_upgradable() + { return true; } + + //!Simulates a mutex timed_lock_upgradable() operation. + //!Equivalent to "return true;" + bool timed_lock_upgradable(const boost::posix_time::ptime &) + { return true; } + + //!Simulates a mutex unlock_upgradable() operation. + //!Empty function. + void unlock_upgradable(){} + + //!Simulates unlock_and_lock_upgradable(). + //!Empty function. + void unlock_and_lock_upgradable(){} + + //!Simulates unlock_and_lock_sharable(). + //!Empty function. + void unlock_and_lock_sharable(){} + + //!Simulates unlock_upgradable_and_lock_sharable(). + //!Empty function. + void unlock_upgradable_and_lock_sharable(){} + + //Promotions + + //!Simulates unlock_upgradable_and_lock(). + //!Empty function. + void unlock_upgradable_and_lock(){} + + //!Simulates try_unlock_upgradable_and_lock(). + //!Equivalent to "return true;" + bool try_unlock_upgradable_and_lock() + { return true; } + + //!Simulates timed_unlock_upgradable_and_lock(). + //!Equivalent to "return true;" + bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &) + { return true; } + + //!Simulates try_unlock_sharable_and_lock(). + //!Equivalent to "return true;" + bool try_unlock_sharable_and_lock() + { return true; } + + //!Simulates try_unlock_sharable_and_lock_upgradable(). + //!Equivalent to "return true;" + bool try_unlock_sharable_and_lock_upgradable() + { return true; } +}; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_NULL_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/posix/mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/posix/mutex.hpp new file mode 100644 index 00000000..344c5e90 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/posix/mutex.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code: +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS +# include +#endif +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class posix_condition; + +class posix_mutex +{ + posix_mutex(const posix_mutex &); + posix_mutex &operator=(const posix_mutex &); + public: + + posix_mutex(); + ~posix_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + + friend class posix_condition; + + private: + pthread_mutex_t m_mut; +}; + +inline posix_mutex::posix_mutex() +{ + mutexattr_wrapper mut_attr; + mutex_initializer mut(m_mut, mut_attr); + mut.release(); +} + +inline posix_mutex::~posix_mutex() +{ + int res = pthread_mutex_destroy(&m_mut); + BOOST_ASSERT(res == 0);(void)res; +} + +inline void posix_mutex::lock() +{ + if (pthread_mutex_lock(&m_mut) != 0) + throw lock_exception(); +} + +inline bool posix_mutex::try_lock() +{ + int res = pthread_mutex_trylock(&m_mut); + if (!(res == 0 || res == EBUSY)) + throw lock_exception(); + return res == 0; +} + +inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + + timespec ts = ptime_to_timespec(abs_time); + int res = pthread_mutex_timedlock(&m_mut, &ts); + if (res != 0 && res != ETIMEDOUT) + throw lock_exception(); + return res == 0; + + #else //BOOST_INTERPROCESS_POSIX_TIMEOUTS + + //Obtain current count and target time + boost::posix_time::ptime now = microsec_clock::universal_time(); + + do{ + if(this->try_lock()){ + break; + } + now = microsec_clock::universal_time(); + + if(now >= abs_time){ + return false; + } + // relinquish current time slice + thread_yield(); + }while (true); + return true; + + #endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS +} + +inline void posix_mutex::unlock() +{ + int res = 0; + res = pthread_mutex_unlock(&m_mut); + (void)res; + BOOST_ASSERT(res == 0); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/posix/pthread_helpers.hpp b/cpp/BoostParts/boost/interprocess/sync/posix/pthread_helpers.hpp new file mode 100644 index 00000000..9e989d58 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/posix/pthread_helpers.hpp @@ -0,0 +1,168 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PTHREAD_HELPERS_HPP +#define BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail{ + + #if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED + + //!Makes pthread_mutexattr_t cleanup easy when using exceptions + struct mutexattr_wrapper + { + //!Constructor + mutexattr_wrapper(bool recursive = false) + { + 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"); + } + + //!Destructor + ~mutexattr_wrapper() { pthread_mutexattr_destroy(&m_attr); } + + //!This allows using mutexattr_wrapper as pthread_mutexattr_t + operator pthread_mutexattr_t&() { return m_attr; } + + pthread_mutexattr_t m_attr; + }; + + //!Makes pthread_condattr_t cleanup easy when using exceptions + struct condattr_wrapper + { + //!Constructor + condattr_wrapper() + { + if(pthread_condattr_init(&m_attr)!=0 || + pthread_condattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0) + throw interprocess_exception("pthread_condattr_xxxx failed"); + } + + //!Destructor + ~condattr_wrapper() { pthread_condattr_destroy(&m_attr); } + + //!This allows using condattr_wrapper as pthread_condattr_t + operator pthread_condattr_t&(){ return m_attr; } + + pthread_condattr_t m_attr; + }; + + //!Makes initialized pthread_mutex_t cleanup easy when using exceptions + class mutex_initializer + { + public: + //!Constructor. Takes interprocess_mutex attributes to initialize the interprocess_mutex + mutex_initializer(pthread_mutex_t &mut, pthread_mutexattr_t &mut_attr) + : mp_mut(&mut) + { + if(pthread_mutex_init(mp_mut, &mut_attr) != 0) + throw interprocess_exception("pthread_mutex_init failed"); + } + + ~mutex_initializer() { if(mp_mut) pthread_mutex_destroy(mp_mut); } + + void release() {mp_mut = 0; } + + private: + pthread_mutex_t *mp_mut; + }; + + //!Makes initialized pthread_cond_t cleanup easy when using exceptions + class condition_initializer + { + public: + condition_initializer(pthread_cond_t &cond, pthread_condattr_t &cond_attr) + : mp_cond(&cond) + { + if(pthread_cond_init(mp_cond, &cond_attr)!= 0) + throw interprocess_exception("pthread_cond_init failed"); + } + + ~condition_initializer() { if(mp_cond) pthread_cond_destroy(mp_cond); } + + void release() { mp_cond = 0; } + + private: + pthread_cond_t *mp_cond; + }; + + #endif // #if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED + + #if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) + + //!Makes pthread_barrierattr_t cleanup easy when using exceptions + struct barrierattr_wrapper + { + //!Constructor + barrierattr_wrapper() + { + if(pthread_barrierattr_init(&m_attr)!=0 || + pthread_barrierattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0) + throw interprocess_exception("pthread_barrierattr_xxx failed"); + } + + //!Destructor + ~barrierattr_wrapper() { pthread_barrierattr_destroy(&m_attr); } + + //!This allows using mutexattr_wrapper as pthread_barrierattr_t + operator pthread_barrierattr_t&() { return m_attr; } + + pthread_barrierattr_t m_attr; + }; + + //!Makes initialized pthread_barrier_t cleanup easy when using exceptions + class barrier_initializer + { + public: + //!Constructor. Takes barrier attributes to initialize the barrier + barrier_initializer(pthread_barrier_t &mut, + pthread_barrierattr_t &mut_attr, + int count) + : mp_barrier(&mut) + { + if(pthread_barrier_init(mp_barrier, &mut_attr, count) != 0) + throw interprocess_exception("pthread_barrier_init failed"); + } + + ~barrier_initializer() { if(mp_barrier) pthread_barrier_destroy(mp_barrier); } + + void release() {mp_barrier = 0; } + + private: + pthread_barrier_t *mp_barrier; + }; + + #endif //#if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) + +}//namespace ipcdetail + +}//namespace interprocess + +}//namespace boost + +#include + +#endif //ifdef BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/posix/ptime_to_timespec.hpp b/cpp/BoostParts/boost/interprocess/sync/posix/ptime_to_timespec.hpp new file mode 100644 index 00000000..3e20dc70 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/posix/ptime_to_timespec.hpp @@ -0,0 +1,38 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 + +#include + +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)); + boost::posix_time::time_duration 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/cpp/BoostParts/boost/interprocess/sync/posix/recursive_mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/posix/recursive_mutex.hpp new file mode 100644 index 00000000..385d714f --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/posix/recursive_mutex.hpp @@ -0,0 +1,142 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code: +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS +# include +#endif +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class posix_recursive_mutex +{ + posix_recursive_mutex(const posix_recursive_mutex &); + posix_recursive_mutex &operator=(const posix_recursive_mutex &); + public: + + posix_recursive_mutex(); + ~posix_recursive_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + + private: + pthread_mutex_t m_mut; +}; + +inline posix_recursive_mutex::posix_recursive_mutex() +{ + mutexattr_wrapper mut_attr(true); + mutex_initializer mut(m_mut, mut_attr); + mut.release(); +} + +inline posix_recursive_mutex::~posix_recursive_mutex() +{ + int res = pthread_mutex_destroy(&m_mut); + BOOST_ASSERT(res == 0);(void)res; +} + +inline void posix_recursive_mutex::lock() +{ + if (pthread_mutex_lock(&m_mut) != 0) + throw lock_exception(); +} + +inline bool posix_recursive_mutex::try_lock() +{ + int res = pthread_mutex_trylock(&m_mut); + if (!(res == 0 || res == EBUSY)) + throw lock_exception(); + return res == 0; +} + +inline bool posix_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + + timespec ts = ptime_to_timespec(abs_time); + int res = pthread_mutex_timedlock(&m_mut, &ts); + if (res != 0 && res != ETIMEDOUT) + throw lock_exception(); + return res == 0; + + #else //BOOST_INTERPROCESS_POSIX_TIMEOUTS + + //Obtain current count and target time + boost::posix_time::ptime now = microsec_clock::universal_time(); + + do{ + if(this->try_lock()){ + break; + } + now = microsec_clock::universal_time(); + + if(now >= abs_time){ + return false; + } + // relinquish current time slice + thread_yield(); + }while (true); + return true; + + #endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS +} + +inline void posix_recursive_mutex::unlock() +{ + int res = 0; + res = pthread_mutex_unlock(&m_mut); + BOOST_ASSERT(res == 0); (void)res; +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/scoped_lock.hpp b/cpp/BoostParts/boost/interprocess/sync/scoped_lock.hpp new file mode 100644 index 00000000..5709f6ff --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/scoped_lock.hpp @@ -0,0 +1,372 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +// +// This interface is inspired by Howard Hinnant's lock proposal. +// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SCOPED_LOCK_HPP +#define BOOST_INTERPROCESS_SCOPED_LOCK_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes the scoped_lock class. + +namespace boost { +namespace interprocess { + + +//!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking +//!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all +//!of this functionality. If the client of scoped_lock does not use +//!functionality which the Mutex does not supply, no harm is done. Mutex ownership +//!transfer is supported through the syntax of move semantics. Ownership transfer +//!is allowed both by construction and assignment. The scoped_lock does not support +//!copy semantics. A compile time error results if copy construction or copy +//!assignment is attempted. Mutex ownership can also be moved from an +//!upgradable_lock and sharable_lock via constructor. In this role, scoped_lock +//!shares the same functionality as a write_lock. +template +class scoped_lock +{ + /// @cond + private: + typedef scoped_lock this_type; + BOOST_MOVABLE_BUT_NOT_COPYABLE(scoped_lock) + typedef bool this_type::*unspecified_bool_type; + /// @endcond + public: + + typedef Mutex mutex_type; + + //!Effects: Default constructs a scoped_lock. + //!Postconditions: owns() == false and mutex() == 0. + scoped_lock() + : mp_mutex(0), m_locked(false) + {} + + //!Effects: m.lock(). + //!Postconditions: owns() == true and mutex() == &m. + //!Notes: The constructor will take ownership of the mutex. If another thread + //! already owns the mutex, this thread will block until the mutex is released. + //! Whether or not this constructor handles recursive locking depends upon the mutex. + explicit scoped_lock(mutex_type& m) + : mp_mutex(&m), m_locked(false) + { mp_mutex->lock(); m_locked = true; } + + //!Postconditions: owns() == false, and mutex() == &m. + //!Notes: The constructor will not take ownership of the mutex. There is no effect + //! required on the referenced mutex. + scoped_lock(mutex_type& m, defer_lock_type) + : mp_mutex(&m), m_locked(false) + {} + + //!Postconditions: owns() == true, and mutex() == &m. + //!Notes: The constructor will suppose that the mutex is already locked. There + //! is no effect required on the referenced mutex. + scoped_lock(mutex_type& m, accept_ownership_type) + : mp_mutex(&m), m_locked(true) + {} + + //!Effects: m.try_lock(). + //!Postconditions: mutex() == &m. owns() == the return value of the + //! m.try_lock() executed within the constructor. + //!Notes: The constructor will take ownership of the mutex if it can do + //! so without waiting. Whether or not this constructor 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, try_to_lock_type) + : mp_mutex(&m), m_locked(mp_mutex->try_lock()) + {} + + //!Effects: m.timed_lock(abs_time). + //!Postconditions: mutex() == &m. owns() == the return value of the + //! m.timed_lock(abs_time) executed within the constructor. + //!Notes: The constructor will take ownership of the mutex if it can do + //! it until abs_time is reached. Whether or not this constructor + //! 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) + : mp_mutex(&m), m_locked(mp_mutex->timed_lock(abs_time)) + {} + + //!Postconditions: mutex() == the value scop.mutex() had before the + //! constructor executes. s1.mutex() == 0. owns() == the value of + //! scop.owns() before the constructor executes. scop.owns(). + //!Notes: If the scop scoped_lock owns the mutex, ownership is moved + //! to thisscoped_lock with no blocking. If the scop scoped_lock does not + //! own the mutex, then neither will this scoped_lock. Only a moved + //! scoped_lock's will match this signature. An non-moved 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) + : mp_mutex(0), m_locked(scop.owns()) + { mp_mutex = scop.release(); } + + //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the + //! referenced mutex. upgr.release() is called. + //!Postconditions: mutex() == the value upgr.mutex() had before the construction. + //! upgr.mutex() == 0. owns() == upgr.owns() before the construction. + //! upgr.owns() == false after the construction. + //!Notes: If upgr is locked, this constructor will lock this scoped_lock while + //! unlocking upgr. If upgr is unlocked, then this scoped_lock will be + //! unlocked as well. Only a moved upgradable_lock's will match this + //! signature. An non-moved upgradable_lock can be moved with + //! the expression: "boost::move(lock);" This constructor may block if + //! other threads hold a sharable_lock on this mutex (sharable_lock's can + //! share ownership with an upgradable_lock). + template + explicit scoped_lock(BOOST_RV_REF(upgradable_lock) upgr + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + upgradable_lock &u_lock = upgr; + if(u_lock.owns()){ + u_lock.mutex()->unlock_upgradable_and_lock(); + m_locked = true; + } + mp_mutex = u_lock.release(); + } + + //!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the + //!referenced mutex: + //! a)if try_unlock_upgradable_and_lock() returns true then mutex() obtains + //! the value from upgr.release() and owns() is set to true. + //! b)if try_unlock_upgradable_and_lock() returns false then upgr is + //! unaffected and this scoped_lock construction as the same effects as + //! a default construction. + //! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release() + //! and owns() is set to false + //!Notes: This construction will not block. It will try to obtain mutex + //! ownership from upgr immediately, while changing the lock type from a + //! "read lock" to a "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 + scoped_lock(BOOST_RV_REF(upgradable_lock) upgr, try_to_lock_type + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + upgradable_lock &u_lock = upgr; + if(u_lock.owns()){ + if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){ + mp_mutex = u_lock.release(); + } + } + else{ + u_lock.release(); + } + } + + //!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time) + //! on the referenced mutex: + //! a)if timed_unlock_upgradable_and_lock(abs_time) returns true then mutex() + //! obtains the value from upgr.release() and owns() is set to true. + //! b)if timed_unlock_upgradable_and_lock(abs_time) returns false then upgr + //! is unaffected and this scoped_lock construction as the same effects + //! as a default construction. + //! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release() + //! and owns() is set to false + //!Notes: This construction will not block. It will try to obtain mutex ownership + //! from upgr immediately, while changing the lock type from a "read lock" to a + //! "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 + scoped_lock(BOOST_RV_REF(upgradable_lock) upgr, boost::posix_time::ptime &abs_time + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + upgradable_lock &u_lock = upgr; + if(u_lock.owns()){ + if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){ + mp_mutex = u_lock.release(); + } + } + else{ + u_lock.release(); + } + } + + //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the + //!referenced mutex. + //! a)if try_unlock_sharable_and_lock() returns true then mutex() obtains + //! the value from shar.release() and owns() is set to true. + //! b)if try_unlock_sharable_and_lock() returns false then shar is + //! unaffected and this scoped_lock construction has the same + //! effects as a default construction. + //! c)Else shar.owns() is false. mutex() obtains the value from + //! shar.release() and owns() is set to false + //!Notes: This construction will not block. It will try to obtain mutex + //! ownership from shar immediately, while changing the lock type from a + //! "read lock" to a "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 + scoped_lock(BOOST_RV_REF(sharable_lock) shar, try_to_lock_type + , typename ipcdetail::enable_if< ipcdetail::is_same >::type * = 0) + : mp_mutex(0), m_locked(false) + { + sharable_lock &s_lock = shar; + if(s_lock.owns()){ + if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){ + mp_mutex = s_lock.release(); + } + } + else{ + s_lock.release(); + } + } + + //!Effects: if (owns()) mp_mutex->unlock(). + //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/ + ~scoped_lock() + { + try{ if(m_locked && mp_mutex) mp_mutex->unlock(); } + catch(...){} + } + + //!Effects: If owns() before the call, then unlock() is called on mutex(). + //! *this gets the state of scop and scop gets set to a default constructed state. + //!Notes: With a recursive mutex it is possible that both this and scop own + //! the same mutex before the assignment. In this case, this will own the + //! mutex after the assignment (and scop will not), but the mutex's lock + //! count will be decremented by one. + scoped_lock &operator=(BOOST_RV_REF(scoped_lock) scop) + { + if(this->owns()) + this->unlock(); + m_locked = scop.owns(); + mp_mutex = scop.release(); + return *this; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls lock() on the referenced mutex. + //!Postconditions: owns() == true. + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, blocking if necessary. + void lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + mp_mutex->lock(); + m_locked = true; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls try_lock() on the referenced mutex. + //!Postconditions: owns() == the value returned from mutex()->try_lock(). + //!Notes: The scoped_lock changes from a state of not owning the mutex, to + //! owning the mutex, but only if blocking was not required. If the + //! mutex_type does not support try_lock(), this function will fail at + //! compile time if instantiated, but otherwise have no effect.*/ + bool try_lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock(); + return m_locked; + } + + //!Effects: If mutex() == 0 or if already locked, throws a lock_exception() + //! exception. Calls timed_lock(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.*/ + bool timed_lock(const boost::posix_time::ptime& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->timed_lock(abs_time); + 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. + //!Notes: The scoped_lock changes from a state of owning the mutex, to not + //! owning the mutex.*/ + void unlock() + { + if(!mp_mutex || !m_locked) + throw lock_exception(); + mp_mutex->unlock(); + m_locked = false; + } + + //!Effects: Returns true if this scoped_lock has acquired + //!the referenced mutex. + bool owns() const + { return m_locked && mp_mutex; } + + //!Conversion to bool. + //!Returns owns(). + operator unspecified_bool_type() const + { 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 + { 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 *mut = mp_mutex; + mp_mutex = 0; + m_locked = false; + return mut; + } + + //!Effects: Swaps state with moved lock. + //!Throws: Nothing. + void swap( scoped_lock &other) + { + std::swap(mp_mutex, other.mp_mutex); + std::swap(m_locked, other.m_locked); + } + + /// @cond + private: + mutex_type *mp_mutex; + bool m_locked; + /// @endcond +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/spin/mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/spin/mutex.hpp new file mode 100644 index 00000000..94c26a16 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/spin/mutex.hpp @@ -0,0 +1,114 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_SPIN_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class spin_mutex +{ + spin_mutex(const spin_mutex &); + spin_mutex &operator=(const spin_mutex &); + public: + + spin_mutex(); + ~spin_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + void take_ownership(){}; + private: + volatile boost::uint32_t m_s; +}; + +inline spin_mutex::spin_mutex() + : m_s(0) +{ + //Note that this class is initialized to zero. + //So zeroed memory can be interpreted as an + //initialized mutex +} + +inline spin_mutex::~spin_mutex() +{ + //Trivial destructor +} + +inline void spin_mutex::lock(void) +{ + do{ + boost::uint32_t prev_s = ipcdetail::atomic_cas32(const_cast(&m_s), 1, 0); + + if (m_s == 1 && prev_s == 0){ + break; + } + // relinquish current timeslice + ipcdetail::thread_yield(); + }while (true); +} + +inline bool spin_mutex::try_lock(void) +{ + boost::uint32_t prev_s = ipcdetail::atomic_cas32(const_cast(&m_s), 1, 0); + return m_s == 1 && prev_s == 0; +} + +inline bool spin_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + //Obtain current count and target time + boost::posix_time::ptime now = microsec_clock::universal_time(); + + do{ + if(this->try_lock()){ + break; + } + now = microsec_clock::universal_time(); + + if(now >= abs_time){ + return false; + } + // relinquish current time slice + ipcdetail::thread_yield(); + }while (true); + + return true; +} + +inline void spin_mutex::unlock(void) +{ ipcdetail::atomic_cas32(const_cast(&m_s), 0, 1); } + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_SPIN_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/spin/recursive_mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/spin/recursive_mutex.hpp new file mode 100644 index 00000000..38e9dcaa --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/spin/recursive_mutex.hpp @@ -0,0 +1,175 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +// +// Parts of the pthread code come from Boost Threads code: +// +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class spin_recursive_mutex +{ + spin_recursive_mutex(const spin_recursive_mutex &); + spin_recursive_mutex &operator=(const spin_recursive_mutex &); + public: + + spin_recursive_mutex(); + ~spin_recursive_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + void take_ownership(); + private: + spin_mutex m_mutex; + unsigned int m_nLockCount; + volatile ipcdetail::OS_systemwide_thread_id_t m_nOwner; + volatile boost::uint32_t m_s; +}; + +inline spin_recursive_mutex::spin_recursive_mutex() + : m_nLockCount(0), m_nOwner(ipcdetail::get_invalid_systemwide_thread_id()){} + +inline spin_recursive_mutex::~spin_recursive_mutex(){} + +inline void spin_recursive_mutex::lock() +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + handle_t old_id; + ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); + if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)){ + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow"); + } + ++m_nLockCount; + } + else{ + m_mutex.lock(); + ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); + m_nLockCount = 1; + } +} + +inline bool spin_recursive_mutex::try_lock() +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + handle_t old_id; + ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); + if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow"); + } + ++m_nLockCount; + return true; + } + if(m_mutex.try_lock()){ + ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); + m_nLockCount = 1; + return true; + } + return false; +} + +inline bool spin_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + handle_t old_id; + ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); + if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it + if((unsigned int)(m_nLockCount+1) == 0){ + //Overflow, throw an exception + throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow"); + } + ++m_nLockCount; + return true; + } + if(m_mutex.timed_lock(abs_time)){ + ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); + m_nLockCount = 1; + return true; + } + return false; +} + +inline void spin_recursive_mutex::unlock() +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + handle_t old_id; + ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id); + const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + (void)old_id; + (void)thr_id; + BOOST_ASSERT(ipcdetail::equal_systemwide_thread_id(thr_id, old_id)); + --m_nLockCount; + if(!m_nLockCount){ + const handle_t new_id(ipcdetail::get_invalid_systemwide_thread_id()); + ipcdetail::systemwide_thread_id_copy(new_id, m_nOwner); + m_mutex.unlock(); + } +} + +inline void spin_recursive_mutex::take_ownership() +{ + typedef ipcdetail::OS_systemwide_thread_id_t handle_t; + this->m_nLockCount = 1; + const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id()); + ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/windows/mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/windows/mutex.hpp new file mode 100644 index 00000000..7da70f4d --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/windows/mutex.hpp @@ -0,0 +1,114 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_WINDOWS_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class windows_mutex +{ + windows_mutex(const windows_mutex &); + windows_mutex &operator=(const windows_mutex &); + public: + + windows_mutex(); + ~windows_mutex(); + + void lock(); + bool try_lock(); + bool timed_lock(const boost::posix_time::ptime &abs_time); + void unlock(); + void take_ownership(){}; + + private: + const sync_id id_; +}; + +inline windows_mutex::windows_mutex() + : id_(this) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //Create mutex with the initial count + bool open_or_created; + (void)handles.obtain_mutex(this->id_, &open_or_created); + //The mutex must be created, never opened + assert(open_or_created); + assert(open_or_created && winapi::get_last_error() != winapi::error_already_exists); + (void)open_or_created; +} + +inline windows_mutex::~windows_mutex() +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + handles.destroy_handle(this->id_); +} + +inline void windows_mutex::lock(void) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + mut.lock(); +} + +inline bool windows_mutex::try_lock(void) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + return mut.try_lock(); +} + +inline bool windows_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + return mut.timed_lock(abs_time); +} + +inline void windows_mutex::unlock(void) +{ + sync_handles &handles = + windows_intermodule_singleton::get(); + //This can throw + winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); + return mut.unlock(); +} + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/windows/recursive_mutex.hpp b/cpp/BoostParts/boost/interprocess/sync/windows/recursive_mutex.hpp new file mode 100644 index 00000000..2b4797e1 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/windows/recursive_mutex.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_WINDOWS_RECURSIVE_MUTEX_HPP +#define BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +//Windows mutex is already recursive +class windows_recursive_mutex + : public windows_mutex +{ + windows_recursive_mutex(const windows_recursive_mutex &); + windows_recursive_mutex &operator=(const windows_recursive_mutex &); + public: + windows_recursive_mutex() : windows_mutex() {} +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/windows/sync_utils.hpp b/cpp/BoostParts/boost/interprocess/sync/windows/sync_utils.hpp new file mode 100644 index 00000000..92d8e55a --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/windows/sync_utils.hpp @@ -0,0 +1,236 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_SYNC_UTILS_HPP +#define BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +//Shield against external warnings +#include + #include +#include + + +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +inline bool bytes_to_str(const void *mem, const std::size_t mem_length, char *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 char Characters [] = + { '0', '1', '2', '3', '4', '5', '6', '7' + , '8', '9', 'A', 'B', 'C', 'D', 'E', '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) + { winapi::query_performance_counter(&rand_); } + + explicit sync_id(internal_type val, const void *map_addr) + : map_addr_(map_addr) + { rand_ = val; } + + const internal_type &internal_pod() const + { return rand_; } + + 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_; } + + private: + internal_type rand_; + const void * const map_addr_; +}; + +class sync_handles +{ + public: + 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(); } + }; + + typedef boost::unordered_map umap_type; + typedef boost::container::map 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"; + std::size_t i = 0; + do{ + name[i] = n[i]; + ++i; + } while(n[i]); + std::size_t len = sizeof(NameBuf) - LengthOfGlobal; + bytes_to_str(&id.internal_pod(), sizeof(id.internal_pod()), &name[LengthOfGlobal], len); + } + + void throw_if_error(void *hnd_val) + { + if(!hnd_val){ + error_info err(winapi::get_last_error()); + throw interprocess_exception(err); + } + } + + void* open_or_create_semaphore(const sync_id &id, unsigned int initial_count) + { + NameBuf name; + fill_name(name, id); + permissions unrestricted_security; + unrestricted_security.set_unrestricted(); + winapi_semaphore_wrapper sem_wrapper; + bool created; + sem_wrapper.open_or_create + (name, (long)initial_count, winapi_semaphore_wrapper::MaxCount, unrestricted_security, created); + throw_if_error(sem_wrapper.handle()); + return sem_wrapper.release(); + } + + void* open_or_create_mutex(const sync_id &id) + { + NameBuf name; + fill_name(name, id); + permissions unrestricted_security; + unrestricted_security.set_unrestricted(); + winapi_mutex_wrapper mtx_wrapper; + mtx_wrapper.open_or_create(name, unrestricted_security); + throw_if_error(mtx_wrapper.handle()); + return mtx_wrapper.release(); + } + + public: + void *obtain_mutex(const sync_id &id, bool *popen_created = 0) + { + umap_type::value_type v(id, (void*)0); + scoped_lock lock(mtx_); + umap_type::iterator it = umap_.insert(v).first; + void *&hnd_val = it->second; + if(!hnd_val){ + map_[&it->first] = it; + hnd_val = open_or_create_mutex(id); + if(popen_created) *popen_created = true; + } + else if(popen_created){ + *popen_created = false; + } + return hnd_val; + } + + void *obtain_semaphore(const sync_id &id, unsigned int initial_count, bool *popen_created = 0) + { + umap_type::value_type v(id, (void*)0); + scoped_lock lock(mtx_); + umap_type::iterator it = umap_.insert(v).first; + void *&hnd_val = it->second; + if(!hnd_val){ + map_[&it->first] = it; + hnd_val = open_or_create_semaphore(id, initial_count); + if(popen_created) *popen_created = true; + } + else if(popen_created){ + *popen_created = false; + } + return hnd_val; + } + + void destroy_handle(const sync_id &id) + { + scoped_lock lock(mtx_); + umap_type::iterator it = umap_.find(id); + umap_type::iterator itend = umap_.end(); + + if(it != itend){ + winapi::close_handle(it->second); + const map_type::key_type &k = &it->first; + map_.erase(k); + 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(addr)+size); + scoped_lock 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); + } + } + + private: + spin_mutex mtx_; + umap_type umap_; + map_type map_; +}; + + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_SYNC_UTILS_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp b/cpp/BoostParts/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp new file mode 100644 index 00000000..0be96011 --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/windows/winapi_mutex_wrapper.hpp @@ -0,0 +1,163 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-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_WINAPI_MUTEX_WRAPPER_HPP +#define BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class winapi_mutex_functions +{ + /// @cond + + //Non-copyable + winapi_mutex_functions(const winapi_mutex_functions &); + winapi_mutex_functions &operator=(const winapi_mutex_functions &); + /// @endcond + + public: + winapi_mutex_functions(void *mtx_hnd) + : m_mtx_hnd(mtx_hnd) + {} + + void unlock() + { + winapi::release_mutex(m_mtx_hnd); + } + + void lock() + { + if(winapi::wait_for_single_object(m_mtx_hnd, winapi::infinite_time) != winapi::wait_object_0){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + } + + bool try_lock() + { + unsigned long ret = winapi::wait_for_single_object(m_mtx_hnd, 0); + if(ret == winapi::wait_object_0){ + return true; + } + else if(ret == winapi::wait_timeout){ + return false; + } + else{ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + } + + bool timed_lock(const boost::posix_time::ptime &abs_time) + { + if(abs_time == boost::posix_time::pos_infin){ + this->lock(); + return true; + } + + unsigned long ret = winapi::wait_for_single_object + (m_mtx_hnd, (abs_time - microsec_clock::universal_time()).total_milliseconds()); + if(ret == winapi::wait_object_0){ + return true; + } + else if(ret == winapi::wait_timeout){ + return false; + } + else{ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + } + + /// @cond + protected: + void *m_mtx_hnd; + /// @endcond +}; + +//Swappable mutex wrapper +class winapi_mutex_wrapper + : public winapi_mutex_functions +{ + /// @cond + + //Non-copyable + winapi_mutex_wrapper(const winapi_mutex_wrapper &); + winapi_mutex_wrapper &operator=(const winapi_mutex_wrapper &); + /// @endcond + + public: + winapi_mutex_wrapper(void *mtx_hnd = winapi::invalid_handle_value) + : winapi_mutex_functions(mtx_hnd) + {} + + ~winapi_mutex_wrapper() + { this->close(); } + + void *release() + { + void *hnd = m_mtx_hnd; + m_mtx_hnd = winapi::invalid_handle_value; + return hnd; + } + + void *handle() const + { return m_mtx_hnd; } + + bool open_or_create(const char *name, const permissions &perm) + { + if(m_mtx_hnd == winapi::invalid_handle_value){ + m_mtx_hnd = winapi::open_or_create_mutex + ( name + , false + , (winapi::interprocess_security_attributes*)perm.get_permissions() + ); + return m_mtx_hnd != winapi::invalid_handle_value; + } + else{ + return false; + } + } + + void close() + { + if(m_mtx_hnd != winapi::invalid_handle_value){ + winapi::close_handle(m_mtx_hnd); + m_mtx_hnd = winapi::invalid_handle_value; + } + } + + void swap(winapi_mutex_wrapper &other) + { void *tmp = m_mtx_hnd; m_mtx_hnd = other.m_mtx_hnd; other.m_mtx_hnd = tmp; } +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_MUTEX_WRAPPER_HPP diff --git a/cpp/BoostParts/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp b/cpp/BoostParts/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp new file mode 100644 index 00000000..de5185ac --- /dev/null +++ b/cpp/BoostParts/boost/interprocess/sync/windows/winapi_semaphore_wrapper.hpp @@ -0,0 +1,198 @@ + ////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-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_WINAPI_SEMAPHORE_WRAPPER_HPP +#define BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace ipcdetail { + +class winapi_semaphore_functions +{ + /// @cond + + //Non-copyable + winapi_semaphore_functions(const winapi_semaphore_functions &); + winapi_semaphore_functions &operator=(const winapi_semaphore_functions &); + /// @endcond + + public: + winapi_semaphore_functions(void *hnd) + : m_sem_hnd(hnd) + {} + + void post(long count = 1) + { + long prev_count; + winapi::release_semaphore(m_sem_hnd, count, &prev_count); + } + + void wait() + { + if(winapi::wait_for_single_object(m_sem_hnd, winapi::infinite_time) != winapi::wait_object_0){ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + } + + bool try_wait() + { + unsigned long ret = winapi::wait_for_single_object(m_sem_hnd, 0); + if(ret == winapi::wait_object_0){ + return true; + } + else if(ret == winapi::wait_timeout){ + return false; + } + else{ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + } + + bool timed_wait(const boost::posix_time::ptime &abs_time) + { + if(abs_time == boost::posix_time::pos_infin){ + this->wait(); + return true; + } + + unsigned long ret = winapi::wait_for_single_object + (m_sem_hnd, (abs_time - microsec_clock::universal_time()).total_milliseconds()); + if(ret == winapi::wait_object_0){ + return true; + } + else if(ret == winapi::wait_timeout){ + return false; + } + else{ + error_info err = system_error_code(); + throw interprocess_exception(err); + } + } + + long value() const + { + long l_count, l_limit; + if(!winapi::get_semaphore_info(m_sem_hnd, l_count, l_limit)) + return 0; + return l_count; + } + + long limit() const + { + long l_count, l_limit; + if(!winapi::get_semaphore_info(m_sem_hnd, l_count, l_limit)) + return 0; + return l_limit; + } + + /// @cond + protected: + void *m_sem_hnd; + /// @endcond +}; + + +//Swappable semaphore wrapper +class winapi_semaphore_wrapper + : public winapi_semaphore_functions +{ + winapi_semaphore_wrapper(const winapi_semaphore_wrapper &); + winapi_semaphore_wrapper &operator=(const winapi_semaphore_wrapper &); + + public: + + //Long is 32 bits in windows + static const long MaxCount = long(0x7FFFFFFF); + + winapi_semaphore_wrapper(void *hnd = winapi::invalid_handle_value) + : winapi_semaphore_functions(hnd) + {} + + ~winapi_semaphore_wrapper() + { this->close(); } + + void *release() + { + void *hnd = m_sem_hnd; + m_sem_hnd = winapi::invalid_handle_value; + return hnd; + } + + void *handle() const + { return m_sem_hnd; } + + bool open_or_create( const char *name + , long sem_count + , long max_count + , const permissions &perm + , bool &created) + { + if(m_sem_hnd == winapi::invalid_handle_value){ + m_sem_hnd = winapi::open_or_create_semaphore + ( name + , sem_count + , max_count + , (winapi::interprocess_security_attributes*)perm.get_permissions() + ); + created = winapi::get_last_error() != winapi::error_already_exists; + return m_sem_hnd != winapi::invalid_handle_value; + } + else{ + return false; + } + } + + bool open_semaphore(const char *name) + { + if(m_sem_hnd == winapi::invalid_handle_value){ + m_sem_hnd = winapi::open_semaphore(name); + return m_sem_hnd != winapi::invalid_handle_value; + } + else{ + return false; + } + } + + void close() + { + if(m_sem_hnd != winapi::invalid_handle_value){ + winapi::close_handle(m_sem_hnd); + m_sem_hnd = winapi::invalid_handle_value; + } + } + + void swap(winapi_semaphore_wrapper &other) + { void *tmp = m_sem_hnd; m_sem_hnd = other.m_sem_hnd; other.m_sem_hnd = tmp; } +}; + +} //namespace ipcdetail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_WINAPI_SEMAPHORE_WRAPPER_HPP diff --git a/cpp/BoostParts/boost/intrusive/circular_slist_algorithms.hpp b/cpp/BoostParts/boost/intrusive/circular_slist_algorithms.hpp new file mode 100644 index 00000000..fc3848e8 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/circular_slist_algorithms.hpp @@ -0,0 +1,404 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! circular_slist_algorithms provides basic algorithms to manipulate nodes +//! forming a circular singly linked list. An empty circular list is formed by a node +//! whose pointer to the next node points to itself. +//! +//! circular_slist_algorithms is configured with a NodeTraits class, which encapsulates the +//! information about the node to be manipulated. NodeTraits must support the +//! following interface: +//! +//! Typedefs: +//! +//! node: The type of the node that forms the circular list +//! +//! node_ptr: A pointer to a node +//! +//! const_node_ptr: A pointer to a const node +//! +//! Static functions: +//! +//! static node_ptr get_next(const_node_ptr n); +//! +//! static void set_next(node_ptr n, node_ptr next); +template +class circular_slist_algorithms + /// @cond + : public detail::common_slist_algorithms + /// @endcond +{ + /// @cond + typedef detail::common_slist_algorithms base_t; + /// @endcond + public: + typedef typename NodeTraits::node node; + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef NodeTraits node_traits; + + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + + //! Effects: Constructs an non-used list element, putting the next + //! pointer to null: + //! NodeTraits::get_next(this_node) == node_ptr() + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init(node_ptr this_node); + + //! Requires: this_node must be in a circular list or be an empty circular list. + //! + //! Effects: Returns true is "this_node" is the only node of a circular list: + //! or it's a not inserted node: + //! return node_ptr() == NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool unique(const_node_ptr this_node); + + //! Effects: Returns true is "this_node" has the same state as + //! if it was inited using "init(node_ptr)" + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool inited(const_node_ptr this_node); + + //! Requires: prev_node must be in a circular list or be an empty circular list. + //! + //! Effects: Unlinks the next node of prev_node from the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(node_ptr prev_node); + + //! Requires: prev_node and last_node must be in a circular list + //! or be an empty circular list. + //! + //! Effects: Unlinks the range (prev_node, last_node) from the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(node_ptr prev_node, node_ptr last_node); + + //! Requires: prev_node must be a node of a circular list. + //! + //! Effects: Links this_node after prev_node in the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void link_after(node_ptr prev_node, node_ptr this_node); + + //! Requires: b and e must be nodes of the same circular list or an empty range. + //! and p must be a node of a different circular list. + //! + //! Effects: Removes the nodes from (b, e] range from their circular list and inserts + //! them after p in p's circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void transfer_after(node_ptr p, node_ptr b, node_ptr e); + + #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + + //! Effects: Constructs an empty list, making this_node the only + //! node of the circular list: + //! NodeTraits::get_next(this_node) == this_node. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init_header(const node_ptr &this_node) + { NodeTraits::set_next(this_node, this_node); } + + //! Requires: this_node and prev_init_node must be in the same circular list. + //! + //! Effects: Returns the previous node of this_node in the circular list starting. + //! the search from prev_init_node. The first node checked for equality + //! is NodeTraits::get_next(prev_init_node). + //! + //! Complexity: Linear to the number of elements between prev_init_node and this_node. + //! + //! Throws: Nothing. + static node_ptr get_previous_node(const node_ptr &prev_init_node, const node_ptr &this_node) + { return base_t::get_previous_node(prev_init_node, this_node); } + + //! Requires: this_node must be in a circular list or be an empty circular list. + //! + //! Effects: Returns the previous node of this_node in the circular list. + //! + //! Complexity: Linear to the number of elements in the circular list. + //! + //! Throws: Nothing. + static node_ptr get_previous_node(const node_ptr & this_node) + { return base_t::get_previous_node(this_node, this_node); } + + //! Requires: this_node must be in a circular list or be an empty circular list. + //! + //! Effects: Returns the previous node of the previous node of this_node in the circular list. + //! + //! Complexity: Linear to the number of elements in the circular list. + //! + //! Throws: Nothing. + static node_ptr get_previous_previous_node(const node_ptr & this_node) + { return get_previous_previous_node(this_node, this_node); } + + //! Requires: this_node and p must be in the same circular list. + //! + //! Effects: Returns the previous node of the previous node of this_node in the + //! circular list starting. the search from p. The first node checked + //! for equality is NodeTraits::get_next((NodeTraits::get_next(p)). + //! + //! Complexity: Linear to the number of elements in the circular list. + //! + //! Throws: Nothing. + static node_ptr get_previous_previous_node(node_ptr p, const node_ptr & this_node) + { + node_ptr p_next = NodeTraits::get_next(p); + node_ptr p_next_next = NodeTraits::get_next(p_next); + while (this_node != p_next_next){ + p = p_next; + p_next = p_next_next; + p_next_next = NodeTraits::get_next(p_next); + } + return p; + } + + //! Requires: this_node must be in a circular list or be an empty circular list. + //! + //! Effects: Returns the number of nodes in a circular list. If the circular list + //! is empty, returns 1. + //! + //! Complexity: Linear + //! + //! Throws: Nothing. + static std::size_t count(const const_node_ptr & this_node) + { + std::size_t result = 0; + const_node_ptr p = this_node; + do{ + p = NodeTraits::get_next(p); + ++result; + } while (p != this_node); + return result; + } + + //! Requires: this_node must be in a circular list, be an empty circular list or be inited. + //! + //! Effects: Unlinks the node from the circular list. + //! + //! Complexity: Linear to the number of elements in the circular list + //! + //! Throws: Nothing. + static void unlink(const node_ptr & this_node) + { + if(NodeTraits::get_next(this_node)) + base_t::unlink_after(get_previous_node(this_node)); + } + + //! Requires: nxt_node must be a node of a circular list. + //! + //! Effects: Links this_node before nxt_node in the circular list. + //! + //! Complexity: Linear to the number of elements in the circular list. + //! + //! Throws: Nothing. + static void link_before (const node_ptr & nxt_node, const node_ptr & this_node) + { base_t::link_after(get_previous_node(nxt_node), this_node); } + + //! Requires: this_node and other_node must be nodes inserted + //! in circular lists or be empty circular lists. + //! + //! Effects: Swaps the position of the nodes: this_node is inserted in + //! other_nodes position in the second circular list and the other_node is inserted + //! in this_node's position in the first circular list. + //! + //! Complexity: Linear to number of elements of both lists + //! + //! Throws: Nothing. + static void swap_nodes(const node_ptr & this_node, const node_ptr & other_node) + { + if (other_node == this_node) + return; + bool this_inited = base_t::inited(this_node); + bool other_inited = base_t::inited(other_node); + if(this_inited){ + base_t::init_header(this_node); + } + if(other_inited){ + base_t::init_header(other_node); + } + + bool empty1 = base_t::unique(this_node); + bool empty2 = base_t::unique(other_node); + node_ptr prev_this (get_previous_node(this_node)); + node_ptr prev_other(get_previous_node(other_node)); + + node_ptr this_next (NodeTraits::get_next(this_node)); + node_ptr other_next(NodeTraits::get_next(other_node)); + NodeTraits::set_next(this_node, other_next); + NodeTraits::set_next(other_node, this_next); + NodeTraits::set_next(empty1 ? other_node : prev_this, other_node); + NodeTraits::set_next(empty2 ? this_node : prev_other, this_node); + + if(this_inited){ + base_t::init(other_node); + } + if(other_inited){ + base_t::init(this_node); + } + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear to the contained elements. + static void reverse(const node_ptr & p) + { + node_ptr i = NodeTraits::get_next(p), e(p); + for (;;) { + node_ptr nxt(NodeTraits::get_next(i)); + if (nxt == e) + break; + base_t::transfer_after(e, i, nxt); + } + } + + //! Effects: Moves the node p n positions towards the end of the list. + //! + //! Returns: The previous node of p after the function if there has been any movement, + //! Null if n leads to no movement. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static node_ptr move_backwards(const node_ptr & p, std::size_t n) + { + //Null shift, nothing to do + if(!n) return node_ptr(); + node_ptr first = NodeTraits::get_next(p); + + //count() == 1 or 2, nothing to do + if(NodeTraits::get_next(first) == p) + return node_ptr(); + + bool end_found = false; + node_ptr new_last = node_ptr(); + + //Now find the new last node according to the shift count. + //If we find p before finding the new last node + //unlink p, shortcut the search now that we know the size of the list + //and continue. + for(std::size_t i = 1; i <= n; ++i){ + new_last = first; + first = NodeTraits::get_next(first); + if(first == p){ + //Shortcut the shift with the modulo of the size of the list + n %= i; + if(!n) + return node_ptr(); + i = 0; + //Unlink p and continue the new first node search + first = NodeTraits::get_next(p); + base_t::unlink_after(new_last); + end_found = true; + } + } + + //If the p has not been found in the previous loop, find it + //starting in the new first node and unlink it + if(!end_found){ + base_t::unlink_after(base_t::get_previous_node(first, p)); + } + + //Now link p after the new last node + base_t::link_after(new_last, p); + return new_last; + } + + //! Effects: Moves the node p n positions towards the beginning of the list. + //! + //! Returns: The previous node of p after the function if there has been any movement, + //! Null if n leads equals to no movement. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static node_ptr move_forward(const node_ptr & p, std::size_t n) + { + //Null shift, nothing to do + if(!n) return node_ptr(); + node_ptr first = node_traits::get_next(p); + + //count() == 1 or 2, nothing to do + if(node_traits::get_next(first) == p) return node_ptr(); + + //Iterate until p is found to know where the current last node is. + //If the shift count is less than the size of the list, we can also obtain + //the position of the new last node after the shift. + node_ptr old_last(first), next_to_it, new_last(p); + std::size_t distance = 1; + while(p != (next_to_it = node_traits::get_next(old_last))){ + if(++distance > n) + new_last = node_traits::get_next(new_last); + old_last = next_to_it; + } + //If the shift was bigger or equal than the size, obtain the equivalent + //forward shifts and find the new last node. + if(distance <= n){ + //Now find the equivalent forward shifts. + //Shortcut the shift with the modulo of the size of the list + std::size_t new_before_last_pos = (distance - (n % distance))% distance; + //If the shift is a multiple of the size there is nothing to do + if(!new_before_last_pos) return node_ptr(); + + for( new_last = p + ; new_before_last_pos-- + ; new_last = node_traits::get_next(new_last)){ + //empty + } + } + + //Now unlink p and link it after the new last node + base_t::unlink_after(old_last); + base_t::link_after(new_last, p); + return new_last; + } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_CIRCULAR_SLIST_ALGORITHMS_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/assert.hpp b/cpp/BoostParts/boost/intrusive/detail/assert.hpp new file mode 100644 index 00000000..33de97f7 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/assert.hpp @@ -0,0 +1,41 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_DETAIL_ASSERT_HPP +#define BOOST_INTRUSIVE_DETAIL_ASSERT_HPP + +#if defined(_MSC_VER)&&(_MSC_VER>=1200) +#pragma once +#endif + +#if !defined(BOOST_INTRUSIVE_INVARIANT_ASSERT) + #include + #define BOOST_INTRUSIVE_INVARIANT_ASSERT BOOST_ASSERT +#elif defined(BOOST_INTRUSIVE_INVARIANT_ASSERT_INCLUDE) + #include BOOST_INTRUSIVE_INVARIANT_ASSERT_INCLUDE +#endif + +#if !defined(BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT) + #include + #define BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT BOOST_ASSERT +#elif defined(BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT_INCLUDE) + #include BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT_INCLUDE +#endif + +#if !defined(BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT) + #include + #define BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT BOOST_ASSERT +#elif defined(BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE) + #include BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT_INCLUDE +#endif + +#endif //BOOST_INTRUSIVE_DETAIL_ASSERT_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/clear_on_destructor_base.hpp b/cpp/BoostParts/boost/intrusive/detail/clear_on_destructor_base.hpp new file mode 100644 index 00000000..1b5c27ff --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/clear_on_destructor_base.hpp @@ -0,0 +1,36 @@ +//////} // /////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP +#define BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP + +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +class clear_on_destructor_base +{ + protected: + ~clear_on_destructor_base() + { + static_cast(this)->clear(); + } +}; + +} // namespace detail { +} // namespace intrusive { +} // namespace boost { + +#include + +#endif //#ifndef BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/common_slist_algorithms.hpp b/cpp/BoostParts/boost/intrusive/detail/common_slist_algorithms.hpp new file mode 100644 index 00000000..166f78d4 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/common_slist_algorithms.hpp @@ -0,0 +1,102 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_COMMON_SLIST_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_COMMON_SLIST_ALGORITHMS_HPP + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +class common_slist_algorithms +{ + public: + typedef typename NodeTraits::node node; + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef NodeTraits node_traits; + + static node_ptr get_previous_node(node_ptr p, const node_ptr & this_node) + { + for( node_ptr p_next + ; this_node != (p_next = NodeTraits::get_next(p)) + ; p = p_next){ + //Logic error: possible use of linear lists with + //operations only permitted with lists + BOOST_INTRUSIVE_INVARIANT_ASSERT(p); + } + return p; + } + + static void init_header(const node_ptr & this_node) + { NodeTraits::set_next(this_node, this_node); } + + static void init(const node_ptr & this_node) + { NodeTraits::set_next(this_node, node_ptr()); } + + static bool unique(const const_node_ptr & this_node) + { + node_ptr next = NodeTraits::get_next(this_node); + return !next || next == this_node; + } + + static bool inited(const const_node_ptr & this_node) + { return !NodeTraits::get_next(this_node); } + + static void unlink_after(const node_ptr & prev_node) + { + const_node_ptr this_node(NodeTraits::get_next(prev_node)); + NodeTraits::set_next(prev_node, NodeTraits::get_next(this_node)); + } + + static void unlink_after(const node_ptr & prev_node, const node_ptr & last_node) + { NodeTraits::set_next(prev_node, last_node); } + + static void link_after(const node_ptr & prev_node, const node_ptr & this_node) + { + NodeTraits::set_next(this_node, NodeTraits::get_next(prev_node)); + NodeTraits::set_next(prev_node, this_node); + } + + static void incorporate_after(const node_ptr & bp, const node_ptr & b, const node_ptr & be) + { + node_ptr p(NodeTraits::get_next(bp)); + NodeTraits::set_next(bp, b); + NodeTraits::set_next(be, p); + } + + static void transfer_after(const node_ptr & bp, const node_ptr & bb, const node_ptr & be) + { + if (bp != bb && bp != be && bb != be) { + node_ptr next_b = NodeTraits::get_next(bb); + node_ptr next_e = NodeTraits::get_next(be); + node_ptr next_p = NodeTraits::get_next(bp); + NodeTraits::set_next(bb, next_e); + NodeTraits::set_next(be, next_p); + NodeTraits::set_next(bp, next_b); + } + } +}; + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_COMMON_SLIST_ALGORITHMS_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/ebo_functor_holder.hpp b/cpp/BoostParts/boost/intrusive/detail/ebo_functor_holder.hpp new file mode 100644 index 00000000..850d0743 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/ebo_functor_holder.hpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Joaquin M Lopez Munoz 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_DETAIL_EBO_HOLDER_HPP +#define BOOST_INTRUSIVE_DETAIL_EBO_HOLDER_HPP + +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +class ebo_functor_holder_impl +{ + public: + ebo_functor_holder_impl() + {} + ebo_functor_holder_impl(const T& t) + : t_(t) + {} + template + ebo_functor_holder_impl(const Arg1& arg1, const Arg2& arg2) + : t_(arg1, arg2) + {} + + T& get(){return t_;} + const T& get()const{return t_;} + + private: + T t_; +}; + +template +class ebo_functor_holder_impl + : public T +{ + public: + ebo_functor_holder_impl() + {} + ebo_functor_holder_impl(const T& t) + : T(t) + {} + template + ebo_functor_holder_impl(const Arg1& arg1, const Arg2& arg2) + : T(arg1, arg2) + {} + + T& get(){return *this;} + const T& get()const{return *this;} +}; + +template +class ebo_functor_holder + : public ebo_functor_holder_impl::value> +{ + private: + typedef ebo_functor_holder_impl::value> super; + + public: + ebo_functor_holder(){} + ebo_functor_holder(const T& t) + : super(t) + {} + + template + ebo_functor_holder(const Arg1& arg1, const Arg2& arg2) + : super(arg1, arg2) + {} + + ebo_functor_holder& operator=(const ebo_functor_holder& x) + { + this->get()=x.get(); + return *this; + } +}; + + +} //namespace detail { +} //namespace intrusive { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTRUSIVE_DETAIL_EBO_HOLDER_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/function_detector.hpp b/cpp/BoostParts/boost/intrusive/detail/function_detector.hpp new file mode 100644 index 00000000..08cee2d5 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/function_detector.hpp @@ -0,0 +1,88 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +// This code was modified from the code posted by Alexandre Courpron in his +// article "Interface Detection" in The Code Project: +// http://www.codeproject.com/KB/architecture/Detector.aspx +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2007 Alexandre Courpron +// +// Permission to use, copy, modify, redistribute and sell this software, +// provided that this copyright notice appears on all copies of the software. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_DETAIL_FUNCTION_DETECTOR_HPP +#define BOOST_INTRUSIVE_DETAIL_FUNCTION_DETECTOR_HPP + +#include + +namespace boost { +namespace intrusive { +namespace function_detector { + + typedef char NotFoundType; + struct StaticFunctionType { NotFoundType x [2]; }; + struct NonStaticFunctionType { NotFoundType x [3]; }; + + enum + { NotFound = 0, + StaticFunction = sizeof( StaticFunctionType ) - sizeof( NotFoundType ), + NonStaticFunction = sizeof( NonStaticFunctionType ) - sizeof( NotFoundType ) + }; + +} //namespace boost { +} //namespace intrusive { +} //namespace function_detector { + +#define BOOST_INTRUSIVE_CREATE_FUNCTION_DETECTOR(Identifier, InstantiationKey) \ + namespace boost { \ + namespace intrusive { \ + namespace function_detector { \ + template < class T, \ + class NonStaticType, \ + class NonStaticConstType, \ + class StaticType > \ + class DetectMember_##InstantiationKey_##Identifier { \ + template < NonStaticType > \ + struct TestNonStaticNonConst ; \ + \ + template < NonStaticConstType > \ + struct TestNonStaticConst ; \ + \ + template < StaticType > \ + struct TestStatic ; \ + \ + template \ + static NonStaticFunctionType Test( TestNonStaticNonConst<&U::Identifier>*, int ); \ + \ + template \ + static NonStaticFunctionType Test( TestNonStaticConst<&U::Identifier>*, int ); \ + \ + template \ + static StaticFunctionType Test( TestStatic<&U::Identifier>*, int ); \ + \ + template \ + static NotFoundType Test( ... ); \ + public : \ + static const int check = NotFound + (sizeof(Test(0, 0)) - sizeof(NotFoundType));\ + };\ +}}} //namespace boost::intrusive::function_detector { + +#define BOOST_INTRUSIVE_DETECT_FUNCTION(Class, InstantiationKey, ReturnType, Identifier, Params) \ + ::boost::intrusive::function_detector::DetectMember_##InstantiationKey_##Identifier< Class,\ + ReturnType (Class::*)Params,\ + ReturnType (Class::*)Params const,\ + ReturnType (*)Params \ + >::check + +#include + +#endif //@ifndef BOOST_INTRUSIVE_DETAIL_FUNCTION_DETECTOR_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/generic_hook.hpp b/cpp/BoostParts/boost/intrusive/detail/generic_hook.hpp new file mode 100644 index 00000000..5ddd5207 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/generic_hook.hpp @@ -0,0 +1,209 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_GENERIC_HOOK_HPP +#define BOOST_INTRUSIVE_GENERIC_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +/// @cond + +enum +{ NoBaseHook +, ListBaseHook +, SlistBaseHook +, SetBaseHook +, UsetBaseHook +, SplaySetBaseHook +, AvlSetBaseHook +, BsSetBaseHook +, AnyBaseHook +}; + +struct no_default_definer{}; + +template +struct default_definer; + +template +struct default_definer +{ typedef Hook default_list_hook; }; + +template +struct default_definer +{ typedef Hook default_slist_hook; }; + +template +struct default_definer +{ typedef Hook default_set_hook; }; + +template +struct default_definer +{ typedef Hook default_uset_hook; }; + +template +struct default_definer +{ typedef Hook default_splay_set_hook; }; + +template +struct default_definer +{ typedef Hook default_avl_set_hook; }; + +template +struct default_definer +{ typedef Hook default_bs_set_hook; }; + +template +struct default_definer +{ typedef Hook default_any_hook; }; + +template +struct make_default_definer +{ + typedef typename detail::if_c + < BaseHookType != 0 + , default_definer + , no_default_definer>::type type; +}; + +template + < class GetNodeAlgorithms + , class Tag + , link_mode_type LinkMode + , int HookType + > +struct make_node_holder +{ + typedef typename detail::if_c + ::value + , detail::node_holder + < typename GetNodeAlgorithms::type::node + , Tag + , LinkMode + , HookType> + , typename GetNodeAlgorithms::type::node + >::type type; +}; + +/// @endcond + +template + < class GetNodeAlgorithms + , class Tag + , link_mode_type LinkMode + , int HookType + > +class generic_hook + /// @cond + + //If the hook is a base hook, derive generic hook from detail::node_holder + //so that a unique base class is created to convert from the node + //to the type. This mechanism will be used by base_hook_traits. + // + //If the hook is a member hook, generic hook will directly derive + //from the hook. + : public make_default_definer + < generic_hook + , detail::is_same::value*HookType + >::type + , public make_node_holder::type + /// @endcond +{ + /// @cond + typedef typename GetNodeAlgorithms::type node_algorithms; + typedef typename node_algorithms::node node; + typedef typename node_algorithms::node_ptr node_ptr; + typedef typename node_algorithms::const_node_ptr const_node_ptr; + + public: + struct boost_intrusive_tags + { + static const int hook_type = HookType; + static const link_mode_type link_mode = LinkMode; + typedef Tag tag; + typedef typename GetNodeAlgorithms::type::node_traits node_traits; + static const bool is_base_hook = !detail::is_same::value; + static const bool safemode_or_autounlink = + (int)link_mode == (int)auto_unlink || (int)link_mode == (int)safe_link; + }; + + node_ptr this_ptr() + { return pointer_traits::pointer_to(static_cast(*this)); } + + const_node_ptr this_ptr() const + { return pointer_traits::pointer_to(static_cast(*this)); } + + public: + /// @endcond + + generic_hook() + { + if(boost_intrusive_tags::safemode_or_autounlink){ + node_algorithms::init(this->this_ptr()); + } + } + + generic_hook(const generic_hook& ) + { + if(boost_intrusive_tags::safemode_or_autounlink){ + node_algorithms::init(this->this_ptr()); + } + } + + generic_hook& operator=(const generic_hook& ) + { return *this; } + + ~generic_hook() + { + destructor_impl + (*this, detail::link_dispatch()); + } + + void swap_nodes(generic_hook &other) + { + node_algorithms::swap_nodes + (this->this_ptr(), other.this_ptr()); + } + + bool is_linked() const + { + //is_linked() can be only used in safe-mode or auto-unlink + BOOST_STATIC_ASSERT(( boost_intrusive_tags::safemode_or_autounlink )); + return !node_algorithms::unique(this->this_ptr()); + } + + void unlink() + { + BOOST_STATIC_ASSERT(( (int)boost_intrusive_tags::link_mode == (int)auto_unlink )); + node_algorithms::unlink(this->this_ptr()); + node_algorithms::init(this->this_ptr()); + } +}; + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_GENERIC_HOOK_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/is_stateful_value_traits.hpp b/cpp/BoostParts/boost/intrusive/detail/is_stateful_value_traits.hpp new file mode 100644 index 00000000..8677c666 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/is_stateful_value_traits.hpp @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_DETAIL_IS_STATEFUL_VALUE_TRAITS_HPP +#define BOOST_INTRUSIVE_DETAIL_IS_STATEFUL_VALUE_TRAITS_HPP + +#include + +#if defined(_MSC_VER) && (_MSC_VER <= 1310) + +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +struct is_stateful_value_traits +{ + static const bool value = !detail::is_empty_class::value; +}; + +}}} + +#else + +#include + +BOOST_INTRUSIVE_CREATE_FUNCTION_DETECTOR(to_node_ptr, boost_intrusive) +BOOST_INTRUSIVE_CREATE_FUNCTION_DETECTOR(to_value_ptr, boost_intrusive) + +namespace boost { +namespace intrusive { +namespace detail { + +template +struct is_stateful_value_traits +{ + typedef typename ValueTraits::node_ptr node_ptr; + typedef typename ValueTraits::pointer pointer; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::const_node_ptr const_node_ptr; + typedef typename ValueTraits::const_pointer const_pointer; + + typedef ValueTraits value_traits; + + static const bool value = + (boost::intrusive::function_detector::NonStaticFunction == + (BOOST_INTRUSIVE_DETECT_FUNCTION(ValueTraits, boost_intrusive, node_ptr, to_node_ptr, (value_type&) ))) + || + (boost::intrusive::function_detector::NonStaticFunction == + (BOOST_INTRUSIVE_DETECT_FUNCTION(ValueTraits, boost_intrusive, pointer, to_value_ptr, (node_ptr) ))) + || + (boost::intrusive::function_detector::NonStaticFunction == + (BOOST_INTRUSIVE_DETECT_FUNCTION(ValueTraits, boost_intrusive, const_node_ptr, to_node_ptr, (const value_type&) ))) + || + (boost::intrusive::function_detector::NonStaticFunction == + (BOOST_INTRUSIVE_DETECT_FUNCTION(ValueTraits, boost_intrusive, const_pointer, to_value_ptr, (const_node_ptr) ))) + ; +}; + +}}} + +#endif + +#include + +#endif //@ifndef BOOST_INTRUSIVE_DETAIL_IS_STATEFUL_VALUE_TRAITS_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/parent_from_member.hpp b/cpp/BoostParts/boost/intrusive/detail/parent_from_member.hpp new file mode 100644 index 00000000..2afffb47 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/parent_from_member.hpp @@ -0,0 +1,93 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTRUSIVE_DETAIL_PARENT_FROM_MEMBER_HPP +#define BOOST_INTRUSIVE_DETAIL_PARENT_FROM_MEMBER_HPP + +#include +#include + +#if defined(BOOST_MSVC) || ((defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && defined(BOOST_INTEL)) + +#define BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER +#include +#endif + +namespace boost { +namespace intrusive { +namespace detail { + +template +inline std::ptrdiff_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member) +{ + //The implementation of a pointer to member is compiler dependent. + #if defined(BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER) + //msvc compliant compilers use their the first 32 bits as offset (even in 64 bit mode) + union caster_union + { + const Member Parent::* ptr_to_member; + boost::int32_t offset; + } caster; + caster.ptr_to_member = ptr_to_member; + return std::ptrdiff_t(caster.offset); + //This works with gcc, msvc, ac++, ibmcpp + #elif defined(__GNUC__) || defined(__HP_aCC) || defined(BOOST_INTEL) || \ + defined(__IBMCPP__) || defined(__DECCXX) + const Parent * const parent = 0; + const char *const member = static_cast(static_cast(&(parent->*ptr_to_member))); + return std::ptrdiff_t(member - static_cast(static_cast(parent))); + #else + //This is the traditional C-front approach: __MWERKS__, __DMC__, __SUNPRO_CC + union caster_union + { + const Member Parent::* ptr_to_member; + std::ptrdiff_t offset; + } caster; + caster.ptr_to_member = ptr_to_member; + return caster.offset - 1; + #endif +} + +template +inline Parent *parent_from_member(Member *member, const Member Parent::* ptr_to_member) +{ + return static_cast + ( + static_cast + ( + static_cast(static_cast(member)) - offset_from_pointer_to_member(ptr_to_member) + ) + ); +} + +template +inline const Parent *parent_from_member(const Member *member, const Member Parent::* ptr_to_member) +{ + return static_cast + ( + static_cast + ( + static_cast(static_cast(member)) - offset_from_pointer_to_member(ptr_to_member) + ) + ); +} + +} //namespace detail { +} //namespace intrusive { +} //namespace boost { + +#ifdef BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER +#undef BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER +#endif + +#include + +#endif //#ifndef BOOST_INTRUSIVE_DETAIL_PARENT_FROM_MEMBER_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/rbtree_node.hpp b/cpp/BoostParts/boost/intrusive/detail/rbtree_node.hpp new file mode 100644 index 00000000..92d9417c --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/rbtree_node.hpp @@ -0,0 +1,201 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_RBTREE_NODE_HPP +#define BOOST_INTRUSIVE_RBTREE_NODE_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +///////////////////////////////////////////////////////////////////////////// +// // +// Generic node_traits for any pointer type // +// // +///////////////////////////////////////////////////////////////////////////// + +//This is the compact representation: 3 pointers +template +struct compact_rbtree_node +{ + typedef typename pointer_traits + ::template rebind_pointer + >::type node_ptr; + enum color { red_t, black_t }; + node_ptr parent_, left_, right_; +}; + +//This is the normal representation: 3 pointers + enum +template +struct rbtree_node +{ + typedef typename pointer_traits + ::template rebind_pointer + >::type node_ptr; + + enum color { red_t, black_t }; + node_ptr parent_, left_, right_; + color color_; +}; + +//This is the default node traits implementation +//using a node with 3 generic pointers plus an enum +template +struct default_rbtree_node_traits_impl +{ + typedef rbtree_node node; + + typedef typename pointer_traits + ::template rebind_pointer::type node_ptr; + typedef typename pointer_traits + ::template rebind_pointer::type const_node_ptr; + + typedef typename node::color color; + + static node_ptr get_parent(const const_node_ptr & n) + { return n->parent_; } + + static node_ptr get_parent(const node_ptr & n) + { return n->parent_; } + + static void set_parent(const node_ptr & n, const node_ptr & p) + { n->parent_ = p; } + + static node_ptr get_left(const const_node_ptr & n) + { return n->left_; } + + static node_ptr get_left(const node_ptr & n) + { return n->left_; } + + static void set_left(const node_ptr & n, const node_ptr & l) + { n->left_ = l; } + + static node_ptr get_right(const const_node_ptr & n) + { return n->right_; } + + static node_ptr get_right(const node_ptr & n) + { return n->right_; } + + static void set_right(const node_ptr & n, const node_ptr & r) + { n->right_ = r; } + + static color get_color(const const_node_ptr & n) + { return n->color_; } + + static color get_color(const node_ptr & n) + { return n->color_; } + + static void set_color(const node_ptr & n, color c) + { n->color_ = c; } + + static color black() + { return node::black_t; } + + static color red() + { return node::red_t; } +}; + +//This is the compact node traits implementation +//using a node with 3 generic pointers +template +struct compact_rbtree_node_traits_impl +{ + typedef compact_rbtree_node node; + typedef typename pointer_traits + ::template rebind_pointer::type node_ptr; + typedef typename pointer_traits + ::template rebind_pointer::type const_node_ptr; + + typedef pointer_plus_bits ptr_bit; + + typedef typename node::color color; + + static node_ptr get_parent(const const_node_ptr & n) + { return ptr_bit::get_pointer(n->parent_); } + + static node_ptr get_parent(const node_ptr & n) + { return ptr_bit::get_pointer(n->parent_); } + + static void set_parent(const node_ptr & n, const node_ptr & p) + { ptr_bit::set_pointer(n->parent_, p); } + + static node_ptr get_left(const const_node_ptr & n) + { return n->left_; } + + static node_ptr get_left(const node_ptr & n) + { return n->left_; } + + static void set_left(const node_ptr & n, const node_ptr & l) + { n->left_ = l; } + + static node_ptr get_right(const const_node_ptr & n) + { return n->right_; } + + static node_ptr get_right(const node_ptr & n) + { return n->right_; } + + static void set_right(const node_ptr & n, const node_ptr & r) + { n->right_ = r; } + + static color get_color(const const_node_ptr & n) + { return (color)ptr_bit::get_bits(n->parent_); } + + static color get_color(const node_ptr & n) + { return (color)ptr_bit::get_bits(n->parent_); } + + static void set_color(const node_ptr & n, color c) + { ptr_bit::set_bits(n->parent_, c != 0); } + + static color black() + { return node::black_t; } + + static color red() + { return node::red_t; } +}; + +//Dispatches the implementation based on the boolean +template +struct rbtree_node_traits_dispatch + : public default_rbtree_node_traits_impl +{}; + +template +struct rbtree_node_traits_dispatch + : public compact_rbtree_node_traits_impl +{}; + +//Inherit from the detail::link_dispatch depending on the embedding capabilities +template +struct rbtree_node_traits + : public rbtree_node_traits_dispatch + < VoidPointer + , OptimizeSize && + (max_pointer_plus_bits + < VoidPointer + , detail::alignment_of >::value + >::value >= 1) + > +{}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_RBTREE_NODE_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/slist_node.hpp b/cpp/BoostParts/boost/intrusive/detail/slist_node.hpp new file mode 100644 index 00000000..ee929198 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/slist_node.hpp @@ -0,0 +1,166 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_SLIST_NODE_HPP +#define BOOST_INTRUSIVE_SLIST_NODE_HPP + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +template +struct slist_node +{ + typedef typename pointer_traits + ::template rebind_pointer::type node_ptr; + node_ptr next_; +}; + +// slist_node_traits can be used with circular_slist_algorithms and supplies +// a slist_node holding the pointers needed for a singly-linked list +// it is used by slist_base_hook and slist_member_hook +template +struct slist_node_traits +{ + typedef slist_node node; + typedef typename pointer_traits + ::template rebind_pointer::type node_ptr; + typedef typename pointer_traits + ::template rebind_pointer::type const_node_ptr; + + static node_ptr get_next(const const_node_ptr & n) + { return n->next_; } + + static node_ptr get_next(const node_ptr & n) + { return n->next_; } + + static void set_next(const node_ptr & n, const node_ptr & next) + { n->next_ = next; } +}; + +// slist_iterator provides some basic functions for a +// node oriented bidirectional iterator: +template +class slist_iterator + : public std::iterator + < std::forward_iterator_tag + , typename Container::value_type + , typename Container::difference_type + , typename detail::if_c::type + , typename detail::if_c::type + > +{ + protected: + typedef typename Container::real_value_traits real_value_traits; + typedef typename real_value_traits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename pointer_traits + ::template rebind_pointer ::type void_pointer; + static const bool store_container_ptr = + detail::store_cont_ptr_on_it::value; + + public: + typedef typename Container::value_type value_type; + typedef typename detail::if_c::type pointer; + typedef typename detail::if_c::type reference; + + slist_iterator() + : members_ (node_ptr(), 0) + {} + + explicit slist_iterator(const node_ptr & node, const Container *cont_ptr) + : members_ (node, cont_ptr) + {} + + slist_iterator(slist_iterator const& other) + : members_(other.pointed_node(), other.get_container()) + {} + + const node_ptr &pointed_node() const + { return members_.nodeptr_; } + + slist_iterator &operator=(const node_ptr &node) + { members_.nodeptr_ = node; return static_cast(*this); } + + public: + slist_iterator& operator++() + { + members_.nodeptr_ = node_traits::get_next(members_.nodeptr_); + return static_cast (*this); + } + + slist_iterator operator++(int) + { + slist_iterator result (*this); + members_.nodeptr_ = node_traits::get_next(members_.nodeptr_); + return result; + } + + friend bool operator== (const slist_iterator& l, const slist_iterator& r) + { return l.pointed_node() == r.pointed_node(); } + + friend bool operator!= (const slist_iterator& l, const slist_iterator& r) + { return !(l == r); } + + reference operator*() const + { return *operator->(); } + + pointer operator->() const + { return this->get_real_value_traits()->to_value_ptr(members_.nodeptr_); } + + const Container *get_container() const + { + if(store_container_ptr) + return static_cast(members_.get_ptr()); + else + return 0; + } + + slist_iterator unconst() const + { return slist_iterator(this->pointed_node(), this->get_container()); } + + const real_value_traits *get_real_value_traits() const + { + if(store_container_ptr) + return &this->get_container()->get_real_value_traits(); + else + return 0; + } + + private: + struct members + : public detail::select_constptr + ::type + { + typedef typename detail::select_constptr + ::type Base; + + members(const node_ptr &n_ptr, const void *cont) + : Base(cont), nodeptr_(n_ptr) + {} + + node_ptr nodeptr_; + } members_; +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SLIST_NODE_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/tree_algorithms.hpp b/cpp/BoostParts/boost/intrusive/detail/tree_algorithms.hpp new file mode 100644 index 00000000..27c86673 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/tree_algorithms.hpp @@ -0,0 +1,1742 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_TREE_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_TREE_ALGORITHMS_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +//! This is an implementation of a binary search tree. +//! A node in the search tree has references to its children and its parent. This +//! is to allow traversal of the whole tree from a given node making the +//! implementation of iterator a pointer to a node. +//! At the top of the tree a node is used specially. This node's parent pointer +//! is pointing to the root of the tree. Its left pointer points to the +//! leftmost node in the tree and the right pointer to the rightmost one. +//! This node is used to represent the end-iterator. +//! +//! +---------+ +//! header------------------------------>| | +//! | | +//! +----------(left)--------| |--------(right)---------+ +//! | +---------+ | +//! | | | +//! | | (parent) | +//! | | | +//! | | | +//! | +---------+ | +//! root of tree ..|......................> | | | +//! | | D | | +//! | | | | +//! | +-------+---------+-------+ | +//! | | | | +//! | | | | +//! | | | | +//! | | | | +//! | | | | +//! | +---------+ +---------+ | +//! | | | | | | +//! | | B | | F | | +//! | | | | | | +//! | +--+---------+--+ +--+---------+--+ | +//! | | | | | | +//! | | | | | | +//! | | | | | | +//! | +---+-----+ +-----+---+ +---+-----+ +-----+---+ | +//! +-->| | | | | | | |<--+ +//! | A | | C | | E | | G | +//! | | | | | | | | +//! +---------+ +---------+ +---------+ +---------+ +//! + +//! tree_algorithms is configured with a NodeTraits class, which encapsulates the +//! information about the node to be manipulated. NodeTraits must support the +//! following interface: +//! +//! Typedefs: +//! +//! node: The type of the node that forms the circular list +//! +//! node_ptr: A pointer to a node +//! +//! const_node_ptr: A pointer to a const node +//! +//! Static functions: +//! +//! static node_ptr get_parent(const_node_ptr n); +//! +//! static void set_parent(node_ptr n, node_ptr parent); +//! +//! static node_ptr get_left(const_node_ptr n); +//! +//! static void set_left(node_ptr n, node_ptr left); +//! +//! static node_ptr get_right(const_node_ptr n); +//! +//! static void set_right(node_ptr n, node_ptr right); +template +class tree_algorithms +{ + public: + typedef typename NodeTraits::node node; + typedef NodeTraits node_traits; + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + + //! This type is the information that will be filled by insert_unique_check + struct insert_commit_data + { + insert_commit_data() + : link_left(false) + , node() + {} + bool link_left; + node_ptr node; + }; + + struct nop_erase_fixup + { + void operator()(const node_ptr&, const node_ptr&){} + }; + + /// @cond + private: + template + struct dispose_subtree_disposer + { + dispose_subtree_disposer(Disposer &disp, const node_ptr & subtree) + : disposer_(&disp), subtree_(subtree) + {} + + void release() + { disposer_ = 0; } + + ~dispose_subtree_disposer() + { + if(disposer_){ + dispose_subtree(subtree_, *disposer_); + } + } + Disposer *disposer_; + node_ptr subtree_; + }; + + static node_ptr uncast(const const_node_ptr & ptr) + { return pointer_traits::const_cast_from(ptr); } + + /// @endcond + + public: + static node_ptr begin_node(const const_node_ptr & header) + { return node_traits::get_left(header); } + + static node_ptr end_node(const const_node_ptr & header) + { return uncast(header); } + + //! Requires: 'node' is a node of the tree or an node initialized + //! by init(...) or init_node. + //! + //! Effects: Returns true if the node is initialized by init() or init_node(). + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + static bool unique(const const_node_ptr & node) + { return !NodeTraits::get_parent(node); } + + static node_ptr get_header(const const_node_ptr & node) + { + node_ptr h = uncast(node); + if(NodeTraits::get_parent(node)){ + h = NodeTraits::get_parent(node); + while(!is_header(h)) + h = NodeTraits::get_parent(h); + } + return h; + } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees. + //! + //! Effects: Swaps two nodes. After the function node1 will be inserted + //! in the position node2 before the function. node2 will be inserted in the + //! position node1 had before the function. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! node1 and node2 are not equivalent according to the ordering rules. + //! + //!Experimental function + static void swap_nodes(const node_ptr & node1, const node_ptr & node2) + { + if(node1 == node2) + return; + + node_ptr header1(get_header(node1)), header2(get_header(node2)); + swap_nodes(node1, header1, node2, header2); + } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees with header header1 and header2. + //! + //! Effects: Swaps two nodes. After the function node1 will be inserted + //! in the position node2 before the function. node2 will be inserted in the + //! position node1 had before the function. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! node1 and node2 are not equivalent according to the ordering rules. + //! + //!Experimental function + static void swap_nodes(const node_ptr & node1, const node_ptr & header1, const node_ptr & node2, const node_ptr & header2) + { + if(node1 == node2) + return; + + //node1 and node2 must not be header nodes + //BOOST_INTRUSIVE_INVARIANT_ASSERT((header1 != node1 && header2 != node2)); + if(header1 != header2){ + //Update header1 if necessary + if(node1 == NodeTraits::get_left(header1)){ + NodeTraits::set_left(header1, node2); + } + + if(node1 == NodeTraits::get_right(header1)){ + NodeTraits::set_right(header1, node2); + } + + if(node1 == NodeTraits::get_parent(header1)){ + NodeTraits::set_parent(header1, node2); + } + + //Update header2 if necessary + if(node2 == NodeTraits::get_left(header2)){ + NodeTraits::set_left(header2, node1); + } + + if(node2 == NodeTraits::get_right(header2)){ + NodeTraits::set_right(header2, node1); + } + + if(node2 == NodeTraits::get_parent(header2)){ + NodeTraits::set_parent(header2, node1); + } + } + else{ + //If both nodes are from the same tree + //Update header if necessary + if(node1 == NodeTraits::get_left(header1)){ + NodeTraits::set_left(header1, node2); + } + else if(node2 == NodeTraits::get_left(header2)){ + NodeTraits::set_left(header2, node1); + } + + if(node1 == NodeTraits::get_right(header1)){ + NodeTraits::set_right(header1, node2); + } + else if(node2 == NodeTraits::get_right(header2)){ + NodeTraits::set_right(header2, node1); + } + + if(node1 == NodeTraits::get_parent(header1)){ + NodeTraits::set_parent(header1, node2); + } + else if(node2 == NodeTraits::get_parent(header2)){ + NodeTraits::set_parent(header2, node1); + } + + //Adjust data in nodes to be swapped + //so that final link swap works as expected + if(node1 == NodeTraits::get_parent(node2)){ + NodeTraits::set_parent(node2, node2); + + if(node2 == NodeTraits::get_right(node1)){ + NodeTraits::set_right(node1, node1); + } + else{ + NodeTraits::set_left(node1, node1); + } + } + else if(node2 == NodeTraits::get_parent(node1)){ + NodeTraits::set_parent(node1, node1); + + if(node1 == NodeTraits::get_right(node2)){ + NodeTraits::set_right(node2, node2); + } + else{ + NodeTraits::set_left(node2, node2); + } + } + } + + //Now swap all the links + node_ptr temp; + //swap left link + temp = NodeTraits::get_left(node1); + NodeTraits::set_left(node1, NodeTraits::get_left(node2)); + NodeTraits::set_left(node2, temp); + //swap right link + temp = NodeTraits::get_right(node1); + NodeTraits::set_right(node1, NodeTraits::get_right(node2)); + NodeTraits::set_right(node2, temp); + //swap parent link + temp = NodeTraits::get_parent(node1); + NodeTraits::set_parent(node1, NodeTraits::get_parent(node2)); + NodeTraits::set_parent(node2, temp); + + //Now adjust adjacent nodes for newly inserted node 1 + if((temp = NodeTraits::get_left(node1))){ + NodeTraits::set_parent(temp, node1); + } + if((temp = NodeTraits::get_right(node1))){ + NodeTraits::set_parent(temp, node1); + } + if((temp = NodeTraits::get_parent(node1)) && + //The header has been already updated so avoid it + temp != header2){ + if(NodeTraits::get_left(temp) == node2){ + NodeTraits::set_left(temp, node1); + } + if(NodeTraits::get_right(temp) == node2){ + NodeTraits::set_right(temp, node1); + } + } + //Now adjust adjacent nodes for newly inserted node 2 + if((temp = NodeTraits::get_left(node2))){ + NodeTraits::set_parent(temp, node2); + } + if((temp = NodeTraits::get_right(node2))){ + NodeTraits::set_parent(temp, node2); + } + if((temp = NodeTraits::get_parent(node2)) && + //The header has been already updated so avoid it + temp != header1){ + if(NodeTraits::get_left(temp) == node1){ + NodeTraits::set_left(temp, node2); + } + if(NodeTraits::get_right(temp) == node1){ + NodeTraits::set_right(temp, node2); + } + } + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! new_node is not equivalent to node_to_be_replaced according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing and comparison is needed. + //! + //!Experimental function + static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & new_node) + { + if(node_to_be_replaced == new_node) + return; + replace_node(node_to_be_replaced, get_header(node_to_be_replaced), new_node); + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! with header "header" and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! new_node is not equivalent to node_to_be_replaced according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + //! + //!Experimental function + static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & header, const node_ptr & new_node) + { + if(node_to_be_replaced == new_node) + return; + + //Update header if necessary + if(node_to_be_replaced == NodeTraits::get_left(header)){ + NodeTraits::set_left(header, new_node); + } + + if(node_to_be_replaced == NodeTraits::get_right(header)){ + NodeTraits::set_right(header, new_node); + } + + if(node_to_be_replaced == NodeTraits::get_parent(header)){ + NodeTraits::set_parent(header, new_node); + } + + //Now set data from the original node + node_ptr temp; + NodeTraits::set_left(new_node, NodeTraits::get_left(node_to_be_replaced)); + NodeTraits::set_right(new_node, NodeTraits::get_right(node_to_be_replaced)); + NodeTraits::set_parent(new_node, NodeTraits::get_parent(node_to_be_replaced)); + + //Now adjust adjacent nodes for newly inserted node + if((temp = NodeTraits::get_left(new_node))){ + NodeTraits::set_parent(temp, new_node); + } + if((temp = NodeTraits::get_right(new_node))){ + NodeTraits::set_parent(temp, new_node); + } + if((temp = NodeTraits::get_parent(new_node)) && + //The header has been already updated so avoid it + temp != header){ + if(NodeTraits::get_left(temp) == node_to_be_replaced){ + NodeTraits::set_left(temp, new_node); + } + if(NodeTraits::get_right(temp) == node_to_be_replaced){ + NodeTraits::set_right(temp, new_node); + } + } + } + + //! Requires: 'node' is a node from the tree except the header. + //! + //! Effects: Returns the next node of the tree. + //! + //! Complexity: Average constant time. + //! + //! Throws: Nothing. + static node_ptr next_node(const node_ptr & node) + { + node_ptr p_right(NodeTraits::get_right(node)); + if(p_right){ + return minimum(p_right); + } + else { + node_ptr p(node); + node_ptr x = NodeTraits::get_parent(p); + while(p == NodeTraits::get_right(x)){ + p = x; + x = NodeTraits::get_parent(x); + } + return NodeTraits::get_right(p) != x ? x : uncast(p); + } + } + + //! Requires: 'node' is a node from the tree except the leftmost node. + //! + //! Effects: Returns the previous node of the tree. + //! + //! Complexity: Average constant time. + //! + //! Throws: Nothing. + static node_ptr prev_node(const node_ptr & node) + { + if(is_header(node)){ + return NodeTraits::get_right(node); + //return maximum(NodeTraits::get_parent(node)); + } + else if(NodeTraits::get_left(node)){ + return maximum(NodeTraits::get_left(node)); + } + else { + node_ptr p(node); + node_ptr x = NodeTraits::get_parent(p); + while(p == NodeTraits::get_left(x)){ + p = x; + x = NodeTraits::get_parent(x); + } + return x; + } + } + + //! Requires: 'node' is a node of a tree but not the header. + //! + //! Effects: Returns the minimum node of the subtree starting at p. + //! + //! Complexity: Logarithmic to the size of the subtree. + //! + //! Throws: Nothing. + static node_ptr minimum (node_ptr node) + { + for(node_ptr p_left = NodeTraits::get_left(node) + ;p_left + ;p_left = NodeTraits::get_left(node)){ + node = p_left; + } + return node; + } + + //! Requires: 'node' is a node of a tree but not the header. + //! + //! Effects: Returns the maximum node of the subtree starting at p. + //! + //! Complexity: Logarithmic to the size of the subtree. + //! + //! Throws: Nothing. + static node_ptr maximum(node_ptr node) + { + for(node_ptr p_right = NodeTraits::get_right(node) + ;p_right + ;p_right = NodeTraits::get_right(node)){ + node = p_right; + } + return node; + } + + //! Requires: 'node' must not be part of any tree. + //! + //! Effects: After the function unique(node) == true. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Nodes: If node is inserted in a tree, this function corrupts the tree. + static void init(const node_ptr & node) + { + NodeTraits::set_parent(node, node_ptr()); + NodeTraits::set_left(node, node_ptr()); + NodeTraits::set_right(node, node_ptr()); + }; + + //! Effects: Returns true if node is in the same state as if called init(node) + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static bool inited(const const_node_ptr & node) + { + return !NodeTraits::get_parent(node) && + !NodeTraits::get_left(node) && + !NodeTraits::get_right(node) ; + }; + + //! Requires: node must not be part of any tree. + //! + //! Effects: Initializes the header to represent an empty tree. + //! unique(header) == true. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Nodes: If node is inserted in a tree, this function corrupts the tree. + static void init_header(const node_ptr & header) + { + NodeTraits::set_parent(header, node_ptr()); + NodeTraits::set_left(header, header); + NodeTraits::set_right(header, header); + } + + //! Requires: "disposer" must be an object function + //! taking a node_ptr parameter and shouldn't throw. + //! + //! Effects: Empties the target tree calling + //! void disposer::operator()(const node_ptr &) for every node of the tree + //! except the header. + //! + //! Complexity: Linear to the number of element of the source tree plus the. + //! number of elements of tree target tree when calling this function. + //! + //! Throws: If cloner functor throws. If this happens target nodes are disposed. + template + static void clear_and_dispose(const node_ptr & header, Disposer disposer) + { + node_ptr source_root = NodeTraits::get_parent(header); + if(!source_root) + return; + dispose_subtree(source_root, disposer); + init_header(header); + } + + //! Requires: header is the header of a tree. + //! + //! Effects: Unlinks the leftmost node from the tree, and + //! updates the header link to the new leftmost node. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + static node_ptr unlink_leftmost_without_rebalance(const node_ptr & header) + { + node_ptr leftmost = NodeTraits::get_left(header); + if (leftmost == header) + return node_ptr(); + node_ptr leftmost_parent(NodeTraits::get_parent(leftmost)); + node_ptr leftmost_right (NodeTraits::get_right(leftmost)); + bool is_root = leftmost_parent == header; + + if (leftmost_right){ + NodeTraits::set_parent(leftmost_right, leftmost_parent); + NodeTraits::set_left(header, tree_algorithms::minimum(leftmost_right)); + + if (is_root) + NodeTraits::set_parent(header, leftmost_right); + else + NodeTraits::set_left(NodeTraits::get_parent(header), leftmost_right); + } + else if (is_root){ + NodeTraits::set_parent(header, node_ptr()); + NodeTraits::set_left(header, header); + NodeTraits::set_right(header, header); + } + else{ + NodeTraits::set_left(leftmost_parent, node_ptr()); + NodeTraits::set_left(header, leftmost_parent); + } + return leftmost; + } + + //! Requires: node is a node of the tree but it's not the header. + //! + //! Effects: Returns the number of nodes of the subtree. + //! + //! Complexity: Linear time. + //! + //! Throws: Nothing. + static std::size_t count(const const_node_ptr & subtree) + { + if(!subtree) return 0; + std::size_t count = 0; + node_ptr p = minimum(uncast(subtree)); + bool continue_looping = true; + while(continue_looping){ + ++count; + node_ptr p_right(NodeTraits::get_right(p)); + if(p_right){ + p = minimum(p_right); + } + else { + for(;;){ + node_ptr q; + if (p == subtree){ + continue_looping = false; + break; + } + q = p; + p = NodeTraits::get_parent(p); + if (NodeTraits::get_left(p) == q) + break; + } + } + } + return count; + } + + //! Requires: node is a node of the tree but it's not the header. + //! + //! Effects: Returns the number of nodes of the subtree. + //! + //! Complexity: Linear time. + //! + //! Throws: Nothing. + static std::size_t size(const const_node_ptr & header) + { + node_ptr beg(begin_node(header)); + node_ptr end(end_node(header)); + std::size_t i = 0; + for(;beg != end; beg = next_node(beg)) ++i; + return i; + } + + //! Requires: header1 and header2 must be the header nodes + //! of two trees. + //! + //! Effects: Swaps two trees. After the function header1 will contain + //! links to the second tree and header2 will have links to the first tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static void swap_tree(const node_ptr & header1, const node_ptr & header2) + { + if(header1 == header2) + return; + + node_ptr tmp; + + //Parent swap + tmp = NodeTraits::get_parent(header1); + NodeTraits::set_parent(header1, NodeTraits::get_parent(header2)); + NodeTraits::set_parent(header2, tmp); + //Left swap + tmp = NodeTraits::get_left(header1); + NodeTraits::set_left(header1, NodeTraits::get_left(header2)); + NodeTraits::set_left(header2, tmp); + //Right swap + tmp = NodeTraits::get_right(header1); + NodeTraits::set_right(header1, NodeTraits::get_right(header2)); + NodeTraits::set_right(header2, tmp); + + //Now test parent + node_ptr h1_parent(NodeTraits::get_parent(header1)); + if(h1_parent){ + NodeTraits::set_parent(h1_parent, header1); + } + else{ + NodeTraits::set_left(header1, header1); + NodeTraits::set_right(header1, header1); + } + + node_ptr h2_parent(NodeTraits::get_parent(header2)); + if(h2_parent){ + NodeTraits::set_parent(h2_parent, header2); + } + else{ + NodeTraits::set_left(header2, header2); + NodeTraits::set_right(header2, header2); + } + } + + static bool is_header(const const_node_ptr & p) + { + node_ptr p_left (NodeTraits::get_left(p)); + node_ptr p_right(NodeTraits::get_right(p)); + if(!NodeTraits::get_parent(p) || //Header condition when empty tree + (p_left && p_right && //Header always has leftmost and rightmost + (p_left == p_right || //Header condition when only node + (NodeTraits::get_parent(p_left) != p || + NodeTraits::get_parent(p_right) != p )) + //When tree size > 1 headers can't be leftmost's + //and rightmost's parent + )){ + return true; + } + return false; + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the element that is equivalent to + //! "key" according to "comp" or "header" if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr find + (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) + { + node_ptr end = uncast(header); + node_ptr y = lower_bound(header, key, comp); + return (y == end || comp(key, y)) ? end : y; + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If + //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise + //! + //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_key and upper_key. + template< class KeyType, class KeyNodePtrCompare> + static std::pair bounded_range + ( const const_node_ptr & header + , const KeyType &lower_key + , const KeyType &upper_key + , KeyNodePtrCompare comp + , bool left_closed + , bool right_closed) + { + node_ptr y = uncast(header); + node_ptr x = NodeTraits::get_parent(header); + + while(x){ + //If x is less than lower_key the target + //range is on the right part + if(comp(x, lower_key)){ + //Check for invalid input range + BOOST_INTRUSIVE_INVARIANT_ASSERT(comp(x, upper_key)); + x = NodeTraits::get_right(x); + } + //If the upper_key is less than x, the target + //range is on the left part + else if(comp(upper_key, x)){ + //y > upper_key + y = x; + x = NodeTraits::get_left(x); + } + else{ + //x is inside the bounded range( x >= lower_key && x <= upper_key), + //so we must split lower and upper searches + // + //Sanity check: if lower_key and upper_key are equal, then both left_closed and right_closed can't be false + BOOST_INTRUSIVE_INVARIANT_ASSERT(left_closed || right_closed || comp(lower_key, x) || comp(x, upper_key)); + return std::pair( + left_closed + //If left_closed, then comp(x, lower_key) is already the lower_bound + //condition so we save one comparison and go to the next level + //following traditional lower_bound algo + ? lower_bound_loop(NodeTraits::get_left(x), x, lower_key, comp) + //If left-open, comp(x, lower_key) is not the upper_bound algo + //condition so we must recheck current 'x' node with upper_bound algo + : upper_bound_loop(x, y, lower_key, comp) + , + right_closed + //If right_closed, then comp(upper_key, x) is already the upper_bound + //condition so we can save one comparison and go to the next level + //following lower_bound algo + ? upper_bound_loop(NodeTraits::get_right(x), y, upper_key, comp) + //If right-open, comp(upper_key, x) is not the lower_bound algo + //condition so we must recheck current 'x' node with lower_bound algo + : lower_bound_loop(x, y, upper_key, comp) + ); + } + } + return std::pair (y, y); + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an a pair of node_ptr delimiting a range containing + //! all elements that are equivalent to "key" according to "comp" or an + //! empty range that indicates the position where those elements would be + //! if there are no equivalent elements. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static std::pair equal_range + (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) + { + return bounded_range(header, key, key, comp, true, true); + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the first element that is + //! not less than "key" according to "comp" or "header" if that element does + //! not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr lower_bound + (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) + { + return lower_bound_loop(NodeTraits::get_parent(header), uncast(header), key, comp); + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the first element that is greater + //! than "key" according to "comp" or "header" if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr upper_bound + (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) + { + return upper_bound_loop(NodeTraits::get_parent(header), uncast(header), key, comp); + } + + //! Requires: "header" must be the header node of a tree. + //! "commit_data" must have been obtained from a previous call to + //! "insert_unique_check". No objects should have been inserted or erased + //! from the set between the "insert_unique_check" that filled "commit_data" + //! and the call to "insert_commit". + //! + //! + //! Effects: Inserts new_node in the set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_unique_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + static void insert_unique_commit + (const node_ptr & header, const node_ptr & new_value, const insert_commit_data &commit_data) + { return insert_commit(header, new_value, commit_data); } + + static void insert_commit + (const node_ptr & header, const node_ptr & new_node, const insert_commit_data &commit_data) + { + //Check if commit_data has not been initialized by a insert_unique_check call. + BOOST_INTRUSIVE_INVARIANT_ASSERT(commit_data.node != node_ptr()); + node_ptr parent_node(commit_data.node); + if(parent_node == header){ + NodeTraits::set_parent(header, new_node); + NodeTraits::set_right(header, new_node); + NodeTraits::set_left(header, new_node); + } + else if(commit_data.link_left){ + NodeTraits::set_left(parent_node, new_node); + if(parent_node == NodeTraits::get_left(header)) + NodeTraits::set_left(header, new_node); + } + else{ + NodeTraits::set_right(parent_node, new_node); + if(parent_node == NodeTraits::get_right(header)) + NodeTraits::set_right(header, new_node); + } + NodeTraits::set_parent(new_node, parent_node); + NodeTraits::set_right(new_node, node_ptr()); + NodeTraits::set_left(new_node, node_ptr()); + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares KeyType with a node_ptr. + //! + //! Effects: Checks if there is an equivalent node to "key" in the + //! tree according to "comp" and obtains the needed information to realize + //! a constant-time node insertion if there is no equivalent node. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing a node_ptr to the already present node + //! and false. If there is not equivalent key can be inserted returns true + //! in the returned pair's boolean and fills "commit_data" that is meant to + //! be used with the "insert_commit" function to achieve a constant-time + //! insertion function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Notes: This function is used to improve performance when constructing + //! a node is expensive and the user does not want to have two equivalent nodes + //! in the tree: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the node and this function offers the possibility to use that part + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the node and use + //! "insert_commit" to insert the node in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_unique_commit" only + //! if no more objects are inserted or erased from the set. + template + static std::pair insert_unique_check + (const const_node_ptr & header, const KeyType &key + ,KeyNodePtrCompare comp, insert_commit_data &commit_data, std::size_t *pdepth = 0) + { + std::size_t depth = 0; + node_ptr h(uncast(header)); + node_ptr y(h); + node_ptr x(NodeTraits::get_parent(y)); + node_ptr prev = node_ptr(); + + //Find the upper bound, cache the previous value and if we should + //store it in the left or right node + bool left_child = true; + while(x){ + ++depth; + y = x; + x = (left_child = comp(key, x)) ? + NodeTraits::get_left(x) : (prev = y, NodeTraits::get_right(x)); + } + + if(pdepth) *pdepth = depth; + + //Since we've found the upper bound there is no other value with the same key if: + // - There is no previous node + // - The previous node is less than the key + if(!prev || comp(prev, key)){ + commit_data.link_left = left_child; + commit_data.node = y; + return std::pair(node_ptr(), true); + } + //If the previous value was not less than key, it means that it's equal + //(because we've checked the upper bound) + else{ + return std::pair(prev, false); + } + } + + template + static std::pair insert_unique_check + (const const_node_ptr & header, const node_ptr &hint, const KeyType &key + ,KeyNodePtrCompare comp, insert_commit_data &commit_data, std::size_t *pdepth = 0) + { + //hint must be bigger than the key + if(hint == header || comp(key, hint)){ + node_ptr prev(hint); + //Previous value should be less than the key + if(hint == begin_node(header) || comp((prev = prev_node(hint)), key)){ + commit_data.link_left = unique(header) || !NodeTraits::get_left(hint); + commit_data.node = commit_data.link_left ? hint : prev; + if(pdepth){ + *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1; + } + return std::pair(node_ptr(), true); + } + } + //Hint was wrong, use hintless insertion + return insert_unique_check(header, key, comp, commit_data, pdepth); + } + + template + static void insert_equal_check + (const node_ptr &header, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp + , insert_commit_data &commit_data, std::size_t *pdepth = 0) + { + if(hint == header || !comp(hint, new_node)){ + node_ptr prev(hint); + if(hint == NodeTraits::get_left(header) || + !comp(new_node, (prev = prev_node(hint)))){ + bool link_left = unique(header) || !NodeTraits::get_left(hint); + commit_data.link_left = link_left; + commit_data.node = link_left ? hint : prev; + if(pdepth){ + *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1; + } + } + else{ + insert_equal_upper_bound_check(header, new_node, comp, commit_data, pdepth); + } + } + else{ + insert_equal_lower_bound_check(header, new_node, comp, commit_data, pdepth); + } + } + + template + static void insert_equal_upper_bound_check + (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0) + { insert_equal_check_impl(true, h, new_node, comp, commit_data, pdepth); } + + template + static void insert_equal_lower_bound_check + (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0) + { insert_equal_check_impl(false, h, new_node, comp, commit_data, pdepth); } + + template + static node_ptr insert_equal + (const node_ptr & h, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + insert_equal_check(h, hint, new_node, comp, commit_data, pdepth); + insert_commit(h, new_node, commit_data); + return new_node; + } + + template + static node_ptr insert_equal_upper_bound + (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + insert_equal_upper_bound_check(h, new_node, comp, commit_data, pdepth); + insert_commit(h, new_node, commit_data); + return new_node; + } + + template + static node_ptr insert_equal_lower_bound + (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + insert_equal_lower_bound_check(h, new_node, comp, commit_data, pdepth); + insert_commit(h, new_node, commit_data); + return new_node; + } + + static node_ptr insert_before + (const node_ptr & header, const node_ptr & pos, const node_ptr & new_node, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + insert_before_check(header, pos, commit_data, pdepth); + insert_commit(header, new_node, commit_data); + return new_node; + } + + static void insert_before_check + (const node_ptr &header, const node_ptr & pos + , insert_commit_data &commit_data, std::size_t *pdepth = 0) + { + node_ptr prev(pos); + if(pos != NodeTraits::get_left(header)) + prev = prev_node(pos); + bool link_left = unique(header) || !NodeTraits::get_left(pos); + commit_data.link_left = link_left; + commit_data.node = link_left ? pos : prev; + if(pdepth){ + *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1; + } + } + + static void push_back + (const node_ptr & header, const node_ptr & new_node, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + push_back_check(header, commit_data, pdepth); + insert_commit(header, new_node, commit_data); + } + + static void push_back_check + (const node_ptr & header, insert_commit_data &commit_data, std::size_t *pdepth = 0) + { + node_ptr prev(NodeTraits::get_right(header)); + if(pdepth){ + *pdepth = prev == header ? 0 : depth(prev) + 1; + } + commit_data.link_left = false; + commit_data.node = prev; + } + + static void push_front + (const node_ptr & header, const node_ptr & new_node, std::size_t *pdepth = 0) + { + insert_commit_data commit_data; + push_front_check(header, commit_data, pdepth); + insert_commit(header, new_node, commit_data); + } + + static void push_front_check + (const node_ptr & header, insert_commit_data &commit_data, std::size_t *pdepth = 0) + { + node_ptr pos(NodeTraits::get_left(header)); + if(pdepth){ + *pdepth = pos == header ? 0 : depth(pos) + 1; + } + commit_data.link_left = true; + commit_data.node = pos; + } + + //! Requires: 'node' can't be a header node. + //! + //! Effects: Calculates the depth of a node: the depth of a + //! node is the length (number of edges) of the path from the root + //! to that node. (The root node is at depth 0.) + //! + //! Complexity: Logarithmic to the number of nodes in the tree. + //! + //! Throws: Nothing. + static std::size_t depth(const_node_ptr node) + { + std::size_t depth = 0; + node_ptr p_parent; + while(node != NodeTraits::get_parent(p_parent = NodeTraits::get_parent(node))){ + ++depth; + node = p_parent; + } + return depth; + } + + //! Requires: "cloner" must be a function + //! object taking a node_ptr and returning a new cloned node of it. "disposer" must + //! take a node_ptr and shouldn't throw. + //! + //! Effects: First empties target tree calling + //! void disposer::operator()(const node_ptr &) for every node of the tree + //! except the header. + //! + //! Then, duplicates the entire tree pointed by "source_header" cloning each + //! source node with node_ptr Cloner::operator()(const node_ptr &) to obtain + //! the nodes of the target tree. If "cloner" throws, the cloned target nodes + //! are disposed using void disposer(const node_ptr &). + //! + //! Complexity: Linear to the number of element of the source tree plus the. + //! number of elements of tree target tree when calling this function. + //! + //! Throws: If cloner functor throws. If this happens target nodes are disposed. + template + static void clone + (const const_node_ptr & source_header, const node_ptr & target_header, Cloner cloner, Disposer disposer) + { + if(!unique(target_header)){ + clear_and_dispose(target_header, disposer); + } + + node_ptr leftmost, rightmost; + node_ptr new_root = clone_subtree + (source_header, target_header, cloner, disposer, leftmost, rightmost); + + //Now update header node + NodeTraits::set_parent(target_header, new_root); + NodeTraits::set_left (target_header, leftmost); + NodeTraits::set_right (target_header, rightmost); + } + + template + static node_ptr clone_subtree + (const const_node_ptr &source_parent, const node_ptr &target_parent + , Cloner cloner, Disposer disposer + , node_ptr &leftmost_out, node_ptr &rightmost_out + ) + { + node_ptr target_sub_root = target_parent; + node_ptr source_root = NodeTraits::get_parent(source_parent); + if(!source_root){ + leftmost_out = rightmost_out = source_root; + } + else{ + //We'll calculate leftmost and rightmost nodes while iterating + node_ptr current = source_root; + node_ptr insertion_point = target_sub_root = cloner(current); + + //We'll calculate leftmost and rightmost nodes while iterating + node_ptr leftmost = target_sub_root; + node_ptr rightmost = target_sub_root; + + //First set the subroot + NodeTraits::set_left(target_sub_root, node_ptr()); + NodeTraits::set_right(target_sub_root, node_ptr()); + NodeTraits::set_parent(target_sub_root, target_parent); + + dispose_subtree_disposer rollback(disposer, target_sub_root); + while(true) { + //First clone left nodes + if( NodeTraits::get_left(current) && + !NodeTraits::get_left(insertion_point)) { + current = NodeTraits::get_left(current); + node_ptr temp = insertion_point; + //Clone and mark as leaf + insertion_point = cloner(current); + NodeTraits::set_left (insertion_point, node_ptr()); + NodeTraits::set_right (insertion_point, node_ptr()); + //Insert left + NodeTraits::set_parent(insertion_point, temp); + NodeTraits::set_left (temp, insertion_point); + //Update leftmost + if(rightmost == target_sub_root) + leftmost = insertion_point; + } + //Then clone right nodes + else if( NodeTraits::get_right(current) && + !NodeTraits::get_right(insertion_point)){ + current = NodeTraits::get_right(current); + node_ptr temp = insertion_point; + //Clone and mark as leaf + insertion_point = cloner(current); + NodeTraits::set_left (insertion_point, node_ptr()); + NodeTraits::set_right (insertion_point, node_ptr()); + //Insert right + NodeTraits::set_parent(insertion_point, temp); + NodeTraits::set_right (temp, insertion_point); + //Update rightmost + rightmost = insertion_point; + } + //If not, go up + else if(current == source_root){ + break; + } + else{ + //Branch completed, go up searching more nodes to clone + current = NodeTraits::get_parent(current); + insertion_point = NodeTraits::get_parent(insertion_point); + } + } + rollback.release(); + leftmost_out = leftmost; + rightmost_out = rightmost; + } + return target_sub_root; + } + + template + static void dispose_subtree(node_ptr x, Disposer disposer) + { + while (x){ + node_ptr save(NodeTraits::get_left(x)); + if (save) { + // Right rotation + NodeTraits::set_left(x, NodeTraits::get_right(save)); + NodeTraits::set_right(save, x); + } + else { + save = NodeTraits::get_right(x); + init(x); + disposer(x); + } + x = save; + } + } + + //! Requires: p is a node of a tree. + //! + //! Effects: Returns true if p is a left child. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static bool is_left_child(const node_ptr & p) + { return NodeTraits::get_left(NodeTraits::get_parent(p)) == p; } + + //! Requires: p is a node of a tree. + //! + //! Effects: Returns true if p is a right child. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static bool is_right_child(const node_ptr & p) + { return NodeTraits::get_right(NodeTraits::get_parent(p)) == p; } + + //Fix header and own's parent data when replacing x with own, providing own's old data with parent + static void replace_own_impl(const node_ptr & own, const node_ptr & x, const node_ptr & header, const node_ptr & own_parent, bool own_was_left) + { + if(NodeTraits::get_parent(header) == own) + NodeTraits::set_parent(header, x); + else if(own_was_left) + NodeTraits::set_left(own_parent, x); + else + NodeTraits::set_right(own_parent, x); + } + + //Fix header and own's parent data when replacing x with own, supposing own + //links with its parent are still ok + static void replace_own(const node_ptr & own, const node_ptr & x, const node_ptr & header) + { + node_ptr own_parent(NodeTraits::get_parent(own)); + bool own_is_left(NodeTraits::get_left(own_parent) == own); + replace_own_impl(own, x, header, own_parent, own_is_left); + } + + // rotate parent p to left (no header and p's parent fixup) + static node_ptr rotate_left(const node_ptr & p) + { + node_ptr x(NodeTraits::get_right(p)); + node_ptr x_left(NodeTraits::get_left(x)); + NodeTraits::set_right(p, x_left); + if(x_left){ + NodeTraits::set_parent(x_left, p); + } + NodeTraits::set_left(x, p); + NodeTraits::set_parent(p, x); + return x; + } + + // rotate parent p to left (with header and p's parent fixup) + static void rotate_left(const node_ptr & p, const node_ptr & header) + { + bool p_was_left(is_left_child(p)); + node_ptr p_old_parent(NodeTraits::get_parent(p)); + node_ptr x(rotate_left(p)); + NodeTraits::set_parent(x, p_old_parent); + replace_own_impl(p, x, header, p_old_parent, p_was_left); + } + + // rotate parent p to right (no header and p's parent fixup) + static node_ptr rotate_right(const node_ptr & p) + { + node_ptr x(NodeTraits::get_left(p)); + node_ptr x_right(NodeTraits::get_right(x)); + NodeTraits::set_left(p, x_right); + if(x_right){ + NodeTraits::set_parent(x_right, p); + } + NodeTraits::set_right(x, p); + NodeTraits::set_parent(p, x); + return x; + } + + // rotate parent p to right (with header and p's parent fixup) + static void rotate_right(const node_ptr & p, const node_ptr & header) + { + bool p_was_left(is_left_child(p)); + node_ptr p_old_parent(NodeTraits::get_parent(p)); + node_ptr x(rotate_right(p)); + NodeTraits::set_parent(x, p_old_parent); + replace_own_impl(p, x, header, p_old_parent, p_was_left); + } + + static void erase(const node_ptr & header, const node_ptr & z) + { + data_for_rebalance ignored; + erase_impl(header, z, ignored); + } + + struct data_for_rebalance + { + node_ptr x; + node_ptr x_parent; + node_ptr y; + }; + + template + static void erase(const node_ptr & header, const node_ptr & z, F z_and_successor_fixup, data_for_rebalance &info) + { + erase_impl(header, z, info); + if(info.y != z){ + z_and_successor_fixup(z, info.y); + } + } + + static void unlink(const node_ptr & node) + { + node_ptr x = NodeTraits::get_parent(node); + if(x){ + while(!is_header(x)) + x = NodeTraits::get_parent(x); + erase(x, node); + } + } + + static void tree_to_vine(const node_ptr & header) + { subtree_to_vine(NodeTraits::get_parent(header)); } + + static void vine_to_tree(const node_ptr & header, std::size_t count) + { vine_to_subtree(NodeTraits::get_parent(header), count); } + + static void rebalance(const node_ptr & header) + { + //Taken from: + //"Tree rebalancing in optimal time and space" + //Quentin F. Stout and Bette L. Warren + std::size_t len = 0; + subtree_to_vine(NodeTraits::get_parent(header), &len); + vine_to_subtree(NodeTraits::get_parent(header), len); + } + + static node_ptr rebalance_subtree(const node_ptr & old_root) + { + std::size_t len = 0; + node_ptr new_root = subtree_to_vine(old_root, &len); + return vine_to_subtree(new_root, len); + } + + static node_ptr subtree_to_vine(const node_ptr & old_root, std::size_t *plen = 0) + { + std::size_t len; + len = 0; + if(!old_root) return node_ptr(); + + //To avoid irregularities in the algorithm (old_root can be a + //left or right child or even the root of the tree) just put the + //root as the right child of its parent. Before doing this backup + //information to restore the original relationship after + //the algorithm is applied. + node_ptr super_root = NodeTraits::get_parent(old_root); + BOOST_INTRUSIVE_INVARIANT_ASSERT(super_root); + + //Get info + node_ptr super_root_right_backup = NodeTraits::get_right(super_root); + bool super_root_is_header = is_header(super_root); + bool old_root_is_right = is_right_child(old_root); + + node_ptr x(old_root); + node_ptr new_root(x); + node_ptr save; + bool moved_to_right = false; + for( ; x; x = save){ + save = NodeTraits::get_left(x); + if(save){ + // Right rotation + node_ptr save_right = NodeTraits::get_right(save); + node_ptr x_parent = NodeTraits::get_parent(x); + NodeTraits::set_parent(save, x_parent); + NodeTraits::set_right (x_parent, save); + NodeTraits::set_parent(x, save); + NodeTraits::set_right (save, x); + NodeTraits::set_left(x, save_right); + if(save_right) + NodeTraits::set_parent(save_right, x); + if(!moved_to_right) + new_root = save; + } + else{ + moved_to_right = true; + save = NodeTraits::get_right(x); + ++len; + } + } + + if(super_root_is_header){ + NodeTraits::set_right(super_root, super_root_right_backup); + NodeTraits::set_parent(super_root, new_root); + } + else if(old_root_is_right){ + NodeTraits::set_right(super_root, new_root); + } + else{ + NodeTraits::set_right(super_root, super_root_right_backup); + NodeTraits::set_left(super_root, new_root); + } + if(plen) *plen = len; + return new_root; + } + + static node_ptr vine_to_subtree(const node_ptr & old_root, std::size_t count) + { + std::size_t leaf_nodes = count + 1 - ((std::size_t) 1 << floor_log2 (count + 1)); + std::size_t vine_nodes = count - leaf_nodes; + + node_ptr new_root = compress_subtree(old_root, leaf_nodes); + while(vine_nodes > 1){ + vine_nodes /= 2; + new_root = compress_subtree(new_root, vine_nodes); + } + return new_root; + } + + static node_ptr compress_subtree(const node_ptr & old_root, std::size_t count) + { + if(!old_root) return old_root; + + //To avoid irregularities in the algorithm (old_root can be + //left or right child or even the root of the tree) just put the + //root as the right child of its parent. First obtain + //information to restore the original relationship after + //the algorithm is applied. + node_ptr super_root = NodeTraits::get_parent(old_root); + BOOST_INTRUSIVE_INVARIANT_ASSERT(super_root); + + //Get info + node_ptr super_root_right_backup = NodeTraits::get_right(super_root); + bool super_root_is_header = is_header(super_root); + bool old_root_is_right = is_right_child(old_root); + + //Put old_root as right child + NodeTraits::set_right(super_root, old_root); + + //Start the compression algorithm + node_ptr even_parent = super_root; + node_ptr new_root = old_root; + + while(count--){ + node_ptr even = NodeTraits::get_right(even_parent); + node_ptr odd = NodeTraits::get_right(even); + + if(new_root == old_root) + new_root = odd; + + node_ptr even_right = NodeTraits::get_left(odd); + NodeTraits::set_right(even, even_right); + if (even_right) + NodeTraits::set_parent(even_right, even); + + NodeTraits::set_right(even_parent, odd); + NodeTraits::set_parent(odd, even_parent); + NodeTraits::set_left(odd, even); + NodeTraits::set_parent(even, odd); + even_parent = odd; + } + + if(super_root_is_header){ + NodeTraits::set_parent(super_root, new_root); + NodeTraits::set_right(super_root, super_root_right_backup); + } + else if(old_root_is_right){ + NodeTraits::set_right(super_root, new_root); + } + else{ + NodeTraits::set_left(super_root, new_root); + NodeTraits::set_right(super_root, super_root_right_backup); + } + return new_root; + } + + //! Requires: "n" must be a node inserted in a tree. + //! + //! Effects: Returns a pointer to the header node of the tree. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + static node_ptr get_root(const node_ptr & node) + { + BOOST_INTRUSIVE_INVARIANT_ASSERT((!inited(node))); + node_ptr x = NodeTraits::get_parent(node); + if(x){ + while(!is_header(x)){ + x = NodeTraits::get_parent(x); + } + return x; + } + else{ + return node; + } + } + + private: + + template + static node_ptr lower_bound_loop + (node_ptr x, node_ptr y, const KeyType &key, KeyNodePtrCompare comp) + { + while(x){ + if(comp(x, key)){ + x = NodeTraits::get_right(x); + } + else{ + y = x; + x = NodeTraits::get_left(x); + } + } + return y; + } + + template + static node_ptr upper_bound_loop + (node_ptr x, node_ptr y, const KeyType &key, KeyNodePtrCompare comp) + { + while(x){ + if(comp(key, x)){ + y = x; + x = NodeTraits::get_left(x); + } + else{ + x = NodeTraits::get_right(x); + } + } + return y; + } + + + template + static void insert_equal_check_impl + (bool upper, const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0) + { + std::size_t depth = 0; + node_ptr y(h); + node_ptr x(NodeTraits::get_parent(y)); + bool link_left; + + if(upper){ + while(x){ + ++depth; + y = x; + x = comp(new_node, x) ? + NodeTraits::get_left(x) : NodeTraits::get_right(x); + } + link_left = (y == h) || comp(new_node, y); + } + else{ + while(x){ + ++depth; + y = x; + x = !comp(x, new_node) ? + NodeTraits::get_left(x) : NodeTraits::get_right(x); + } + link_left = (y == h) || !comp(y, new_node); + } + + commit_data.link_left = link_left; + commit_data.node = y; + if(pdepth) *pdepth = depth; + } + + static void erase_impl(const node_ptr & header, const node_ptr & z, data_for_rebalance &info) + { + node_ptr y(z); + node_ptr x; + node_ptr x_parent = node_ptr(); + node_ptr z_left(NodeTraits::get_left(z)); + node_ptr z_right(NodeTraits::get_right(z)); + if(!z_left){ + x = z_right; // x might be null. + } + else if(!z_right){ // z has exactly one non-null child. y == z. + x = z_left; // x is not null. + } + else{ + // find z's successor + y = tree_algorithms::minimum (z_right); + x = NodeTraits::get_right(y); // x might be null. + } + + if(y != z){ + // relink y in place of z. y is z's successor + NodeTraits::set_parent(NodeTraits::get_left(z), y); + NodeTraits::set_left(y, NodeTraits::get_left(z)); + if(y != NodeTraits::get_right(z)){ + x_parent = NodeTraits::get_parent(y); + if(x) + NodeTraits::set_parent(x, x_parent); + NodeTraits::set_left(x_parent, x); // y must be a child of left_ + NodeTraits::set_right(y, NodeTraits::get_right(z)); + NodeTraits::set_parent(NodeTraits::get_right(z), y); + } + else + x_parent = y; + tree_algorithms::replace_own (z, y, header); + NodeTraits::set_parent(y, NodeTraits::get_parent(z)); + } + else { // y == z --> z has only one child, or none + x_parent = NodeTraits::get_parent(z); + if(x) + NodeTraits::set_parent(x, x_parent); + tree_algorithms::replace_own (z, x, header); + if(NodeTraits::get_left(header) == z){ + NodeTraits::set_left(header, !NodeTraits::get_right(z) ? // z->get_left() must be null also + NodeTraits::get_parent(z) : // makes leftmost == header if z == root + tree_algorithms::minimum (x)); + } + if(NodeTraits::get_right(header) == z){ + NodeTraits::set_right(header, !NodeTraits::get_left(z) ? // z->get_right() must be null also + NodeTraits::get_parent(z) : // makes rightmost == header if z == root + tree_algorithms::maximum(x)); + } + } + + info.x = x; + info.x_parent = x_parent; + info.y = y; + } +}; + +} //namespace detail { +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_TREE_ALGORITHMS_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/tree_node.hpp b/cpp/BoostParts/boost/intrusive/detail/tree_node.hpp new file mode 100644 index 00000000..aa3374e9 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/tree_node.hpp @@ -0,0 +1,199 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_TREE_NODE_HPP +#define BOOST_INTRUSIVE_TREE_NODE_HPP + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +template +struct tree_node +{ + typedef typename pointer_traits + ::template rebind_pointer + >::type node_ptr; + + node_ptr parent_, left_, right_; +}; + +template +struct tree_node_traits +{ + typedef tree_node node; + + typedef typename pointer_traits::template + rebind_pointer::type node_ptr; + typedef typename pointer_traits::template + rebind_pointer::type const_node_ptr; + + static node_ptr get_parent(const const_node_ptr & n) + { return n->parent_; } + + static node_ptr get_parent(const node_ptr & n) + { return n->parent_; } + + static void set_parent(const node_ptr & n, const node_ptr & p) + { n->parent_ = p; } + + static node_ptr get_left(const const_node_ptr & n) + { return n->left_; } + + static node_ptr get_left(const node_ptr & n) + { return n->left_; } + + static void set_left(const node_ptr & n, const node_ptr & l) + { n->left_ = l; } + + static node_ptr get_right(const const_node_ptr & n) + { return n->right_; } + + static node_ptr get_right(const node_ptr & n) + { return n->right_; } + + static void set_right(const node_ptr & n, const node_ptr & r) + { n->right_ = r; } +}; + +///////////////////////////////////////////////////////////////////////////// +// // +// Implementation of the tree iterator // +// // +///////////////////////////////////////////////////////////////////////////// + +// tree_iterator provides some basic functions for a +// node oriented bidirectional iterator: +template +class tree_iterator + : public std::iterator + < std::bidirectional_iterator_tag + , typename Container::value_type + , typename Container::difference_type + , typename detail::if_c::type + , typename detail::if_c::type + > +{ + protected: + typedef typename Container::real_value_traits real_value_traits; + typedef typename Container::node_algorithms node_algorithms; + typedef typename real_value_traits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename pointer_traits::template + rebind_pointer::type void_pointer; + static const bool store_container_ptr = + detail::store_cont_ptr_on_it::value; + + public: + typedef typename Container::value_type value_type; + typedef typename detail::if_c::type pointer; + typedef typename detail::if_c::type reference; + + + tree_iterator() + : members_ (node_ptr(), (const void *)0) + {} + + explicit tree_iterator(const node_ptr & nodeptr, const Container *cont_ptr) + : members_ (nodeptr, cont_ptr) + {} + + tree_iterator(tree_iterator const& other) + : members_(other.pointed_node(), other.get_container()) + {} + + const node_ptr &pointed_node() const + { return members_.nodeptr_; } + + tree_iterator &operator=(const node_ptr &nodeptr) + { members_.nodeptr_ = nodeptr; return static_cast(*this); } + + public: + tree_iterator& operator++() + { + members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_); + return static_cast (*this); + } + + tree_iterator operator++(int) + { + tree_iterator result (*this); + members_.nodeptr_ = node_algorithms::next_node(members_.nodeptr_); + return result; + } + + tree_iterator& operator--() + { + members_.nodeptr_ = node_algorithms::prev_node(members_.nodeptr_); + return static_cast (*this); + } + + tree_iterator operator--(int) + { + tree_iterator result (*this); + members_.nodeptr_ = node_algorithms::prev_node(members_.nodeptr_); + return result; + } + + friend bool operator== (const tree_iterator& l, const tree_iterator& r) + { return l.pointed_node() == r.pointed_node(); } + + friend bool operator!= (const tree_iterator& l, const tree_iterator& r) + { return !(l == r); } + + reference operator*() const + { return *operator->(); } + + pointer operator->() const + { return this->get_real_value_traits()->to_value_ptr(members_.nodeptr_); } + + const Container *get_container() const + { return static_cast(members_.get_ptr()); } + + const real_value_traits *get_real_value_traits() const + { return &this->get_container()->get_real_value_traits(); } + + tree_iterator end_iterator_from_it() const + { + return tree_iterator(node_algorithms::get_header(this->pointed_node()), this->get_container()); + } + + tree_iterator unconst() const + { return tree_iterator(this->pointed_node(), this->get_container()); } + + private: + struct members + : public detail::select_constptr + ::type + { + typedef typename detail::select_constptr + ::type Base; + + members(const node_ptr &n_ptr, const void *cont) + : Base(cont), nodeptr_(n_ptr) + {} + + node_ptr nodeptr_; + } members_; +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_TREE_NODE_HPP diff --git a/cpp/BoostParts/boost/intrusive/detail/utilities.hpp b/cpp/BoostParts/boost/intrusive/detail/utilities.hpp new file mode 100644 index 00000000..722a7a3e --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/detail/utilities.hpp @@ -0,0 +1,844 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP +#define BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { +namespace detail { + +template +struct internal_member_value_traits +{ + template static detail::one test(...); + template static detail::two test(typename U::member_value_traits* = 0); + static const bool value = sizeof(test(0)) == sizeof(detail::two); +}; + +#define BOOST_INTRUSIVE_INTERNAL_STATIC_BOOL_IS_TRUE(TRAITS_PREFIX, TYPEDEF_TO_FIND) \ +template \ +struct TRAITS_PREFIX##_bool\ +{\ + template\ + struct two_or_three {one _[2 + Add];};\ + template static one test(...);\ + template static two_or_three test (int);\ + static const std::size_t value = sizeof(test(0));\ +};\ +\ +template \ +struct TRAITS_PREFIX##_bool_is_true\ +{\ + static const bool value = TRAITS_PREFIX##_bool::value > sizeof(one)*2;\ +};\ +// + +BOOST_INTRUSIVE_INTERNAL_STATIC_BOOL_IS_TRUE(internal_base_hook, boost_intrusive_tags::is_base_hook) +BOOST_INTRUSIVE_INTERNAL_STATIC_BOOL_IS_TRUE(internal_any_hook, is_any_hook) +BOOST_INTRUSIVE_INTERNAL_STATIC_BOOL_IS_TRUE(external_value_traits, external_value_traits) +BOOST_INTRUSIVE_INTERNAL_STATIC_BOOL_IS_TRUE(external_bucket_traits, external_bucket_traits) +BOOST_INTRUSIVE_INTERNAL_STATIC_BOOL_IS_TRUE(resizable, resizable) + +template +struct node_holder + : public Node +{}; + +template +inline T* to_raw_pointer(T* p) +{ return p; } + +template +inline typename boost::intrusive::pointer_traits::element_type* +to_raw_pointer(const Pointer &p) +{ return boost::intrusive::detail::to_raw_pointer(p.operator->()); } + +//This functor compares a stored value +//and the one passed as an argument +template +class equal_to_value +{ + ConstReference t_; + + public: + equal_to_value(ConstReference t) + : t_(t) + {} + + bool operator()(ConstReference t)const + { return t_ == t; } +}; + +class null_disposer +{ + public: + template + void operator()(Pointer) + {} +}; + +template +class init_disposer +{ + typedef typename NodeAlgorithms::node_ptr node_ptr; + + public: + void operator()(const node_ptr & p) + { NodeAlgorithms::init(p); } +}; + +template +struct size_holder +{ + static const bool constant_time_size = ConstantSize; + typedef SizeType size_type; + + SizeType get_size() const + { return size_; } + + void set_size(SizeType size) + { size_ = size; } + + void decrement() + { --size_; } + + void increment() + { ++size_; } + + SizeType size_; +}; + +template +struct size_holder +{ + static const bool constant_time_size = false; + typedef SizeType size_type; + + size_type get_size() const + { return 0; } + + void set_size(size_type) + {} + + void decrement() + {} + + void increment() + {} +}; + +template +struct key_nodeptr_comp + : private detail::ebo_functor_holder +{ + typedef typename Container::real_value_traits real_value_traits; + typedef typename Container::value_type value_type; + typedef typename real_value_traits::node_ptr node_ptr; + typedef typename real_value_traits::const_node_ptr const_node_ptr; + typedef detail::ebo_functor_holder base_t; + key_nodeptr_comp(KeyValueCompare kcomp, const Container *cont) + : base_t(kcomp), cont_(cont) + {} + + template + struct is_node_ptr + { + static const bool value = is_same::value || is_same::value; + }; + + template + const value_type & key_forward + (const T &node, typename enable_if_c::value>::type * = 0) const + { return *cont_->get_real_value_traits().to_value_ptr(node); } + + template + const T & key_forward(const T &key, typename enable_if_c::value>::type* = 0) const + { return key; } + + + template + bool operator()(const KeyType &key1, const KeyType2 &key2) const + { return base_t::get()(this->key_forward(key1), this->key_forward(key2)); } + + const Container *cont_; +}; + +template +struct node_cloner + : private detail::ebo_functor_holder +{ + typedef typename Container::real_value_traits real_value_traits; + typedef typename Container::node_algorithms node_algorithms; + typedef typename real_value_traits::value_type value_type; + typedef typename real_value_traits::pointer pointer; + typedef typename real_value_traits::node_traits::node node; + typedef typename real_value_traits::node_ptr node_ptr; + typedef typename real_value_traits::const_node_ptr const_node_ptr; + typedef detail::ebo_functor_holder base_t; + enum { safemode_or_autounlink = + (int)real_value_traits::link_mode == (int)auto_unlink || + (int)real_value_traits::link_mode == (int)safe_link }; + + node_cloner(F f, const Container *cont) + : base_t(f), cont_(cont) + {} + + node_ptr operator()(const node_ptr & p) + { return this->operator()(*p); } + + node_ptr operator()(const node &to_clone) + { + const value_type &v = + *cont_->get_real_value_traits().to_value_ptr + (pointer_traits::pointer_to(to_clone)); + node_ptr n = cont_->get_real_value_traits().to_node_ptr(*base_t::get()(v)); + //Cloned node must be in default mode if the linking mode requires it + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(n)); + return n; + } + + const Container *cont_; +}; + +template +struct node_disposer + : private detail::ebo_functor_holder +{ + typedef typename Container::real_value_traits real_value_traits; + typedef typename real_value_traits::node_ptr node_ptr; + typedef detail::ebo_functor_holder base_t; + typedef typename Container::node_algorithms node_algorithms; + enum { safemode_or_autounlink = + (int)real_value_traits::link_mode == (int)auto_unlink || + (int)real_value_traits::link_mode == (int)safe_link }; + + node_disposer(F f, const Container *cont) + : base_t(f), cont_(cont) + {} + + void operator()(const node_ptr & p) + { + if(safemode_or_autounlink) + node_algorithms::init(p); + base_t::get()(cont_->get_real_value_traits().to_value_ptr(p)); + } + const Container *cont_; +}; + +struct dummy_constptr +{ + dummy_constptr(const void *) + {} + + const void *get_ptr() const + { return 0; } +}; + +template +struct constptr +{ + typedef typename boost::intrusive::pointer_traits:: + template rebind_pointer::type ConstVoidPtr; + + constptr(const void *ptr) + : const_void_ptr_(ptr) + {} + + const void *get_ptr() const + { return boost::intrusive::detail::to_raw_pointer(const_void_ptr_); } + + ConstVoidPtr const_void_ptr_; +}; + +template +struct select_constptr +{ + typedef typename detail::if_c + < store_ptr + , constptr + , dummy_constptr + >::type type; +}; + +template +struct add_const_if_c +{ + typedef typename detail::if_c + < Add + , typename detail::add_const::type + , T + >::type type; +}; + +template +struct link_dispatch +{}; + +template +void destructor_impl(Hook &hook, detail::link_dispatch) +{ //If this assertion raises, you might have destroyed an object + //while it was still inserted in a container that is alive. + //If so, remove the object from the container before destroying it. + (void)hook; BOOST_INTRUSIVE_SAFE_HOOK_DESTRUCTOR_ASSERT(!hook.is_linked()); +} + +template +void destructor_impl(Hook &hook, detail::link_dispatch) +{ hook.unlink(); } + +template +void destructor_impl(Hook &, detail::link_dispatch) +{} + +template +struct base_hook_traits +{ + public: + typedef detail::node_holder + node_holder; + typedef typename NodeTraits::node node; + typedef NodeTraits node_traits; + typedef T value_type; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef typename pointer_traits:: + template rebind_pointer::type pointer; + typedef typename pointer_traits:: + template rebind_pointer::type const_pointer; + //typedef typename pointer_traits::reference reference; + //typedef typename pointer_traits::reference const_reference; + typedef T & reference; + typedef const T & const_reference; + typedef node_holder & node_holder_reference; + typedef const node_holder & const_node_holder_reference; + typedef node& node_reference; + typedef const node & const_node_reference; + + static const link_mode_type link_mode = LinkMode; + + static pointer to_value_ptr(const node_ptr & n) + { + return pointer_traits::pointer_to + (static_cast(static_cast(*n))); + } + + static const_pointer to_value_ptr(const const_node_ptr & n) + { + return pointer_traits::pointer_to + (static_cast(static_cast(*n))); + } + + static node_ptr to_node_ptr(reference value) + { + return pointer_traits::pointer_to + (static_cast(static_cast(value))); + } + + static const_node_ptr to_node_ptr(const_reference value) + { + return pointer_traits::pointer_to + (static_cast(static_cast(value))); + } +}; + +template +struct member_hook_traits +{ + public: + typedef Hook hook_type; + typedef typename hook_type::boost_intrusive_tags::node_traits node_traits; + typedef typename node_traits::node node; + typedef T value_type; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef typename pointer_traits:: + template rebind_pointer::type pointer; + typedef typename pointer_traits:: + template rebind_pointer::type const_pointer; + typedef T & reference; + typedef const T & const_reference; + typedef node& node_reference; + typedef const node & const_node_reference; + typedef hook_type& hook_reference; + typedef const hook_type & const_hook_reference; + + static const link_mode_type link_mode = Hook::boost_intrusive_tags::link_mode; + + static node_ptr to_node_ptr(reference value) + { + return pointer_traits::pointer_to + (static_cast(static_cast(value.*P))); + } + + static const_node_ptr to_node_ptr(const_reference value) + { + return pointer_traits::pointer_to + (static_cast(static_cast(value.*P))); + } + + static pointer to_value_ptr(const node_ptr & n) + { + return pointer_traits::pointer_to + (*detail::parent_from_member + (static_cast(boost::intrusive::detail::to_raw_pointer(n)), P)); + } + + static const_pointer to_value_ptr(const const_node_ptr & n) + { + return pointer_traits::pointer_to + (*detail::parent_from_member + (static_cast(boost::intrusive::detail::to_raw_pointer(n)), P)); + } +}; + +template +struct function_hook_traits +{ + public: + typedef typename Functor::hook_type hook_type; + typedef typename Functor::hook_ptr hook_ptr; + typedef typename Functor::const_hook_ptr const_hook_ptr; + typedef typename hook_type::boost_intrusive_tags::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename Functor::value_type value_type; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef typename pointer_traits:: + template rebind_pointer::type pointer; + typedef typename pointer_traits:: + template rebind_pointer::type const_pointer; + typedef value_type & reference; + typedef const value_type & const_reference; + static const link_mode_type link_mode = hook_type::boost_intrusive_tags::link_mode; + + static node_ptr to_node_ptr(reference value) + { return static_cast(boost::intrusive::detail::to_raw_pointer(Functor::to_hook_ptr(value))); } + + static const_node_ptr to_node_ptr(const_reference value) + { return static_cast(boost::intrusive::detail::to_raw_pointer(Functor::to_hook_ptr(value))); } + + static pointer to_value_ptr(const node_ptr & n) + { return Functor::to_value_ptr(to_hook_ptr(n)); } + + static const_pointer to_value_ptr(const const_node_ptr & n) + { return Functor::to_value_ptr(to_hook_ptr(n)); } + + private: + static hook_ptr to_hook_ptr(const node_ptr & n) + { return hook_ptr(&*static_cast(&*n)); } + + static const_hook_ptr to_hook_ptr(const const_node_ptr & n) + { return const_hook_ptr(&*static_cast(&*n)); } +}; + + +//This function uses binary search to discover the +//highest set bit of the integer +inline std::size_t floor_log2 (std::size_t x) +{ + const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; + const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); + BOOST_STATIC_ASSERT(Size_t_Bits_Power_2); + + std::size_t n = x; + std::size_t log2 = 0; + + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ + std::size_t tmp = n >> shift; + if (tmp) + log2 += shift, n = tmp; + } + + return log2; +} + +inline float fast_log2 (float val) +{ + union caster_t + { + boost::uint32_t x; + float val; + } caster; + + caster.val = val; + boost::uint32_t x = caster.x; + const int log_2 = (int)(((x >> 23) & 255) - 128); + x &= ~(255 << 23); + x += 127 << 23; + caster.x = x; + val = caster.val; + val = ((-1.0f/3.f) * val + 2.f) * val - (2.0f/3.f); + + return (val + log_2); +} + +inline std::size_t ceil_log2 (std::size_t x) +{ + return ((x & (x-1))!= 0) + floor_log2(x); +} + +template +struct numbits_eq +{ + static const bool value = sizeof(SizeType)*CHAR_BIT == N; +}; + +template +struct sqrt2_pow_max; + +template +struct sqrt2_pow_max >::type> +{ + static const boost::uint32_t value = 0xb504f334; + static const std::size_t pow = 31; +}; + +template +struct sqrt2_pow_max >::type> +{ + static const boost::uint64_t value = 0xb504f333f9de6484ull; + static const std::size_t pow = 63; +}; + +// Returns floor(pow(sqrt(2), x * 2 + 1)). +// Defined for X from 0 up to the number of bits in size_t minus 1. +inline std::size_t sqrt2_pow_2xplus1 (std::size_t x) +{ + const std::size_t value = (std::size_t)sqrt2_pow_max::value; + const std::size_t pow = (std::size_t)sqrt2_pow_max::pow; + return (value >> (pow - x)) + 1; +} + +template +class exception_disposer +{ + Container *cont_; + Disposer &disp_; + + exception_disposer(const exception_disposer&); + exception_disposer &operator=(const exception_disposer&); + + public: + exception_disposer(Container &cont, Disposer &disp) + : cont_(&cont), disp_(disp) + {} + + void release() + { cont_ = 0; } + + ~exception_disposer() + { + if(cont_){ + cont_->clear_and_dispose(disp_); + } + } +}; + +template +class exception_array_disposer +{ + Container *cont_; + Disposer &disp_; + SizeType &constructed_; + + exception_array_disposer(const exception_array_disposer&); + exception_array_disposer &operator=(const exception_array_disposer&); + + public: + + exception_array_disposer + (Container &cont, Disposer &disp, SizeType &constructed) + : cont_(&cont), disp_(disp), constructed_(constructed) + {} + + void release() + { cont_ = 0; } + + ~exception_array_disposer() + { + SizeType n = constructed_; + if(cont_){ + while(n--){ + cont_[n].clear_and_dispose(disp_); + } + } + } +}; + +template +struct store_cont_ptr_on_it_impl +{ + static const bool value = is_stateful_value_traits::value; +}; + +template +struct store_cont_ptr_on_it_impl +{ + static const bool value = true; +}; + +template +struct store_cont_ptr_on_it +{ + typedef typename Container::value_traits value_traits; + static const bool value = store_cont_ptr_on_it_impl + ::value>::value; +}; + +template +struct node_to_value + : public detail::select_constptr + < typename pointer_traits + ::template rebind_pointer::type + , detail::store_cont_ptr_on_it::value + >::type +{ + static const bool store_container_ptr = + detail::store_cont_ptr_on_it::value; + + typedef typename Container::real_value_traits real_value_traits; + typedef typename real_value_traits::value_type value_type; + typedef typename detail::select_constptr + < typename pointer_traits + ::template rebind_pointer::type + , store_container_ptr >::type Base; + typedef typename real_value_traits::node_traits::node node; + typedef typename detail::add_const_if_c + ::type vtype; + typedef typename detail::add_const_if_c + ::type ntype; + typedef typename pointer_traits + ::template rebind_pointer::type npointer; + + node_to_value(const Container *cont) + : Base(cont) + {} + + typedef vtype & result_type; + typedef ntype & first_argument_type; + + const Container *get_container() const + { + if(store_container_ptr) + return static_cast(Base::get_ptr()); + else + return 0; + } + + const real_value_traits *get_real_value_traits() const + { + if(store_container_ptr) + return &this->get_container()->get_real_value_traits(); + else + return 0; + } + + result_type operator()(first_argument_type arg) const + { + return *(this->get_real_value_traits()->to_value_ptr + (pointer_traits::pointer_to(arg))); + } +}; + +//This is not standard, but should work with all compilers +union max_align +{ + char char_; + short short_; + int int_; + long long_; + #ifdef BOOST_HAS_LONG_LONG + long long long_long_; + #endif + float float_; + double double_; + long double long_double_; + void * void_ptr_; +}; + +template +class array_initializer +{ + public: + template + array_initializer(const CommonInitializer &init) + { + char *init_buf = (char*)rawbuf; + std::size_t i = 0; + try{ + for(; i != N; ++i){ + new(init_buf)T(init); + init_buf += sizeof(T); + } + } + catch(...){ + while(i--){ + init_buf -= sizeof(T); + ((T*)init_buf)->~T(); + } + throw; + } + } + + operator T* () + { return (T*)(rawbuf); } + + operator const T*() const + { return (const T*)(rawbuf); } + + ~array_initializer() + { + char *init_buf = (char*)rawbuf + N*sizeof(T); + for(std::size_t i = 0; i != N; ++i){ + init_buf -= sizeof(T); + ((T*)init_buf)->~T(); + } + } + + private: + detail::max_align rawbuf[(N*sizeof(T)-1)/sizeof(detail::max_align)+1]; +}; + + + + +template +class reverse_iterator + : public std::iterator< + typename std::iterator_traits::iterator_category, + typename std::iterator_traits::value_type, + typename std::iterator_traits::difference_type, + typename std::iterator_traits::pointer, + typename std::iterator_traits::reference> +{ + public: + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It iterator_type; + + reverse_iterator(){} + + explicit reverse_iterator(It r) + : m_current(r) + {} + + template + reverse_iterator(const reverse_iterator& r) + : m_current(r.base()) + {} + + It base() const + { return m_current; } + + reference operator*() const + { It temp(m_current); --temp; return *temp; } + + pointer operator->() const + { It temp(m_current); --temp; return temp.operator->(); } + + reference operator[](difference_type off) const + { return this->m_current[-off]; } + + reverse_iterator& operator++() + { --m_current; return *this; } + + reverse_iterator operator++(int) + { + reverse_iterator temp = *this; + --m_current; + return temp; + } + + reverse_iterator& operator--() + { + ++m_current; + return *this; + } + + reverse_iterator operator--(int) + { + reverse_iterator temp(*this); + ++m_current; + return temp; + } + + friend bool operator==(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current == r.m_current; } + + friend bool operator!=(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current != r.m_current; } + + friend bool operator<(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current < r.m_current; } + + friend bool operator<=(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current <= r.m_current; } + + friend bool operator>(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current > r.m_current; } + + friend bool operator>=(const reverse_iterator& l, const reverse_iterator& r) + { return l.m_current >= r.m_current; } + + reverse_iterator& operator+=(difference_type off) + { m_current -= off; return *this; } + + friend reverse_iterator operator+(const reverse_iterator & l, difference_type off) + { + reverse_iterator tmp(l.m_current); + tmp.m_current -= off; + return tmp; + } + + reverse_iterator& operator-=(difference_type off) + { m_current += off; return *this; } + + friend reverse_iterator operator-(const reverse_iterator & l, difference_type off) + { + reverse_iterator tmp(l.m_current); + tmp.m_current += off; + return tmp; + } + + friend difference_type operator-(const reverse_iterator& l, const reverse_iterator& r) + { return r.m_current - l.m_current; } + + private: + It m_current; // the wrapped iterator +}; + +} //namespace detail +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_DETAIL_UTILITIES_HPP diff --git a/cpp/BoostParts/boost/intrusive/intrusive_fwd.hpp b/cpp/BoostParts/boost/intrusive/intrusive_fwd.hpp new file mode 100644 index 00000000..c95767ef --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/intrusive_fwd.hpp @@ -0,0 +1,542 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_FWD_HPP +#define BOOST_INTRUSIVE_FWD_HPP + +#include +#include +#include + +/// @cond + +namespace boost { + +namespace intrusive { + +struct none; + +} //namespace intrusive{ +} //namespace boost{ + +namespace boost { +namespace intrusive { + +//////////////////////////// +// Node algorithms +//////////////////////////// + +//Algorithms predeclarations +template +class circular_list_algorithms; + +template +class circular_slist_algorithms; + +template +class rbtree_algorithms; + +//////////////////////////// +// Containers +//////////////////////////// + +//slist +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + , class O5 = none + > +#else +template +#endif +class slist; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class slist_base_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class slist_member_hook; + +//list +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class list; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class list_base_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class list_member_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class list_hook; + +//rbtree/set/multiset +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class rbtree; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class set; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class multiset; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class set_base_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class set_member_hook; + +//splaytree/splay_set/splay_multiset +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class splaytree; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class splay_set; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class splay_multiset; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class splay_set_base_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class splay_set_member_hook; + +//avltree/avl_set/avl_multiset +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class avltree; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class avl_set; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class avl_multiset; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class avl_set_base_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class avl_set_member_hook; + + +//treap/treap_set/treap_multiset +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class treap; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class treap_set; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class treap_multiset; + +//Default priority comparison functor +template +struct priority_compare; + +//sgtree/sg_set/sg_multiset +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class sgtree; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class sg_set; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class sg_multiset; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class bs_set_base_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class bs_set_member_hook; + +//hashtable/unordered_set/unordered_multiset + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + , class O5 = none + , class O6 = none + , class O7 = none + , class O8 = none + , class O9 = none + , class O10 = none + > +#else +template +#endif +class hashtable; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + , class O5 = none + , class O6 = none + , class O7 = none + , class O8 = none + , class O9 = none + , class O10 = none + > +#else +template +#endif +class unordered_set; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class T + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + , class O5 = none + , class O6 = none + , class O7 = none + , class O8 = none + , class O9 = none + , class O10 = none + > +#else +template +#endif +class unordered_multiset; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class unordered_set_base_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + > +#else +template +#endif +class unordered_set_member_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class any_base_hook; + +#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template + < class O1 = none + , class O2 = none + , class O3 = none + > +#else +template +#endif +class any_member_hook; + +} //namespace intrusive { +} //namespace boost { + +/// @endcond + +#endif //#ifndef BOOST_INTRUSIVE_FWD_HPP diff --git a/cpp/BoostParts/boost/intrusive/linear_slist_algorithms.hpp b/cpp/BoostParts/boost/intrusive/linear_slist_algorithms.hpp new file mode 100644 index 00000000..db4092d2 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/linear_slist_algorithms.hpp @@ -0,0 +1,327 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! linear_slist_algorithms provides basic algorithms to manipulate nodes +//! forming a linear singly linked list. +//! +//! linear_slist_algorithms is configured with a NodeTraits class, which encapsulates the +//! information about the node to be manipulated. NodeTraits must support the +//! following interface: +//! +//! Typedefs: +//! +//! node: The type of the node that forms the linear list +//! +//! node_ptr: A pointer to a node +//! +//! const_node_ptr: A pointer to a const node +//! +//! Static functions: +//! +//! static node_ptr get_next(const_node_ptr n); +//! +//! static void set_next(node_ptr n, node_ptr next); +template +class linear_slist_algorithms + /// @cond + : public detail::common_slist_algorithms + /// @endcond +{ + /// @cond + typedef detail::common_slist_algorithms base_t; + /// @endcond + public: + typedef typename NodeTraits::node node; + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef NodeTraits node_traits; + + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + + //! Effects: Constructs an non-used list element, putting the next + //! pointer to null: + //! NodeTraits::get_next(this_node) == node_ptr() + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init(const node_ptr & this_node); + + //! Requires: this_node must be in a circular list or be an empty circular list. + //! + //! Effects: Returns true is "this_node" is the only node of a circular list: + //! or it's a not inserted node: + //! return node_ptr() == NodeTraits::get_next(this_node) || NodeTraits::get_next(this_node) == this_node + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool unique(const_node_ptr this_node); + + //! Effects: Returns true is "this_node" has the same state as if + //! it was inited using "init(node_ptr)" + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static bool inited(const_node_ptr this_node); + + //! Requires: prev_node must be in a circular list or be an empty circular list. + //! + //! Effects: Unlinks the next node of prev_node from the circular list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(const node_ptr & prev_node); + + //! Requires: prev_node and last_node must be in a circular list + //! or be an empty circular list. + //! + //! Effects: Unlinks the range (prev_node, last_node) from the linear list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void unlink_after(const node_ptr & prev_node, const node_ptr & last_node); + + //! Requires: prev_node must be a node of a linear list. + //! + //! Effects: Links this_node after prev_node in the linear list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void link_after(const node_ptr & prev_node, const node_ptr & this_node); + + //! Requires: b and e must be nodes of the same linear list or an empty range. + //! and p must be a node of a different linear list. + //! + //! Effects: Removes the nodes from (b, e] range from their linear list and inserts + //! them after p in p's linear list. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void transfer_after(const node_ptr & p, const node_ptr & b, const node_ptr & e); + + #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + + //! Effects: Constructs an empty list, making this_node the only + //! node of the circular list: + //! NodeTraits::get_next(this_node) == this_node. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void init_header(const node_ptr & this_node) + { NodeTraits::set_next(this_node, node_ptr ()); } + + //! Requires: this_node and prev_init_node must be in the same linear list. + //! + //! Effects: Returns the previous node of this_node in the linear list starting. + //! the search from prev_init_node. The first node checked for equality + //! is NodeTraits::get_next(prev_init_node). + //! + //! Complexity: Linear to the number of elements between prev_init_node and this_node. + //! + //! Throws: Nothing. + static node_ptr get_previous_node(const node_ptr & prev_init_node, const node_ptr & this_node) + { return base_t::get_previous_node(prev_init_node, this_node); } + + //! Requires: this_node must be in a linear list or be an empty linear list. + //! + //! Effects: Returns the number of nodes in a linear list. If the linear list + //! is empty, returns 1. + //! + //! Complexity: Linear + //! + //! Throws: Nothing. + static std::size_t count(const const_node_ptr & this_node) + { + std::size_t result = 0; + const_node_ptr p = this_node; + do{ + p = NodeTraits::get_next(p); + ++result; + } while (p); + return result; + } + + //! Requires: this_node and other_node must be nodes inserted + //! in linear lists or be empty linear lists. + //! + //! Effects: Moves all the nodes previously chained after this_node after other_node + //! and vice-versa. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + static void swap_trailing_nodes(const node_ptr & this_node, const node_ptr & other_node) + { + node_ptr this_nxt = NodeTraits::get_next(this_node); + node_ptr other_nxt = NodeTraits::get_next(other_node); + NodeTraits::set_next(this_node, other_nxt); + NodeTraits::set_next(other_node, this_nxt); + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Returns: The new first node of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear to the contained elements. + static node_ptr reverse(const node_ptr & p) + { + if(!p) return node_ptr(); + node_ptr i = NodeTraits::get_next(p); + node_ptr first(p); + while(i){ + node_ptr nxti(NodeTraits::get_next(i)); + base_t::unlink_after(p); + NodeTraits::set_next(i, first); + first = i; + i = nxti; + } + return first; + } + + //! Effects: Moves the first n nodes starting at p to the end of the list. + //! + //! Returns: A pair containing the new first and last node of the list or + //! if there has been any movement, a null pair if n leads to no movement. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static std::pair move_first_n_backwards(const node_ptr & p, std::size_t n) + { + std::pair ret; + //Null shift, or count() == 0 or 1, nothing to do + if(!n || !p || !NodeTraits::get_next(p)){ + return ret; + } + + node_ptr first = p; + bool end_found = false; + node_ptr new_last = node_ptr(); + node_ptr old_last = node_ptr(); + + //Now find the new last node according to the shift count. + //If we find 0 before finding the new last node + //unlink p, shortcut the search now that we know the size of the list + //and continue. + for(std::size_t i = 1; i <= n; ++i){ + new_last = first; + first = NodeTraits::get_next(first); + if(first == node_ptr()){ + //Shortcut the shift with the modulo of the size of the list + n %= i; + if(!n) return ret; + old_last = new_last; + i = 0; + //Unlink p and continue the new first node search + first = p; + //unlink_after(new_last); + end_found = true; + } + } + + //If the p has not been found in the previous loop, find it + //starting in the new first node and unlink it + if(!end_found){ + old_last = base_t::get_previous_node(first, node_ptr()); + } + + //Now link p after the new last node + NodeTraits::set_next(old_last, p); + NodeTraits::set_next(new_last, node_ptr()); + ret.first = first; + ret.second = new_last; + return ret; + } + + //! Effects: Moves the first n nodes starting at p to the beginning of the list. + //! + //! Returns: A pair containing the new first and last node of the list or + //! if there has been any movement, a null pair if n leads to no movement. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number moved positions. + static std::pair move_first_n_forward(const node_ptr & p, std::size_t n) + { + std::pair ret; + //Null shift, or count() == 0 or 1, nothing to do + if(!n || !p || !NodeTraits::get_next(p)) + return ret; + + node_ptr first = p; + + //Iterate until p is found to know where the current last node is. + //If the shift count is less than the size of the list, we can also obtain + //the position of the new last node after the shift. + node_ptr old_last(first), next_to_it, new_last(p); + std::size_t distance = 1; + while(!!(next_to_it = node_traits::get_next(old_last))){ + if(distance++ > n) + new_last = node_traits::get_next(new_last); + old_last = next_to_it; + } + //If the shift was bigger or equal than the size, obtain the equivalent + //forward shifts and find the new last node. + if(distance <= n){ + //Now find the equivalent forward shifts. + //Shortcut the shift with the modulo of the size of the list + std::size_t new_before_last_pos = (distance - (n % distance))% distance; + //If the shift is a multiple of the size there is nothing to do + if(!new_before_last_pos) + return ret; + + for( new_last = p + ; --new_before_last_pos + ; new_last = node_traits::get_next(new_last)){ + //empty + } + } + + //Get the first new node + node_ptr new_first(node_traits::get_next(new_last)); + //Now put the old beginning after the old end + NodeTraits::set_next(old_last, p); + NodeTraits::set_next(new_last, node_ptr()); + ret.first = new_first; + ret.second = new_last; + return ret; + } +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_LINEAR_SLIST_ALGORITHMS_HPP diff --git a/cpp/BoostParts/boost/intrusive/link_mode.hpp b/cpp/BoostParts/boost/intrusive/link_mode.hpp new file mode 100644 index 00000000..c04f7752 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/link_mode.hpp @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP +#define BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP + +namespace boost { +namespace intrusive { + +//!This enumeration defines the type of value_traits that can be defined +//!for Boost.Intrusive containers +enum link_mode_type{ + //!If this linking policy is specified in a value_traits class + //!as the link_mode, containers + //!configured with such value_traits won't set the hooks + //!of the erased values to a default state. Containers also won't + //!check that the hooks of the new values are default initialized. + normal_link, + + //!If this linking policy is specified in a value_traits class + //!as the link_mode, containers + //!configured with such value_traits will set the hooks + //!of the erased values to a default state. Containers also will + //!check that the hooks of the new values are default initialized. + safe_link, + + //!Same as "safe_link" but the user type is an auto-unlink + //!type, so the containers with constant-time size features won't be + //!compatible with value_traits configured with this policy. + //!Containers also know that the a value can be silently erased from + //!the container without using any function provided by the containers. + auto_unlink +}; +} //namespace intrusive +} //namespace boost + +#endif //BOOST_INTRUSIVE_VALUE_LINK_TYPE_HPP diff --git a/cpp/BoostParts/boost/intrusive/options.hpp b/cpp/BoostParts/boost/intrusive/options.hpp new file mode 100644 index 00000000..b1dd9441 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/options.hpp @@ -0,0 +1,806 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_OPTIONS_HPP +#define BOOST_INTRUSIVE_OPTIONS_HPP + +#include +#include +#include +#include +#include +#include + + +namespace boost { +namespace intrusive { + +/// @cond + +struct default_tag; +struct member_tag; + +namespace detail{ + +struct default_hook_tag{}; + +#define BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER) \ +struct BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER : public default_hook_tag\ +{\ + template \ + struct apply\ + { typedef typename T::BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER type; };\ +}\ + +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_list_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_slist_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_set_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_uset_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_avl_set_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_splay_set_hook); +BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION(default_bs_set_hook); + +#undef BOOST_INTRUSIVE_DEFAULT_HOOK_MARKER_DEFINITION + +template +struct eval_value_traits +{ + typedef typename ValueTraits::value_traits type; +}; + +template +struct eval_bucket_traits +{ + typedef typename BucketTraits::bucket_traits type; +}; + +template +struct concrete_hook_base_value_traits +{ + typedef typename BaseHook::boost_intrusive_tags tags; + typedef detail::base_hook_traits + < T + , typename tags::node_traits + , tags::link_mode + , typename tags::tag + , tags::hook_type> type; +}; + +template +struct concrete_hook_base_node_traits +{ typedef typename BaseHook::boost_intrusive_tags::node_traits type; }; + +template +struct any_hook_base_value_traits +{ + typedef typename BaseHook::boost_intrusive_tags tags; + typedef detail::base_hook_traits + < T + , typename BaseHook::node_traits + , tags::link_mode + , typename tags::tag + , tags::hook_type> type; +}; + +template +struct any_hook_base_node_traits +{ typedef typename BaseHook::node_traits type; }; + +template +struct get_base_value_traits +{ + typedef typename detail::eval_if_c + < internal_any_hook_bool_is_true::value + , any_hook_base_value_traits + , concrete_hook_base_value_traits + >::type type; +}; + +template +struct get_base_node_traits +{ + typedef typename detail::eval_if_c + < internal_any_hook_bool_is_true::value + , any_hook_base_node_traits + , concrete_hook_base_node_traits + >::type type; +}; + +template +struct get_member_value_traits +{ + typedef typename MemberHook::member_value_traits type; +}; + +template +struct get_member_node_traits +{ + typedef typename MemberHook::member_value_traits::node_traits type; +}; + +template +struct get_value_traits +{ + typedef typename detail::eval_if_c + ::value + ,detail::apply + ,detail::identity + >::type supposed_value_traits; + //...if it's a default hook + typedef typename detail::eval_if_c + < internal_base_hook_bool_is_true::value + //...get it's internal value traits using + //the provided T value type. + , get_base_value_traits + //...else use it's internal value traits tag + //(member hooks and custom value traits are in this group) + , detail::eval_if_c + < internal_member_value_traits::value + , get_member_value_traits + , detail::identity + > + >::type type; +}; + +template +struct get_explicit_node_traits +{ + typedef typename ValueTraits::node_traits type; +}; + +template +struct get_node_traits +{ + typedef SupposedValueTraits supposed_value_traits; + //...if it's a base hook + typedef typename detail::eval_if_c + < internal_base_hook_bool_is_true::value + //...get it's internal value traits using + //the provided T value type. + , get_base_node_traits + //...else use it's internal value traits tag + //(member hooks and custom value traits are in this group) + , detail::eval_if_c + < internal_member_value_traits::value + , get_member_node_traits + , get_explicit_node_traits + > + >::type type; +}; + +} //namespace detail{ + + +//!This type indicates that no option is being used +//!and that the default options should be used +struct none +{ + template + struct pack : Base + { }; +}; + +/// @endcond + +//!This option setter specifies if the intrusive +//!container stores its size as a member to +//!obtain constant-time size() member. +template +struct constant_time_size +{ +/// @cond + template + struct pack : Base + { + static const bool constant_time_size = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies the type that +//!the container will use to store its size. +template +struct size_type +{ +/// @cond + template + struct pack : Base + { + typedef SizeType size_type; + }; +/// @endcond +}; + +//!This option setter specifies the strict weak ordering +//!comparison functor for the value type +template +struct compare +{ +/// @cond + template + struct pack : Base + { + typedef Compare compare; + }; +/// @endcond +}; + +//!This option setter for scapegoat containers specifies if +//!the intrusive scapegoat container should use a non-variable +//!alpha value that does not need floating-point operations. +//! +//!If activated, the fixed alpha value is 1/sqrt(2). This +//!option also saves some space in the container since +//!the alpha value and some additional data does not need +//!to be stored in the container. +//! +//!If the user only needs an alpha value near 1/sqrt(2), this +//!option also improves performance since avoids logarithm +//!and division operations when rebalancing the tree. +template +struct floating_point +{ +/// @cond + template + struct pack : Base + { + static const bool floating_point = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies the equality +//!functor for the value type +template +struct equal +{ +/// @cond + template + struct pack : Base + { + typedef Equal equal; + }; +/// @endcond +}; + +//!This option setter specifies the equality +//!functor for the value type +template +struct priority +{ +/// @cond + template + struct pack : Base + { + typedef Priority priority; + }; +/// @endcond +}; + +//!This option setter specifies the hash +//!functor for the value type +template +struct hash +{ +/// @cond + template + struct pack : Base + { + typedef Hash hash; + }; +/// @endcond +}; + +//!This option setter specifies the relationship between the type +//!to be managed by the container (the value type) and the node to be +//!used in the node algorithms. It also specifies the linking policy. +template +struct value_traits +{ +/// @cond + template + struct pack : Base + { + typedef ValueTraits value_traits; + }; +/// @endcond +}; + +//!This option setter specifies the member hook the +//!container must use. +template< typename Parent + , typename MemberHook + , MemberHook Parent::* PtrToMember> +struct member_hook +{ +/// @cond + typedef detail::member_hook_traits + < Parent + , MemberHook + , PtrToMember + > member_value_traits; + template + struct pack : Base + { + typedef member_value_traits value_traits; + }; +/// @endcond +}; + + +//!This option setter specifies the function object that will +//!be used to convert between values to be inserted in a container +//!and the hook to be used for that purpose. +template< typename Functor> +struct function_hook +{ +/// @cond + typedef detail::function_hook_traits + function_value_traits; + template + struct pack : Base + { + typedef function_value_traits value_traits; + }; +/// @endcond +}; + + +//!This option setter specifies that the container +//!must use the specified base hook +template +struct base_hook +{ +/// @cond + template + struct pack : Base + { + typedef BaseHook value_traits; + }; +/// @endcond +}; + +//!This option setter specifies the type of +//!a void pointer. This will instruct the hook +//!to use this type of pointer instead of the +//!default one +template +struct void_pointer +{ +/// @cond + template + struct pack : Base + { + typedef VoidPointer void_pointer; + }; +/// @endcond +}; + +//!This option setter specifies the type of +//!the tag of a base hook. A type cannot have two +//!base hooks of the same type, so a tag can be used +//!to differentiate two base hooks with otherwise same type +template +struct tag +{ +/// @cond + template + struct pack : Base + { + typedef Tag tag; + }; +/// @endcond +}; + +//!This option setter specifies the link mode +//!(normal_link, safe_link or auto_unlink) +template +struct link_mode +{ +/// @cond + template + struct pack : Base + { + static const link_mode_type link_mode = LinkType; + }; +/// @endcond +}; + +//!This option setter specifies if the hook +//!should be optimized for size instead of for speed. +template +struct optimize_size +{ +/// @cond + template + struct pack : Base + { + static const bool optimize_size = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the list container should +//!use a linear implementation instead of a circular one. +template +struct linear +{ +/// @cond + template + struct pack : Base + { + static const bool linear = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the list container should +//!use a linear implementation instead of a circular one. +template +struct cache_last +{ +/// @cond + template + struct pack : Base + { + static const bool cache_last = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies the bucket traits +//!class for unordered associative containers. When this option is specified, +//!instead of using the default bucket traits, a user defined holder will be defined +template +struct bucket_traits +{ +/// @cond + template + struct pack : Base + { + typedef BucketTraits bucket_traits; + }; +/// @endcond +}; + +//!This option setter specifies if the unordered hook +//!should offer room to store the hash value. +//!Storing the hash in the hook will speed up rehashing +//!processes in applications where rehashing is frequent, +//!rehashing might throw or the value is heavy to hash. +template +struct store_hash +{ +/// @cond + template + struct pack : Base + { + static const bool store_hash = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the unordered hook +//!should offer room to store another link to another node +//!with the same key. +//!Storing this link will speed up lookups and insertions on +//!unordered_multiset containers with a great number of elements +//!with the same key. +template +struct optimize_multikey +{ +/// @cond + template + struct pack : Base + { + static const bool optimize_multikey = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the bucket array will be always power of two. +//!This allows using masks instead of the default modulo operation to determine +//!the bucket number from the hash value, leading to better performance. +//!In debug mode, if power of two buckets mode is activated, the bucket length +//!will be checked to through assertions to assure the bucket length is power of two. +template +struct power_2_buckets +{ +/// @cond + template + struct pack : Base + { + static const bool power_2_buckets = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the container will cache a pointer to the first +//!non-empty bucket so that begin() is always constant-time. +//!This is specially helpful when we can have containers with a few elements +//!but with big bucket arrays (that is, hashtables with low load factors). +template +struct cache_begin +{ +/// @cond + template + struct pack : Base + { + static const bool cache_begin = Enabled; + }; +/// @endcond +}; + + +//!This option setter specifies if the container will compare the hash value +//!before comparing objects. This option can't be specified if store_hash<> +//!is not true. +//!This is specially helpful when we have containers with a high load factor. +//!and the comparison function is much more expensive that comparing already +//!stored hash values. +template +struct compare_hash +{ +/// @cond + template + struct pack : Base + { + static const bool compare_hash = Enabled; + }; +/// @endcond +}; + +//!This option setter specifies if the hash container will use incremental +//!hashing. With incremental hashing the cost of hash table expansion is spread +//!out across each hash table insertion operation, as opposed to be incurred all at once. +//!Therefore linear hashing is well suited for interactive applications or real-time +//!appplications where the worst-case insertion time of non-incremental hash containers +//!(rehashing the whole bucket array) is not admisible. +template +struct incremental +{ + /// @cond + template + struct pack : Base + { + static const bool incremental = Enabled; + }; + /// @endcond +}; + +/// @cond + +//To-do: pass to variadic templates +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + +template +struct do_pack +{ + //Use "pack" member template to pack options + typedef typename Next::template pack type; +}; + +template +struct do_pack +{ + //Avoid packing "none" to shorten template names + typedef Prev type; +}; + +template + < class DefaultOptions + , class O1 = none + , class O2 = none + , class O3 = none + , class O4 = none + , class O5 = none + , class O6 = none + , class O7 = none + , class O8 = none + , class O9 = none + , class O10 = none + , class O11 = none + > +struct pack_options +{ + // join options + typedef + typename do_pack + < typename do_pack + < typename do_pack + < typename do_pack + < typename do_pack + < typename do_pack + < typename do_pack + < typename do_pack + < typename do_pack + < typename do_pack + < typename do_pack + < DefaultOptions + , O1 + >::type + , O2 + >::type + , O3 + >::type + , O4 + >::type + , O5 + >::type + , O6 + >::type + , O7 + >::type + , O8 + >::type + , O9 + >::type + , O10 + >::type + , O11 + >::type + type; +}; +#else + +//index_tuple +template +struct index_tuple{}; + +//build_number_seq +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + +template +struct typelist +{}; + +//invert_typelist +template +struct invert_typelist; + +template +struct typelist_element; + +template +struct typelist_element > +{ + typedef typename typelist_element >::type type; +}; + +template +struct typelist_element<0, typelist > +{ + typedef Head type; +}; + +template +typelist >::type...> + inverted_typelist(index_tuple, typelist) +{ + return typelist >::type...>(); +} + +//sizeof_typelist +template +struct sizeof_typelist; + +template +struct sizeof_typelist< typelist > +{ + static const std::size_t value = sizeof...(Types); +}; + +//invert_typelist_impl +template +struct invert_typelist_impl; + + +template +struct invert_typelist_impl< Typelist, index_tuple > +{ + static const std::size_t last_idx = sizeof_typelist::value - 1; + typedef typelist + ::type...> type; +}; + +template +struct invert_typelist_impl< Typelist, index_tuple > +{ + typedef Typelist type; +}; + +template +struct invert_typelist_impl< Typelist, index_tuple<> > +{ + typedef Typelist type; +}; + +//invert_typelist +template +struct invert_typelist; + +template +struct invert_typelist< typelist > +{ + typedef typelist typelist_t; + typedef typename build_number_seq::type indexes_t; + typedef typename invert_typelist_impl::type type; +}; + +//Do pack +template +struct do_pack; + +template<> +struct do_pack >; + +template +struct do_pack > +{ + typedef Prev type; +}; + +template +struct do_pack > +{ + typedef typename Prev::template pack type; +}; + +template +struct do_pack > +{ + typedef typename Prev::template pack + >::type> type; +}; + + +template +struct pack_options +{ + typedef typelist typelist_t; + typedef typename invert_typelist::type inverted_typelist; + typedef typename do_pack::type type; +}; + +#endif + +struct hook_defaults + : public pack_options + < none + , void_pointer + , link_mode + , tag + , optimize_size + , store_hash + , linear + , optimize_multikey + >::type +{}; + +/// @endcond + +} //namespace intrusive { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTRUSIVE_OPTIONS_HPP diff --git a/cpp/BoostParts/boost/intrusive/pointer_plus_bits.hpp b/cpp/BoostParts/boost/intrusive/pointer_plus_bits.hpp new file mode 100644 index 00000000..a2a9f1bf --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/pointer_plus_bits.hpp @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_POINTER_PLUS_BITS_HPP +#define BOOST_INTRUSIVE_POINTER_PLUS_BITS_HPP + +#include //ls_zeros +#include //BOOST_INTRUSIVE_INVARIANT_ASSERT + +namespace boost { +namespace intrusive { + +//!This trait class is used to know if a pointer +//!can embed extra bits of information if +//!it's going to be used to point to objects +//!with an alignment of "Alignment" bytes. +template +struct max_pointer_plus_bits +{ + static const std::size_t value = 0; +}; + +//!This is a specialization for raw pointers. +//!Raw pointers can embed extra bits in the lower bits +//!if the alignment is multiple of 2pow(NumBits). +template +struct max_pointer_plus_bits +{ + static const std::size_t value = detail::ls_zeros::value; +}; + +//!This is class that is supposed to have static methods +//!to embed extra bits of information in a pointer. +//!This is a declaration and there is no default implementation, +//!because operations to embed the bits change with every pointer type. +//! +//!An implementation that detects that a pointer type whose +//!has_pointer_plus_bits<>::value is non-zero can make use of these +//!operations to embed the bits in the pointer. +template +struct pointer_plus_bits; + +//!This is the specialization to embed extra bits of information +//!in a raw pointer. The extra bits are stored in the lower bits of the pointer. +template +struct pointer_plus_bits +{ + static const std::size_t Mask = ((std::size_t(1u) << NumBits) - 1); + typedef T* pointer; + + static pointer get_pointer(pointer n) + { return pointer(std::size_t(n) & ~Mask); } + + static void set_pointer(pointer &n, pointer p) + { + BOOST_INTRUSIVE_INVARIANT_ASSERT(0 == (std::size_t(p) & Mask)); + n = pointer(std::size_t(p) | (std::size_t(n) & Mask)); + } + + static std::size_t get_bits(pointer n) + { return (std::size_t(n) & Mask); } + + static void set_bits(pointer &n, std::size_t c) + { + BOOST_INTRUSIVE_INVARIANT_ASSERT(c <= Mask); + n = pointer(std::size_t(get_pointer(n)) | c); + } +}; + +} //namespace intrusive +} //namespace boost + +#endif //BOOST_INTRUSIVE_POINTER_PLUS_BITS_HPP diff --git a/cpp/BoostParts/boost/intrusive/rbtree.hpp b/cpp/BoostParts/boost/intrusive/rbtree.hpp new file mode 100644 index 00000000..32e6b9e1 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/rbtree.hpp @@ -0,0 +1,1785 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTRUSIVE_RBTREE_HPP +#define BOOST_INTRUSIVE_RBTREE_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +/// @cond + +template +struct setopt +{ + typedef ValueTraits value_traits; + typedef Compare compare; + typedef SizeType size_type; + static const bool constant_time_size = ConstantTimeSize; +}; + +template +struct set_defaults + : pack_options + < none + , base_hook + , constant_time_size + , size_type + , compare > + >::type +{}; + +/// @endcond + +//! The class template rbtree is an intrusive red-black tree container, that +//! is used to construct intrusive set and multiset containers. The no-throw +//! guarantee holds only, if the value_compare object +//! doesn't throw. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<> and +//! \c compare<>. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +class rbtree_impl + : private detail::clear_on_destructor_base > +{ + template friend class detail::clear_on_destructor_base; + public: + typedef typename Config::value_traits value_traits; + /// @cond + static const bool external_value_traits = + detail::external_value_traits_bool_is_true::value; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::type real_value_traits; + /// @endcond + typedef typename real_value_traits::pointer pointer; + typedef typename real_value_traits::const_pointer const_pointer; + + typedef typename pointer_traits::element_type value_type; + typedef value_type key_type; + typedef typename pointer_traits::reference reference; + typedef typename pointer_traits::reference const_reference; + typedef typename pointer_traits::difference_type difference_type; + typedef typename Config::size_type size_type; + typedef typename Config::compare value_compare; + typedef value_compare key_compare; + typedef tree_iterator iterator; + typedef tree_iterator const_iterator; + typedef boost::intrusive::detail::reverse_iterator reverse_iterator; + typedef boost::intrusive::detail::reverse_iteratorconst_reverse_iterator; + typedef typename real_value_traits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef rbtree_algorithms node_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + static const bool stateful_value_traits = detail::is_stateful_value_traits::value; + /// @cond + private: + typedef detail::size_holder size_traits; + + //noncopyable + BOOST_MOVABLE_BUT_NOT_COPYABLE(rbtree_impl) + + enum { safemode_or_autounlink = + (int)real_value_traits::link_mode == (int)auto_unlink || + (int)real_value_traits::link_mode == (int)safe_link }; + + //Constant-time size is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink))); + + struct header_plus_size : public size_traits + { node header_; }; + + struct node_plus_pred_t : public detail::ebo_functor_holder + { + node_plus_pred_t(const value_compare &comp) + : detail::ebo_functor_holder(comp) + {} + header_plus_size header_plus_size_; + }; + + struct data_t : public rbtree_impl::value_traits + { + typedef typename rbtree_impl::value_traits value_traits; + data_t(const value_compare & comp, const value_traits &val_traits) + : value_traits(val_traits), node_plus_pred_(comp) + {} + node_plus_pred_t node_plus_pred_; + } data_; + + const value_compare &priv_comp() const + { return data_.node_plus_pred_.get(); } + + value_compare &priv_comp() + { return data_.node_plus_pred_.get(); } + + const value_traits &priv_value_traits() const + { return data_; } + + value_traits &priv_value_traits() + { return data_; } + + node_ptr priv_header_ptr() + { return pointer_traits::pointer_to(data_.node_plus_pred_.header_plus_size_.header_); } + + const_node_ptr priv_header_ptr() const + { return pointer_traits::pointer_to(data_.node_plus_pred_.header_plus_size_.header_); } + + static node_ptr uncast(const const_node_ptr & ptr) + { return pointer_traits::const_cast_from(ptr); } + + size_traits &priv_size_traits() + { return data_.node_plus_pred_.header_plus_size_; } + + const size_traits &priv_size_traits() const + { return data_.node_plus_pred_.header_plus_size_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_.get_value_traits(*this); } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_; } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_.get_value_traits(*this); } + + protected: + value_compare &prot_comp() + { return priv_comp(); } + + const node &prot_header_node() const + { return data_.node_plus_pred_.header_plus_size_.header_; } + + node &prot_header_node() + { return data_.node_plus_pred_.header_plus_size_.header_; } + + void prot_set_size(size_type s) + { this->priv_size_traits().set_size(s); } + + /// @endcond + + public: + + const real_value_traits &get_real_value_traits() const + { return this->get_real_value_traits(detail::bool_()); } + + real_value_traits &get_real_value_traits() + { return this->get_real_value_traits(detail::bool_()); } + + typedef typename node_algorithms::insert_commit_data insert_commit_data; + + //! Effects: Constructs an empty tree. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructorof the value_compare object throws. Basic guarantee. + explicit rbtree_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : data_(cmp, v_traits) + { + node_algorithms::init_header(this->priv_header_ptr()); + this->priv_size_traits().set_size(size_type(0)); + } + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty tree and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is the distance between first and last. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. Basic guarantee. + template + rbtree_impl( bool unique, Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : data_(cmp, v_traits) + { + node_algorithms::init_header(this->priv_header_ptr()); + this->priv_size_traits().set_size(size_type(0)); + if(unique) + this->insert_unique(b, e); + else + this->insert_equal(b, e); + } + + //! Effects: to-do + //! + rbtree_impl(BOOST_RV_REF(rbtree_impl) x) + : data_(::boost::move(x.priv_comp()), ::boost::move(x.priv_value_traits())) + { + node_algorithms::init_header(this->priv_header_ptr()); + this->priv_size_traits().set_size(size_type(0)); + this->swap(x); + } + + //! Effects: to-do + //! + rbtree_impl& operator=(BOOST_RV_REF(rbtree_impl) x) + { this->swap(x); return *this; } + + //! Effects: Detaches all elements from this. The objects in the set + //! are not deleted (i.e. no destructors are called), but the nodes according to + //! the value_traits template parameter are reinitialized and thus can be reused. + //! + //! Complexity: Linear to elements contained in *this. + //! + //! Throws: Nothing. + ~rbtree_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return iterator (node_traits::get_left(this->priv_header_ptr()), this); } + + //! Effects: Returns a const_iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return cbegin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return const_iterator (node_traits::get_left(this->priv_header_ptr()), this); } + + //! Effects: Returns an iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return iterator (this->priv_header_ptr(), this); } + + //! Effects: Returns a const_iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return cend(); } + + //! Effects: Returns a const_iterator pointing to the end of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return const_iterator (uncast(this->priv_header_ptr()), this); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return reverse_iterator(end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return const_reverse_iterator(end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(end()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return reverse_iterator(begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return const_reverse_iterator(begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return const_reverse_iterator(begin()); } + + //! Precondition: end_iterator must be a valid end iterator + //! of rbtree. + //! + //! Effects: Returns a const reference to the rbtree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static rbtree_impl &container_from_end_iterator(iterator end_iterator) + { return priv_container_from_end_iterator(end_iterator); } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of rbtree. + //! + //! Effects: Returns a const reference to the rbtree associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const rbtree_impl &container_from_end_iterator(const_iterator end_iterator) + { return priv_container_from_end_iterator(end_iterator); } + + //! Precondition: it must be a valid iterator + //! of rbtree. + //! + //! Effects: Returns a const reference to the tree associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static rbtree_impl &container_from_iterator(iterator it) + { return priv_container_from_iterator(it); } + + //! Precondition: it must be a valid end const_iterator + //! of rbtree. + //! + //! Effects: Returns a const reference to the tree associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static const rbtree_impl &container_from_iterator(const_iterator it) + { return priv_container_from_iterator(it); } + + //! Effects: Returns the value_compare object used by the tree. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return priv_comp(); } + + //! Effects: Returns true if the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return node_algorithms::unique(this->priv_header_ptr()); } + + //! Effects: Returns the number of elements stored in the tree. + //! + //! Complexity: Linear to elements contained in *this + //! if constant-time size option is disabled. Constant time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { + if(constant_time_size) + return this->priv_size_traits().get_size(); + else{ + return (size_type)node_algorithms::size(this->priv_header_ptr()); + } + } + + //! Effects: Swaps the contents of two rbtrees. + //! + //! Complexity: Constant. + //! + //! Throws: If the comparison functor's swap call throws. + void swap(rbtree_impl& other) + { + //This can throw + using std::swap; + swap(priv_comp(), priv_comp()); + //These can't throw + node_algorithms::swap_tree(this->priv_header_ptr(), node_ptr(other.priv_header_ptr())); + if(constant_time_size){ + size_type backup = this->priv_size_traits().get_size(); + this->priv_size_traits().set_size(other.priv_size_traits().get_size()); + other.priv_size_traits().set_size(backup); + } + } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the tree before the upper bound. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_equal(reference value) + { + detail::key_nodeptr_comp + key_node_comp(priv_comp(), this); + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + iterator ret(node_algorithms::insert_equal_upper_bound + (this->priv_header_ptr(), to_insert, key_node_comp), this); + this->priv_size_traits().increment(); + return ret; + } + + //! Requires: value must be an lvalue, and "hint" must be + //! a valid iterator. + //! + //! Effects: Inserts x into the tree, using "hint" as a hint to + //! where it will be inserted. If "hint" is the upper_bound + //! the insertion takes constant time (two comparisons in the worst case) + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_equal(const_iterator hint, reference value) + { + detail::key_nodeptr_comp + key_node_comp(priv_comp(), this); + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + iterator ret(node_algorithms::insert_equal + (this->priv_header_ptr(), hint.pointed_node(), to_insert, key_node_comp), this); + this->priv_size_traits().increment(); + return ret; + } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a each element of a range into the tree + //! before the upper bound of the key of each element. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert_equal(Iterator b, Iterator e) + { + iterator iend(this->end()); + for (; b != e; ++b) + this->insert_equal(iend, *b); + } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the tree if the value + //! is not already present. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + std::pair insert_unique(reference value) + { + insert_commit_data commit_data; + std::pair ret = insert_unique_check(value, priv_comp(), commit_data); + if(!ret.second) + return ret; + return std::pair (insert_unique_commit(value, commit_data), true); + } + + //! Requires: value must be an lvalue, and "hint" must be + //! a valid iterator + //! + //! Effects: Tries to insert x into the tree, using "hint" as a hint + //! to where it will be inserted. + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time (two comparisons in the worst case) + //! if t is inserted immediately before hint. + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert_unique(const_iterator hint, reference value) + { + insert_commit_data commit_data; + std::pair ret = insert_unique_check(hint, value, priv_comp(), commit_data); + if(!ret.second) + return ret.first; + return insert_unique_commit(value, commit_data); + } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Tries to insert each element of a range into the tree. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: Nothing. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert_unique(Iterator b, Iterator e) + { + if(this->empty()){ + iterator iend(this->end()); + for (; b != e; ++b) + this->insert_unique(iend, *b); + } + else{ + for (; b != e; ++b) + this->insert_unique(*b); + } + } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. + template + std::pair insert_unique_check + (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { + detail::key_nodeptr_comp + comp(key_value_comp, this); + std::pair ret = + (node_algorithms::insert_unique_check + (this->priv_header_ptr(), key, comp, commit_data)); + return std::pair(iterator(ret.first, this), ret.second); + } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the container, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the container. + template + std::pair insert_unique_check + (const_iterator hint, const KeyType &key + ,KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { + detail::key_nodeptr_comp + comp(key_value_comp, this); + std::pair ret = + (node_algorithms::insert_unique_check + (this->priv_header_ptr(), hint.pointed_node(), key, comp, commit_data)); + return std::pair(iterator(ret.first, this), ret.second); + } + + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the container between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the avl_set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + iterator insert_unique_commit(reference value, const insert_commit_data &commit_data) + { + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + node_algorithms::insert_unique_commit + (this->priv_header_ptr(), to_insert, commit_data); + this->priv_size_traits().increment(); + return iterator(to_insert, this); + } + + //! Requires: value must be an lvalue, "pos" must be + //! a valid iterator (or end) and must be the succesor of value + //! once inserted according to the predicate + //! + //! Effects: Inserts x into the tree before "pos". + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if "pos" is not + //! the successor of "value" tree ordering invariant will be broken. + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + iterator insert_before(const_iterator pos, reference value) + { + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + return iterator(node_algorithms::insert_before + (this->priv_header_ptr(), pos.pointed_node(), to_insert), this); + } + + //! Requires: value must be an lvalue, and it must be no less + //! than the greatest inserted key + //! + //! Effects: Inserts x into the tree in the last position. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if value is + //! less than the greatest inserted key tree ordering invariant will be broken. + //! This function is slightly more efficient than using "insert_before". + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + void push_back(reference value) + { + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + node_algorithms::push_back(this->priv_header_ptr(), to_insert); + } + + //! Requires: value must be an lvalue, and it must be no greater + //! than the minimum inserted key + //! + //! Effects: Inserts x into the tree in the first position. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if value is + //! greater than the minimum inserted key tree ordering invariant will be broken. + //! This function is slightly more efficient than using "insert_before". + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + void push_front(reference value) + { + node_ptr to_insert(get_real_value_traits().to_node_ptr(value)); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::unique(to_insert)); + this->priv_size_traits().increment(); + node_algorithms::push_front(this->priv_header_ptr(), to_insert); + } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator i) + { + const_iterator ret(i); + ++ret; + node_ptr to_erase(i.pointed_node()); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(!node_algorithms::unique(to_erase)); + node_algorithms::erase(this->priv_header_ptr(), to_erase); + this->priv_size_traits().decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + return ret.unconst(); + } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator b, const_iterator e) + { size_type n; return private_erase(b, e, n); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return this->erase(value, priv_comp()); } + + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { + std::pair p = this->equal_range(key, comp); + size_type n; + private_erase(p.first, p.second, n); + return n; + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator i, Disposer disposer) + { + node_ptr to_erase(i.pointed_node()); + iterator ret(this->erase(i)); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + return ret; + } + + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_dispose(const_reference value, Disposer disposer) + { + std::pair p = this->equal_range(value); + size_type n; + private_erase(p.first, p.second, n, disposer); + return n; + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) + { size_type n; return private_erase(b, e, n, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + N). + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { + std::pair p = this->equal_range(key, comp); + size_type n; + private_erase(p.first, p.second, n, disposer); + return n; + } + + //! Effects: Erases all of the elements. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { + if(safemode_or_autounlink){ + this->clear_and_dispose(detail::null_disposer()); + } + else{ + node_algorithms::init_header(this->priv_header_ptr()); + this->priv_size_traits().set_size(0); + } + } + + //! Effects: Erases all of the elements calling disposer(p) for + //! each node to be erased. + //! Complexity: Average complexity for is at most O(log(size() + N)), + //! where N is the number of elements in the container. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. Calls N times to disposer functor. + template + void clear_and_dispose(Disposer disposer) + { + node_algorithms::clear_and_dispose(this->priv_header_ptr() + , detail::node_disposer(disposer, this)); + node_algorithms::init_header(this->priv_header_ptr()); + this->priv_size_traits().set_size(0); + } + + //! Effects: Returns the number of contained elements with the given value + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given value. + //! + //! Throws: Nothing. + size_type count(const_reference value) const + { return this->count(value, priv_comp()); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: Nothing. + template + size_type count(const KeyType &key, KeyValueCompare comp) const + { + std::pair ret = this->equal_range(key, comp); + return std::distance(ret.first, ret.second); + } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator lower_bound(const_reference value) + { return this->lower_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator lower_bound(const_reference value) const + { return this->lower_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator lower_bound(const KeyType &key, KeyValueCompare comp) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return iterator(node_algorithms::lower_bound + (this->priv_header_ptr(), key, key_node_comp), this); + } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator lower_bound(const KeyType &key, KeyValueCompare comp) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return const_iterator(node_algorithms::lower_bound + (this->priv_header_ptr(), key, key_node_comp), this); + } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator upper_bound(const_reference value) + { return this->upper_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k according to comp or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator upper_bound(const KeyType &key, KeyValueCompare comp) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return iterator(node_algorithms::upper_bound + (this->priv_header_ptr(), key, key_node_comp), this); + } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator upper_bound(const_reference value) const + { return this->upper_bound(value, priv_comp()); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k according to comp or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator upper_bound(const KeyType &key, KeyValueCompare comp) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return const_iterator(node_algorithms::upper_bound + (this->priv_header_ptr(), key, key_node_comp), this); + } + + //! Effects: Finds an iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + iterator find(const_reference value) + { return this->find(value, priv_comp()); } + + //! Effects: Finds an iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + iterator find(const KeyType &key, KeyValueCompare comp) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return iterator + (node_algorithms::find(this->priv_header_ptr(), key, key_node_comp), this); + } + + //! Effects: Finds a const_iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + const_iterator find(const_reference value) const + { return this->find(value, priv_comp()); } + + //! Effects: Finds a const_iterator to the first element whose key is + //! k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + const_iterator find(const KeyType &key, KeyValueCompare comp) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + return const_iterator + (node_algorithms::find(this->priv_header_ptr(), key, key_node_comp), this); + } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + std::pair equal_range(const_reference value) + { return this->equal_range(value, priv_comp()); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + std::pair equal_range(const KeyType &key, KeyValueCompare comp) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + std::pair ret + (node_algorithms::equal_range(this->priv_header_ptr(), key, key_node_comp)); + return std::pair(iterator(ret.first, this), iterator(ret.second, this)); + } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + std::pair + equal_range(const_reference value) const + { return this->equal_range(value, priv_comp()); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + template + std::pair + equal_range(const KeyType &key, KeyValueCompare comp) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + std::pair ret + (node_algorithms::equal_range(this->priv_header_ptr(), key, key_node_comp)); + return std::pair(const_iterator(ret.first, this), const_iterator(ret.second, this)); + } + + //! Requires: 'lower_value' must not be greater than 'upper_value'. If + //! 'lower_value' == 'upper_value', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise + //! + //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the predicate throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_value and upper_value. + std::pair bounded_range + (const_reference lower_value, const_reference upper_value, bool left_closed, bool right_closed) + { return this->bounded_range(lower_value, upper_value, priv_comp(), left_closed, right_closed); } + + //! Requires: KeyValueCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. + //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If + //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key, comp) if left_closed, upper_bound(lower_key, comp) otherwise + //! + //! second = upper_bound(upper_key, comp) if right_closed, lower_bound(upper_key, comp) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_key and upper_key. + template + std::pair bounded_range + (const KeyType &lower_key, const KeyType &upper_key, KeyValueCompare comp, bool left_closed, bool right_closed) + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + std::pair ret + (node_algorithms::bounded_range + (this->priv_header_ptr(), lower_key, upper_key, key_node_comp, left_closed, right_closed)); + return std::pair(iterator(ret.first, this), iterator(ret.second, this)); + } + + //! Requires: 'lower_value' must not be greater than 'upper_value'. If + //! 'lower_value' == 'upper_value', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise + //! + //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the predicate throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_value and upper_value. + std::pair bounded_range + (const_reference lower_value, const_reference upper_value, bool left_closed, bool right_closed) const + { return this->bounded_range(lower_value, upper_value, priv_comp(), left_closed, right_closed); } + + //! Requires: KeyValueCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. + //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If + //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key, comp) if left_closed, upper_bound(lower_key, comp) otherwise + //! + //! second = upper_bound(upper_key, comp) if right_closed, lower_bound(upper_key, comp) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_key and upper_key. + template + std::pair bounded_range + (const KeyType &lower_key, const KeyType &upper_key, KeyValueCompare comp, bool left_closed, bool right_closed) const + { + detail::key_nodeptr_comp + key_node_comp(comp, this); + std::pair ret + (node_algorithms::bounded_range + (this->priv_header_ptr(), lower_key, upper_key, key_node_comp, left_closed, right_closed)); + return std::pair(const_iterator(ret.first, this), const_iterator(ret.second, this)); + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. Copies the predicate from the source container. + //! + //! If cloner throws, all cloned elements are unlinked and disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. + template + void clone_from(const rbtree_impl &src, Cloner cloner, Disposer disposer) + { + this->clear_and_dispose(disposer); + if(!src.empty()){ + detail::exception_disposer + rollback(*this, disposer); + node_algorithms::clone + (const_node_ptr(src.priv_header_ptr()) + ,node_ptr(this->priv_header_ptr()) + ,detail::node_cloner(cloner, this) + ,detail::node_disposer(disposer, this)); + this->priv_size_traits().set_size(src.priv_size_traits().get_size()); + this->priv_comp() = src.priv_comp(); + rollback.release(); + } + } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + pointer unlink_leftmost_without_rebalance() + { + node_ptr to_be_disposed(node_algorithms::unlink_leftmost_without_rebalance + (this->priv_header_ptr())); + if(!to_be_disposed) + return 0; + this->priv_size_traits().decrement(); + if(safemode_or_autounlink)//If this is commented does not work with normal_link + node_algorithms::init(to_be_disposed); + return get_real_value_traits().to_value_ptr(to_be_disposed); + } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { + node_algorithms::replace_node( get_real_value_traits().to_node_ptr(*replace_this) + , this->priv_header_ptr() + , get_real_value_traits().to_node_ptr(with_this)); + if(safemode_or_autounlink) + node_algorithms::init(replace_this.pointed_node()); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + return iterator (value_traits::to_node_ptr(value), 0); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + return const_iterator (value_traits::to_node_ptr(const_cast (value)), 0); + } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return iterator (value_traits::to_node_ptr(value), this); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return const_iterator (value_traits::to_node_ptr(const_cast (value)), this); } + + //! Requires: value shall not be in a tree. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { node_algorithms::init(value_traits::to_node_ptr(value)); } + + //! Effects: removes "value" from the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic time. + //! + //! Note: This static function is only usable with non-constant + //! time size containers that have stateless comparison functors. + //! + //! If the user calls + //! this function with a constant time size container or stateful comparison + //! functor a compilation error will be issued. + static void remove_node(reference value) + { + BOOST_STATIC_ASSERT((!constant_time_size)); + node_ptr to_remove(value_traits::to_node_ptr(value)); + node_algorithms::unlink(to_remove); + if(safemode_or_autounlink) + node_algorithms::init(to_remove); + } + + /// @cond + private: + template + iterator private_erase(const_iterator b, const_iterator e, size_type &n, Disposer disposer) + { + for(n = 0; b != e; ++n) + this->erase_and_dispose(b++, disposer); + return b.unconst(); + } + + iterator private_erase(const_iterator b, const_iterator e, size_type &n) + { + for(n = 0; b != e; ++n) + this->erase(b++); + return b.unconst(); + } + /// @endcond + + private: + static rbtree_impl &priv_container_from_end_iterator(const const_iterator &end_iterator) + { + header_plus_size *r = detail::parent_from_member + ( boost::intrusive::detail::to_raw_pointer(end_iterator.pointed_node()), &header_plus_size::header_); + node_plus_pred_t *n = detail::parent_from_member + (r, &node_plus_pred_t::header_plus_size_); + data_t *d = detail::parent_from_member(n, &data_t::node_plus_pred_); + rbtree_impl *rb = detail::parent_from_member(d, &rbtree_impl::data_); + return *rb; + } + + static rbtree_impl &priv_container_from_iterator(const const_iterator &it) + { return priv_container_from_end_iterator(it.end_iterator_from_it()); } +}; + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator< +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +bool operator== +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif +{ + typedef rbtree_impl tree_type; + typedef typename tree_type::const_iterator const_iterator; + + if(tree_type::constant_time_size && x.size() != y.size()){ + return false; + } + const_iterator end1 = x.end(); + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + if(tree_type::constant_time_size){ + while (i1 != end1 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1; + } + else{ + const_iterator end2 = y.end(); + while (i1 != end1 && i2 != end2 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1 && i2 == end2; + } +} + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator!= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif +{ return !(x == y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif +{ return y < x; } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator<= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif +{ return !(y < x); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator>= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const rbtree_impl &x, const rbtree_impl &y) +#else +(const rbtree_impl &x, const rbtree_impl &y) +#endif +{ return !(x < y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline void swap +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(rbtree_impl &x, rbtree_impl &y) +#else +(rbtree_impl &x, rbtree_impl &y) +#endif +{ x.swap(y); } + +/// @cond +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_rbtree_opt +{ + typedef typename pack_options + < set_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + typedef typename detail::get_value_traits + ::type value_traits; + + typedef setopt + < value_traits + , typename packed_options::compare + , typename packed_options::size_type + , packed_options::constant_time_size + > type; +}; +/// @endcond + +//! Helper metafunction to define a \c rbtree that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_rbtree +{ + /// @cond + typedef rbtree_impl + < typename make_rbtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class rbtree + : public make_rbtree::type +{ + typedef typename make_rbtree + ::type Base; + BOOST_MOVABLE_BUT_NOT_COPYABLE(rbtree) + + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::real_value_traits real_value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + rbtree( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + rbtree( bool unique, Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(unique, b, e, cmp, v_traits) + {} + + rbtree(BOOST_RV_REF(rbtree) x) + : Base(::boost::move(static_cast(x))) + {} + + rbtree& operator=(BOOST_RV_REF(rbtree) x) + { this->Base::operator=(::boost::move(static_cast(x))); return *this; } + + static rbtree &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const rbtree &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static rbtree &container_from_it(iterator it) + { return static_cast(Base::container_from_iterator(it)); } + + static const rbtree &container_from_it(const_iterator it) + { return static_cast(Base::container_from_iterator(it)); } +}; + +#endif + + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_RBTREE_HPP diff --git a/cpp/BoostParts/boost/intrusive/rbtree_algorithms.hpp b/cpp/BoostParts/boost/intrusive/rbtree_algorithms.hpp new file mode 100644 index 00000000..fc28630d --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/rbtree_algorithms.hpp @@ -0,0 +1,934 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +// The internal implementation of red-black trees is based on that of SGI STL +// stl_tree.h file: +// +// Copyright (c) 1996,1997 +// Silicon Graphics Computer Systems, Inc. +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Silicon Graphics makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +// +// +// Copyright (c) 1994 +// Hewlett-Packard Company +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Hewlett-Packard Company makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +// +// The tree destruction algorithm is based on Julienne Walker and The EC Team code: +// +// This code is in the public domain. Anyone may use it or change it in any way that +// they see fit. The author assumes no responsibility for damages incurred through +// use of the original code or any variations thereof. +// +// It is requested, but not required, that due credit is given to the original author +// and anyone who has modified the code through a header comment, such as this one. + +#ifndef BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP +#define BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP + +#include + +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! rbtree_algorithms provides basic algorithms to manipulate +//! nodes forming a red-black tree. The insertion and deletion algorithms are +//! based on those in Cormen, Leiserson, and Rivest, Introduction to Algorithms +//! (MIT Press, 1990), except that +//! +//! (1) the header node is maintained with links not only to the root +//! but also to the leftmost node of the tree, to enable constant time +//! begin(), and to the rightmost node of the tree, to enable linear time +//! performance when used with the generic set algorithms (set_union, +//! etc.); +//! +//! (2) when a node being deleted has two children its successor node is +//! relinked into its place, rather than copied, so that the only +//! pointers invalidated are those referring to the deleted node. +//! +//! rbtree_algorithms is configured with a NodeTraits class, which encapsulates the +//! information about the node to be manipulated. NodeTraits must support the +//! following interface: +//! +//! Typedefs: +//! +//! node: The type of the node that forms the circular list +//! +//! node_ptr: A pointer to a node +//! +//! const_node_ptr: A pointer to a const node +//! +//! color: The type that can store the color of a node +//! +//! Static functions: +//! +//! static node_ptr get_parent(const_node_ptr n); +//! +//! static void set_parent(node_ptr n, node_ptr parent); +//! +//! static node_ptr get_left(const_node_ptr n); +//! +//! static void set_left(node_ptr n, node_ptr left); +//! +//! static node_ptr get_right(const_node_ptr n); +//! +//! static void set_right(node_ptr n, node_ptr right); +//! +//! static color get_color(const_node_ptr n); +//! +//! static void set_color(node_ptr n, color c); +//! +//! static color black(); +//! +//! static color red(); +template +class rbtree_algorithms +{ + public: + typedef NodeTraits node_traits; + typedef typename NodeTraits::node node; + typedef typename NodeTraits::node_ptr node_ptr; + typedef typename NodeTraits::const_node_ptr const_node_ptr; + typedef typename NodeTraits::color color; + + /// @cond + private: + + typedef detail::tree_algorithms tree_algorithms; + + template + struct rbtree_node_cloner + : private detail::ebo_functor_holder + { + typedef detail::ebo_functor_holder base_t; + + rbtree_node_cloner(F f) + : base_t(f) + {} + + node_ptr operator()(const node_ptr & p) + { + node_ptr n = base_t::get()(p); + NodeTraits::set_color(n, NodeTraits::get_color(p)); + return n; + } + }; + + struct rbtree_erase_fixup + { + void operator()(const node_ptr & to_erase, const node_ptr & successor) + { + //Swap color of y and z + color tmp(NodeTraits::get_color(successor)); + NodeTraits::set_color(successor, NodeTraits::get_color(to_erase)); + NodeTraits::set_color(to_erase, tmp); + } + }; + + static node_ptr uncast(const const_node_ptr & ptr) + { return pointer_traits::const_cast_from(ptr); } + /// @endcond + + public: + static node_ptr begin_node(const const_node_ptr & header) + { return tree_algorithms::begin_node(header); } + + static node_ptr end_node(const const_node_ptr & header) + { return tree_algorithms::end_node(header); } + + //! This type is the information that will be + //! filled by insert_unique_check + typedef typename tree_algorithms::insert_commit_data insert_commit_data; + + //! Requires: header1 and header2 must be the header nodes + //! of two trees. + //! + //! Effects: Swaps two trees. After the function header1 will contain + //! links to the second tree and header2 will have links to the first tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static void swap_tree(const node_ptr & header1, const node_ptr & header2) + { return tree_algorithms::swap_tree(header1, header2); } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees. + //! + //! Effects: Swaps two nodes. After the function node1 will be inserted + //! in the position node2 before the function. node2 will be inserted in the + //! position node1 had before the function. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! node1 and node2 are not equivalent according to the ordering rules. + //! + //!Experimental function + static void swap_nodes(const node_ptr & node1, const node_ptr & node2) + { + if(node1 == node2) + return; + + node_ptr header1(tree_algorithms::get_header(node1)), header2(tree_algorithms::get_header(node2)); + swap_nodes(node1, header1, node2, header2); + } + + //! Requires: node1 and node2 can't be header nodes + //! of two trees with header header1 and header2. + //! + //! Effects: Swaps two nodes. After the function node1 will be inserted + //! in the position node2 before the function. node2 will be inserted in the + //! position node1 had before the function. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! node1 and node2 are not equivalent according to the ordering rules. + //! + //!Experimental function + static void swap_nodes(const node_ptr & node1, const node_ptr & header1, const node_ptr & node2, const node_ptr & header2) + { + if(node1 == node2) return; + + tree_algorithms::swap_nodes(node1, header1, node2, header2); + //Swap color + color c = NodeTraits::get_color(node1); + NodeTraits::set_color(node1, NodeTraits::get_color(node2)); + NodeTraits::set_color(node2, c); + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! new_node is not equivalent to node_to_be_replaced according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing and comparison is needed. + //! + //!Experimental function + static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & new_node) + { + if(node_to_be_replaced == new_node) + return; + replace_node(node_to_be_replaced, tree_algorithms::get_header(node_to_be_replaced), new_node); + } + + //! Requires: node_to_be_replaced must be inserted in a tree + //! with header "header" and new_node must not be inserted in a tree. + //! + //! Effects: Replaces node_to_be_replaced in its position in the + //! tree with new_node. The tree does not need to be rebalanced + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! new_node is not equivalent to node_to_be_replaced according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + //! + //!Experimental function + static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & header, const node_ptr & new_node) + { + tree_algorithms::replace_node(node_to_be_replaced, header, new_node); + NodeTraits::set_color(new_node, NodeTraits::get_color(node_to_be_replaced)); + } + + //! Requires: node is a tree node but not the header. + //! + //! Effects: Unlinks the node and rebalances the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + static void unlink(const node_ptr & node) + { + node_ptr x = NodeTraits::get_parent(node); + if(x){ + while(!is_header(x)) + x = NodeTraits::get_parent(x); + erase(x, node); + } + } + + //! Requires: header is the header of a tree. + //! + //! Effects: Unlinks the leftmost node from the tree, and + //! updates the header link to the new leftmost node. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + static node_ptr unlink_leftmost_without_rebalance(const node_ptr & header) + { return tree_algorithms::unlink_leftmost_without_rebalance(header); } + + //! Requires: node is a node of the tree or an node initialized + //! by init(...). + //! + //! Effects: Returns true if the node is initialized by init(). + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + static bool unique(const const_node_ptr & node) + { return tree_algorithms::unique(node); } + + //! Requires: node is a node of the tree but it's not the header. + //! + //! Effects: Returns the number of nodes of the subtree. + //! + //! Complexity: Linear time. + //! + //! Throws: Nothing. + static std::size_t count(const const_node_ptr & node) + { return tree_algorithms::count(node); } + + //! Requires: header is the header node of the tree. + //! + //! Effects: Returns the number of nodes above the header. + //! + //! Complexity: Linear time. + //! + //! Throws: Nothing. + static std::size_t size(const const_node_ptr & header) + { return tree_algorithms::size(header); } + + //! Requires: p is a node from the tree except the header. + //! + //! Effects: Returns the next node of the tree. + //! + //! Complexity: Average constant time. + //! + //! Throws: Nothing. + static node_ptr next_node(const node_ptr & p) + { return tree_algorithms::next_node(p); } + + //! Requires: p is a node from the tree except the leftmost node. + //! + //! Effects: Returns the previous node of the tree. + //! + //! Complexity: Average constant time. + //! + //! Throws: Nothing. + static node_ptr prev_node(const node_ptr & p) + { return tree_algorithms::prev_node(p); } + + //! Requires: node must not be part of any tree. + //! + //! Effects: After the function unique(node) == true. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Nodes: If node is inserted in a tree, this function corrupts the tree. + static void init(const node_ptr & node) + { tree_algorithms::init(node); } + + //! Requires: node must not be part of any tree. + //! + //! Effects: Initializes the header to represent an empty tree. + //! unique(header) == true. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Nodes: If node is inserted in a tree, this function corrupts the tree. + static void init_header(const node_ptr & header) + { + tree_algorithms::init_header(header); + NodeTraits::set_color(header, NodeTraits::red()); + } + + //! Requires: header must be the header of a tree, z a node + //! of that tree and z != header. + //! + //! Effects: Erases node "z" from the tree with header "header". + //! + //! Complexity: Amortized constant time. + //! + //! Throws: Nothing. + static node_ptr erase(const node_ptr & header, const node_ptr & z) + { + typename tree_algorithms::data_for_rebalance info; + tree_algorithms::erase(header, z, rbtree_erase_fixup(), info); + node_ptr x = info.x; + node_ptr x_parent = info.x_parent; + + //Rebalance rbtree + if(NodeTraits::get_color(z) != NodeTraits::red()){ + rebalance_after_erasure(header, x, x_parent); + } + return z; + } + + //! Requires: "cloner" must be a function + //! object taking a node_ptr and returning a new cloned node of it. "disposer" must + //! take a node_ptr and shouldn't throw. + //! + //! Effects: First empties target tree calling + //! void disposer::operator()(const node_ptr &) for every node of the tree + //! except the header. + //! + //! Then, duplicates the entire tree pointed by "source_header" cloning each + //! source node with node_ptr Cloner::operator()(const node_ptr &) to obtain + //! the nodes of the target tree. If "cloner" throws, the cloned target nodes + //! are disposed using void disposer(const node_ptr &). + //! + //! Complexity: Linear to the number of element of the source tree plus the. + //! number of elements of tree target tree when calling this function. + //! + //! Throws: If cloner functor throws. If this happens target nodes are disposed. + template + static void clone + (const const_node_ptr & source_header, const node_ptr & target_header, Cloner cloner, Disposer disposer) + { + rbtree_node_cloner new_cloner(cloner); + tree_algorithms::clone(source_header, target_header, new_cloner, disposer); + } + + //! Requires: "disposer" must be an object function + //! taking a node_ptr parameter and shouldn't throw. + //! + //! Effects: Empties the target tree calling + //! void disposer::operator()(const node_ptr &) for every node of the tree + //! except the header. + //! + //! Complexity: Linear to the number of element of the source tree plus the. + //! number of elements of tree target tree when calling this function. + //! + //! Throws: If cloner functor throws. If this happens target nodes are disposed. + template + static void clear_and_dispose(const node_ptr & header, Disposer disposer) + { tree_algorithms::clear_and_dispose(header, disposer); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the first element that is + //! not less than "key" according to "comp" or "header" if that element does + //! not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr lower_bound + (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) + { return tree_algorithms::lower_bound(header, key, comp); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the first element that is greater + //! than "key" according to "comp" or "header" if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr upper_bound + (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) + { return tree_algorithms::upper_bound(header, key, comp); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an node_ptr to the element that is equivalent to + //! "key" according to "comp" or "header" if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr find + (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) + { return tree_algorithms::find(header, key, comp); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! + //! Effects: Returns an a pair of node_ptr delimiting a range containing + //! all elements that are equivalent to "key" according to "comp" or an + //! empty range that indicates the position where those elements would be + //! if they there are no equivalent elements. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + template + static std::pair equal_range + (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) + { return tree_algorithms::equal_range(header, key, comp); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. + //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If + //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise + //! + //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_key and upper_key. + template + static std::pair bounded_range + (const const_node_ptr & header, const KeyType &lower_key, const KeyType &upper_key, KeyNodePtrCompare comp + , bool left_closed, bool right_closed) + { return tree_algorithms::bounded_range(header, lower_key, upper_key, comp, left_closed, right_closed); } + + //! Requires: "h" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. + //! + //! Effects: Inserts new_node into the tree before the upper bound + //! according to "comp". + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal_upper_bound + (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp) + { + tree_algorithms::insert_equal_upper_bound(h, new_node, comp); + rebalance_after_insertion(h, new_node); + return new_node; + } + + //! Requires: "h" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. + //! + //! Effects: Inserts new_node into the tree before the lower bound + //! according to "comp". + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal_lower_bound + (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp) + { + tree_algorithms::insert_equal_lower_bound(h, new_node, comp); + rebalance_after_insertion(h, new_node); + return new_node; + } + + //! Requires: "header" must be the header node of a tree. + //! NodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from + //! the "header"'s tree. + //! + //! Effects: Inserts new_node into the tree, using "hint" as a hint to + //! where it will be inserted. If "hint" is the upper_bound + //! the insertion takes constant time (two comparisons in the worst case). + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if new_node is inserted immediately before "hint". + //! + //! Throws: If "comp" throws. + template + static node_ptr insert_equal + (const node_ptr & header, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp) + { + tree_algorithms::insert_equal(header, hint, new_node, comp); + rebalance_after_insertion(header, new_node); + return new_node; + } + + //! Requires: "header" must be the header node of a tree. + //! "pos" must be a valid iterator or header (end) node. + //! "pos" must be an iterator pointing to the successor to "new_node" + //! once inserted according to the order of already inserted nodes. This function does not + //! check "pos" and this precondition must be guaranteed by the caller. + //! + //! Effects: Inserts new_node into the tree before "pos". + //! + //! Complexity: Constant-time. + //! + //! Throws: Nothing. + //! + //! Note: If "pos" is not the successor of the newly inserted "new_node" + //! tree invariants might be broken. + static node_ptr insert_before + (const node_ptr & header, const node_ptr & pos, const node_ptr & new_node) + { + tree_algorithms::insert_before(header, pos, new_node); + rebalance_after_insertion(header, new_node); + return new_node; + } + + //! Requires: "header" must be the header node of a tree. + //! "new_node" must be, according to the used ordering no less than the + //! greatest inserted key. + //! + //! Effects: Inserts new_node into the tree before "pos". + //! + //! Complexity: Constant-time. + //! + //! Throws: Nothing. + //! + //! Note: If "new_node" is less than the greatest inserted key + //! tree invariants are broken. This function is slightly faster than + //! using "insert_before". + static void push_back(const node_ptr & header, const node_ptr & new_node) + { + tree_algorithms::push_back(header, new_node); + rebalance_after_insertion(header, new_node); + } + + //! Requires: "header" must be the header node of a tree. + //! "new_node" must be, according to the used ordering, no greater than the + //! lowest inserted key. + //! + //! Effects: Inserts new_node into the tree before "pos". + //! + //! Complexity: Constant-time. + //! + //! Throws: Nothing. + //! + //! Note: If "new_node" is greater than the lowest inserted key + //! tree invariants are broken. This function is slightly faster than + //! using "insert_before". + static void push_front(const node_ptr & header, const node_ptr & new_node) + { + tree_algorithms::push_front(header, new_node); + rebalance_after_insertion(header, new_node); + } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares KeyType with a node_ptr. + //! + //! Effects: Checks if there is an equivalent node to "key" in the + //! tree according to "comp" and obtains the needed information to realize + //! a constant-time node insertion if there is no equivalent node. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing a node_ptr to the already present node + //! and false. If there is not equivalent key can be inserted returns true + //! in the returned pair's boolean and fills "commit_data" that is meant to + //! be used with the "insert_commit" function to achieve a constant-time + //! insertion function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Notes: This function is used to improve performance when constructing + //! a node is expensive and the user does not want to have two equivalent nodes + //! in the tree: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the node and this function offers the possibility to use that part + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the node and use + //! "insert_commit" to insert the node in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_unique_commit" only + //! if no more objects are inserted or erased from the set. + template + static std::pair insert_unique_check + (const const_node_ptr & header, const KeyType &key + ,KeyNodePtrCompare comp, insert_commit_data &commit_data) + { return tree_algorithms::insert_unique_check(header, key, comp, commit_data); } + + //! Requires: "header" must be the header node of a tree. + //! KeyNodePtrCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. NodePtrCompare compares KeyType with a node_ptr. + //! "hint" is node from the "header"'s tree. + //! + //! Effects: Checks if there is an equivalent node to "key" in the + //! tree according to "comp" using "hint" as a hint to where it should be + //! inserted and obtains the needed information to realize + //! a constant-time node insertion if there is no equivalent node. + //! If "hint" is the upper_bound the function has constant time + //! complexity (two comparisons in the worst case). + //! + //! Returns: If there is an equivalent value + //! returns a pair containing a node_ptr to the already present node + //! and false. If there is not equivalent key can be inserted returns true + //! in the returned pair's boolean and fills "commit_data" that is meant to + //! be used with the "insert_commit" function to achieve a constant-time + //! insertion function. + //! + //! Complexity: Average complexity is at most logarithmic, but it is + //! amortized constant time if new_node should be inserted immediately before "hint". + //! + //! Throws: If "comp" throws. + //! + //! Notes: This function is used to improve performance when constructing + //! a node is expensive and the user does not want to have two equivalent nodes + //! in the tree: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the node and this function offers the possibility to use that part + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the node and use + //! "insert_commit" to insert the node in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_unique_commit" only + //! if no more objects are inserted or erased from the set. + template + static std::pair insert_unique_check + (const const_node_ptr & header, const node_ptr &hint, const KeyType &key + ,KeyNodePtrCompare comp, insert_commit_data &commit_data) + { return tree_algorithms::insert_unique_check(header, hint, key, comp, commit_data); } + + //! Requires: "header" must be the header node of a tree. + //! "commit_data" must have been obtained from a previous call to + //! "insert_unique_check". No objects should have been inserted or erased + //! from the set between the "insert_unique_check" that filled "commit_data" + //! and the call to "insert_commit". + //! + //! + //! Effects: Inserts new_node in the set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_unique_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + static void insert_unique_commit + (const node_ptr & header, const node_ptr & new_value, const insert_commit_data &commit_data) + { + tree_algorithms::insert_unique_commit(header, new_value, commit_data); + rebalance_after_insertion(header, new_value); + } + + //! Requires: "n" must be a node inserted in a tree. + //! + //! Effects: Returns a pointer to the header node of the tree. + //! + //! Complexity: Logarithmic. + //! + //! Throws: Nothing. + static node_ptr get_header(const node_ptr & n) + { return tree_algorithms::get_header(n); } + + /// @cond + private: + + //! Requires: p is a node of a tree. + //! + //! Effects: Returns true if p is the header of the tree. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + static bool is_header(const const_node_ptr & p) + { + return NodeTraits::get_color(p) == NodeTraits::red() && + tree_algorithms::is_header(p); + //return NodeTraits::get_color(p) == NodeTraits::red() && + // NodeTraits::get_parent(NodeTraits::get_parent(p)) == p; + } + + static void rebalance_after_erasure(const node_ptr & header, node_ptr x, node_ptr x_parent) + { + while(x != NodeTraits::get_parent(header) && (!x || NodeTraits::get_color(x) == NodeTraits::black())){ + if(x == NodeTraits::get_left(x_parent)){ + node_ptr w = NodeTraits::get_right(x_parent); + BOOST_ASSERT(w); + if(NodeTraits::get_color(w) == NodeTraits::red()){ + NodeTraits::set_color(w, NodeTraits::black()); + NodeTraits::set_color(x_parent, NodeTraits::red()); + tree_algorithms::rotate_left(x_parent, header); + w = NodeTraits::get_right(x_parent); + } + if((!NodeTraits::get_left(w) || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black()) && + (!NodeTraits::get_right(w) || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black())){ + NodeTraits::set_color(w, NodeTraits::red()); + x = x_parent; + x_parent = NodeTraits::get_parent(x_parent); + } + else { + if(!NodeTraits::get_right(w) || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black()){ + NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black()); + NodeTraits::set_color(w, NodeTraits::red()); + tree_algorithms::rotate_right(w, header); + w = NodeTraits::get_right(x_parent); + } + NodeTraits::set_color(w, NodeTraits::get_color(x_parent)); + NodeTraits::set_color(x_parent, NodeTraits::black()); + if(NodeTraits::get_right(w)) + NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black()); + tree_algorithms::rotate_left(x_parent, header); + break; + } + } + else { + // same as above, with right_ <-> left_. + node_ptr w = NodeTraits::get_left(x_parent); + if(NodeTraits::get_color(w) == NodeTraits::red()){ + NodeTraits::set_color(w, NodeTraits::black()); + NodeTraits::set_color(x_parent, NodeTraits::red()); + tree_algorithms::rotate_right(x_parent, header); + w = NodeTraits::get_left(x_parent); + } + if((!NodeTraits::get_right(w) || NodeTraits::get_color(NodeTraits::get_right(w)) == NodeTraits::black()) && + (!NodeTraits::get_left(w) || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black())){ + NodeTraits::set_color(w, NodeTraits::red()); + x = x_parent; + x_parent = NodeTraits::get_parent(x_parent); + } + else { + if(!NodeTraits::get_left(w) || NodeTraits::get_color(NodeTraits::get_left(w)) == NodeTraits::black()){ + NodeTraits::set_color(NodeTraits::get_right(w), NodeTraits::black()); + NodeTraits::set_color(w, NodeTraits::red()); + tree_algorithms::rotate_left(w, header); + w = NodeTraits::get_left(x_parent); + } + NodeTraits::set_color(w, NodeTraits::get_color(x_parent)); + NodeTraits::set_color(x_parent, NodeTraits::black()); + if(NodeTraits::get_left(w)) + NodeTraits::set_color(NodeTraits::get_left(w), NodeTraits::black()); + tree_algorithms::rotate_right(x_parent, header); + break; + } + } + } + if(x) + NodeTraits::set_color(x, NodeTraits::black()); + } + + + static void rebalance_after_insertion(const node_ptr & header, node_ptr p) + { + NodeTraits::set_color(p, NodeTraits::red()); + while(p != NodeTraits::get_parent(header) && NodeTraits::get_color(NodeTraits::get_parent(p)) == NodeTraits::red()){ + node_ptr p_parent(NodeTraits::get_parent(p)); + node_ptr p_parent_parent(NodeTraits::get_parent(p_parent)); + if(tree_algorithms::is_left_child(p_parent)){ + node_ptr x = NodeTraits::get_right(p_parent_parent); + if(x && NodeTraits::get_color(x) == NodeTraits::red()){ + NodeTraits::set_color(p_parent, NodeTraits::black()); + NodeTraits::set_color(p_parent_parent, NodeTraits::red()); + NodeTraits::set_color(x, NodeTraits::black()); + p = p_parent_parent; + } + else { + if(!tree_algorithms::is_left_child(p)){ + p = p_parent; + tree_algorithms::rotate_left(p, header); + } + node_ptr new_p_parent(NodeTraits::get_parent(p)); + node_ptr new_p_parent_parent(NodeTraits::get_parent(new_p_parent)); + NodeTraits::set_color(new_p_parent, NodeTraits::black()); + NodeTraits::set_color(new_p_parent_parent, NodeTraits::red()); + tree_algorithms::rotate_right(new_p_parent_parent, header); + } + } + else{ + node_ptr x = NodeTraits::get_left(p_parent_parent); + if(x && NodeTraits::get_color(x) == NodeTraits::red()){ + NodeTraits::set_color(p_parent, NodeTraits::black()); + NodeTraits::set_color(p_parent_parent, NodeTraits::red()); + NodeTraits::set_color(x, NodeTraits::black()); + p = p_parent_parent; + } + else{ + if(tree_algorithms::is_left_child(p)){ + p = p_parent; + tree_algorithms::rotate_right(p, header); + } + node_ptr new_p_parent(NodeTraits::get_parent(p)); + node_ptr new_p_parent_parent(NodeTraits::get_parent(new_p_parent)); + NodeTraits::set_color(new_p_parent, NodeTraits::black()); + NodeTraits::set_color(new_p_parent_parent, NodeTraits::red()); + tree_algorithms::rotate_left(new_p_parent_parent, header); + } + } + } + NodeTraits::set_color(NodeTraits::get_parent(header), NodeTraits::black()); + } + /// @endcond +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_RBTREE_ALGORITHMS_HPP diff --git a/cpp/BoostParts/boost/intrusive/set.hpp b/cpp/BoostParts/boost/intrusive/set.hpp new file mode 100644 index 00000000..f753a2c5 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/set.hpp @@ -0,0 +1,2554 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_INTRUSIVE_SET_HPP +#define BOOST_INTRUSIVE_SET_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +//! The class template set is an intrusive container, that mimics most of +//! the interface of std::set as described in the C++ standard. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<> and +//! \c compare<>. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +class set_impl +{ + /// @cond + typedef rbtree_impl tree_type; + BOOST_MOVABLE_BUT_NOT_COPYABLE(set_impl) + + typedef tree_type implementation_defined; + /// @endcond + + public: + typedef typename implementation_defined::value_type value_type; + typedef typename implementation_defined::value_traits value_traits; + typedef typename implementation_defined::pointer pointer; + typedef typename implementation_defined::const_pointer const_pointer; + typedef typename implementation_defined::reference reference; + typedef typename implementation_defined::const_reference const_reference; + typedef typename implementation_defined::difference_type difference_type; + typedef typename implementation_defined::size_type size_type; + typedef typename implementation_defined::value_compare value_compare; + typedef typename implementation_defined::key_compare key_compare; + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::reverse_iterator reverse_iterator; + typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator; + typedef typename implementation_defined::insert_commit_data insert_commit_data; + typedef typename implementation_defined::node_traits node_traits; + typedef typename implementation_defined::node node; + typedef typename implementation_defined::node_ptr node_ptr; + typedef typename implementation_defined::const_node_ptr const_node_ptr; + typedef typename implementation_defined::node_algorithms node_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + //static const bool stateful_value_traits = detail::is_stateful_value_traits::value; + + /// @cond + private: + tree_type tree_; + + protected: + node &prot_header_node(){ return tree_.prot_header_node(); } + node const &prot_header_node() const{ return tree_.prot_header_node(); } + void prot_set_size(size_type s){ tree_.prot_set_size(s); } + value_compare &prot_comp(){ return tree_.prot_comp(); } + + /// @endcond + + public: + //! Effects: Constructs an empty set. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor of the value_compare object throws. + explicit set_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(cmp, v_traits) + {} + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty set and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is std::distance(last, first). + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. + template + set_impl( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(true, b, e, cmp, v_traits) + {} + + //! Effects: to-do + //! + set_impl(BOOST_RV_REF(set_impl) x) + : tree_(::boost::move(x.tree_)) + {} + + //! Effects: to-do + //! + set_impl& operator=(BOOST_RV_REF(set_impl) x) + { tree_ = ::boost::move(x.tree_); return *this; } + + //! Effects: Detaches all elements from this. The objects in the set + //! are not deleted (i.e. no destructors are called). + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + ~set_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return tree_.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed set. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of set. + //! + //! Effects: Returns a reference to the set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static set_impl &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &set_impl::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of set. + //! + //! Effects: Returns a const reference to the set associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const set_impl &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &set_impl::tree_); + } + + //! Precondition: it must be a valid iterator of set. + //! + //! Effects: Returns a reference to the set associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static set_impl &container_from_iterator(iterator it) + { + return *detail::parent_from_member + ( &tree_type::container_from_iterator(it) + , &set_impl::tree_); + } + + //! Precondition: it must be a valid const_iterator of set. + //! + //! Effects: Returns a const reference to the set associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static const set_impl &container_from_iterator(const_iterator it) + { + return *detail::parent_from_member + ( &tree_type::container_from_iterator(it) + , &set_impl::tree_); + } + + //! Effects: Returns the key_compare object used by the set. + //! + //! Complexity: Constant. + //! + //! Throws: If key_compare copy-constructor throws. + key_compare key_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns the value_compare object used by the set. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns true if the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return tree_.empty(); } + + //! Effects: Returns the number of elements stored in the set. + //! + //! Complexity: Linear to elements contained in *this if, + //! constant-time size option is enabled. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return tree_.size(); } + + //! Effects: Swaps the contents of two sets. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison functor + //! found using ADL throws. Strong guarantee. + void swap(set_impl& other) + { tree_.swap(other.tree_); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. Copies the predicate from the source container. + //! + //! If cloner throws, all cloned elements are unlinked and disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. + template + void clone_from(const set_impl &src, Cloner cloner, Disposer disposer) + { tree_.clone_from(src.tree_, cloner, disposer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Tries to inserts value into the set. + //! + //! Returns: If the value + //! is not already present inserts it and returns a pair containing the + //! iterator to the new value and true. If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + std::pair insert(reference value) + { return tree_.insert_unique(value); } + + //! Requires: value must be an lvalue + //! + //! Effects: Tries to to insert x into the set, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: An iterator that points to the position where the + //! new element was inserted into the set. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(const_iterator hint, reference value) + { return tree_.insert_unique(hint, value); } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the set, using + //! a user provided key instead of the value itself. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Average complexity is at most logarithmic. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! node that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that + //! part to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This gives a total + //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the set. + template + std::pair insert_check + (const KeyType &key, KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { return tree_.insert_unique_check(key, key_value_comp, commit_data); } + + //! Requires: key_value_comp must be a comparison function that induces + //! the same strict weak ordering as value_compare. The difference is that + //! key_value_comp compares an arbitrary key with the contained values. + //! + //! Effects: Checks if a value can be inserted in the set, using + //! a user provided key instead of the value itself, using "hint" + //! as a hint to where it will be inserted. + //! + //! Returns: If there is an equivalent value + //! returns a pair containing an iterator to the already present value + //! and false. If the value can be inserted returns true in the returned + //! pair boolean and fills "commit_data" that is meant to be used with + //! the "insert_commit" function. + //! + //! Complexity: Logarithmic in general, but it's amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the key_value_comp ordering function throws. Strong guarantee. + //! + //! Notes: This function is used to improve performance when constructing + //! a value_type is expensive: if there is an equivalent value + //! the constructed object must be discarded. Many times, the part of the + //! constructing that is used to impose the order is much cheaper to construct + //! than the value_type and this function offers the possibility to use that key + //! to check if the insertion will be successful. + //! + //! If the check is successful, the user can construct the value_type and use + //! "insert_commit" to insert the object in constant-time. This can give a total + //! constant-time complexity to the insertion: check(O(1)) + commit(O(1)). + //! + //! "commit_data" remains valid for a subsequent "insert_commit" only if no more + //! objects are inserted or erased from the set. + template + std::pair insert_check + (const_iterator hint, const KeyType &key + ,KeyValueCompare key_value_comp, insert_commit_data &commit_data) + { return tree_.insert_unique_check(hint, key, key_value_comp, commit_data); } + + //! Requires: value must be an lvalue of type value_type. commit_data + //! must have been obtained from a previous call to "insert_check". + //! No objects should have been inserted or erased from the set between + //! the "insert_check" that filled "commit_data" and the call to "insert_commit". + //! + //! Effects: Inserts the value in the set using the information obtained + //! from the "commit_data" that a previous "insert_check" filled. + //! + //! Returns: An iterator to the newly inserted object. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function has only sense if a "insert_check" has been + //! previously executed to fill "commit_data". No value should be inserted or + //! erased between the "insert_check" and "insert_commit" calls. + iterator insert_commit(reference value, const insert_commit_data &commit_data) + { return tree_.insert_unique_commit(value, commit_data); } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a range into the set. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert(Iterator b, Iterator e) + { tree_.insert_unique(b, e); } + + //! Requires: value must be an lvalue, "pos" must be + //! a valid iterator (or end) and must be the succesor of value + //! once inserted according to the predicate. "value" must not be equal to any + //! inserted key according to the predicate. + //! + //! Effects: Inserts x into the tree before "pos". + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if "pos" is not + //! the successor of "value" or "value" is not unique tree ordering and uniqueness + //! invariants will be broken respectively. + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + iterator insert_before(const_iterator pos, reference value) + { return tree_.insert_before(pos, value); } + + //! Requires: value must be an lvalue, and it must be greater than + //! any inserted key according to the predicate. + //! + //! Effects: Inserts x into the tree in the last position. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if value is + //! less than or equal to the greatest inserted key tree ordering invariant will be broken. + //! This function is slightly more efficient than using "insert_before". + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + void push_back(reference value) + { tree_.push_back(value); } + + //! Requires: value must be an lvalue, and it must be less + //! than any inserted key according to the predicate. + //! + //! Effects: Inserts x into the tree in the first position. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if value is + //! greater than or equal to the the mimum inserted key tree ordering or uniqueness + //! invariants will be broken. + //! This function is slightly more efficient than using "insert_before". + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + void push_front(reference value) + { tree_.push_front(value); } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator i) + { return tree_.erase(i); } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator b, const_iterator e) + { return tree_.erase(b, e); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size()) + this->count(value)). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return tree_.erase(value); } + + //! Effects: Erases all the elements that compare equal with + //! the given key and the given comparison functor. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If the comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { return tree_.erase(key, comp); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator i, Disposer disposer) + { return tree_.erase_and_dispose(i, disposer); } + + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) + { return tree_.erase_and_dispose(b, e, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: If the internal value_compare ordering function throws. + //! + //! Complexity: O(log(size() + this->count(value)). Basic guarantee. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_dispose(const_reference value, Disposer disposer) + { return tree_.erase_and_dispose(value, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { return tree_.erase_and_dispose(key, comp, disposer); } + + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { return tree_.clear(); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + void clear_and_dispose(Disposer disposer) + { return tree_.clear_and_dispose(disposer); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If the internal value_compare ordering function throws. + size_type count(const_reference value) const + { return tree_.find(value) != end(); } + + //! Effects: Returns the number of contained elements with the same key + //! compared with the given comparison functor. + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If comp ordering function throws. + template + size_type count(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp) != end(); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator lower_bound(const_reference value) + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator lower_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator lower_bound(const_reference value) const + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator lower_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator upper_bound(const_reference value) + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator upper_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.upper_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator upper_bound(const_reference value) const + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator upper_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.upper_bound(key, comp); } + + //! Effects: Finds an iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator find(const_reference value) + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator find(const KeyType& key, KeyValueCompare comp) + { return tree_.find(key, comp); } + + //! Effects: Finds a const_iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator find(const_reference value) const + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a const_iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator find(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + std::pair equal_range(const_reference value) + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair equal_range(const KeyType& key, KeyValueCompare comp) + { return tree_.equal_range(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + std::pair + equal_range(const_reference value) const + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair + equal_range(const KeyType& key, KeyValueCompare comp) const + { return tree_.equal_range(key, comp); } + + //! Requires: 'lower_value' must not be greater than 'upper_value'. If + //! 'lower_value' == 'upper_value', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise + //! + //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the predicate throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_value and upper_value. + std::pair bounded_range + (const_reference lower_value, const_reference upper_value, bool left_closed, bool right_closed) + { return tree_.bounded_range(lower_value, upper_value, left_closed, right_closed); } + + //! Requires: KeyValueCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. + //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If + //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key, comp) if left_closed, upper_bound(lower_key, comp) otherwise + //! + //! second = upper_bound(upper_key, comp) if right_closed, lower_bound(upper_key, comp) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_key and upper_key. + template + std::pair bounded_range + (const KeyType& lower_key, const KeyType& upper_key, KeyValueCompare comp, bool left_closed, bool right_closed) + { return tree_.bounded_range(lower_key, upper_key, comp, left_closed, right_closed); } + + //! Requires: 'lower_value' must not be greater than 'upper_value'. If + //! 'lower_value' == 'upper_value', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise + //! + //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the predicate throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_value and upper_value. + std::pair + bounded_range(const_reference lower_value, const_reference upper_value, bool left_closed, bool right_closed) const + { return tree_.bounded_range(lower_value, upper_value, left_closed, right_closed); } + + //! Requires: KeyValueCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. + //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If + //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key, comp) if left_closed, upper_bound(lower_key, comp) otherwise + //! + //! second = upper_bound(upper_key, comp) if right_closed, lower_bound(upper_key, comp) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_key and upper_key. + template + std::pair + bounded_range + (const KeyType& lower_key, const KeyType& upper_key, KeyValueCompare comp, bool left_closed, bool right_closed) const + { return tree_.bounded_range(lower_key, upper_key, comp, left_closed, right_closed); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return tree_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return tree_.iterator_to(value); } + + //! Requires: value shall not be in a set/multiset. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { tree_type::init_node(value); } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + pointer unlink_leftmost_without_rebalance() + { return tree_.unlink_leftmost_without_rebalance(); } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { tree_.replace_node(replace_this, with_this); } + + /// @cond + friend bool operator==(const set_impl &x, const set_impl &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const set_impl &x, const set_impl &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator!= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const set_impl &x, const set_impl &y) +#else +(const set_impl &x, const set_impl &y) +#endif +{ return !(x == y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const set_impl &x, const set_impl &y) +#else +(const set_impl &x, const set_impl &y) +#endif +{ return y < x; } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator<= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const set_impl &x, const set_impl &y) +#else +(const set_impl &x, const set_impl &y) +#endif +{ return !(y < x); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator>= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const set_impl &x, const set_impl &y) +#else +(const set_impl &x, const set_impl &y) +#endif +{ return !(x < y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline void swap +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(set_impl &x, set_impl &y) +#else +(set_impl &x, set_impl &y) +#endif +{ x.swap(y); } + +//! Helper metafunction to define a \c set that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_set +{ + /// @cond + typedef set_impl + < typename make_rbtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class set + : public make_set::type +{ + typedef typename make_set + ::type Base; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(set) + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + set( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + set( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(b, e, cmp, v_traits) + {} + + set(BOOST_RV_REF(set) x) + : Base(::boost::move(static_cast(x))) + {} + + set& operator=(BOOST_RV_REF(set) x) + { this->Base::operator=(::boost::move(static_cast(x))); return *this; } + + static set &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const set &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static set &container_from_iterator(iterator it) + { return static_cast(Base::container_from_iterator(it)); } + + static const set &container_from_iterator(const_iterator it) + { return static_cast(Base::container_from_iterator(it)); } +}; + +#endif + +//! The class template multiset is an intrusive container, that mimics most of +//! the interface of std::multiset as described in the C++ standard. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<> and +//! \c compare<>. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +class multiset_impl +{ + /// @cond + typedef rbtree_impl tree_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(multiset_impl) + typedef tree_type implementation_defined; + /// @endcond + + public: + typedef typename implementation_defined::value_type value_type; + typedef typename implementation_defined::value_traits value_traits; + typedef typename implementation_defined::pointer pointer; + typedef typename implementation_defined::const_pointer const_pointer; + typedef typename implementation_defined::reference reference; + typedef typename implementation_defined::const_reference const_reference; + typedef typename implementation_defined::difference_type difference_type; + typedef typename implementation_defined::size_type size_type; + typedef typename implementation_defined::value_compare value_compare; + typedef typename implementation_defined::key_compare key_compare; + typedef typename implementation_defined::iterator iterator; + typedef typename implementation_defined::const_iterator const_iterator; + typedef typename implementation_defined::reverse_iterator reverse_iterator; + typedef typename implementation_defined::const_reverse_iterator const_reverse_iterator; + typedef typename implementation_defined::insert_commit_data insert_commit_data; + typedef typename implementation_defined::node_traits node_traits; + typedef typename implementation_defined::node node; + typedef typename implementation_defined::node_ptr node_ptr; + typedef typename implementation_defined::const_node_ptr const_node_ptr; + typedef typename implementation_defined::node_algorithms node_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + //static const bool stateful_value_traits = detail::is_stateful_value_traits::value; + + /// @cond + private: + tree_type tree_; + + protected: + node &prot_header_node(){ return tree_.prot_header_node(); } + node const &prot_header_node() const{ return tree_.prot_header_node(); } + void prot_set_size(size_type s){ tree_.prot_set_size(s); } + value_compare &prot_comp(){ return tree_.prot_comp(); } + /// @endcond + + public: + //! Effects: Constructs an empty multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. + explicit multiset_impl( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(cmp, v_traits) + {} + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! cmp must be a comparison function that induces a strict weak ordering. + //! + //! Effects: Constructs an empty multiset and inserts elements from + //! [b, e). + //! + //! Complexity: Linear in N if [b, e) is already sorted using + //! comp and otherwise N * log N, where N is the distance between first and last + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the copy constructor/operator() of the value_compare object throws. + template + multiset_impl( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : tree_(false, b, e, cmp, v_traits) + {} + + //! Effects: to-do + //! + multiset_impl(BOOST_RV_REF(multiset_impl) x) + : tree_(::boost::move(x.tree_)) + {} + + //! Effects: to-do + //! + multiset_impl& operator=(BOOST_RV_REF(multiset_impl) x) + { tree_ = ::boost::move(x.tree_); return *this; } + + //! Effects: Detaches all elements from this. The objects in the set + //! are not deleted (i.e. no destructors are called). + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + ~multiset_impl() + {} + + //! Effects: Returns an iterator pointing to the beginning of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator begin() + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator begin() const + { return tree_.begin(); } + + //! Effects: Returns a const_iterator pointing to the beginning of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cbegin() const + { return tree_.cbegin(); } + + //! Effects: Returns an iterator pointing to the end of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator end() + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator end() const + { return tree_.end(); } + + //! Effects: Returns a const_iterator pointing to the end of the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator cend() const + { return tree_.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning of the + //! reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rbegin() + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rbegin() const + { return tree_.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crbegin() const + { return tree_.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + reverse_iterator rend() + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator rend() const + { return tree_.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed multiset. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_reverse_iterator crend() const + { return tree_.crend(); } + + //! Precondition: end_iterator must be a valid end iterator + //! of multiset. + //! + //! Effects: Returns a const reference to the multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static multiset_impl &container_from_end_iterator(iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &multiset_impl::tree_); + } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of multiset. + //! + //! Effects: Returns a const reference to the multiset associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const multiset_impl &container_from_end_iterator(const_iterator end_iterator) + { + return *detail::parent_from_member + ( &tree_type::container_from_end_iterator(end_iterator) + , &multiset_impl::tree_); + } + + //! Precondition: it must be a valid iterator of multiset. + //! + //! Effects: Returns a const reference to the multiset associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static multiset_impl &container_from_iterator(iterator it) + { + return *detail::parent_from_member + ( &tree_type::container_from_iterator(it) + , &multiset_impl::tree_); + } + + //! Precondition: it must be a valid const_iterator of multiset. + //! + //! Effects: Returns a const reference to the multiset associated to the iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic. + static const multiset_impl &container_from_iterator(const_iterator it) + { + return *detail::parent_from_member + ( &tree_type::container_from_iterator(it) + , &multiset_impl::tree_); + } + + //! Effects: Returns the key_compare object used by the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If key_compare copy-constructor throws. + key_compare key_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns the value_compare object used by the multiset. + //! + //! Complexity: Constant. + //! + //! Throws: If value_compare copy-constructor throws. + value_compare value_comp() const + { return tree_.value_comp(); } + + //! Effects: Returns true if the container is empty. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + bool empty() const + { return tree_.empty(); } + + //! Effects: Returns the number of elements stored in the multiset. + //! + //! Complexity: Linear to elements contained in *this if, + //! constant-time size option is enabled. Constant-time otherwise. + //! + //! Throws: Nothing. + size_type size() const + { return tree_.size(); } + + //! Effects: Swaps the contents of two multisets. + //! + //! Complexity: Constant. + //! + //! Throws: If the swap() call for the comparison functor + //! found using ADL throws. Strong guarantee. + void swap(multiset_impl& other) + { tree_.swap(other.tree_); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. Copies the predicate from the source container. + //! + //! If cloner throws, all cloned elements are unlinked and disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws or predicate copy assignment throws. Basic guarantee. + template + void clone_from(const multiset_impl &src, Cloner cloner, Disposer disposer) + { tree_.clone_from(src.tree_, cloner, disposer); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts value into the multiset. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Average complexity for insert element is at + //! most logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(reference value) + { return tree_.insert_equal(value); } + + //! Requires: value must be an lvalue + //! + //! Effects: Inserts x into the multiset, using pos as a hint to + //! where it will be inserted. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Logarithmic in general, but it is amortized + //! constant time if t is inserted immediately before hint. + //! + //! Throws: If the internal value_compare ordering function throws. Strong guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + iterator insert(const_iterator hint, reference value) + { return tree_.insert_equal(hint, value); } + + //! Requires: Dereferencing iterator must yield an lvalue + //! of type value_type. + //! + //! Effects: Inserts a range into the multiset. + //! + //! Returns: An iterator that points to the position where the new + //! element was inserted. + //! + //! Complexity: Insert range is in general O(N * log(N)), where N is the + //! size of the range. However, it is linear in N if the range is already sorted + //! by value_comp(). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Does not affect the validity of iterators and references. + //! No copy-constructors are called. + template + void insert(Iterator b, Iterator e) + { tree_.insert_equal(b, e); } + + //! Requires: value must be an lvalue, "pos" must be + //! a valid iterator (or end) and must be the succesor of value + //! once inserted according to the predicate + //! + //! Effects: Inserts x into the tree before "pos". + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if "pos" is not + //! the successor of "value" tree ordering invariant will be broken. + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + iterator insert_before(const_iterator pos, reference value) + { return tree_.insert_before(pos, value); } + + //! Requires: value must be an lvalue, and it must be no less + //! than the greatest inserted key + //! + //! Effects: Inserts x into the tree in the last position. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if value is + //! less than the greatest inserted key tree ordering invariant will be broken. + //! This function is slightly more efficient than using "insert_before". + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + void push_back(reference value) + { tree_.push_back(value); } + + //! Requires: value must be an lvalue, and it must be no greater + //! than the minimum inserted key + //! + //! Effects: Inserts x into the tree in the first position. + //! + //! Complexity: Constant time. + //! + //! Throws: Nothing. + //! + //! Note: This function does not check preconditions so if value is + //! greater than the minimum inserted key tree ordering invariant will be broken. + //! This function is slightly more efficient than using "insert_before". + //! This is a low-level function to be used only for performance reasons + //! by advanced users. + void push_front(reference value) + { tree_.push_front(value); } + + //! Effects: Erases the element pointed to by pos. + //! + //! Complexity: Average complexity is constant time. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator i) + { return tree_.erase(i); } + + //! Effects: Erases the range pointed to by b end e. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + iterator erase(const_iterator b, iterator e) + { return tree_.erase(b, e); } + + //! Effects: Erases all the elements with the given value. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(value)). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + size_type erase(const_reference value) + { return tree_.erase(value); } + + //! Effects: Erases all the elements that compare equal with + //! the given key and the given comparison functor. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase(const KeyType& key, KeyValueCompare comp + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { return tree_.erase(key, comp); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Returns: An iterator to the element after the erased element. + //! + //! Effects: Erases the element pointed to by pos. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Complexity: Average complexity for erase element is constant time. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator i, Disposer disposer) + { return tree_.erase_and_dispose(i, disposer); } + + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Returns: An iterator to the element after the erased elements. + //! + //! Effects: Erases the range pointed to by b end e. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Complexity: Average complexity for erase range is at most + //! O(log(size() + N)), where N is the number of elements in the range. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) + { return tree_.erase_and_dispose(b, e, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given value. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(value)). + //! + //! Throws: If the internal value_compare ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + size_type erase_and_dispose(const_reference value, Disposer disposer) + { return tree_.erase_and_dispose(value, disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements with the given key. + //! according to the comparison functor "comp". + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: The number of erased elements. + //! + //! Complexity: O(log(size() + this->count(key, comp)). + //! + //! Throws: If comp ordering function throws. Basic guarantee. + //! + //! Note: Invalidates the iterators + //! to the erased elements. + template + size_type erase_and_dispose(const KeyType& key, KeyValueCompare comp, Disposer disposer + /// @cond + , typename detail::enable_if_c::value >::type * = 0 + /// @endcond + ) + { return tree_.erase_and_dispose(key, comp, disposer); } + + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + void clear() + { return tree_.clear(); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container. + //! + //! Complexity: Linear to the number of elements on the container. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. No destructors are called. + template + void clear_and_dispose(Disposer disposer) + { return tree_.clear_and_dispose(disposer); } + + //! Effects: Returns the number of contained elements with the given key + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If the internal value_compare ordering function throws. + size_type count(const_reference value) const + { return tree_.count(value); } + + //! Effects: Returns the number of contained elements with the same key + //! compared with the given comparison functor. + //! + //! Complexity: Logarithmic to the number of elements contained plus lineal + //! to number of objects with the given key. + //! + //! Throws: If comp ordering function throws. + template + size_type count(const KeyType& key, KeyValueCompare comp) const + { return tree_.count(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator lower_bound(const_reference value) + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator lower_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns a const iterator to the first element whose + //! key is not less than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator lower_bound(const_reference value) const + { return tree_.lower_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is not less than k or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator lower_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.lower_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator upper_bound(const_reference value) + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns an iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator upper_bound(const KeyType& key, KeyValueCompare comp) + { return tree_.upper_bound(key, comp); } + + //! Effects: Returns an iterator to the first element whose + //! key is greater than k or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator upper_bound(const_reference value) const + { return tree_.upper_bound(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Returns a const_iterator to the first element whose + //! key according to the comparison functor is greater than key or + //! end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator upper_bound(const KeyType& key, KeyValueCompare comp) const + { return tree_.upper_bound(key, comp); } + + //! Effects: Finds an iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + iterator find(const_reference value) + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds an iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + iterator find(const KeyType& key, KeyValueCompare comp) + { return tree_.find(key, comp); } + + //! Effects: Finds a const_iterator to the first element whose value is + //! "value" or end() if that element does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + const_iterator find(const_reference value) const + { return tree_.find(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a const_iterator to the first element whose key is + //! "key" according to the comparison functor or end() if that element + //! does not exist. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + const_iterator find(const KeyType& key, KeyValueCompare comp) const + { return tree_.find(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + std::pair equal_range(const_reference value) + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair equal_range(const KeyType& key, KeyValueCompare comp) + { return tree_.equal_range(key, comp); } + + //! Effects: Finds a range containing all elements whose key is k or + //! an empty range that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the internal value_compare ordering function throws. + std::pair + equal_range(const_reference value) const + { return tree_.equal_range(value); } + + //! Requires: comp must imply the same element order as + //! value_compare. Usually key is the part of the value_type + //! that is used in the ordering functor. + //! + //! Effects: Finds a range containing all elements whose key is k + //! according to the comparison functor or an empty range + //! that indicates the position where those elements would be + //! if they there is no elements with key k. + //! + //! Complexity: Logarithmic. + //! + //! Throws: If comp ordering function throws. + //! + //! Note: This function is used when constructing a value_type + //! is expensive and the value_type can be compared with a cheaper + //! key type. Usually this key is part of the value_type. + template + std::pair + equal_range(const KeyType& key, KeyValueCompare comp) const + { return tree_.equal_range(key, comp); } + + //! Requires: 'lower_value' must not be greater than 'upper_value'. If + //! 'lower_value' == 'upper_value', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise + //! + //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the predicate throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_value and upper_value. + std::pair bounded_range + (const_reference lower_value, const_reference upper_value, bool left_closed, bool right_closed) + { return tree_.bounded_range(lower_value, upper_value, left_closed, right_closed); } + + //! Requires: KeyValueCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. + //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If + //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key, comp) if left_closed, upper_bound(lower_key, comp) otherwise + //! + //! second = upper_bound(upper_key, comp) if right_closed, lower_bound(upper_key, comp) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_key and upper_key. + template + std::pair bounded_range + (const KeyType& lower_key, const KeyType& upper_key, KeyValueCompare comp, bool left_closed, bool right_closed) + { return tree_.bounded_range(lower_key, upper_key, comp, left_closed, right_closed); } + + //! Requires: 'lower_value' must not be greater than 'upper_value'. If + //! 'lower_value' == 'upper_value', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise + //! + //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If the predicate throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_value and upper_value. + std::pair + bounded_range(const_reference lower_value, const_reference upper_value, bool left_closed, bool right_closed) const + { return tree_.bounded_range(lower_value, upper_value, left_closed, right_closed); } + + //! Requires: KeyValueCompare is a function object that induces a strict weak + //! ordering compatible with the strict weak ordering used to create the + //! the tree. + //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If + //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be false. + //! + //! Effects: Returns an a pair with the following criteria: + //! + //! first = lower_bound(lower_key, comp) if left_closed, upper_bound(lower_key, comp) otherwise + //! + //! second = upper_bound(upper_key, comp) if right_closed, lower_bound(upper_key, comp) otherwise + //! + //! Complexity: Logarithmic. + //! + //! Throws: If "comp" throws. + //! + //! Note: This function can be more efficient than calling upper_bound + //! and lower_bound for lower_key and upper_key. + template + std::pair + bounded_range + (const KeyType& lower_key, const KeyType& upper_key, KeyValueCompare comp, bool left_closed, bool right_closed) const + { return tree_.bounded_range(lower_key, upper_key, comp, left_closed, right_closed); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { return tree_type::s_iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid iterator i belonging to the set + //! that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + iterator iterator_to(reference value) + { return tree_.iterator_to(value); } + + //! Requires: value must be an lvalue and shall be in a set of + //! appropriate type. Otherwise the behavior is undefined. + //! + //! Effects: Returns: a valid const_iterator i belonging to the + //! set that points to the value + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + const_iterator iterator_to(const_reference value) const + { return tree_.iterator_to(value); } + + //! Requires: value shall not be in a set/multiset. + //! + //! Effects: init_node puts the hook of a value in a well-known default + //! state. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: This function puts the hook in the well-known default state + //! used by auto_unlink and safe hooks. + static void init_node(reference value) + { tree_type::init_node(value); } + + //! Effects: Unlinks the leftmost node from the tree. + //! + //! Complexity: Average complexity is constant time. + //! + //! Throws: Nothing. + //! + //! Notes: This function breaks the tree and the tree can + //! only be used for more unlink_leftmost_without_rebalance calls. + //! This function is normally used to achieve a step by step + //! controlled destruction of the tree. + pointer unlink_leftmost_without_rebalance() + { return tree_.unlink_leftmost_without_rebalance(); } + + //! Requires: replace_this must be a valid iterator of *this + //! and with_this must not be inserted in any tree. + //! + //! Effects: Replaces replace_this in its position in the + //! tree with with_this. The tree does not need to be rebalanced. + //! + //! Complexity: Constant. + //! + //! Throws: Nothing. + //! + //! Note: This function will break container ordering invariants if + //! with_this is not equivalent to *replace_this according to the + //! ordering rules. This function is faster than erasing and inserting + //! the node, since no rebalancing or comparison is needed. + void replace_node(iterator replace_this, reference with_this) + { tree_.replace_node(replace_this, with_this); } + + //! Effects: removes "value" from the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Logarithmic time. + //! + //! Note: This static function is only usable with non-constant + //! time size containers that have stateless comparison functors. + //! + //! If the user calls + //! this function with a constant time size container or stateful comparison + //! functor a compilation error will be issued. + static void remove_node(reference value) + { tree_type::remove_node(value); } + + /// @cond + friend bool operator==(const multiset_impl &x, const multiset_impl &y) + { return x.tree_ == y.tree_; } + + friend bool operator<(const multiset_impl &x, const multiset_impl &y) + { return x.tree_ < y.tree_; } + /// @endcond +}; + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator!= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const multiset_impl &x, const multiset_impl &y) +#else +(const multiset_impl &x, const multiset_impl &y) +#endif +{ return !(x == y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const multiset_impl &x, const multiset_impl &y) +#else +(const multiset_impl &x, const multiset_impl &y) +#endif +{ return y < x; } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator<= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const multiset_impl &x, const multiset_impl &y) +#else +(const multiset_impl &x, const multiset_impl &y) +#endif +{ return !(y < x); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator>= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const multiset_impl &x, const multiset_impl &y) +#else +(const multiset_impl &x, const multiset_impl &y) +#endif +{ return !(x < y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline void swap +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(multiset_impl &x, multiset_impl &y) +#else +(multiset_impl &x, multiset_impl &y) +#endif +{ x.swap(y); } + +//! Helper metafunction to define a \c multiset that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_multiset +{ + /// @cond + typedef multiset_impl + < typename make_rbtree_opt::type + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class multiset + : public make_multiset::type +{ + typedef typename make_multiset::type Base; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(multiset) + + public: + typedef typename Base::value_compare value_compare; + typedef typename Base::value_traits value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + + multiset( const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(cmp, v_traits) + {} + + template + multiset( Iterator b, Iterator e + , const value_compare &cmp = value_compare() + , const value_traits &v_traits = value_traits()) + : Base(b, e, cmp, v_traits) + {} + + multiset(BOOST_RV_REF(multiset) x) + : Base(::boost::move(static_cast(x))) + {} + + multiset& operator=(BOOST_RV_REF(multiset) x) + { this->Base::operator=(::boost::move(static_cast(x))); return *this; } + + static multiset &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const multiset &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static multiset &container_from_iterator(iterator it) + { return static_cast(Base::container_from_iterator(it)); } + + static const multiset &container_from_iterator(const_iterator it) + { return static_cast(Base::container_from_iterator(it)); } +}; + +#endif + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SET_HPP diff --git a/cpp/BoostParts/boost/intrusive/set_hook.hpp b/cpp/BoostParts/boost/intrusive/set_hook.hpp new file mode 100644 index 00000000..2634b42e --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/set_hook.hpp @@ -0,0 +1,300 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_SET_HOOK_HPP +#define BOOST_INTRUSIVE_SET_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +/// @cond +template +struct get_set_node_algo +{ + typedef rbtree_algorithms > type; +}; +/// @endcond + +//! Helper metafunction to define a \c set_base_hook that yields to the same +//! type when the same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_set_base_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + + typedef detail::generic_hook + < get_set_node_algo + , typename packed_options::tag + , packed_options::link_mode + , detail::SetBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Derive a class from set_base_hook in order to store objects in +//! in a set/multiset. set_base_hook holds the data necessary to maintain +//! the set/multiset and provides an appropriate value_traits class for set/multiset. +//! +//! The hook admits the following options: \c tag<>, \c void_pointer<>, +//! \c link_mode<> and \c optimize_size<>. +//! +//! \c tag<> defines a tag to identify the node. +//! The same tag value can be used in different classes, but if a class is +//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its +//! unique tag. +//! +//! \c void_pointer<> is the pointer type that will be used internally in the hook +//! and the the container configured to use this hook. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c optimize_size<> will tell the hook to optimize the hook for size instead +//! of speed. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class set_base_hook + : public make_set_base_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type +{ + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + public: + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + set_base_hook(); + + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + set_base_hook(const set_base_hook& ); + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + set_base_hook& operator=(const set_base_hook& ); + + //! Effects: If link_mode is \c normal_link, the destructor does + //! nothing (ie. no code is generated). If link_mode is \c safe_link and the + //! object is stored in a set an assertion is raised. If link_mode is + //! \c auto_unlink and \c is_linked() is true, the node is unlinked. + //! + //! Throws: Nothing. + ~set_base_hook(); + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(set_base_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c set::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #endif +}; + +//! Helper metafunction to define a \c set_member_hook that yields to the same +//! type when the same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_set_member_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + + typedef detail::generic_hook + < get_set_node_algo + , member_tag + , packed_options::link_mode + , detail::NoBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Put a public data member set_member_hook in order to store objects of this class in +//! a set/multiset. set_member_hook holds the data necessary for maintaining the +//! set/multiset and provides an appropriate value_traits class for set/multiset. +//! +//! The hook admits the following options: \c void_pointer<>, +//! \c link_mode<> and \c optimize_size<>. +//! +//! \c void_pointer<> is the pointer type that will be used internally in the hook +//! and the the container configured to use this hook. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c optimize_size<> will tell the hook to optimize the hook for size instead +//! of speed. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class set_member_hook + : public make_set_member_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type +{ + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + public: + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + set_member_hook(); + + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + set_member_hook(const set_member_hook& ); + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + set_member_hook& operator=(const set_member_hook& ); + + //! Effects: If link_mode is \c normal_link, the destructor does + //! nothing (ie. no code is generated). If link_mode is \c safe_link and the + //! object is stored in a set an assertion is raised. If link_mode is + //! \c auto_unlink and \c is_linked() is true, the node is unlinked. + //! + //! Throws: Nothing. + ~set_member_hook(); + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(set_member_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c set::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #endif +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SET_HOOK_HPP diff --git a/cpp/BoostParts/boost/intrusive/slist.hpp b/cpp/BoostParts/boost/intrusive/slist.hpp new file mode 100644 index 00000000..b0629b42 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/slist.hpp @@ -0,0 +1,2204 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_SLIST_HPP +#define BOOST_INTRUSIVE_SLIST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //std::size_t +#include //std::pair +#include + +namespace boost { +namespace intrusive { + +/// @cond + +template +struct slistopt +{ + typedef ValueTraits value_traits; + typedef SizeType size_type; + static const bool constant_time_size = ConstantTimeSize; + static const bool linear = Linear; + static const bool cache_last = CacheLast; +}; + +template +struct root_plus_last +{ + Node root_; + NodePtr last_; +}; + +template +struct root_plus_last +{ + Node root_; +}; + +template +struct slist_defaults + : pack_options + < none + , base_hook + , constant_time_size + , linear + , size_type + , cache_last + >::type +{}; + +/// @endcond + +//! The class template slist is an intrusive container, that encapsulates +//! a singly-linked list. You can use such a list to squeeze the last bit +//! of performance from your application. Unfortunately, the little gains +//! come with some huge drawbacks. A lot of member functions can't be +//! implemented as efficiently as for standard containers. To overcome +//! this limitation some other member functions with rather unusual semantics +//! have to be introduced. +//! +//! The template parameter \c T is the type to be managed by the container. +//! The user can specify additional options and if no options are provided +//! default options are used. +//! +//! The container supports the following options: +//! \c base_hook<>/member_hook<>/value_traits<>, +//! \c constant_time_size<>, \c size_type<>, +//! \c linear<> and \c cache_last<>. +//! +//! The iterators of slist are forward iterators. slist provides a static +//! function called "previous" to compute the previous iterator of a given iterator. +//! This function has linear complexity. To improve the usability esp. with +//! the '*_after' functions, ++end() == begin() and previous(begin()) == end() +//! are defined. An new special function "before_begin()" is defined, which returns +//! an iterator that points one less the beginning of the list: ++before_begin() == begin() +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +class slist_impl + : private detail::clear_on_destructor_base > +{ + template friend class detail::clear_on_destructor_base; + //Public typedefs + public: + typedef typename Config::value_traits value_traits; + /// @cond + static const bool external_value_traits = + detail::external_value_traits_bool_is_true::value; + typedef typename detail::eval_if_c + < external_value_traits + , detail::eval_value_traits + , detail::identity + >::type real_value_traits; + /// @endcond + typedef typename real_value_traits::pointer pointer; + typedef typename real_value_traits::const_pointer const_pointer; + typedef typename pointer_traits::element_type value_type; + typedef typename pointer_traits::reference reference; + typedef typename pointer_traits::reference const_reference; + typedef typename pointer_traits::difference_type difference_type; + typedef typename Config::size_type size_type; + typedef slist_iterator iterator; + typedef slist_iterator const_iterator; + typedef typename real_value_traits::node_traits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + + typedef typename detail::if_c + < Config::linear + , linear_slist_algorithms + , circular_slist_algorithms + >::type node_algorithms; + + static const bool constant_time_size = Config::constant_time_size; + static const bool stateful_value_traits = detail::is_stateful_value_traits::value; + static const bool linear = Config::linear; + static const bool cache_last = Config::cache_last; + + /// @cond + private: + typedef detail::size_holder size_traits; + + //noncopyable + BOOST_MOVABLE_BUT_NOT_COPYABLE(slist_impl) + + enum { safemode_or_autounlink = + (int)real_value_traits::link_mode == (int)auto_unlink || + (int)real_value_traits::link_mode == (int)safe_link }; + + //Constant-time size is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(constant_time_size && ((int)real_value_traits::link_mode == (int)auto_unlink))); + //Linear singly linked lists are incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(linear && ((int)real_value_traits::link_mode == (int)auto_unlink))); + //A list with cached last node is incompatible with auto-unlink hooks! + BOOST_STATIC_ASSERT(!(cache_last && ((int)real_value_traits::link_mode == (int)auto_unlink))); + + node_ptr get_end_node() + { return node_ptr(linear ? node_ptr() : this->get_root_node()); } + + const_node_ptr get_end_node() const + { + return const_node_ptr + (linear ? const_node_ptr() : this->get_root_node()); } + + node_ptr get_root_node() + { return pointer_traits::pointer_to(data_.root_plus_size_.root_); } + + const_node_ptr get_root_node() const + { return pointer_traits::pointer_to(data_.root_plus_size_.root_); } + + node_ptr get_last_node() + { return this->get_last_node(detail::bool_()); } + + const_node_ptr get_last_node() const + { return this->get_last_node(detail::bool_()); } + + void set_last_node(const node_ptr &n) + { return this->set_last_node(n, detail::bool_()); } + + static node_ptr get_last_node(detail::bool_) + { + //This function shall not be used if cache_last is not true + BOOST_INTRUSIVE_INVARIANT_ASSERT(cache_last); + return node_ptr(); + } + + static void set_last_node(const node_ptr &, detail::bool_) + { + //This function shall not be used if cache_last is not true + BOOST_INTRUSIVE_INVARIANT_ASSERT(cache_last); + } + + node_ptr get_last_node(detail::bool_) + { return node_ptr(data_.root_plus_size_.last_); } + + const_node_ptr get_last_node(detail::bool_) const + { return const_node_ptr(data_.root_plus_size_.last_); } + + void set_last_node(const node_ptr & n, detail::bool_) + { data_.root_plus_size_.last_ = n; } + + static node_ptr uncast(const const_node_ptr & ptr) + { return pointer_traits::const_cast_from(ptr); } + + void set_default_constructed_state() + { + node_algorithms::init_header(this->get_root_node()); + this->priv_size_traits().set_size(size_type(0)); + if(cache_last){ + this->set_last_node(this->get_root_node()); + } + } + + struct root_plus_size + : public size_traits + , public root_plus_last + {}; + + struct data_t + : public slist_impl::value_traits + { + typedef typename slist_impl::value_traits value_traits; + data_t(const value_traits &val_traits) + : value_traits(val_traits) + {} + + root_plus_size root_plus_size_; + } data_; + + size_traits &priv_size_traits() + { return data_.root_plus_size_; } + + const size_traits &priv_size_traits() const + { return data_.root_plus_size_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_; } + + const real_value_traits &get_real_value_traits(detail::bool_) const + { return data_.get_value_traits(*this); } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_; } + + real_value_traits &get_real_value_traits(detail::bool_) + { return data_.get_value_traits(*this); } + + const value_traits &priv_value_traits() const + { return data_; } + + value_traits &priv_value_traits() + { return data_; } + + protected: + node &prot_root_node() + { return data_.root_plus_size_.root_; } + + node const &prot_root_node() const + { return data_.root_plus_size_.root_; } + + void prot_set_size(size_type s) + { data_.root_plus_size_.set_size(s); } + + /// @endcond + + public: + + const real_value_traits &get_real_value_traits() const + { return this->get_real_value_traits(detail::bool_()); } + + real_value_traits &get_real_value_traits() + { return this->get_real_value_traits(detail::bool_()); } + + public: + + ///@cond + + //! Requires: f and before_l belong to another slist. + //! + //! Effects: Transfers the range [f, before_l] to this + //! list, after the element pointed by prev_pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements transferred + //! if constant_time_size is true. Constant-time otherwise. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + //! + //! Warning: Experimental function, don't use it! + slist_impl( const node_ptr & f, const node_ptr & before_l + , size_type n, const value_traits &v_traits = value_traits()) + : data_(v_traits) + { + if(n){ + this->priv_size_traits().set_size(n); + if(cache_last){ + this->set_last_node(before_l); + } + node_traits::set_next(this->get_root_node(), f); + node_traits::set_next(before_l, this->get_end_node()); + } + else{ + this->set_default_constructed_state(); + } + } + + ///@endcond + + //! Effects: constructs an empty list. + //! + //! Complexity: Constant + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). + explicit slist_impl(const value_traits &v_traits = value_traits()) + : data_(v_traits) + { this->set_default_constructed_state(); } + + //! Requires: Dereferencing iterator must yield an lvalue of type value_type. + //! + //! Effects: Constructs a list equal to [b ,e). + //! + //! Complexity: Linear in std::distance(b, e). No copy constructors are called. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks). + template + slist_impl(Iterator b, Iterator e, const value_traits &v_traits = value_traits()) + : data_(v_traits) + { + this->set_default_constructed_state(); + this->insert_after(this->cbefore_begin(), b, e); + } + + //! Effects: to-do + //! + slist_impl(BOOST_RV_REF(slist_impl) x) + : data_(::boost::move(x.priv_value_traits())) + { + this->priv_size_traits().set_size(size_type(0)); + node_algorithms::init_header(this->get_root_node()); + this->swap(x); + } + + //! Effects: to-do + //! + slist_impl& operator=(BOOST_RV_REF(slist_impl) x) + { this->swap(x); return *this; } + + //! Effects: If it's a safe-mode + //! or auto-unlink value, the destructor does nothing + //! (ie. no code is generated). Otherwise it detaches all elements from this. + //! In this case the objects in the list are not deleted (i.e. no destructors + //! are called), but the hooks according to the value_traits template parameter + //! are set to their default value. + //! + //! Complexity: Linear to the number of elements in the list, if + //! it's a safe-mode or auto-unlink value. Otherwise constant. + ~slist_impl() + {} + + //! Effects: Erases all the elements of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements of the list. + //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the erased elements. + void clear() + { + if(safemode_or_autounlink){ + this->clear_and_dispose(detail::null_disposer()); + } + else{ + this->set_default_constructed_state(); + } + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases all the elements of the container + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements of the list. + //! + //! Note: Invalidates the iterators to the erased elements. + template + void clear_and_dispose(Disposer disposer) + { + const_iterator it(this->begin()), itend(this->end()); + while(it != itend){ + node_ptr to_erase(it.pointed_node()); + ++it; + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + } + this->set_default_constructed_state(); + } + + //! Requires: value must be an lvalue. + //! + //! Effects: Inserts the value in the front of the list. + //! No copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + void push_front(reference value) + { + node_ptr to_insert = get_real_value_traits().to_node_ptr(value); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(to_insert)); + if(cache_last){ + if(this->empty()){ + this->set_last_node(to_insert); + } + } + node_algorithms::link_after(this->get_root_node(), to_insert); + this->priv_size_traits().increment(); + } + + //! Requires: value must be an lvalue. + //! + //! Effects: Inserts the value in the back of the list. + //! No copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + //! This function is only available is cache_last<> is true. + void push_back(reference value) + { + BOOST_STATIC_ASSERT((cache_last)); + node_ptr n = get_real_value_traits().to_node_ptr(value); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(n)); + node_algorithms::link_after(this->get_last_node(), n); + if(cache_last){ + this->set_last_node(n); + } + this->priv_size_traits().increment(); + } + + //! Effects: Erases the first element of the list. + //! No destructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators (but not the references) to the erased element. + void pop_front() + { return this->pop_front_and_dispose(detail::null_disposer()); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the first element of the list. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators to the erased element. + template + void pop_front_and_dispose(Disposer disposer) + { + node_ptr to_erase = node_traits::get_next(this->get_root_node()); + node_algorithms::unlink_after(this->get_root_node()); + this->priv_size_traits().decrement(); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + if(cache_last){ + if(this->empty()){ + this->set_last_node(this->get_root_node()); + } + } + } + + //! Effects: Returns a reference to the first element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->get_real_value_traits().to_value_ptr(node_traits::get_next(this->get_root_node())); } + + //! Effects: Returns a const_reference to the first element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->get_real_value_traits().to_value_ptr(uncast(node_traits::get_next(this->get_root_node()))); } + + //! Effects: Returns a reference to the last element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + //! This function is only available is cache_last<> is true. + reference back() + { + BOOST_STATIC_ASSERT((cache_last)); + return *this->get_real_value_traits().to_value_ptr(this->get_last_node()); + } + + //! Effects: Returns a const_reference to the last element of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + //! This function is only available is cache_last<> is true. + const_reference back() const + { + BOOST_STATIC_ASSERT((cache_last)); + return *this->get_real_value_traits().to_value_ptr(this->get_last_node()); + } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator (node_traits::get_next(this->get_root_node()), this); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return const_iterator (node_traits::get_next(this->get_root_node()), this); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(node_traits::get_next(this->get_root_node()), this); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->get_end_node(), this); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return const_iterator(uncast(this->get_end_node()), this); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return this->end(); } + + //! Effects: Returns an iterator that points to a position + //! before the first element. Equivalent to "end()" + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator before_begin() + { return iterator(this->get_root_node(), this); } + + //! Effects: Returns an iterator that points to a position + //! before the first element. Equivalent to "end()" + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator before_begin() const + { return const_iterator(uncast(this->get_root_node()), this); } + + //! Effects: Returns an iterator that points to a position + //! before the first element. Equivalent to "end()" + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbefore_begin() const + { return this->before_begin(); } + + //! Effects: Returns an iterator to the last element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: This function is present only if cached_last<> option is true. + iterator last() + { + //This function shall not be used if cache_last is not true + BOOST_INTRUSIVE_INVARIANT_ASSERT(cache_last); + return iterator (this->get_last_node(), this); + } + + //! Effects: Returns a const_iterator to the last element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: This function is present only if cached_last<> option is true. + const_iterator last() const + { + //This function shall not be used if cache_last is not true + BOOST_INTRUSIVE_INVARIANT_ASSERT(cache_last); + return const_iterator (this->get_last_node(), this); + } + + //! Effects: Returns a const_iterator to the last element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: This function is present only if cached_last<> option is true. + const_iterator clast() const + { return const_iterator(this->get_last_node(), this); } + + //! Precondition: end_iterator must be a valid end iterator + //! of slist. + //! + //! Effects: Returns a const reference to the slist associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static slist_impl &container_from_end_iterator(iterator end_iterator) + { return slist_impl::priv_container_from_end_iterator(end_iterator); } + + //! Precondition: end_iterator must be a valid end const_iterator + //! of slist. + //! + //! Effects: Returns a const reference to the slist associated to the end iterator + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + static const slist_impl &container_from_end_iterator(const_iterator end_iterator) + { return slist_impl::priv_container_from_end_iterator(end_iterator); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements contained in the list. + //! if constant_time_size is false. Constant time otherwise. + //! + //! Note: Does not affect the validity of iterators and references. + size_type size() const + { + if(constant_time_size) + return this->priv_size_traits().get_size(); + else + return node_algorithms::count(this->get_root_node()) - 1; + } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + bool empty() const + { return node_algorithms::unique(this->get_root_node()); } + + //! Effects: Swaps the elements of x and *this. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements of both lists. + //! Constant-time if linear<> and/or cache_last<> options are used. + //! + //! Note: Does not affect the validity of iterators and references. + void swap(slist_impl& other) + { + if(cache_last){ + priv_swap_cache_last(this, &other); + } + else{ + this->priv_swap_lists(this->get_root_node(), other.get_root_node(), detail::bool_()); + } + if(constant_time_size){ + size_type backup = this->priv_size_traits().get_size(); + this->priv_size_traits().set_size(other.priv_size_traits().get_size()); + other.priv_size_traits().set_size(backup); + } + } + + //! Effects: Moves backwards all the elements, so that the first + //! element becomes the second, the second becomes the third... + //! the last element becomes the first one. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number shifts. + //! + //! Note: Iterators Does not affect the validity of iterators and references. + void shift_backwards(size_type n = 1) + { this->priv_shift_backwards(n, detail::bool_()); } + + //! Effects: Moves forward all the elements, so that the second + //! element becomes the first, the third becomes the second... + //! the first element becomes the last one. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements plus the number shifts. + //! + //! Note: Does not affect the validity of iterators and references. + void shift_forward(size_type n = 1) + { this->priv_shift_forward(n, detail::bool_()); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! Cloner should yield to nodes equivalent to the original nodes. + //! + //! Effects: Erases all the elements from *this + //! calling Disposer::operator()(pointer), clones all the + //! elements from src calling Cloner::operator()(const_reference ) + //! and inserts them on *this. + //! + //! If cloner throws, all cloned elements are unlinked and disposed + //! calling Disposer::operator()(pointer). + //! + //! Complexity: Linear to erased plus inserted elements. + //! + //! Throws: If cloner throws. + template + void clone_from(const slist_impl &src, Cloner cloner, Disposer disposer) + { + this->clear_and_dispose(disposer); + detail::exception_disposer + rollback(*this, disposer); + const_iterator prev(this->cbefore_begin()); + const_iterator b(src.begin()), e(src.end()); + for(; b != e; ++b){ + prev = this->insert_after(prev, *cloner(*b)); + } + rollback.release(); + } + + //! Requires: value must be an lvalue and prev_p must point to an element + //! contained by the list or to end(). + //! + //! Effects: Inserts the value after the position pointed by prev_p. + //! No copy constructor is called. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Does not affect the validity of iterators and references. + iterator insert_after(const_iterator prev_p, reference value) + { + node_ptr n = get_real_value_traits().to_node_ptr(value); + if(safemode_or_autounlink) + BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(node_algorithms::inited(n)); + node_ptr prev_n(prev_p.pointed_node()); + node_algorithms::link_after(prev_n, n); + if(cache_last && (this->get_last_node() == prev_n)){ + this->set_last_node(n); + } + this->priv_size_traits().increment(); + return iterator (n, this); + } + + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type and prev_p must point to an element + //! contained by the list or to the end node. + //! + //! Effects: Inserts the [f, l) + //! after the position prev_p. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted. + //! + //! Note: Does not affect the validity of iterators and references. + template + void insert_after(const_iterator prev_p, Iterator f, Iterator l) + { + for (; f != l; ++f) + prev_p = this->insert_after(prev_p, *f); + } + + //! Requires: value must be an lvalue and p must point to an element + //! contained by the list or to end(). + //! + //! Effects: Inserts the value before the position pointed by p. + //! No copy constructor is called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before p. + //! Constant-time if cache_last<> is true and p == end(). + //! + //! Note: Does not affect the validity of iterators and references. + iterator insert(const_iterator p, reference value) + { return this->insert_after(this->previous(p), value); } + + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type and p must point to an element + //! contained by the list or to the end node. + //! + //! Effects: Inserts the pointed by b and e + //! before the position p. No copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted plus linear + //! to the elements before b. + //! Linear to the number of elements to insert if cache_last<> option is true and p == end(). + //! + //! Note: Does not affect the validity of iterators and references. + template + void insert(const_iterator p, Iterator b, Iterator e) + { return this->insert_after(this->previous(p), b, e); } + + //! Effects: Erases the element after the element pointed by prev of + //! the list. No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + iterator erase_after(const_iterator prev) + { return this->erase_after_and_dispose(prev, detail::null_disposer()); } + + //! Effects: Erases the range (before_f, l) from + //! the list. No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of erased elements if it's a safe-mode + //! , auto-unlink value or constant-time size is activated. Constant time otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + iterator erase_after(const_iterator before_f, const_iterator l) + { + if(safemode_or_autounlink || constant_time_size){ + return this->erase_after_and_dispose(before_f, l, detail::null_disposer()); + } + else{ + const node_ptr bfp = before_f.pointed_node(); + const node_ptr lp = l.pointed_node(); + if(cache_last){ + if(lp == this->get_end_node()){ + this->set_last_node(bfp); + } + } + node_algorithms::unlink_after(bfp, lp); + return l.unconst(); + } + } + + //! Effects: Erases the range (before_f, l) from + //! the list. n must be std::distance(before_f, l) - 1. + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: constant-time if link_mode is normal_link. + //! Linear to the elements (l - before_f) otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + iterator erase_after(const_iterator before_f, const_iterator l, size_type n) + { + BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(++const_iterator(before_f), l) == difference_type(n)); + if(safemode_or_autounlink){ + return this->erase_after(before_f, l); + } + else{ + const node_ptr bfp = before_f.pointed_node(); + const node_ptr lp = l.pointed_node(); + if(cache_last){ + if((lp == this->get_end_node())){ + this->set_last_node(bfp); + } + } + node_algorithms::unlink_after(bfp, lp); + if(constant_time_size){ + this->priv_size_traits().set_size(this->priv_size_traits().get_size() - n); + } + return l.unconst(); + } + } + + //! Effects: Erases the element pointed by i of the list. + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed element, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements before i. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + iterator erase(const_iterator i) + { return this->erase_after(this->previous(i)); } + + //! Requires: f and l must be valid iterator to elements in *this. + //! + //! Effects: Erases the range pointed by b and e. + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements before l. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased elements. + iterator erase(const_iterator f, const_iterator l) + { return this->erase_after(this->previous(f), l); } + + //! Effects: Erases the range [f, l) from + //! the list. n must be std::distance(f, l). + //! No destructors are called. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: linear to the elements before f if link_mode is normal_link + //! and constant_time_size is activated. Linear to the elements before l otherwise. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + iterator erase(const_iterator f, const_iterator l, size_type n) + { return this->erase_after(this->previous(f), l, n); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element after the element pointed by prev of + //! the list. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Invalidates the iterators to the erased element. + template + iterator erase_after_and_dispose(const_iterator prev, Disposer disposer) + { + const_iterator it(prev); + ++it; + node_ptr to_erase(it.pointed_node()); + ++it; + node_ptr prev_n(prev.pointed_node()); + node_algorithms::unlink_after(prev_n); + if(cache_last && (to_erase == this->get_last_node())){ + this->set_last_node(prev_n); + } + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + this->priv_size_traits().decrement(); + return it.unconst(); + } + + /// @cond + + template + static iterator s_erase_after_and_dispose(const_iterator prev, Disposer disposer) + { + BOOST_STATIC_ASSERT(((!cache_last)&&(!constant_time_size)&&(!stateful_value_traits))); + const_iterator it(prev); + ++it; + node_ptr to_erase(it.pointed_node()); + ++it; + node_ptr prev_n(prev.pointed_node()); + node_algorithms::unlink_after(prev_n); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(real_value_traits::to_value_ptr(to_erase)); + return it.unconst(); + } + + static iterator s_erase_after(const_iterator prev) + { return s_erase_after_and_dispose(prev, detail::null_disposer()); } + + /// @endcond + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range (before_f, l) from + //! the list. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Lineal to the elements (l - before_f + 1). + //! + //! Note: Invalidates the iterators to the erased element. + template + iterator erase_after_and_dispose(const_iterator before_f, const_iterator l, Disposer disposer) + { + node_ptr bfp(before_f.pointed_node()), lp(l.pointed_node()); + node_ptr fp(node_traits::get_next(bfp)); + node_algorithms::unlink_after(bfp, lp); + while(fp != lp){ + node_ptr to_erase(fp); + fp = node_traits::get_next(fp); + if(safemode_or_autounlink) + node_algorithms::init(to_erase); + disposer(get_real_value_traits().to_value_ptr(to_erase)); + this->priv_size_traits().decrement(); + } + if(cache_last && (node_traits::get_next(bfp) == this->get_end_node())){ + this->set_last_node(bfp); + } + return l.unconst(); + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the element pointed by i of the list. + //! No destructors are called. + //! Disposer::operator()(pointer) is called for the removed element. + //! + //! Returns: the first element remaining beyond the removed element, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements before i. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased element. + template + iterator erase_and_dispose(const_iterator i, Disposer disposer) + { return this->erase_after_and_dispose(this->previous(i), disposer); } + + #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + template + iterator erase_and_dispose(iterator i, Disposer disposer) + { return this->erase_and_dispose(const_iterator(i), disposer); } + #endif + + //! Requires: f and l must be valid iterator to elements in *this. + //! Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Erases the range pointed by b and e. + //! No destructors are called. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of erased elements plus linear + //! to the elements before f. + //! + //! Note: Invalidates the iterators (but not the references) to the + //! erased elements. + template + iterator erase_and_dispose(const_iterator f, const_iterator l, Disposer disposer) + { return this->erase_after_and_dispose(this->previous(f), l, disposer); } + + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type. + //! + //! Effects: Clears the list and inserts the range pointed by b and e. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted plus + //! linear to the elements contained in the list if it's a safe-mode + //! or auto-unlink value. + //! Linear to the number of elements inserted in the list otherwise. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. + template + void assign(Iterator b, Iterator e) + { + this->clear(); + this->insert_after(this->cbefore_begin(), b, e); + } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Requires: Dereferencing iterator must yield + //! an lvalue of type value_type. + //! + //! Effects: Clears the list and inserts the range pointed by b and e. + //! No destructors or copy constructors are called. + //! Disposer::operator()(pointer) is called for the removed elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements inserted plus + //! linear to the elements contained in the list. + //! + //! Note: Invalidates the iterators (but not the references) + //! to the erased elements. + template + void dispose_and_assign(Disposer disposer, Iterator b, Iterator e) + { + this->clear_and_dispose(disposer); + this->insert_after(this->cbefore_begin(), b, e, disposer); + } + + //! Requires: prev must point to an element contained by this list or + //! to the before_begin() element + //! + //! Effects: Transfers all the elements of list x to this list, after the + //! the element pointed by prev. No destructors or copy constructors are called. + //! + //! Returns: Nothing. + //! + //! Throws: Nothing. + //! + //! Complexity: In general, linear to the elements contained in x. + //! Constant-time if cache_last<> option is true and also constant-time if + //! linear<> option is true "this" is empty and "l" is not used. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + //! + //! Additional note: If the optional parameter "l" is provided, it will be + //! assigned to the last spliced element or prev if x is empty. + //! This iterator can be used as new "prev" iterator for a new splice_after call. + //! that will splice new values after the previously spliced values. + void splice_after(const_iterator prev, slist_impl &x, const_iterator *l = 0) + { + if(x.empty()){ + if(l) *l = prev; + } + else if(linear && this->empty()){ + this->swap(x); + if(l) *l = this->previous(this->cend()); + } + else{ + const_iterator last_x(x.previous(x.end())); //<- constant time if cache_last is active + node_ptr prev_n(prev.pointed_node()); + node_ptr last_x_n(last_x.pointed_node()); + if(cache_last){ + x.set_last_node(x.get_root_node()); + if(node_traits::get_next(prev_n) == this->get_end_node()){ + this->set_last_node(last_x_n); + } + } + node_algorithms::transfer_after( prev_n, x.before_begin().pointed_node(), last_x_n); + this->priv_size_traits().set_size(this->priv_size_traits().get_size() + x.priv_size_traits().get_size()); + x.priv_size_traits().set_size(size_type(0)); + if(l) *l = last_x; + } + } + + //! Requires: prev must point to an element contained by this list or + //! to the before_begin() element. prev_ele must point to an element contained in list + //! x or must be x.before_begin(). + //! + //! Effects: Transfers the element after prev_ele, from list x to this list, + //! after the element pointed by prev. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist_impl &x, const_iterator prev_ele) + { + const_iterator elem = prev_ele; + this->splice_after(prev_pos, x, prev_ele, ++elem, 1); + } + + //! Requires: prev_pos must be a dereferenceable iterator in *this or be + //! before_begin(), and before_f and before_l belong to x and + //! ++before_f != x.end() && before_l != x.end(). + //! + //! Effects: Transfers the range (before_f, before_l] from list x to this + //! list, after the element pointed by prev_pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements transferred + //! if constant_time_size is true. Constant-time otherwise. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist_impl &x, const_iterator before_f, const_iterator before_l) + { + if(constant_time_size) + this->splice_after(prev_pos, x, before_f, before_l, std::distance(before_f, before_l)); + else + this->priv_splice_after + (prev_pos.pointed_node(), x, before_f.pointed_node(), before_l.pointed_node()); + } + + //! Requires: prev_pos must be a dereferenceable iterator in *this or be + //! before_begin(), and before_f and before_l belong to x and + //! ++before_f != x.end() && before_l != x.end() and + //! n == std::distance(before_f, before_l). + //! + //! Effects: Transfers the range (before_f, before_l] from list x to this + //! list, after the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice_after(const_iterator prev_pos, slist_impl &x, const_iterator before_f, const_iterator before_l, size_type n) + { + BOOST_INTRUSIVE_INVARIANT_ASSERT(std::distance(before_f, before_l) == difference_type(n)); + this->priv_splice_after + (prev_pos.pointed_node(), x, before_f.pointed_node(), before_l.pointed_node()); + if(constant_time_size){ + this->priv_size_traits().set_size(this->priv_size_traits().get_size() + n); + x.priv_size_traits().set_size(x.priv_size_traits().get_size() - n); + } + } + + //! Requires: it is an iterator to an element in *this. + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by it. No destructors or copy constructors are called. + //! + //! Returns: Nothing. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements contained in x plus linear to + //! the elements before it. + //! Linear to the elements before it if cache_last<> option is true. + //! Constant-time if cache_last<> option is true and it == end(). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + //! + //! Additional note: If the optional parameter "l" is provided, it will be + //! assigned to the last spliced element or prev if x is empty. + //! This iterator can be used as new "prev" iterator for a new splice_after call. + //! that will splice new values after the previously spliced values. + void splice(const_iterator it, slist_impl &x, const_iterator *l = 0) + { this->splice_after(this->previous(it), x, l); } + + //! Requires: it p must be a valid iterator of *this. + //! elem must point to an element contained in list + //! x. + //! + //! Effects: Transfers the element elem, from list x to this list, + //! before the element pointed by pos. No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements before pos and before elem. + //! Linear to the elements before elem if cache_last<> option is true and pos == end(). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator pos, slist_impl &x, const_iterator elem) + { return this->splice_after(this->previous(pos), x, x.previous(elem)); } + + //! Requires: pos must be a dereferenceable iterator in *this + //! and f and f belong to x and f and f a valid range on x. + //! + //! Effects: Transfers the range [f, l) from list x to this + //! list, before the element pointed by pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the sum of elements before pos, f, and l + //! plus linear to the number of elements transferred if constant_time_size is true. + //! Linear to the sum of elements before f, and l + //! plus linear to the number of elements transferred if constant_time_size is true + //! if cache_last<> is true and pos == end() + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator pos, slist_impl &x, const_iterator f, const_iterator l) + { return this->splice_after(this->previous(pos), x, x.previous(f), x.previous(l)); } + + //! Requires: pos must be a dereferenceable iterator in *this + //! and f and l belong to x and f and l a valid range on x. + //! n == std::distance(f, l). + //! + //! Effects: Transfers the range [f, l) from list x to this + //! list, before the element pointed by pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the sum of elements before pos, f, and l. + //! Linear to the sum of elements before f and l + //! if cache_last<> is true and pos == end(). + //! + //! Note: Iterators of values obtained from list x now point to elements of this + //! list. Iterators of this list and all the references are not invalidated. + void splice(const_iterator pos, slist_impl &x, const_iterator f, const_iterator l, size_type n) + { return this->splice_after(this->previous(pos), x, x.previous(f), x.previous(l), n); } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or the predicate throws. Basic guarantee. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + //! + //! Note: Iterators and references are not invalidated + template + void sort(Predicate p) + { + if (node_traits::get_next(node_traits::get_next(this->get_root_node())) + != this->get_root_node()) { + + slist_impl carry(this->priv_value_traits()); + detail::array_initializer counter(this->priv_value_traits()); + int fill = 0; + const_iterator last_inserted; + while(!this->empty()){ + last_inserted = this->cbegin(); + carry.splice_after(carry.cbefore_begin(), *this, this->cbefore_begin()); + int i = 0; + while(i < fill && !counter[i].empty()) { + carry.swap(counter[i]); + carry.merge(counter[i++], p, &last_inserted); + } + BOOST_INTRUSIVE_INVARIANT_ASSERT(counter[i].empty()); + const_iterator last_element(carry.previous(last_inserted, carry.end())); + + if(constant_time_size){ + counter[i].splice_after( counter[i].cbefore_begin(), carry + , carry.cbefore_begin(), last_element + , carry.size()); + } + else{ + counter[i].splice_after( counter[i].cbefore_begin(), carry + , carry.cbefore_begin(), last_element); + } + if(i == fill) + ++fill; + } + + for (int i = 1; i < fill; ++i) + counter[i].merge(counter[i-1], p, &last_inserted); + --fill; + const_iterator last_element(counter[fill].previous(last_inserted, counter[fill].end())); + if(constant_time_size){ + this->splice_after( cbefore_begin(), counter[fill], counter[fill].cbefore_begin() + , last_element, counter[fill].size()); + } + else{ + this->splice_after( cbefore_begin(), counter[fill], counter[fill].cbefore_begin() + , last_element); + } + } + } + + //! Requires: p must be a comparison function that induces a strict weak + //! ordering and both *this and x must be sorted according to that ordering + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Throws: If value_traits::node_traits::node + //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) + //! or std::less throws. Basic guarantee. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references are not invalidated. + void sort() + { this->sort(std::less()); } + + //! Requires: p must be a comparison function that induces a strict weak + //! ordering and both *this and x must be sorted according to that ordering + //! The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this. The merge is stable; that is, if an element from *this is + //! equivalent to one from x, then the element from *this will precede the one from x. + //! + //! Returns: Nothing. + //! + //! Throws: If the predicate throws. Basic guarantee. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references are not invalidated. + //! + //! Additional note: If optional "l" argument is passed, it is assigned + //! to an iterator to the last transferred value or end() is x is empty. + template + void merge(slist_impl& x, Predicate p, const_iterator *l = 0) + { + const_iterator e(this->cend()), ex(x.cend()), bb(this->cbefore_begin()), + bb_next; + if(l) *l = e.unconst(); + while(!x.empty()){ + const_iterator ibx_next(x.cbefore_begin()), ibx(ibx_next++); + while (++(bb_next = bb) != e && !p(*ibx_next, *bb_next)){ + bb = bb_next; + } + if(bb_next == e){ + //Now transfer the rest to the end of the container + this->splice_after(bb, x, l); + break; + } + else{ + size_type n(0); + do{ + ibx = ibx_next; ++n; + } while(++(ibx_next = ibx) != ex && p(*ibx_next, *bb_next)); + this->splice_after(bb, x, x.before_begin(), ibx, n); + if(l) *l = ibx; + } + } + } + + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. The merge is stable; + //! that is, if an element from *this is equivalent to one from x, then the element + //! from *this will precede the one from x. + //! + //! Throws: if std::less throws. Basic guarantee. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references are not invalidated + void merge(slist_impl& x) + { this->merge(x, std::less()); } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear to the contained elements. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { + if(cache_last && !this->empty()){ + this->set_last_node(node_traits::get_next(this->get_root_node())); + } + this->priv_reverse(detail::bool_()); + } + + //! Effects: Removes all the elements that compare equal to value. + //! No destructors are called. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. This function is + //! linear time: it performs exactly size() comparisons for equality. + void remove(const_reference value) + { this->remove_if(detail::equal_to_value(value)); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes all the elements that compare equal to value. + //! Disposer::operator()(pointer) is called for every removed element. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_and_dispose(const_reference value, Disposer disposer) + { this->remove_and_dispose_if(detail::equal_to_value(value), disposer); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. No destructors are called. + //! + //! Throws: If pred throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { this->remove_and_dispose_if(pred, detail::null_disposer()); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! Disposer::operator()(pointer) is called for every removed element. + //! + //! Throws: If pred throws. Basic guarantee. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_and_dispose_if(Pred pred, Disposer disposer) + { + const_iterator bcur(this->before_begin()), cur(this->begin()), e(this->end()); + + while(cur != e){ + if (pred(*cur)){ + cur = this->erase_after_and_dispose(bcur, disposer); + } + else{ + bcur = cur; + ++cur; + } + } + if(cache_last){ + this->set_last_node(bcur.pointed_node()); + } + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. No destructors are called. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons calls to pred()). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + void unique() + { this->unique_and_dispose(std::equal_to(), detail::null_disposer()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! No destructors are called. + //! + //! Throws: If the predicate throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons equality comparisons. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(BinaryPredicate pred) + { this->unique_and_dispose(pred, detail::null_disposer()); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! Disposer::operator()(pointer) is called for every removed element. + //! + //! Throws: If std::equal_to throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons equality comparisons. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique_and_dispose(Disposer disposer) + { this->unique(std::equal_to(), disposer); } + + //! Requires: Disposer::operator()(pointer) shouldn't throw. + //! + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! Disposer::operator()(pointer) is called for every removed element. + //! + //! Throws: If the predicate throws. Basic guarantee. + //! + //! Complexity: Linear time (size()-1) comparisons equality comparisons. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique_and_dispose(BinaryPredicate pred, Disposer disposer) + { + const_iterator end_n(this->cend()); + const_iterator bcur(this->cbegin()); + if(bcur != end_n){ + const_iterator cur(bcur); + ++cur; + while(cur != end_n) { + if (pred(*bcur, *cur)){ + cur = this->erase_after_and_dispose(bcur, disposer); + } + else{ + bcur = cur; + ++cur; + } + } + if(cache_last){ + this->set_last_node(bcur.pointed_node()); + } + } + } + + //! Requires: value must be a reference to a value inserted in a list. + //! + //! Effects: This function returns a const_iterator pointing to the element + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + //! This static function is available only if the value traits + //! is stateless. + static iterator s_iterator_to(reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + //BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::inited(value_traits::to_node_ptr(value))); + return iterator (value_traits::to_node_ptr(value), 0); + } + + //! Requires: value must be a const reference to a value inserted in a list. + //! + //! Effects: This function returns an iterator pointing to the element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + //! This static function is available only if the value traits + //! is stateless. + static const_iterator s_iterator_to(const_reference value) + { + BOOST_STATIC_ASSERT((!stateful_value_traits)); + //BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::inited(value_traits::to_node_ptr(const_cast (value)))); + return const_iterator (value_traits::to_node_ptr(const_cast (value)), 0); + } + + //! Requires: value must be a reference to a value inserted in a list. + //! + //! Effects: This function returns a const_iterator pointing to the element + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + iterator iterator_to(reference value) + { + //BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::inited(value_traits::to_node_ptr(value))); + return iterator (value_traits::to_node_ptr(value), this); + } + + //! Requires: value must be a const reference to a value inserted in a list. + //! + //! Effects: This function returns an iterator pointing to the element. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators and references are not invalidated. + const_iterator iterator_to(const_reference value) const + { + //BOOST_INTRUSIVE_INVARIANT_ASSERT (!node_algorithms::inited(value_traits::to_node_ptr(const_cast (value)))); + return const_iterator (value_traits::to_node_ptr(const_cast (value)), this); + } + + //! Returns: The iterator to the element before i in the list. + //! Returns the end-iterator, if either i is the begin-iterator or the + //! list is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + //! Constant if cache_last<> is true and i == end(). + iterator previous(iterator i) + { return this->previous(this->cbefore_begin(), i); } + + //! Returns: The const_iterator to the element before i in the list. + //! Returns the end-const_iterator, if either i is the begin-const_iterator or + //! the list is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + //! Constant if cache_last<> is true and i == end(). + const_iterator previous(const_iterator i) const + { return this->previous(this->cbefore_begin(), i); } + + //! Returns: The iterator to the element before i in the list, + //! starting the search on element after prev_from. + //! Returns the end-iterator, if either i is the begin-iterator or the + //! list is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + //! Constant if cache_last<> is true and i == end(). + iterator previous(const_iterator prev_from, iterator i) + { return this->previous(prev_from, const_iterator(i)).unconst(); } + + //! Returns: The const_iterator to the element before i in the list, + //! starting the search on element after prev_from. + //! Returns the end-const_iterator, if either i is the begin-const_iterator or + //! the list is empty. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + //! Constant if cache_last<> is true and i == end(). + const_iterator previous(const_iterator prev_from, const_iterator i) const + { + if(cache_last && (i.pointed_node() == this->get_end_node())){ + return const_iterator(uncast(this->get_last_node()), this); + } + return const_iterator + (node_algorithms::get_previous_node + (prev_from.pointed_node(), i.pointed_node()), this); + } + + ///@cond + + //! Requires: prev_pos must be a dereferenceable iterator in *this or be + //! before_begin(), and f and before_l belong to another slist. + //! + //! Effects: Transfers the range [f, before_l] to this + //! list, after the element pointed by prev_pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements transferred + //! if constant_time_size is true. Constant-time otherwise. + //! + //! Note: Iterators of values obtained from the list that owned f and before_l now + //! point to elements of this list. Iterators of this list and all the references are not invalidated. + //! + //! Warning: Experimental function, don't use it! + void incorporate_after(const_iterator prev_pos, const node_ptr & f, const node_ptr & before_l) + { + if(constant_time_size) + this->incorporate_after(prev_pos, f, before_l, std::distance(f, before_l)+1); + else + this->priv_incorporate_after(prev_pos.pointed_node(), f, before_l); + } + + //! Requires: prev_pos must be a dereferenceable iterator in *this or be + //! before_begin(), and f and before_l belong to another slist. + //! n == std::distance(f, before_l) + 1. + //! + //! Effects: Transfers the range [f, before_l] to this + //! list, after the element pointed by prev_pos. + //! No destructors or copy constructors are called. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + //! + //! Note: Iterators of values obtained from the list that owned f and before_l now + //! point to elements of this list. Iterators of this list and all the references are not invalidated. + //! + //! Warning: Experimental function, don't use it! + void incorporate_after(const_iterator prev_pos, const node_ptr & f, const node_ptr & before_l, size_type n) + { + if(n){ + BOOST_INTRUSIVE_INVARIANT_ASSERT(n > 0); + BOOST_INTRUSIVE_INVARIANT_ASSERT(size_type(std::distance(iterator(f, this), iterator(before_l, this)))+1 == n); + this->priv_incorporate_after(prev_pos.pointed_node(), f, before_l); + if(constant_time_size){ + this->priv_size_traits().set_size(this->priv_size_traits().get_size() + n); + } + } + } + + ///@endcond + + private: + void priv_splice_after(const node_ptr & prev_pos_n, slist_impl &x, const node_ptr & before_f_n, const node_ptr & before_l_n) + { + if (cache_last && (before_f_n != before_l_n)){ + if(prev_pos_n == this->get_last_node()){ + this->set_last_node(before_l_n); + } + if(&x != this && node_traits::get_next(before_l_n) == x.get_end_node()){ + x.set_last_node(before_f_n); + } + } + node_algorithms::transfer_after(prev_pos_n, before_f_n, before_l_n); + } + + void priv_incorporate_after(const node_ptr & prev_pos_n, const node_ptr & first_n, const node_ptr & before_l_n) + { + if(cache_last){ + if(prev_pos_n == this->get_last_node()){ + this->set_last_node(before_l_n); + } + } + node_algorithms::incorporate_after(prev_pos_n, first_n, before_l_n); + } + + void priv_reverse(detail::bool_) + { node_algorithms::reverse(this->get_root_node()); } + + void priv_reverse(detail::bool_) + { + node_ptr new_first = node_algorithms::reverse + (node_traits::get_next(this->get_root_node())); + node_traits::set_next(this->get_root_node(), new_first); + } + + void priv_shift_backwards(size_type n, detail::bool_) + { + node_ptr l = node_algorithms::move_forward(this->get_root_node(), (std::size_t)n); + if(cache_last && l){ + this->set_last_node(l); + } + } + + void priv_shift_backwards(size_type n, detail::bool_) + { + std::pair ret( + node_algorithms::move_first_n_forward + (node_traits::get_next(this->get_root_node()), (std::size_t)n)); + if(ret.first){ + node_traits::set_next(this->get_root_node(), ret.first); + if(cache_last){ + this->set_last_node(ret.second); + } + } + } + + void priv_shift_forward(size_type n, detail::bool_) + { + node_ptr l = node_algorithms::move_backwards(this->get_root_node(), (std::size_t)n); + if(cache_last && l){ + this->set_last_node(l); + } + } + + void priv_shift_forward(size_type n, detail::bool_) + { + std::pair ret( + node_algorithms::move_first_n_backwards + (node_traits::get_next(this->get_root_node()), (std::size_t)n)); + if(ret.first){ + node_traits::set_next(this->get_root_node(), ret.first); + if(cache_last){ + this->set_last_node(ret.second); + } + } + } + + static void priv_swap_cache_last(slist_impl *this_impl, slist_impl *other_impl) + { + bool other_was_empty = false; + if(this_impl->empty()){ + //Check if both are empty or + if(other_impl->empty()) + return; + //If this is empty swap pointers + slist_impl *tmp = this_impl; + this_impl = other_impl; + other_impl = tmp; + other_was_empty = true; + } + else{ + other_was_empty = other_impl->empty(); + } + + //Precondition: this is not empty + node_ptr other_old_last(other_impl->get_last_node()); + node_ptr other_bfirst(other_impl->get_root_node()); + node_ptr this_bfirst(this_impl->get_root_node()); + node_ptr this_old_last(this_impl->get_last_node()); + + //Move all nodes from this to other's beginning + node_algorithms::transfer_after(other_bfirst, this_bfirst, this_old_last); + other_impl->set_last_node(this_old_last); + + if(other_was_empty){ + this_impl->set_last_node(this_bfirst); + } + else{ + //Move trailing nodes from other to this + node_algorithms::transfer_after(this_bfirst, this_old_last, other_old_last); + this_impl->set_last_node(other_old_last); + } + } + + //circular version + static void priv_swap_lists(const node_ptr & this_node, const node_ptr & other_node, detail::bool_) + { node_algorithms::swap_nodes(this_node, other_node); } + + //linear version + static void priv_swap_lists(const node_ptr & this_node, const node_ptr & other_node, detail::bool_) + { node_algorithms::swap_trailing_nodes(this_node, other_node); } + + static slist_impl &priv_container_from_end_iterator(const const_iterator &end_iterator) + { + //Obtaining the container from the end iterator is not possible with linear + //singly linked lists (because "end" is represented by the null pointer) + BOOST_STATIC_ASSERT(!linear); + root_plus_size *r = detail::parent_from_member + ( boost::intrusive::detail::to_raw_pointer(end_iterator.pointed_node()), (&root_plus_size::root_)); + data_t *d = detail::parent_from_member + ( r, &data_t::root_plus_size_); + slist_impl *s = detail::parent_from_member(d, &slist_impl::data_); + return *s; + } +}; + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator< +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif +{ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +bool operator== +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif +{ + typedef slist_impl slist_type; + typedef typename slist_type::const_iterator const_iterator; + const bool C = slist_type::constant_time_size; + if(C && x.size() != y.size()){ + return false; + } + const_iterator end1 = x.end(); + + const_iterator i1 = x.begin(); + const_iterator i2 = y.begin(); + if(C){ + while (i1 != end1 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1; + } + else{ + const_iterator end2 = y.end(); + while (i1 != end1 && i2 != end2 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1 && i2 == end2; + } +} + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator!= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif +{ return !(x == y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator> +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif +{ return y < x; } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator<= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif +{ return !(y < x); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline bool operator>= +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(const slist_impl &x, const slist_impl &y) +#else +(const slist_impl &x, const slist_impl &y) +#endif +{ return !(x < y); } + +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +template +#else +template +#endif +inline void swap +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) +(slist_impl &x, slist_impl &y) +#else +(slist_impl &x, slist_impl &y) +#endif +{ x.swap(y); } + +//! Helper metafunction to define a \c slist that yields to the same type when the +//! same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_slist +{ + /// @cond + typedef typename pack_options + < slist_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3, O4, O5 + #else + Options... + #endif + >::type packed_options; + typedef typename detail::get_value_traits + ::type value_traits; + typedef slist_impl + < + slistopt + < value_traits + , typename packed_options::size_type + , packed_options::constant_time_size + , packed_options::linear + , packed_options::cache_last + > + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + + +#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED + +#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class slist + : public make_slist::type +{ + typedef typename make_slist + ::type Base; + typedef typename Base::real_value_traits real_value_traits; + //Assert if passed value traits are compatible with the type + BOOST_STATIC_ASSERT((detail::is_same::value)); + BOOST_MOVABLE_BUT_NOT_COPYABLE(slist) + + public: + typedef typename Base::value_traits value_traits; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + typedef typename Base::size_type size_type; + typedef typename Base::node_ptr node_ptr; + + explicit slist(const value_traits &v_traits = value_traits()) + : Base(v_traits) + {} + + struct incorporate_t{}; + + slist( const node_ptr & f, const node_ptr & before_l + , size_type n, const value_traits &v_traits = value_traits()) + : Base(f, before_l, n, v_traits) + {} + + template + slist(Iterator b, Iterator e, const value_traits &v_traits = value_traits()) + : Base(b, e, v_traits) + {} + + slist(BOOST_RV_REF(slist) x) + : Base(::boost::move(static_cast(x))) + {} + + slist& operator=(BOOST_RV_REF(slist) x) + { this->Base::operator=(::boost::move(static_cast(x))); return *this; } + + static slist &container_from_end_iterator(iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } + + static const slist &container_from_end_iterator(const_iterator end_iterator) + { return static_cast(Base::container_from_end_iterator(end_iterator)); } +}; + +#endif + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SLIST_HPP diff --git a/cpp/BoostParts/boost/intrusive/slist_hook.hpp b/cpp/BoostParts/boost/intrusive/slist_hook.hpp new file mode 100644 index 00000000..cd94a7e7 --- /dev/null +++ b/cpp/BoostParts/boost/intrusive/slist_hook.hpp @@ -0,0 +1,294 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Olaf Krzikalla 2004-2006. +// (C) Copyright Ion Gaztanaga 2006-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/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTRUSIVE_SLIST_HOOK_HPP +#define BOOST_INTRUSIVE_SLIST_HOOK_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace intrusive { + +/// @cond +template +struct get_slist_node_algo +{ + typedef circular_slist_algorithms > type; +}; + +/// @endcond + +//! Helper metafunction to define a \c slist_base_hook that yields to the same +//! type when the same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_slist_base_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; + + typedef detail::generic_hook + < get_slist_node_algo + , typename packed_options::tag + , packed_options::link_mode + , detail::SlistBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Derive a class from slist_base_hook in order to store objects in +//! in an list. slist_base_hook holds the data necessary to maintain the +//! list and provides an appropriate value_traits class for list. +//! +//! The hook admits the following options: \c tag<>, \c void_pointer<> and +//! \c link_mode<>. +//! +//! \c tag<> defines a tag to identify the node. +//! The same tag value can be used in different classes, but if a class is +//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its +//! unique tag. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c void_pointer<> is the pointer type that will be used internally in the hook +//! and the the container configured to use this hook. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class slist_base_hook + : public make_slist_base_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type +{ + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + public: + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + slist_base_hook(); + + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + slist_base_hook(const slist_base_hook& ); + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + slist_base_hook& operator=(const slist_base_hook& ); + + //! Effects: If link_mode is \c normal_link, the destructor does + //! nothing (ie. no code is generated). If link_mode is \c safe_link and the + //! object is stored in an slist an assertion is raised. If link_mode is + //! \c auto_unlink and \c is_linked() is true, the node is unlinked. + //! + //! Throws: Nothing. + ~slist_base_hook(); + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(slist_base_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c slist::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #endif +}; + +//! Helper metafunction to define a \c slist_member_hook that yields to the same +//! type when the same options (either explicitly or implicitly) are used. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct make_slist_member_hook +{ + /// @cond + typedef typename pack_options + < hook_defaults, + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type packed_options; + + typedef detail::generic_hook + < get_slist_node_algo + , member_tag + , packed_options::link_mode + , detail::NoBaseHook + > implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +//! Put a public data member slist_member_hook in order to store objects of this class in +//! an list. slist_member_hook holds the data necessary for maintaining the list and +//! provides an appropriate value_traits class for list. +//! +//! The hook admits the following options: \c void_pointer<> and +//! \c link_mode<>. +//! +//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, +//! \c auto_unlink or \c safe_link). +//! +//! \c void_pointer<> is the pointer type that will be used internally in the hook +//! and the the container configured to use this hook. +#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) +template +#else +template +#endif +class slist_member_hook + : public make_slist_member_hook< + #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES) + O1, O2, O3 + #else + Options... + #endif + >::type +{ + #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) + public: + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. + //! + //! Throws: Nothing. + slist_member_hook(); + + //! Effects: If link_mode is \c auto_unlink or \c safe_link + //! initializes the node to an unlinked state. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing a copy-constructor + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + slist_member_hook(const slist_member_hook& ); + + //! Effects: Empty function. The argument is ignored. + //! + //! Throws: Nothing. + //! + //! Rationale: Providing an assignment operator + //! makes classes using the hook STL-compliant without forcing the + //! user to do some additional work. \c swap can be used to emulate + //! move-semantics. + slist_member_hook& operator=(const slist_member_hook& ); + + //! Effects: If link_mode is \c normal_link, the destructor does + //! nothing (ie. no code is generated). If link_mode is \c safe_link and the + //! object is stored in an slist an assertion is raised. If link_mode is + //! \c auto_unlink and \c is_linked() is true, the node is unlinked. + //! + //! Throws: Nothing. + ~slist_member_hook(); + + //! Effects: Swapping two nodes swaps the position of the elements + //! related to those nodes in one or two containers. That is, if the node + //! this is part of the element e1, the node x is part of the element e2 + //! and both elements are included in the containers s1 and s2, then after + //! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1 + //! at the position of e1. If one element is not in a container, then + //! after the swap-operation the other element is not in a container. + //! Iterators to e1 and e2 related to those nodes are invalidated. + //! + //! Complexity: Constant + //! + //! Throws: Nothing. + void swap_nodes(slist_member_hook &other); + + //! Precondition: link_mode must be \c safe_link or \c auto_unlink. + //! + //! Returns: true, if the node belongs to a container, false + //! otherwise. This function can be used to test whether \c slist::iterator_to + //! will return a valid iterator. + //! + //! Complexity: Constant + bool is_linked() const; + + //! Effects: Removes the node if it's inserted in a container. + //! This function is only allowed if link_mode is \c auto_unlink. + //! + //! Throws: Nothing. + void unlink(); + #endif +}; + +} //namespace intrusive +} //namespace boost + +#include + +#endif //BOOST_INTRUSIVE_SLIST_HOOK_HPP diff --git a/cpp/BoostParts/boost/lockfree/detail/atomic.hpp b/cpp/BoostParts/boost/lockfree/detail/atomic.hpp new file mode 100644 index 00000000..5ef16dd7 --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/atomic.hpp @@ -0,0 +1,71 @@ +// Copyright (C) 2011 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_DETAIL_ATOMIC_HPP +#define BOOST_LOCKFREE_DETAIL_ATOMIC_HPP + +#include + +// at this time, few compiles completely implement atomic<> +#define BOOST_LOCKFREE_NO_HDR_ATOMIC + +// MSVC supports atomic<> from version 2012 onwards. +#if defined(BOOST_MSVC) && (BOOST_MSVC >= 1700) +#undef BOOST_LOCKFREE_NO_HDR_ATOMIC +#endif + +// GCC supports atomic<> from version 4.8 onwards. +#if defined(__GNUC__) +# if defined(__GNUC_PATCHLEVEL__) +# define __GNUC_VERSION__ (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +# else +# define __GNUC_VERSION__ (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100) +# endif +#endif + +#if (__GNUC_VERSION__ >= 40800) && (__cplusplus >= 201103L) +#undef BOOST_LOCKFREE_NO_HDR_ATOMIC +#endif + +#undef __GNUC_VERSION__ + +#if defined(BOOST_LOCKFREE_NO_HDR_ATOMIC) +#include +#else +#include +#endif + +namespace boost { +namespace lockfree { +namespace detail { + +#if defined(BOOST_LOCKFREE_NO_HDR_ATOMIC) +using boost::atomic; +using boost::memory_order_acquire; +using boost::memory_order_consume; +using boost::memory_order_relaxed; +using boost::memory_order_release; +#else +using std::atomic; +using std::memory_order_acquire; +using std::memory_order_consume; +using std::memory_order_relaxed; +using std::memory_order_release; +#endif + +} +using detail::atomic; +using detail::memory_order_acquire; +using detail::memory_order_consume; +using detail::memory_order_relaxed; +using detail::memory_order_release; + +}} + +#endif /* BOOST_LOCKFREE_DETAIL_ATOMIC_HPP */ diff --git a/cpp/BoostParts/boost/lockfree/detail/branch_hints.hpp b/cpp/BoostParts/boost/lockfree/detail/branch_hints.hpp new file mode 100644 index 00000000..3a193f8b --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/branch_hints.hpp @@ -0,0 +1,38 @@ +// branch hints +// Copyright (C) 2007, 2008 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_BRANCH_HINTS_HPP_INCLUDED +#define BOOST_LOCKFREE_BRANCH_HINTS_HPP_INCLUDED + +namespace boost { +namespace lockfree { +namespace detail { +/** \brief hint for the branch prediction */ +inline bool likely(bool expr) +{ +#ifdef __GNUC__ + return __builtin_expect(expr, true); +#else + return expr; +#endif + } + +/** \brief hint for the branch prediction */ +inline bool unlikely(bool expr) +{ +#ifdef __GNUC__ + return __builtin_expect(expr, false); +#else + return expr; +#endif +} + +} /* namespace detail */ +} /* namespace lockfree */ +} /* namespace boost */ + +#endif /* BOOST_LOCKFREE_BRANCH_HINTS_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/detail/copy_payload.hpp b/cpp/BoostParts/boost/lockfree/detail/copy_payload.hpp new file mode 100644 index 00000000..1e83eb29 --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/copy_payload.hpp @@ -0,0 +1,49 @@ +// boost lockfree: copy_payload helper +// +// Copyright (C) 2011 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_DETAIL_COPY_PAYLOAD_HPP_INCLUDED +#define BOOST_LOCKFREE_DETAIL_COPY_PAYLOAD_HPP_INCLUDED + +#include +#include + +namespace boost { +namespace lockfree { +namespace detail { + +struct copy_convertible +{ + template + static void copy(T & t, U & u) + { + u = t; + } +}; + +struct copy_constructible_and_copyable +{ + template + static void copy(T & t, U & u) + { + u = U(t); + } +}; + +template +void copy_payload(T & t, U & u) +{ + typedef typename boost::mpl::if_::type, + copy_convertible, + copy_constructible_and_copyable + >::type copy_type; + copy_type::copy(t, u); +} + +}}} + +#endif /* BOOST_LOCKFREE_DETAIL_COPY_PAYLOAD_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/detail/freelist.hpp b/cpp/BoostParts/boost/lockfree/detail/freelist.hpp new file mode 100644 index 00000000..d69f4af3 --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/freelist.hpp @@ -0,0 +1,625 @@ +// lock-free freelist +// +// Copyright (C) 2008, 2009, 2011 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_FREELIST_HPP_INCLUDED +#define BOOST_LOCKFREE_FREELIST_HPP_INCLUDED + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace boost { +namespace lockfree { +namespace detail { + +template + > +class freelist_stack: + Alloc +{ + struct freelist_node + { + tagged_ptr next; + }; + + typedef tagged_ptr tagged_node_ptr; + +public: + typedef tagged_ptr tagged_node_handle; + + template + freelist_stack (Allocator const & alloc, std::size_t n = 0): + Alloc(alloc), + pool_(tagged_node_ptr(NULL)) + { + for (std::size_t i = 0; i != n; ++i) { + T * node = Alloc::allocate(1); +#ifdef BOOST_LOCKFREE_FREELIST_INIT_RUNS_DTOR + destruct(node); +#else + deallocate(node); +#endif + } + } + + template + void reserve (std::size_t count) + { + for (std::size_t i = 0; i != count; ++i) { + T * node = Alloc::allocate(1); + deallocate(node); + } + } + + template + T * construct (void) + { + T * node = allocate(); + if (node) + new(node) T(); + return node; + } + + template + T * construct (ArgumentType const & arg) + { + T * node = allocate(); + if (node) + new(node) T(arg); + return node; + } + + template + T * construct (ArgumentType1 const & arg1, ArgumentType2 const & arg2) + { + T * node = allocate(); + if (node) + new(node) T(arg1, arg2); + return node; + } + + template + void destruct (tagged_node_handle tagged_ptr) + { + T * n = tagged_ptr.get_ptr(); + n->~T(); + deallocate(n); + } + + template + void destruct (T * n) + { + n->~T(); + deallocate(n); + } + + ~freelist_stack(void) + { + tagged_node_ptr current (pool_); + + while (current) { + freelist_node * current_ptr = current.get_ptr(); + if (current_ptr) + current = current_ptr->next; + Alloc::deallocate((T*)current_ptr, 1); + } + } + + bool is_lock_free(void) const + { + return pool_.is_lock_free(); + } + + T * get_handle(T * pointer) const + { + return pointer; + } + + T * get_handle(tagged_node_handle const & handle) const + { + return get_pointer(handle); + } + + T * get_pointer(tagged_node_handle const & tptr) const + { + return tptr.get_ptr(); + } + + T * get_pointer(T * pointer) const + { + return pointer; + } + + T * null_handle(void) const + { + return NULL; + } + +protected: // allow use from subclasses + template + T * allocate (void) + { + if (ThreadSafe) + return allocate_impl(); + else + return allocate_impl_unsafe(); + } + +private: + template + T * allocate_impl (void) + { + tagged_node_ptr old_pool = pool_.load(memory_order_consume); + + for(;;) { + if (!old_pool.get_ptr()) { + if (!Bounded) + return Alloc::allocate(1); + else + return 0; + } + + freelist_node * new_pool_ptr = old_pool->next.get_ptr(); + tagged_node_ptr new_pool (new_pool_ptr, old_pool.get_tag() + 1); + + if (pool_.compare_exchange_weak(old_pool, new_pool)) { + void * ptr = old_pool.get_ptr(); + return reinterpret_cast(ptr); + } + } + } + + template + T * allocate_impl_unsafe (void) + { + tagged_node_ptr old_pool = pool_.load(memory_order_relaxed); + + if (!old_pool.get_ptr()) { + if (!Bounded) + return Alloc::allocate(1); + else + return 0; + } + + freelist_node * new_pool_ptr = old_pool->next.get_ptr(); + tagged_node_ptr new_pool (new_pool_ptr, old_pool.get_tag() + 1); + + pool_.store(new_pool, memory_order_relaxed); + void * ptr = old_pool.get_ptr(); + return reinterpret_cast(ptr); + } + +protected: + template + void deallocate (T * n) + { + if (ThreadSafe) + deallocate_impl(n); + else + deallocate_impl_unsafe(n); + } + +private: + void deallocate_impl (T * n) + { + void * node = n; + tagged_node_ptr old_pool = pool_.load(memory_order_consume); + freelist_node * new_pool_ptr = reinterpret_cast(node); + + for(;;) { + tagged_node_ptr new_pool (new_pool_ptr, old_pool.get_tag()); + new_pool->next.set_ptr(old_pool.get_ptr()); + + if (pool_.compare_exchange_weak(old_pool, new_pool)) + return; + } + } + + void deallocate_impl_unsafe (T * n) + { + void * node = n; + tagged_node_ptr old_pool = pool_.load(memory_order_relaxed); + freelist_node * new_pool_ptr = reinterpret_cast(node); + + tagged_node_ptr new_pool (new_pool_ptr, old_pool.get_tag()); + new_pool->next.set_ptr(old_pool.get_ptr()); + + pool_.store(new_pool, memory_order_relaxed); + } + + atomic pool_; +}; + +class tagged_index +{ +public: + typedef boost::uint16_t tag_t; + typedef boost::uint16_t index_t; + + /** uninitialized constructor */ + tagged_index(void) BOOST_NOEXCEPT //: index(0), tag(0) + {} + + /** copy constructor */ +#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + tagged_index(tagged_index const & rhs): + index(rhs.index), tag(rhs.tag) + {} +#else + tagged_index(tagged_index const & rhs) = default; +#endif + + explicit tagged_index(index_t i, tag_t t = 0): + index(i), tag(t) + {} + + /** index access */ + /* @{ */ + index_t get_index() const + { + return index; + } + + void set_index(index_t i) + { + index = i; + } + /* @} */ + + /** tag access */ + /* @{ */ + tag_t get_tag() const + { + return tag; + } + + void set_tag(tag_t t) + { + tag = t; + } + /* @} */ + + bool operator==(tagged_index const & rhs) const + { + return (index == rhs.index) && (tag == rhs.tag); + } + +protected: + index_t index; + tag_t tag; +}; + +template +struct compiletime_sized_freelist_storage +{ + // array-based freelists only support a 16bit address space. + BOOST_STATIC_ASSERT(size < 65536); + + boost::array data; + + // unused ... only for API purposes + template + compiletime_sized_freelist_storage(Allocator const & alloc, std::size_t count) + {} + + T * nodes(void) const + { + return reinterpret_cast(const_cast(data.data())); + } + + std::size_t node_count(void) const + { + return size; + } +}; + +template > +struct runtime_sized_freelist_storage: + Alloc +{ + T * nodes_; + std::size_t node_count_; + + template + runtime_sized_freelist_storage(Allocator const & alloc, std::size_t count): + Alloc(alloc), node_count_(count) + { + if (count > 65535) + boost::throw_exception(std::runtime_error("boost.lockfree: freelist size is limited to a maximum of 65535 objects")); + nodes_ = Alloc::allocate(count); + } + + ~runtime_sized_freelist_storage(void) + { + Alloc::deallocate(nodes_, node_count_); + } + + T * nodes(void) const + { + return nodes_; + } + + std::size_t node_count(void) const + { + return node_count_; + } +}; + + +template + > +class fixed_size_freelist: + NodeStorage +{ + struct freelist_node + { + tagged_index next; + }; + + typedef tagged_index::index_t index_t; + + void initialize(void) + { + T * nodes = NodeStorage::nodes(); + for (std::size_t i = 0; i != NodeStorage::node_count(); ++i) { + tagged_index * next_index = reinterpret_cast(nodes + i); + next_index->set_index(null_handle()); + +#ifdef BOOST_LOCKFREE_FREELIST_INIT_RUNS_DTOR + destruct(nodes + i); +#else + deallocate(static_cast(i)); +#endif + } + } + +public: + typedef tagged_index tagged_node_handle; + + template + fixed_size_freelist (Allocator const & alloc, std::size_t count): + NodeStorage(alloc, count), + pool_(tagged_index(static_cast(count), 0)) + { + initialize(); + } + + fixed_size_freelist (void): + pool_(tagged_index(NodeStorage::node_count(), 0)) + { + initialize(); + } + + template + T * construct (void) + { + index_t node_index = allocate(); + if (node_index == null_handle()) + return NULL; + + T * node = NodeStorage::nodes() + node_index; + new(node) T(); + return node; + } + + template + T * construct (ArgumentType const & arg) + { + index_t node_index = allocate(); + if (node_index == null_handle()) + return NULL; + + T * node = NodeStorage::nodes() + node_index; + new(node) T(arg); + return node; + } + + template + T * construct (ArgumentType1 const & arg1, ArgumentType2 const & arg2) + { + index_t node_index = allocate(); + if (node_index == null_handle()) + return NULL; + + T * node = NodeStorage::nodes() + node_index; + new(node) T(arg1, arg2); + return node; + } + + template + void destruct (tagged_node_handle tagged_index) + { + index_t index = tagged_index.get_index(); + T * n = NodeStorage::nodes() + index; + n->~T(); + deallocate(index); + } + + template + void destruct (T * n) + { + n->~T(); + deallocate(n - NodeStorage::nodes()); + } + + bool is_lock_free(void) const + { + return pool_.is_lock_free(); + } + + index_t null_handle(void) const + { + return static_cast(NodeStorage::node_count()); + } + + index_t get_handle(T * pointer) const + { + if (pointer == NULL) + return null_handle(); + else + return static_cast(pointer - NodeStorage::nodes()); + } + + index_t get_handle(tagged_node_handle const & handle) const + { + return handle.get_index(); + } + + T * get_pointer(tagged_node_handle const & tptr) const + { + return get_pointer(tptr.get_index()); + } + + T * get_pointer(index_t index) const + { + if (index == null_handle()) + return 0; + else + return NodeStorage::nodes() + index; + } + + T * get_pointer(T * ptr) const + { + return ptr; + } + +protected: // allow use from subclasses + template + index_t allocate (void) + { + if (ThreadSafe) + return allocate_impl(); + else + return allocate_impl_unsafe(); + } + +private: + index_t allocate_impl (void) + { + tagged_index old_pool = pool_.load(memory_order_consume); + + for(;;) { + index_t index = old_pool.get_index(); + if (index == null_handle()) + return index; + + T * old_node = NodeStorage::nodes() + index; + tagged_index * next_index = reinterpret_cast(old_node); + + tagged_index new_pool(next_index->get_index(), old_pool.get_tag() + 1); + + if (pool_.compare_exchange_weak(old_pool, new_pool)) + return old_pool.get_index(); + } + } + + index_t allocate_impl_unsafe (void) + { + tagged_index old_pool = pool_.load(memory_order_consume); + + index_t index = old_pool.get_index(); + if (index == null_handle()) + return index; + + T * old_node = NodeStorage::nodes() + index; + tagged_index * next_index = reinterpret_cast(old_node); + + tagged_index new_pool(next_index->get_index(), old_pool.get_tag() + 1); + + pool_.store(new_pool, memory_order_relaxed); + return old_pool.get_index(); + } + + template + void deallocate (index_t index) + { + if (ThreadSafe) + deallocate_impl(index); + else + deallocate_impl_unsafe(index); + } + + void deallocate_impl (index_t index) + { + freelist_node * new_pool_node = reinterpret_cast(NodeStorage::nodes() + index); + tagged_index old_pool = pool_.load(memory_order_consume); + + for(;;) { + tagged_index new_pool (index, old_pool.get_tag()); + new_pool_node->next.set_index(old_pool.get_index()); + + if (pool_.compare_exchange_weak(old_pool, new_pool)) + return; + } + } + + void deallocate_impl_unsafe (index_t index) + { + freelist_node * new_pool_node = reinterpret_cast(NodeStorage::nodes() + index); + tagged_index old_pool = pool_.load(memory_order_consume); + + tagged_index new_pool (index, old_pool.get_tag()); + new_pool_node->next.set_index(old_pool.get_index()); + + pool_.store(new_pool); + } + + atomic pool_; +}; + +template +struct select_freelist +{ + typedef typename mpl::if_c, + runtime_sized_freelist_storage + >::type fixed_sized_storage_type; + + typedef typename mpl::if_c, + freelist_stack + >::type type; +}; + +template +struct select_tagged_handle +{ + typedef typename mpl::if_c, + tagged_index + >::type tagged_handle_type; + + typedef typename mpl::if_c::type handle_type; +}; + + +} /* namespace detail */ +} /* namespace lockfree */ +} /* namespace boost */ + +#endif /* BOOST_LOCKFREE_FREELIST_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/detail/parameter.hpp b/cpp/BoostParts/boost/lockfree/detail/parameter.hpp new file mode 100644 index 00000000..2e2b068b --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/parameter.hpp @@ -0,0 +1,73 @@ +// boost lockfree +// +// Copyright (C) 2011 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_DETAIL_PARAMETER_HPP +#define BOOST_LOCKFREE_DETAIL_PARAMETER_HPP + +#include + +namespace boost { +namespace lockfree { +namespace detail { + +namespace mpl = boost::mpl; + +template +struct has_arg +{ + typedef typename parameter::binding::type type; + static const bool value = mpl::is_not_void_::type::value; +}; + + +template +struct extract_capacity +{ + static const bool has_capacity = has_arg::value; + + typedef typename mpl::if_c::type, + mpl::size_t< 0 > + >::type capacity_t; + + static const std::size_t capacity = capacity_t::value; +}; + + +template +struct extract_allocator +{ + static const bool has_allocator = has_arg::value; + + typedef typename mpl::if_c::type, + std::allocator + >::type allocator_arg; + + typedef typename allocator_arg::template rebind::other type; +}; + +template +struct extract_fixed_sized +{ + static const bool has_fixed_sized = has_arg::value; + + typedef typename mpl::if_c::type, + mpl::bool_ + >::type type; + + static const bool value = type::value; +}; + + +} /* namespace detail */ +} /* namespace lockfree */ +} /* namespace boost */ + +#endif /* BOOST_LOCKFREE_DETAIL_PARAMETER_HPP */ diff --git a/cpp/BoostParts/boost/lockfree/detail/prefix.hpp b/cpp/BoostParts/boost/lockfree/detail/prefix.hpp new file mode 100644 index 00000000..6ed9446c --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/prefix.hpp @@ -0,0 +1,56 @@ +// Copyright (C) 2009 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_PREFIX_HPP_INCLUDED +#define BOOST_LOCKFREE_PREFIX_HPP_INCLUDED + +/* this file defines the following macros: + BOOST_LOCKFREE_CACHELINE_BYTES: size of a cache line + BOOST_LOCKFREE_PTR_COMPRESSION: use tag/pointer compression to utilize parts + of the virtual address space as tag (at least 16bit) + BOOST_LOCKFREE_DCAS_ALIGNMENT: symbol used for aligning structs at cache line + boundaries +*/ + +#define BOOST_LOCKFREE_CACHELINE_BYTES 64 + +#ifdef _MSC_VER + +#define BOOST_LOCKFREE_CACHELINE_ALIGNMENT __declspec(align(BOOST_LOCKFREE_CACHELINE_BYTES)) + +#if defined(_M_IX86) + #define BOOST_LOCKFREE_DCAS_ALIGNMENT +#elif defined(_M_X64) || defined(_M_IA64) + #define BOOST_LOCKFREE_PTR_COMPRESSION 1 + #define BOOST_LOCKFREE_DCAS_ALIGNMENT __declspec(align(16)) +#endif + +#endif /* _MSC_VER */ + +#ifdef __GNUC__ + +#define BOOST_LOCKFREE_CACHELINE_ALIGNMENT __attribute__((aligned(BOOST_LOCKFREE_CACHELINE_BYTES))) + +#if defined(__i386__) || defined(__ppc__) + #define BOOST_LOCKFREE_DCAS_ALIGNMENT +#elif defined(__x86_64__) + #define BOOST_LOCKFREE_PTR_COMPRESSION 1 + #define BOOST_LOCKFREE_DCAS_ALIGNMENT __attribute__((aligned(16))) +#elif defined(__alpha__) + // LATER: alpha may benefit from pointer compression. but what is the maximum size of the address space? + #define BOOST_LOCKFREE_DCAS_ALIGNMENT +#endif +#endif /* __GNUC__ */ + +#ifndef BOOST_LOCKFREE_DCAS_ALIGNMENT +#define BOOST_LOCKFREE_DCAS_ALIGNMENT /*BOOST_LOCKFREE_DCAS_ALIGNMENT*/ +#endif + +#ifndef BOOST_LOCKFREE_CACHELINE_ALIGNMENT +#define BOOST_LOCKFREE_CACHELINE_ALIGNMENT /*BOOST_LOCKFREE_CACHELINE_ALIGNMENT*/ +#endif + +#endif /* BOOST_LOCKFREE_PREFIX_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/detail/tagged_ptr.hpp b/cpp/BoostParts/boost/lockfree/detail/tagged_ptr.hpp new file mode 100644 index 00000000..f70a2c75 --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/tagged_ptr.hpp @@ -0,0 +1,21 @@ +// tagged pointer, for aba prevention +// +// Copyright (C) 2008 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_TAGGED_PTR_HPP_INCLUDED +#define BOOST_LOCKFREE_TAGGED_PTR_HPP_INCLUDED + +#include +#include + +#ifndef BOOST_LOCKFREE_PTR_COMPRESSION +#include +#else +#include +#endif + +#endif /* BOOST_LOCKFREE_TAGGED_PTR_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/detail/tagged_ptr_dcas.hpp b/cpp/BoostParts/boost/lockfree/detail/tagged_ptr_dcas.hpp new file mode 100644 index 00000000..ca6a3218 --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/tagged_ptr_dcas.hpp @@ -0,0 +1,127 @@ +// tagged pointer, for aba prevention +// +// Copyright (C) 2008 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_TAGGED_PTR_DCAS_HPP_INCLUDED +#define BOOST_LOCKFREE_TAGGED_PTR_DCAS_HPP_INCLUDED + +#include + +#include /* for std::size_t */ + +namespace boost { +namespace lockfree { +namespace detail { + +template +class BOOST_LOCKFREE_DCAS_ALIGNMENT tagged_ptr +{ +public: + typedef std::size_t tag_t; + + /** uninitialized constructor */ + tagged_ptr(void) BOOST_NOEXCEPT//: ptr(0), tag(0) + {} + +#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + tagged_ptr(tagged_ptr const & p): + ptr(p.ptr), tag(p.tag) + {} +#else + tagged_ptr(tagged_ptr const & p) = default; +#endif + + explicit tagged_ptr(T * p, tag_t t = 0): + ptr(p), tag(t) + {} + + /** unsafe set operation */ + /* @{ */ +#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + tagged_ptr & operator= (tagged_ptr const & p) + { + set(p.ptr, p.tag); + return *this; + } +#else + tagged_ptr & operator= (tagged_ptr const & p) = default; +#endif + + void set(T * p, tag_t t) + { + ptr = p; + tag = t; + } + /* @} */ + + /** comparing semantics */ + /* @{ */ + bool operator== (volatile tagged_ptr const & p) const + { + return (ptr == p.ptr) && (tag == p.tag); + } + + bool operator!= (volatile tagged_ptr const & p) const + { + return !operator==(p); + } + /* @} */ + + /** pointer access */ + /* @{ */ + T * get_ptr(void) const volatile + { + return ptr; + } + + void set_ptr(T * p) volatile + { + ptr = p; + } + /* @} */ + + /** tag access */ + /* @{ */ + tag_t get_tag() const volatile + { + return tag; + } + + void set_tag(tag_t t) volatile + { + tag = t; + } + /* @} */ + + /** smart pointer support */ + /* @{ */ + T & operator*() const + { + return *ptr; + } + + T * operator->() const + { + return ptr; + } + + operator bool(void) const + { + return ptr != 0; + } + /* @} */ + +protected: + T * ptr; + tag_t tag; +}; + +} /* namespace detail */ +} /* namespace lockfree */ +} /* namespace boost */ + +#endif /* BOOST_LOCKFREE_TAGGED_PTR_DCAS_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/detail/tagged_ptr_ptrcompression.hpp b/cpp/BoostParts/boost/lockfree/detail/tagged_ptr_ptrcompression.hpp new file mode 100644 index 00000000..8f71bc0b --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/detail/tagged_ptr_ptrcompression.hpp @@ -0,0 +1,168 @@ +// tagged pointer, for aba prevention +// +// Copyright (C) 2008, 2009 Tim Blechmann, based on code by Cory Nelson +// +// Distributed under the 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_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED +#define BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED + +#include + +#include /* for std::size_t */ + +#include + +namespace boost { +namespace lockfree { +namespace detail { + +#if defined (__x86_64__) || defined (_M_X64) + +template +class tagged_ptr +{ + typedef boost::uint64_t compressed_ptr_t; + +public: + typedef boost::uint16_t tag_t; + +private: + union cast_unit + { + compressed_ptr_t value; + tag_t tag[4]; + }; + + static const int tag_index = 3; + static const compressed_ptr_t ptr_mask = 0xffffffffffffUL; //(1L<<48L)-1; + + static T* extract_ptr(volatile compressed_ptr_t const & i) + { + return (T*)(i & ptr_mask); + } + + static tag_t extract_tag(volatile compressed_ptr_t const & i) + { + cast_unit cu; + cu.value = i; + return cu.tag[tag_index]; + } + + static compressed_ptr_t pack_ptr(T * ptr, int tag) + { + cast_unit ret; + ret.value = compressed_ptr_t(ptr); + ret.tag[tag_index] = tag; + return ret.value; + } + +public: + /** uninitialized constructor */ + tagged_ptr(void) BOOST_NOEXCEPT//: ptr(0), tag(0) + {} + + /** copy constructor */ +#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + tagged_ptr(tagged_ptr const & p): + ptr(p.ptr) + {} +#else + tagged_ptr(tagged_ptr const & p) = default; +#endif + + explicit tagged_ptr(T * p, tag_t t = 0): + ptr(pack_ptr(p, t)) + {} + + /** unsafe set operation */ + /* @{ */ +#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + tagged_ptr & operator= (tagged_ptr const & p) + { + ptr = p.ptr; + return *this; + } +#else + tagged_ptr & operator= (tagged_ptr const & p) = default; +#endif + + void set(T * p, tag_t t) + { + ptr = pack_ptr(p, t); + } + /* @} */ + + /** comparing semantics */ + /* @{ */ + bool operator== (volatile tagged_ptr const & p) const + { + return (ptr == p.ptr); + } + + bool operator!= (volatile tagged_ptr const & p) const + { + return !operator==(p); + } + /* @} */ + + /** pointer access */ + /* @{ */ + T * get_ptr() const volatile + { + return extract_ptr(ptr); + } + + void set_ptr(T * p) volatile + { + tag_t tag = get_tag(); + ptr = pack_ptr(p, tag); + } + /* @} */ + + /** tag access */ + /* @{ */ + tag_t get_tag() const volatile + { + return extract_tag(ptr); + } + + void set_tag(tag_t t) volatile + { + T * p = get_ptr(); + ptr = pack_ptr(p, t); + } + /* @} */ + + /** smart pointer support */ + /* @{ */ + T & operator*() const + { + return *get_ptr(); + } + + T * operator->() const + { + return get_ptr(); + } + + operator bool(void) const + { + return get_ptr() != 0; + } + /* @} */ + +protected: + compressed_ptr_t ptr; +}; +#else +#error unsupported platform +#endif + +} /* namespace detail */ +} /* namespace lockfree */ +} /* namespace boost */ + +#endif /* BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/policies.hpp b/cpp/BoostParts/boost/lockfree/policies.hpp new file mode 100644 index 00000000..cec9b57f --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/policies.hpp @@ -0,0 +1,59 @@ +// boost lockfree +// +// Copyright (C) 2011 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_POLICIES_HPP_INCLUDED +#define BOOST_LOCKFREE_POLICIES_HPP_INCLUDED + +#include +#include +#include +#include + +namespace boost { +namespace lockfree { + +#ifndef BOOST_DOXYGEN_INVOKED +namespace tag { struct allocator ; } +namespace tag { struct fixed_sized; } +namespace tag { struct capacity; } + +#endif + +/** Configures a data structure as \b fixed-sized. + * + * The internal nodes are stored inside an array and they are addressed by array indexing. This limits the possible size of the + * queue to the number of elements that can be addressed by the index type (usually 2**16-2), but on platforms that lack + * double-width compare-and-exchange instructions, this is the best way to achieve lock-freedom. + * This implies that a data structure is bounded. + * */ +template +struct fixed_sized: + boost::parameter::template_keyword > +{}; + +/** Sets the \b capacity of a data structure at compile-time. + * + * This implies that a data structure is bounded and fixed-sized. + * */ +template +struct capacity: + boost::parameter::template_keyword > +{}; + +/** Defines the \b allocator type of a data structure. + * */ +template +struct allocator: + boost::parameter::template_keyword +{}; + +} +} + +#endif /* BOOST_LOCKFREE_POLICIES_HPP_INCLUDED */ + diff --git a/cpp/BoostParts/boost/lockfree/queue.hpp b/cpp/BoostParts/boost/lockfree/queue.hpp new file mode 100644 index 00000000..f95fb032 --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/queue.hpp @@ -0,0 +1,476 @@ +// lock-free queue from +// Michael, M. M. and Scott, M. L., +// "simple, fast and practical non-blocking and blocking concurrent queue algorithms" +// +// Copyright (C) 2008, 2009, 2010, 2011 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_FIFO_HPP_INCLUDED +#define BOOST_LOCKFREE_FIFO_HPP_INCLUDED + +#include /* std::auto_ptr */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace boost { +namespace lockfree { +namespace detail { + +typedef parameter::parameters, + boost::parameter::optional + > queue_signature; + +} /* namespace detail */ + + +/** The queue class provides a multi-writer/multi-reader queue, pushing and popping is lock-free, + * construction/destruction has to be synchronized. It uses a freelist for memory management, + * freed nodes are pushed to the freelist and not returned to the OS before the queue is destroyed. + * + * \b Policies: + * - \ref boost::lockfree::fixed_sized, defaults to \c boost::lockfree::fixed_sized \n + * Can be used to completely disable dynamic memory allocations during push in order to ensure lockfree behavior. \n + * If the data structure is configured as fixed-sized, the internal nodes are stored inside an array and they are addressed + * by array indexing. This limits the possible size of the queue to the number of elements that can be addressed by the index + * type (usually 2**16-2), but on platforms that lack double-width compare-and-exchange instructions, this is the best way + * to achieve lock-freedom. + * + * - \ref boost::lockfree::capacity, optional \n + * If this template argument is passed to the options, the size of the queue is set at compile-time.\n + * It this option implies \c fixed_sized + * + * - \ref boost::lockfree::allocator, defaults to \c boost::lockfree::allocator> \n + * Specifies the allocator that is used for the internal freelist + * + * \b Requirements: + * - T must have a copy constructor + * - T must have a trivial assignment operator + * - T must have a trivial destructor + * + * */ +#ifndef BOOST_DOXYGEN_INVOKED +template +#else +template +#endif +class queue: + boost::noncopyable +{ +private: +#ifndef BOOST_DOXYGEN_INVOKED + +#ifdef BOOST_HAS_TRIVIAL_DESTRUCTOR + BOOST_STATIC_ASSERT((boost::has_trivial_destructor::value)); +#endif + +#ifdef BOOST_HAS_TRIVIAL_ASSIGN + BOOST_STATIC_ASSERT((boost::has_trivial_assign::value)); +#endif + + typedef typename detail::queue_signature::bind::type bound_args; + + static const bool has_capacity = detail::extract_capacity::has_capacity; + static const size_t capacity = detail::extract_capacity::capacity; + static const bool fixed_sized = detail::extract_fixed_sized::value; + static const bool node_based = !(has_capacity || fixed_sized); + static const bool compile_time_sized = has_capacity; + + struct BOOST_LOCKFREE_CACHELINE_ALIGNMENT node + { + typedef typename detail::select_tagged_handle::tagged_handle_type tagged_node_handle; + typedef typename detail::select_tagged_handle::handle_type handle_type; + + node(T const & v, handle_type null_handle): + data(v)//, next(tagged_node_handle(0, 0)) + { + /* increment tag to avoid ABA problem */ + tagged_node_handle old_next = next.load(memory_order_relaxed); + tagged_node_handle new_next (null_handle, old_next.get_tag()+1); + next.store(new_next, memory_order_release); + } + + node (handle_type null_handle): + next(tagged_node_handle(null_handle, 0)) + {} + + node(void) + {} + + atomic next; + T data; + }; + + typedef typename detail::extract_allocator::type node_allocator; + typedef typename detail::select_freelist::type pool_t; + typedef typename pool_t::tagged_node_handle tagged_node_handle; + typedef typename detail::select_tagged_handle::handle_type handle_type; + + void initialize(void) + { + node * n = pool.template construct(pool.null_handle()); + tagged_node_handle dummy_node(pool.get_handle(n), 0); + head_.store(dummy_node, memory_order_relaxed); + tail_.store(dummy_node, memory_order_release); + } + + struct implementation_defined + { + typedef node_allocator allocator; + typedef std::size_t size_type; + }; + +#endif + +public: + typedef T value_type; + typedef typename implementation_defined::allocator allocator; + typedef typename implementation_defined::size_type size_type; + + /** + * \return true, if implementation is lock-free. + * + * \warning It only checks, if the queue head and tail nodes and the freelist can be modified in a lock-free manner. + * On most platforms, the whole implementation is lock-free, if this is true. Using c++0x-style atomics, there is + * no possibility to provide a completely accurate implementation, because one would need to test every internal + * node, which is impossible if further nodes will be allocated from the operating system. + * */ + bool is_lock_free (void) const + { + return head_.is_lock_free() && tail_.is_lock_free() && pool.is_lock_free(); + } + + //! Construct queue + // @{ + queue(void): + head_(tagged_node_handle(0, 0)), + tail_(tagged_node_handle(0, 0)), + pool(node_allocator(), capacity) + { + BOOST_ASSERT(has_capacity); + initialize(); + } + + template + explicit queue(typename node_allocator::template rebind::other const & alloc): + head_(tagged_node_handle(0, 0)), + tail_(tagged_node_handle(0, 0)), + pool(alloc, capacity) + { + BOOST_STATIC_ASSERT(has_capacity); + initialize(); + } + + explicit queue(allocator const & alloc): + head_(tagged_node_handle(0, 0)), + tail_(tagged_node_handle(0, 0)), + pool(alloc, capacity) + { + BOOST_ASSERT(has_capacity); + initialize(); + } + // @} + + //! Construct queue, allocate n nodes for the freelist. + // @{ + explicit queue(size_type n): + head_(tagged_node_handle(0, 0)), + tail_(tagged_node_handle(0, 0)), + pool(node_allocator(), n + 1) + { + BOOST_ASSERT(!has_capacity); + initialize(); + } + + template + queue(size_type n, typename node_allocator::template rebind::other const & alloc): + head_(tagged_node_handle(0, 0)), + tail_(tagged_node_handle(0, 0)), + pool(alloc, n + 1) + { + BOOST_STATIC_ASSERT(!has_capacity); + initialize(); + } + // @} + + /** \copydoc boost::lockfree::stack::reserve + * */ + void reserve(size_type n) + { + pool.template reserve(n); + } + + /** \copydoc boost::lockfree::stack::reserve_unsafe + * */ + void reserve_unsafe(size_type n) + { + pool.template reserve(n); + } + + /** Destroys queue, free all nodes from freelist. + * */ + ~queue(void) + { + T dummy; + while(unsynchronized_pop(dummy)) + {} + + pool.template destruct(head_.load(memory_order_relaxed)); + } + + /** Check if the queue is empty + * + * \return true, if the queue is empty, false otherwise + * \note The result is only accurate, if no other thread modifies the queue. Therefore it is rarely practical to use this + * value in program logic. + * */ + bool empty(void) + { + return pool.get_handle(head_.load()) == pool.get_handle(tail_.load()); + } + + /** Pushes object t to the queue. + * + * \post object will be pushed to the queue, if internal node can be allocated + * \returns true, if the push operation is successful. + * + * \note Thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will be allocated + * from the OS. This may not be lock-free. + * */ + bool push(T const & t) + { + return do_push(t); + } + + /** Pushes object t to the queue. + * + * \post object will be pushed to the queue, if internal node can be allocated + * \returns true, if the push operation is successful. + * + * \note Thread-safe and non-blocking. If internal memory pool is exhausted, operation will fail + * \throws if memory allocator throws + * */ + bool bounded_push(T const & t) + { + return do_push(t); + } + + +private: +#ifndef BOOST_DOXYGEN_INVOKED + template + bool do_push(T const & t) + { + using detail::likely; + + node * n = pool.template construct(t, pool.null_handle()); + handle_type node_handle = pool.get_handle(n); + + if (n == NULL) + return false; + + for (;;) { + tagged_node_handle tail = tail_.load(memory_order_acquire); + node * tail_node = pool.get_pointer(tail); + tagged_node_handle next = tail_node->next.load(memory_order_acquire); + node * next_ptr = pool.get_pointer(next); + + tagged_node_handle tail2 = tail_.load(memory_order_acquire); + if (likely(tail == tail2)) { + if (next_ptr == 0) { + tagged_node_handle new_tail_next(node_handle, next.get_tag() + 1); + if ( tail_node->next.compare_exchange_weak(next, new_tail_next) ) { + tagged_node_handle new_tail(node_handle, tail.get_tag() + 1); + tail_.compare_exchange_strong(tail, new_tail); + return true; + } + } + else { + tagged_node_handle new_tail(pool.get_handle(next_ptr), tail.get_tag() + 1); + tail_.compare_exchange_strong(tail, new_tail); + } + } + } + } +#endif + +public: + + /** Pushes object t to the queue. + * + * \post object will be pushed to the queue, if internal node can be allocated + * \returns true, if the push operation is successful. + * + * \note Not Thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will be allocated + * from the OS. This may not be lock-free. + * \throws if memory allocator throws + * */ + bool unsynchronized_push(T const & t) + { + node * n = pool.template construct(t, pool.null_handle()); + + if (n == NULL) + return false; + + for (;;) { + tagged_node_handle tail = tail_.load(memory_order_relaxed); + tagged_node_handle next = tail->next.load(memory_order_relaxed); + node * next_ptr = next.get_ptr(); + + if (next_ptr == 0) { + tail->next.store(tagged_node_handle(n, next.get_tag() + 1), memory_order_relaxed); + tail_.store(tagged_node_handle(n, tail.get_tag() + 1), memory_order_relaxed); + return true; + } + else + tail_.store(tagged_node_handle(next_ptr, tail.get_tag() + 1), memory_order_relaxed); + } + } + + /** Pops object from queue. + * + * \post if pop operation is successful, object will be copied to ret. + * \returns true, if the pop operation is successful, false if queue was empty. + * + * \note Thread-safe and non-blocking + * */ + bool pop (T & ret) + { + return pop(ret); + } + + /** Pops object from queue. + * + * \pre type U must be constructible by T and copyable, or T must be convertible to U + * \post if pop operation is successful, object will be copied to ret. + * \returns true, if the pop operation is successful, false if queue was empty. + * + * \note Thread-safe and non-blocking + * */ + template + bool pop (U & ret) + { + using detail::likely; + for (;;) { + tagged_node_handle head = head_.load(memory_order_acquire); + node * head_ptr = pool.get_pointer(head); + + tagged_node_handle tail = tail_.load(memory_order_acquire); + tagged_node_handle next = head_ptr->next.load(memory_order_acquire); + node * next_ptr = pool.get_pointer(next); + + tagged_node_handle head2 = head_.load(memory_order_acquire); + if (likely(head == head2)) { + if (pool.get_handle(head) == pool.get_handle(tail)) { + if (next_ptr == 0) + return false; + + tagged_node_handle new_tail(pool.get_handle(next), tail.get_tag() + 1); + tail_.compare_exchange_strong(tail, new_tail); + + } else { + if (next_ptr == 0) + /* this check is not part of the original algorithm as published by michael and scott + * + * however we reuse the tagged_ptr part for the freelist and clear the next part during node + * allocation. we can observe a null-pointer here. + * */ + continue; + detail::copy_payload(next_ptr->data, ret); + + tagged_node_handle new_head(pool.get_handle(next), head.get_tag() + 1); + if (head_.compare_exchange_weak(head, new_head)) { + pool.template destruct(head); + return true; + } + } + } + } + } + + /** Pops object from queue. + * + * \post if pop operation is successful, object will be copied to ret. + * \returns true, if the pop operation is successful, false if queue was empty. + * + * \note Not thread-safe, but non-blocking + * + * */ + bool unsynchronized_pop (T & ret) + { + return unsynchronized_pop(ret); + } + + /** Pops object from queue. + * + * \pre type U must be constructible by T and copyable, or T must be convertible to U + * \post if pop operation is successful, object will be copied to ret. + * \returns true, if the pop operation is successful, false if queue was empty. + * + * \note Not thread-safe, but non-blocking + * + * */ + template + bool unsynchronized_pop (U & ret) + { + for (;;) { + tagged_node_handle head = head_.load(memory_order_relaxed); + node * head_ptr = pool.get_pointer(head); + tagged_node_handle tail = tail_.load(memory_order_relaxed); + tagged_node_handle next = head_ptr->next.load(memory_order_relaxed); + node * next_ptr = pool.get_pointer(next); + + if (pool.get_handle(head) == pool.get_handle(tail)) { + if (next_ptr == 0) + return false; + + tagged_node_handle new_tail(pool.get_handle(next), tail.get_tag() + 1); + tail_.store(new_tail); + } else { + if (next_ptr == 0) + /* this check is not part of the original algorithm as published by michael and scott + * + * however we reuse the tagged_ptr part for the freelist and clear the next part during node + * allocation. we can observe a null-pointer here. + * */ + continue; + detail::copy_payload(next_ptr->data, ret); + tagged_node_handle new_head(pool.get_handle(next), head.get_tag() + 1); + head_.store(new_head); + pool.template destruct(head); + return true; + } + } + } + +private: +#ifndef BOOST_DOXYGEN_INVOKED + atomic head_; + static const int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof(tagged_node_handle); + char padding1[padding_size]; + atomic tail_; + char padding2[padding_size]; + + pool_t pool; +#endif +}; + +} /* namespace lockfree */ +} /* namespace boost */ + +#endif /* BOOST_LOCKFREE_FIFO_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/spsc_queue.hpp b/cpp/BoostParts/boost/lockfree/spsc_queue.hpp new file mode 100644 index 00000000..641e0a44 --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/spsc_queue.hpp @@ -0,0 +1,650 @@ +// lock-free single-producer/single-consumer ringbuffer +// this algorithm is implemented in various projects (linux kernel) +// +// Copyright (C) 2009, 2011 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_SPSC_QUEUE_HPP_INCLUDED +#define BOOST_LOCKFREE_SPSC_QUEUE_HPP_INCLUDED + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace boost { +namespace lockfree { +namespace detail { + +typedef parameter::parameters, + boost::parameter::optional + > ringbuffer_signature; + +template +class ringbuffer_base: + boost::noncopyable +{ +#ifndef BOOST_DOXYGEN_INVOKED + typedef std::size_t size_t; + static const int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof(size_t); + atomic write_index_; + char padding1[padding_size]; /* force read_index and write_index to different cache lines */ + atomic read_index_; + +protected: + ringbuffer_base(void): + write_index_(0), read_index_(0) + {} + + static size_t next_index(size_t arg, size_t max_size) + { + size_t ret = arg + 1; + while (unlikely(ret >= max_size)) + ret -= max_size; + return ret; + } + + static size_t read_available(size_t write_index, size_t read_index, size_t max_size) + { + if (write_index >= read_index) + return write_index - read_index; + + size_t ret = write_index + max_size - read_index; + return ret; + } + + static size_t write_available(size_t write_index, size_t read_index, size_t max_size) + { + size_t ret = read_index - write_index - 1; + if (write_index >= read_index) + ret += max_size; + return ret; + } + + bool push(T const & t, T * buffer, size_t max_size) + { + size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread + size_t next = next_index(write_index, max_size); + + if (next == read_index_.load(memory_order_acquire)) + return false; /* ringbuffer is full */ + + buffer[write_index] = t; + + write_index_.store(next, memory_order_release); + + return true; + } + + size_t push(const T * input_buffer, size_t input_count, T * internal_buffer, size_t max_size) + { + size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread + const size_t read_index = read_index_.load(memory_order_acquire); + const size_t avail = write_available(write_index, read_index, max_size); + + if (avail == 0) + return 0; + + input_count = (std::min)(input_count, avail); + + size_t new_write_index = write_index + input_count; + + if (write_index + input_count > max_size) { + /* copy data in two sections */ + size_t count0 = max_size - write_index; + + std::copy(input_buffer, input_buffer + count0, internal_buffer + write_index); + std::copy(input_buffer + count0, input_buffer + input_count, internal_buffer); + new_write_index -= max_size; + } else { + std::copy(input_buffer, input_buffer + input_count, internal_buffer + write_index); + + if (new_write_index == max_size) + new_write_index = 0; + } + + write_index_.store(new_write_index, memory_order_release); + return input_count; + } + + template + ConstIterator push(ConstIterator begin, ConstIterator end, T * internal_buffer, size_t max_size) + { + // FIXME: avoid std::distance and std::advance + + size_t write_index = write_index_.load(memory_order_relaxed); // only written from push thread + const size_t read_index = read_index_.load(memory_order_acquire); + const size_t avail = write_available(write_index, read_index, max_size); + + if (avail == 0) + return begin; + + size_t input_count = std::distance(begin, end); + input_count = (std::min)(input_count, avail); + + size_t new_write_index = write_index + input_count; + + ConstIterator last = begin; + std::advance(last, input_count); + + if (write_index + input_count > max_size) { + /* copy data in two sections */ + size_t count0 = max_size - write_index; + ConstIterator midpoint = begin; + std::advance(midpoint, count0); + + std::copy(begin, midpoint, internal_buffer + write_index); + std::copy(midpoint, last, internal_buffer); + new_write_index -= max_size; + } else { + std::copy(begin, last, internal_buffer + write_index); + + if (new_write_index == max_size) + new_write_index = 0; + } + + write_index_.store(new_write_index, memory_order_release); + return last; + } + + bool pop (T & ret, T * buffer, size_t max_size) + { + size_t write_index = write_index_.load(memory_order_acquire); + size_t read_index = read_index_.load(memory_order_relaxed); // only written from pop thread + if (empty(write_index, read_index)) + return false; + + ret = buffer[read_index]; + size_t next = next_index(read_index, max_size); + read_index_.store(next, memory_order_release); + return true; + } + + size_t pop (T * output_buffer, size_t output_count, const T * internal_buffer, size_t max_size) + { + const size_t write_index = write_index_.load(memory_order_acquire); + size_t read_index = read_index_.load(memory_order_relaxed); // only written from pop thread + + const size_t avail = read_available(write_index, read_index, max_size); + + if (avail == 0) + return 0; + + output_count = (std::min)(output_count, avail); + + size_t new_read_index = read_index + output_count; + + if (read_index + output_count > max_size) { + /* copy data in two sections */ + size_t count0 = max_size - read_index; + size_t count1 = output_count - count0; + + std::copy(internal_buffer + read_index, internal_buffer + max_size, output_buffer); + std::copy(internal_buffer, internal_buffer + count1, output_buffer + count0); + + new_read_index -= max_size; + } else { + std::copy(internal_buffer + read_index, internal_buffer + read_index + output_count, output_buffer); + if (new_read_index == max_size) + new_read_index = 0; + } + + read_index_.store(new_read_index, memory_order_release); + return output_count; + } + + template + size_t pop (OutputIterator it, const T * internal_buffer, size_t max_size) + { + const size_t write_index = write_index_.load(memory_order_acquire); + size_t read_index = read_index_.load(memory_order_relaxed); // only written from pop thread + + const size_t avail = read_available(write_index, read_index, max_size); + if (avail == 0) + return 0; + + size_t new_read_index = read_index + avail; + + if (read_index + avail > max_size) { + /* copy data in two sections */ + size_t count0 = max_size - read_index; + size_t count1 = avail - count0; + + std::copy(internal_buffer + read_index, internal_buffer + max_size, it); + std::copy(internal_buffer, internal_buffer + count1, it); + + new_read_index -= max_size; + } else { + std::copy(internal_buffer + read_index, internal_buffer + read_index + avail, it); + if (new_read_index == max_size) + new_read_index = 0; + } + + read_index_.store(new_read_index, memory_order_release); + return avail; + } +#endif + + +public: + /** reset the ringbuffer + * + * \note Not thread-safe + * */ + void reset(void) + { + write_index_.store(0, memory_order_relaxed); + read_index_.store(0, memory_order_release); + } + + /** Check if the ringbuffer is empty + * + * \return true, if the ringbuffer is empty, false otherwise + * \note Due to the concurrent nature of the ringbuffer the result may be inaccurate. + * */ + bool empty(void) + { + return empty(write_index_.load(memory_order_relaxed), read_index_.load(memory_order_relaxed)); + } + + /** + * \return true, if implementation is lock-free. + * + * */ + bool is_lock_free(void) const + { + return write_index_.is_lock_free() && read_index_.is_lock_free(); + } + +private: + bool empty(size_t write_index, size_t read_index) + { + return write_index == read_index; + } +}; + +template +class compile_time_sized_ringbuffer: + public ringbuffer_base +{ + typedef std::size_t size_t; + boost::array array_; + +public: + bool push(T const & t) + { + return ringbuffer_base::push(t, array_.c_array(), max_size); + } + + bool pop(T & ret) + { + return ringbuffer_base::pop(ret, array_.c_array(), max_size); + } + + size_t push(T const * t, size_t size) + { + return ringbuffer_base::push(t, size, array_.c_array(), max_size); + } + + template + size_t push(T const (&t)[size]) + { + return push(t, size); + } + + template + ConstIterator push(ConstIterator begin, ConstIterator end) + { + return ringbuffer_base::push(begin, end, array_.c_array(), max_size); + } + + size_t pop(T * ret, size_t size) + { + return ringbuffer_base::pop(ret, size, array_.c_array(), max_size); + } + + template + size_t pop(T (&ret)[size]) + { + return pop(ret, size); + } + + template + size_t pop(OutputIterator it) + { + return ringbuffer_base::pop(it, array_.c_array(), max_size); + } +}; + +template +class runtime_sized_ringbuffer: + public ringbuffer_base, + private Alloc +{ + typedef std::size_t size_t; + size_t max_elements_; + typedef typename Alloc::pointer pointer; + pointer array_; + +public: + explicit runtime_sized_ringbuffer(size_t max_elements): + max_elements_(max_elements) + { + // TODO: we don't necessarily need to construct all elements + array_ = Alloc::allocate(max_elements); + for (size_t i = 0; i != max_elements; ++i) + Alloc::construct(array_ + i, T()); + } + + template + runtime_sized_ringbuffer(typename Alloc::template rebind::other const & alloc, size_t max_elements): + Alloc(alloc), max_elements_(max_elements) + { + // TODO: we don't necessarily need to construct all elements + array_ = Alloc::allocate(max_elements); + for (size_t i = 0; i != max_elements; ++i) + Alloc::construct(array_ + i, T()); + } + + runtime_sized_ringbuffer(Alloc const & alloc, size_t max_elements): + Alloc(alloc), max_elements_(max_elements) + { + // TODO: we don't necessarily need to construct all elements + array_ = Alloc::allocate(max_elements); + for (size_t i = 0; i != max_elements; ++i) + Alloc::construct(array_ + i, T()); + } + + ~runtime_sized_ringbuffer(void) + { + for (size_t i = 0; i != max_elements_; ++i) + Alloc::destroy(array_ + i); + Alloc::deallocate(array_, max_elements_); + } + + bool push(T const & t) + { + return ringbuffer_base::push(t, &*array_, max_elements_); + } + + bool pop(T & ret) + { + return ringbuffer_base::pop(ret, &*array_, max_elements_); + } + + size_t push(T const * t, size_t size) + { + return ringbuffer_base::push(t, size, &*array_, max_elements_); + } + + template + size_t push(T const (&t)[size]) + { + return push(t, size); + } + + template + ConstIterator push(ConstIterator begin, ConstIterator end) + { + return ringbuffer_base::push(begin, end, array_, max_elements_); + } + + size_t pop(T * ret, size_t size) + { + return ringbuffer_base::pop(ret, size, array_, max_elements_); + } + + template + size_t pop(T (&ret)[size]) + { + return pop(ret, size); + } + + template + size_t pop(OutputIterator it) + { + return ringbuffer_base::pop(it, array_, max_elements_); + } +}; + +template +struct make_ringbuffer +{ + typedef typename ringbuffer_signature::bind::type bound_args; + + typedef extract_capacity extract_capacity_t; + + static const bool runtime_sized = !extract_capacity_t::has_capacity; + static const size_t capacity = extract_capacity_t::capacity; + + typedef extract_allocator extract_allocator_t; + typedef typename extract_allocator_t::type allocator; + + // allocator argument is only sane, for run-time sized ringbuffers + BOOST_STATIC_ASSERT((mpl::if_, + mpl::bool_, + mpl::true_ + >::type::value)); + + typedef typename mpl::if_c, + compile_time_sized_ringbuffer + >::type ringbuffer_type; +}; + + +} /* namespace detail */ + + +/** The spsc_queue class provides a single-writer/single-reader fifo queue, pushing and popping is wait-free. + * + * \b Policies: + * - \c boost::lockfree::capacity<>, optional
+ * If this template argument is passed to the options, the size of the ringbuffer is set at compile-time. + * + * - \c boost::lockfree::allocator<>, defaults to \c boost::lockfree::allocator>
+ * Specifies the allocator that is used to allocate the ringbuffer. This option is only valid, if the ringbuffer is configured + * to be sized at run-time + * + * \b Requirements: + * - T must have a default constructor + * - T must be copyable + * */ +#ifndef BOOST_DOXYGEN_INVOKED +template +#else +template +#endif +class spsc_queue: + public detail::make_ringbuffer::ringbuffer_type +{ +private: + +#ifndef BOOST_DOXYGEN_INVOKED + typedef typename detail::make_ringbuffer::ringbuffer_type base_type; + static const bool runtime_sized = detail::make_ringbuffer::runtime_sized; + typedef typename detail::make_ringbuffer::allocator allocator_arg; + + struct implementation_defined + { + typedef allocator_arg allocator; + typedef std::size_t size_type; + }; +#endif + +public: + typedef T value_type; + typedef typename implementation_defined::allocator allocator; + typedef typename implementation_defined::size_type size_type; + + /** Constructs a spsc_queue + * + * \pre spsc_queue must be configured to be sized at compile-time + */ + // @{ + spsc_queue(void) + { + BOOST_ASSERT(!runtime_sized); + } + + template + explicit spsc_queue(typename allocator::template rebind::other const & alloc) + { + // just for API compatibility: we don't actually need an allocator + BOOST_STATIC_ASSERT(!runtime_sized); + } + + explicit spsc_queue(allocator const & alloc) + { + // just for API compatibility: we don't actually need an allocator + BOOST_ASSERT(!runtime_sized); + } + // @} + + + /** Constructs a spsc_queue for element_count elements + * + * \pre spsc_queue must be configured to be sized at run-time + */ + // @{ + explicit spsc_queue(size_type element_count): + base_type(element_count) + { + BOOST_ASSERT(runtime_sized); + } + + template + spsc_queue(size_type element_count, typename allocator::template rebind::other const & alloc): + base_type(alloc, element_count) + { + BOOST_STATIC_ASSERT(runtime_sized); + } + + spsc_queue(size_type element_count, allocator_arg const & alloc): + base_type(alloc, element_count) + { + BOOST_ASSERT(runtime_sized); + } + // @} + + /** Pushes object t to the ringbuffer. + * + * \pre only one thread is allowed to push data to the spsc_queue + * \post object will be pushed to the spsc_queue, unless it is full. + * \return true, if the push operation is successful. + * + * \note Thread-safe and wait-free + * */ + bool push(T const & t) + { + return base_type::push(t); + } + + /** Pops one object from ringbuffer. + * + * \pre only one thread is allowed to pop data to the spsc_queue + * \post if ringbuffer is not empty, object will be copied to ret. + * \return true, if the pop operation is successful, false if ringbuffer was empty. + * + * \note Thread-safe and wait-free + */ + bool pop(T & ret) + { + return base_type::pop(ret); + } + + /** Pushes as many objects from the array t as there is space. + * + * \pre only one thread is allowed to push data to the spsc_queue + * \return number of pushed items + * + * \note Thread-safe and wait-free + */ + size_type push(T const * t, size_type size) + { + return base_type::push(t, size); + } + + /** Pushes as many objects from the array t as there is space available. + * + * \pre only one thread is allowed to push data to the spsc_queue + * \return number of pushed items + * + * \note Thread-safe and wait-free + */ + template + size_type push(T const (&t)[size]) + { + return push(t, size); + } + + /** Pushes as many objects from the range [begin, end) as there is space . + * + * \pre only one thread is allowed to push data to the spsc_queue + * \return iterator to the first element, which has not been pushed + * + * \note Thread-safe and wait-free + */ + template + ConstIterator push(ConstIterator begin, ConstIterator end) + { + return base_type::push(begin, end); + } + + /** Pops a maximum of size objects from ringbuffer. + * + * \pre only one thread is allowed to pop data to the spsc_queue + * \return number of popped items + * + * \note Thread-safe and wait-free + * */ + size_type pop(T * ret, size_type size) + { + return base_type::pop(ret, size); + } + + /** Pops a maximum of size objects from spsc_queue. + * + * \pre only one thread is allowed to pop data to the spsc_queue + * \return number of popped items + * + * \note Thread-safe and wait-free + * */ + template + size_type pop(T (&ret)[size]) + { + return pop(ret, size); + } + + /** Pops objects to the output iterator it + * + * \pre only one thread is allowed to pop data to the spsc_queue + * \return number of popped items + * + * \note Thread-safe and wait-free + * */ + template + size_type pop(OutputIterator it) + { + return base_type::pop(it); + } +}; + +} /* namespace lockfree */ +} /* namespace boost */ + + +#endif /* BOOST_LOCKFREE_SPSC_QUEUE_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/lockfree/stack.hpp b/cpp/BoostParts/boost/lockfree/stack.hpp new file mode 100644 index 00000000..8d82308f --- /dev/null +++ b/cpp/BoostParts/boost/lockfree/stack.hpp @@ -0,0 +1,512 @@ +// Copyright (C) 2008, 2009, 2010, 2011 Tim Blechmann +// +// Distributed under the 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_LOCKFREE_STACK_HPP_INCLUDED +#define BOOST_LOCKFREE_STACK_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace boost { +namespace lockfree { +namespace detail { + +typedef parameter::parameters, + boost::parameter::optional + > stack_signature; + +} + +/** The stack class provides a multi-writer/multi-reader stack, pushing and popping is lock-free, + * construction/destruction has to be synchronized. It uses a freelist for memory management, + * freed nodes are pushed to the freelist and not returned to the OS before the stack is destroyed. + * + * \b Policies: + * + * - \c boost::lockfree::fixed_sized<>, defaults to \c boost::lockfree::fixed_sized
+ * Can be used to completely disable dynamic memory allocations during push in order to ensure lockfree behavior.
+ * If the data structure is configured as fixed-sized, the internal nodes are stored inside an array and they are addressed + * by array indexing. This limits the possible size of the stack to the number of elements that can be addressed by the index + * type (usually 2**16-2), but on platforms that lack double-width compare-and-exchange instructions, this is the best way + * to achieve lock-freedom. + * + * - \c boost::lockfree::capacity<>, optional
+ * If this template argument is passed to the options, the size of the stack is set at compile-time.
+ * It this option implies \c fixed_sized + * + * - \c boost::lockfree::allocator<>, defaults to \c boost::lockfree::allocator>
+ * Specifies the allocator that is used for the internal freelist + * + * \b Requirements: + * - T must have a copy constructor + * */ +#ifndef BOOST_DOXYGEN_INVOKED +template +#else +template +#endif +class stack: + boost::noncopyable +{ +private: +#ifndef BOOST_DOXYGEN_INVOKED + BOOST_STATIC_ASSERT(boost::has_trivial_assign::value); + BOOST_STATIC_ASSERT(boost::has_trivial_destructor::value); + + typedef typename detail::stack_signature::bind::type bound_args; + + static const bool has_capacity = detail::extract_capacity::has_capacity; + static const size_t capacity = detail::extract_capacity::capacity; + static const bool fixed_sized = detail::extract_fixed_sized::value; + static const bool node_based = !(has_capacity || fixed_sized); + static const bool compile_time_sized = has_capacity; + + struct node + { + node(T const & val): + v(val) + {} + + typedef typename detail::select_tagged_handle::handle_type handle_t; + handle_t next; + const T v; + }; + + typedef typename detail::extract_allocator::type node_allocator; + typedef typename detail::select_freelist::type pool_t; + typedef typename pool_t::tagged_node_handle tagged_node_handle; + + // check compile-time capacity + BOOST_STATIC_ASSERT((mpl::if_c::const_max>, + mpl::true_ + >::type::value)); + + struct implementation_defined + { + typedef node_allocator allocator; + typedef std::size_t size_type; + }; + +#endif + +public: + typedef T value_type; + typedef typename implementation_defined::allocator allocator; + typedef typename implementation_defined::size_type size_type; + + /** + * \return true, if implementation is lock-free. + * + * \warning It only checks, if the top stack node and the freelist can be modified in a lock-free manner. + * On most platforms, the whole implementation is lock-free, if this is true. Using c++0x-style atomics, + * there is no possibility to provide a completely accurate implementation, because one would need to test + * every internal node, which is impossible if further nodes will be allocated from the operating system. + * + * */ + bool is_lock_free (void) const + { + return tos.is_lock_free() && pool.is_lock_free(); + } + + //! Construct stack + // @{ + stack(void): + pool(node_allocator(), capacity) + { + BOOST_ASSERT(has_capacity); + initialize(); + } + + template + explicit stack(typename node_allocator::template rebind::other const & alloc): + pool(alloc, capacity) + { + BOOST_STATIC_ASSERT(has_capacity); + initialize(); + } + + explicit stack(allocator const & alloc): + pool(alloc, capacity) + { + BOOST_ASSERT(has_capacity); + initialize(); + } + // @} + + //! Construct stack, allocate n nodes for the freelist. + // @{ + explicit stack(size_type n): + pool(node_allocator(), n) + { + BOOST_ASSERT(!has_capacity); + initialize(); + } + + template + stack(size_type n, typename node_allocator::template rebind::other const & alloc): + pool(alloc, n) + { + BOOST_STATIC_ASSERT(!has_capacity); + initialize(); + } + // @} + + /** Allocate n nodes for freelist + * + * \pre only valid if no capacity<> argument given + * \note thread-safe, may block if memory allocator blocks + * + * */ + void reserve(size_type n) + { + BOOST_STATIC_ASSERT(!has_capacity); + pool.reserve(n); + } + + /** Allocate n nodes for freelist + * + * \pre only valid if no capacity<> argument given + * \note not thread-safe, may block if memory allocator blocks + * + * */ + void reserve_unsafe(size_type n) + { + BOOST_STATIC_ASSERT(!has_capacity); + pool.reserve_unsafe(n); + } + + /** Destroys stack, free all nodes from freelist. + * + * \note not thread-safe + * + * */ + ~stack(void) + { + T dummy; + while(unsynchronized_pop(dummy)) + {} + } + +private: +#ifndef BOOST_DOXYGEN_INVOKED + void initialize(void) + { + tos.store(tagged_node_handle(pool.null_handle(), 0)); + } + + void link_nodes_atomic(node * new_top_node, node * end_node) + { + tagged_node_handle old_tos = tos.load(detail::memory_order_relaxed); + for (;;) { + tagged_node_handle new_tos (pool.get_handle(new_top_node), old_tos.get_tag()); + end_node->next = pool.get_handle(old_tos); + + if (tos.compare_exchange_weak(old_tos, new_tos)) + break; + } + } + + void link_nodes_unsafe(node * new_top_node, node * end_node) + { + tagged_node_handle old_tos = tos.load(detail::memory_order_relaxed); + + tagged_node_handle new_tos (pool.get_handle(new_top_node), old_tos.get_tag()); + end_node->next = pool.get_pointer(old_tos); + + tos.store(new_tos, memory_order_relaxed); + } + + template + tuple prepare_node_list(ConstIterator begin, ConstIterator end, ConstIterator & ret) + { + ConstIterator it = begin; + node * end_node = pool.template construct(*it++); + if (end_node == NULL) { + ret = begin; + return make_tuple(NULL, NULL); + } + + node * new_top_node = end_node; + end_node->next = NULL; + + try { + /* link nodes */ + for (; it != end; ++it) { + node * newnode = pool.template construct(*it); + if (newnode == NULL) + break; + newnode->next = new_top_node; + new_top_node = newnode; + } + } catch (...) { + for (node * current_node = new_top_node; current_node != NULL;) { + node * next = current_node->next; + pool.template destruct(current_node); + current_node = next; + } + throw; + } + ret = it; + return make_tuple(new_top_node, end_node); + } +#endif + +public: + /** Pushes object t to the stack. + * + * \post object will be pushed to the stack, if internal node can be allocated + * \returns true, if the push operation is successful. + * + * \note Thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will be allocated + * from the OS. This may not be lock-free. + * \throws if memory allocator throws + * */ + bool push(T const & v) + { + return do_push(v); + } + + /** Pushes object t to the stack. + * + * \post object will be pushed to the stack, if internal node can be allocated + * \returns true, if the push operation is successful. + * + * \note Thread-safe and non-blocking. If internal memory pool is exhausted, the push operation will fail + * */ + bool bounded_push(T const & v) + { + return do_push(v); + } + +#ifndef BOOST_DOXYGEN_INVOKED +private: + template + bool do_push(T const & v) + { + node * newnode = pool.template construct(v); + if (newnode == 0) + return false; + + link_nodes_atomic(newnode, newnode); + return true; + } + + template + ConstIterator do_push(ConstIterator begin, ConstIterator end) + { + node * new_top_node; + node * end_node; + ConstIterator ret; + + tie(new_top_node, end_node) = prepare_node_list(begin, end, ret); + if (new_top_node) + link_nodes_atomic(new_top_node, end_node); + + return ret; + } + +public: +#endif + + /** Pushes as many objects from the range [begin, end) as freelist node can be allocated. + * + * \return iterator to the first element, which has not been pushed + * + * \note Operation is applied atomically + * \note Thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will be allocated + * from the OS. This may not be lock-free. + * \throws if memory allocator throws + */ + template + ConstIterator push(ConstIterator begin, ConstIterator end) + { + return do_push(begin, end); + } + + /** Pushes as many objects from the range [begin, end) as freelist node can be allocated. + * + * \return iterator to the first element, which has not been pushed + * + * \note Operation is applied atomically + * \note Thread-safe and non-blocking. If internal memory pool is exhausted, the push operation will fail + * \throws if memory allocator throws + */ + template + ConstIterator bounded_push(ConstIterator begin, ConstIterator end) + { + return do_push(begin, end); + } + + + /** Pushes object t to the stack. + * + * \post object will be pushed to the stack, if internal node can be allocated + * \returns true, if the push operation is successful. + * + * \note Not thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will be allocated + * from the OS. This may not be lock-free. + * \throws if memory allocator throws + * */ + bool unsynchronized_push(T const & v) + { + node * newnode = pool.template construct(v); + if (newnode == 0) + return false; + + link_nodes_unsafe(newnode, newnode); + return true; + } + + /** Pushes as many objects from the range [begin, end) as freelist node can be allocated. + * + * \return iterator to the first element, which has not been pushed + * + * \note Not thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will be allocated + * from the OS. This may not be lock-free. + * \throws if memory allocator throws + */ + template + ConstIterator unsynchronized_push(ConstIterator begin, ConstIterator end) + { + node * new_top_node; + node * end_node; + ConstIterator ret; + + tie(new_top_node, end_node) = prepare_node_list(begin, end, ret); + if (new_top_node) + link_nodes_unsafe(new_top_node, end_node); + + return ret; + } + + + /** Pops object from stack. + * + * \post if pop operation is successful, object will be copied to ret. + * \returns true, if the pop operation is successful, false if stack was empty. + * + * \note Thread-safe and non-blocking + * + * */ + bool pop(T & ret) + { + return pop(ret); + } + + /** Pops object from stack. + * + * \pre type T must be convertible to U + * \post if pop operation is successful, object will be copied to ret. + * \returns true, if the pop operation is successful, false if stack was empty. + * + * \note Thread-safe and non-blocking + * + * */ + template + bool pop(U & ret) + { + BOOST_STATIC_ASSERT((boost::is_convertible::value)); + tagged_node_handle old_tos = tos.load(detail::memory_order_consume); + + for (;;) { + node * old_tos_pointer = pool.get_pointer(old_tos); + if (!old_tos_pointer) + return false; + + tagged_node_handle new_tos(old_tos_pointer->next, old_tos.get_tag() + 1); + + if (tos.compare_exchange_weak(old_tos, new_tos)) { + detail::copy_payload(old_tos_pointer->v, ret); + pool.template destruct(old_tos); + return true; + } + } + } + + + /** Pops object from stack. + * + * \post if pop operation is successful, object will be copied to ret. + * \returns true, if the pop operation is successful, false if stack was empty. + * + * \note Not thread-safe, but non-blocking + * + * */ + bool unsynchronized_pop(T & ret) + { + return unsynchronized_pop(ret); + } + + /** Pops object from stack. + * + * \pre type T must be convertible to U + * \post if pop operation is successful, object will be copied to ret. + * \returns true, if the pop operation is successful, false if stack was empty. + * + * \note Not thread-safe, but non-blocking + * + * */ + template + bool unsynchronized_pop(U & ret) + { + BOOST_STATIC_ASSERT((boost::is_convertible::value)); + tagged_node_handle old_tos = tos.load(detail::memory_order_relaxed); + node * old_tos_pointer = pool.get_pointer(old_tos); + + if (!pool.get_pointer(old_tos)) + return false; + + node * new_tos_ptr = pool.get_pointer(old_tos_pointer->next); + tagged_node_handle new_tos(pool.get_handle(new_tos_ptr), old_tos.get_tag() + 1); + + tos.store(new_tos, memory_order_relaxed); + detail::copy_payload(old_tos_pointer->v, ret); + pool.template destruct(old_tos); + return true; + } + + /** + * \return true, if stack is empty. + * + * \note It only guarantees that at some point during the execution of the function the stack has been empty. + * It is rarely practical to use this value in program logic, because the stack can be modified by other threads. + * */ + bool empty(void) const + { + return pool.get_pointer(tos.load()) == NULL; + } + +private: +#ifndef BOOST_DOXYGEN_INVOKED + detail::atomic tos; + + static const int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof(tagged_node_handle); + char padding[padding_size]; + + pool_t pool; +#endif +}; + +} /* namespace lockfree */ +} /* namespace boost */ + +#endif /* BOOST_LOCKFREE_STACK_HPP_INCLUDED */ diff --git a/cpp/BoostParts/boost/move/detail/move_helpers.hpp b/cpp/BoostParts/boost/move/detail/move_helpers.hpp new file mode 100644 index 00000000..ddfea9bc --- /dev/null +++ b/cpp/BoostParts/boost/move/detail/move_helpers.hpp @@ -0,0 +1,175 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2010-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/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_MOVE_HELPERS_HPP +#define BOOST_MOVE_MOVE_HELPERS_HPP + +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || (defined(_MSC_VER) && (_MSC_VER == 1600)) +#include +#include +#endif +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#include +#endif + + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +struct not_a_type; +#define BOOST_MOVE_CATCH_CONST(U) \ + typename ::boost::mpl::if_< ::boost::is_class, BOOST_CATCH_CONST_RLVALUE(U), const U &>::type +#define BOOST_MOVE_CATCH_RVALUE(U)\ + typename ::boost::mpl::if_< ::boost::is_class, BOOST_RV_REF(U), not_a_type>::type +#define BOOST_MOVE_CATCH_FWD(U) BOOST_FWD_REF(U) +#else +#define BOOST_MOVE_CATCH_CONST(U) const U & +#define BOOST_MOVE_CATCH_RVALUE(U) U && +#define BOOST_MOVE_CATCH_FWD(U) U && +#endif + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + +#define BOOST_MOVE_CONVERSION_AWARE_CATCH(PUB_FUNCTION, TYPE, RETURN_VALUE, FWD_FUNCTION)\ + RETURN_VALUE PUB_FUNCTION(BOOST_MOVE_CATCH_CONST(TYPE) x)\ + { return FWD_FUNCTION(static_cast(x)); }\ +\ + RETURN_VALUE PUB_FUNCTION(BOOST_MOVE_CATCH_RVALUE(TYPE) x) \ + { return FWD_FUNCTION(::boost::move(x)); }\ +\ + RETURN_VALUE PUB_FUNCTION(TYPE &x)\ + { return FWD_FUNCTION(const_cast(x)); }\ +\ + template\ + typename ::boost::enable_if_c\ + < ::boost::is_class::value &&\ + ::boost::is_same::value &&\ + !::boost::has_move_emulation_enabled::value\ + , RETURN_VALUE >::type\ + PUB_FUNCTION(const BOOST_MOVE_TEMPL_PARAM &u)\ + { return FWD_FUNCTION(u); }\ +\ + template\ + typename ::boost::enable_if_c\ + < (!::boost::is_class::value || \ + !::boost::move_detail::is_rv::value) && \ + !::boost::is_same::value \ + , RETURN_VALUE >::type\ + PUB_FUNCTION(const BOOST_MOVE_TEMPL_PARAM &u)\ + {\ + TYPE t(u);\ + return FWD_FUNCTION(::boost::move(t));\ + }\ +// + +#elif (defined(_MSC_VER) && (_MSC_VER == 1600)) + +#define BOOST_MOVE_CONVERSION_AWARE_CATCH(PUB_FUNCTION, TYPE, RETURN_VALUE, FWD_FUNCTION)\ + RETURN_VALUE PUB_FUNCTION(BOOST_MOVE_CATCH_CONST(TYPE) x)\ + { return FWD_FUNCTION(static_cast(x)); }\ +\ + RETURN_VALUE PUB_FUNCTION(BOOST_MOVE_CATCH_RVALUE(TYPE) x) \ + { return FWD_FUNCTION(::boost::move(x)); }\ +\ + template\ + typename ::boost::enable_if_c\ + < !::boost::is_same::value\ + , RETURN_VALUE >::type\ + PUB_FUNCTION(const BOOST_MOVE_TEMPL_PARAM &u)\ + {\ + TYPE t(u);\ + return FWD_FUNCTION(::boost::move(t));\ + }\ +// + +#else + +#define BOOST_MOVE_CONVERSION_AWARE_CATCH(PUB_FUNCTION, TYPE, RETURN_VALUE, FWD_FUNCTION)\ + RETURN_VALUE PUB_FUNCTION(BOOST_MOVE_CATCH_CONST(TYPE) x)\ + { return FWD_FUNCTION(static_cast(x)); }\ +\ + RETURN_VALUE PUB_FUNCTION(BOOST_MOVE_CATCH_RVALUE(TYPE) x) \ + { return FWD_FUNCTION(::boost::move(x)); }\ +// + +#endif + + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + +#define BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(PUB_FUNCTION, TYPE, RETURN_VALUE, FWD_FUNCTION, ARG1)\ + RETURN_VALUE PUB_FUNCTION(ARG1 arg1, BOOST_MOVE_CATCH_CONST(TYPE) x)\ + { return FWD_FUNCTION(arg1, static_cast(x)); }\ +\ + RETURN_VALUE PUB_FUNCTION(ARG1 arg1, BOOST_MOVE_CATCH_RVALUE(TYPE) x) \ + { return FWD_FUNCTION(arg1, ::boost::move(x)); }\ +\ + RETURN_VALUE PUB_FUNCTION(ARG1 arg1, TYPE &x)\ + { return FWD_FUNCTION(arg1, const_cast(x)); }\ +\ + template\ + typename ::boost::enable_if_c\ + < ::boost::is_class::value &&\ + ::boost::is_same::value &&\ + !::boost::has_move_emulation_enabled::value\ + , RETURN_VALUE >::type\ + PUB_FUNCTION(ARG1 arg1, const BOOST_MOVE_TEMPL_PARAM &u)\ + { return FWD_FUNCTION(arg1, u); }\ +\ + template\ + typename ::boost::enable_if_c\ + < (!::boost::is_class::value || \ + !::boost::move_detail::is_rv::value) && \ + !::boost::is_same::value \ + , RETURN_VALUE >::type\ + PUB_FUNCTION(ARG1 arg1, const BOOST_MOVE_TEMPL_PARAM &u)\ + {\ + TYPE t(u);\ + return FWD_FUNCTION(arg1, ::boost::move(t));\ + }\ +// + +#elif (defined(_MSC_VER) && (_MSC_VER == 1600)) + +#define BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(PUB_FUNCTION, TYPE, RETURN_VALUE, FWD_FUNCTION, ARG1)\ + RETURN_VALUE PUB_FUNCTION(ARG1 arg1, BOOST_MOVE_CATCH_CONST(TYPE) x)\ + { return FWD_FUNCTION(arg1, static_cast(x)); }\ +\ + RETURN_VALUE PUB_FUNCTION(ARG1 arg1, BOOST_MOVE_CATCH_RVALUE(TYPE) x) \ + { return FWD_FUNCTION(arg1, ::boost::move(x)); }\ +\ + template\ + typename ::boost::enable_if_c\ + < !::boost::is_same::value\ + , RETURN_VALUE >::type\ + PUB_FUNCTION(ARG1 arg1, const BOOST_MOVE_TEMPL_PARAM &u)\ + {\ + TYPE t(u);\ + return FWD_FUNCTION(arg1, ::boost::move(t));\ + }\ +// + +#else + +#define BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(PUB_FUNCTION, TYPE, RETURN_VALUE, FWD_FUNCTION, ARG1)\ + RETURN_VALUE PUB_FUNCTION(ARG1 arg1, BOOST_MOVE_CATCH_CONST(TYPE) x)\ + { return FWD_FUNCTION(arg1, static_cast(x)); }\ +\ + RETURN_VALUE PUB_FUNCTION(ARG1 arg1, BOOST_MOVE_CATCH_RVALUE(TYPE) x) \ + { return FWD_FUNCTION(arg1, ::boost::move(x)); }\ +// + +#endif + +#endif //#ifndef BOOST_MOVE_MOVE_HELPERS_HPP diff --git a/cpp/BoostParts/boost/mpl/aux_/insert_impl.hpp b/cpp/BoostParts/boost/mpl/aux_/insert_impl.hpp new file mode 100644 index 00000000..a0de6e90 --- /dev/null +++ b/cpp/BoostParts/boost/mpl/aux_/insert_impl.hpp @@ -0,0 +1,68 @@ + +#ifndef BOOST_MPL_INSERT_IMPL_HPP_INCLUDED +#define BOOST_MPL_INSERT_IMPL_HPP_INCLUDED + +// Copyright Aleksey Gurtovoy 2000-2004 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/mpl for documentation. + +// $Id: insert_impl.hpp 49267 2008-10-11 06:19:02Z agurtovoy $ +// $Date: 2008-10-10 23:19:02 -0700 (Fri, 10 Oct 2008) $ +// $Revision: 49267 $ + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace mpl { + +// default implementation; conrete sequences might override it by +// specializing either the 'insert_impl' or the primary 'insert' template + +template< typename Tag > +struct insert_impl +{ + template< + typename Sequence + , typename Pos + , typename T + > + struct apply + { + typedef iterator_range< + typename begin::type + , Pos + > first_half_; + + typedef iterator_range< + Pos + , typename end::type + > second_half_; + + typedef typename reverse_fold< + second_half_ + , typename clear::type + , push_front<_,_> + >::type half_sequence_; + + typedef typename reverse_fold< + first_half_ + , typename push_front::type + , push_front<_,_> + >::type type; + }; +}; + +BOOST_MPL_ALGORITM_TRAITS_LAMBDA_SPEC(3,insert_impl) + +}} + +#endif // BOOST_MPL_INSERT_IMPL_HPP_INCLUDED diff --git a/cpp/BoostParts/boost/mpl/insert.hpp b/cpp/BoostParts/boost/mpl/insert.hpp new file mode 100644 index 00000000..ff03de62 --- /dev/null +++ b/cpp/BoostParts/boost/mpl/insert.hpp @@ -0,0 +1,41 @@ + +#ifndef BOOST_MPL_INSERT_HPP_INCLUDED +#define BOOST_MPL_INSERT_HPP_INCLUDED + +// Copyright Aleksey Gurtovoy 2000-2004 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/mpl for documentation. + +// $Id: insert.hpp 49267 2008-10-11 06:19:02Z agurtovoy $ +// $Date: 2008-10-10 23:19:02 -0700 (Fri, 10 Oct 2008) $ +// $Revision: 49267 $ + +#include +#include +#include +#include +#include + +namespace boost { namespace mpl { + +template< + typename BOOST_MPL_AUX_NA_PARAM(Sequence) + , typename BOOST_MPL_AUX_NA_PARAM(Pos_or_T) + , typename BOOST_MPL_AUX_NA_PARAM(T) + > +struct insert + : insert_impl< typename sequence_tag::type > + ::template apply< Sequence,Pos_or_T,T > +{ + BOOST_MPL_AUX_LAMBDA_SUPPORT(3,insert,(Sequence,Pos_or_T,T)) +}; + +BOOST_MPL_AUX_NA_SPEC(3, insert) + +}} + +#endif // BOOST_MPL_INSERT_HPP_INCLUDED diff --git a/cpp/BoostParts/boost/parameter.hpp b/cpp/BoostParts/boost/parameter.hpp new file mode 100644 index 00000000..3cc70cb1 --- /dev/null +++ b/cpp/BoostParts/boost/parameter.hpp @@ -0,0 +1,21 @@ +// Copyright David Abrahams, Daniel Wallin 2005. Use, modification and +// distribution is subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See www.boost.org/libs/parameter for documentation. + +#ifndef BOOST_PARAMETER_050401_HPP +#define BOOST_PARAMETER_050401_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_PARAMETER_050401_HPP + diff --git a/cpp/BoostParts/boost/parameter/aux_/cast.hpp b/cpp/BoostParts/boost/parameter/aux_/cast.hpp new file mode 100644 index 00000000..b94c764e --- /dev/null +++ b/cpp/BoostParts/boost/parameter/aux_/cast.hpp @@ -0,0 +1,143 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PARAMETER_CAST_060902_HPP +# define BOOST_PARAMETER_CAST_060902_HPP + +# include + +# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + && !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# include +# include +# endif + +namespace boost { namespace parameter { namespace aux { + +struct use_default_tag {}; + +# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +# define BOOST_PARAMETER_FUNCTION_CAST(value, predicate) value + +# else + +// Handles possible implicit casts. Used by preprocessor.hpp to +// normalize user input. +// +// cast::execute() is identity +// cast::execute() is identity +// cast::execute() casts to X +// +// preprocessor.hpp uses this like this: +// +// #define X(value, predicate) +// cast::execute(value) +// +// X(something, *) +// X(something, *(predicate)) +// X(something, (int)) + +template +struct cast; + +template +struct cast +{ + static use_default_tag execute(use_default_tag) + { + return use_default_tag(); + } + + static use_default_tag remove_const(use_default_tag) + { + return use_default_tag(); + } + + template + static U& execute(U& value) + { + return value; + } + + template + static U& remove_const(U& x) + { + return x; + } +}; + +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) + +typedef void* voidstar; + +template +struct cast + : cast +{ +}; + +#else + +template +struct cast + : cast +{ +}; + +#endif + +// This is a hack used in cast<> to turn the user supplied type, +// which may or may not be a placeholder expression into one, so +// that it will be properly evaluated by mpl::apply. +template +struct as_placeholder_expr +{ + typedef T type; +}; + +template +struct cast +{ + typedef typename mpl::apply2< + as_placeholder_expr, Args, Args>::type type0; + + typedef typename boost::add_reference< + typename boost::remove_const::type + >::type reference; + + static use_default_tag execute(use_default_tag) + { + return use_default_tag(); + } + + static use_default_tag remove_const(use_default_tag) + { + return use_default_tag(); + } + + static type0 execute(type0 value) + { + return value; + } + + template + static reference remove_const(U const& x) + { + return const_cast(x); + } +}; + +# define BOOST_PARAMETER_FUNCTION_CAST(value, predicate, args) \ + boost::parameter::aux::cast::remove_const( \ + boost::parameter::aux::cast::execute(value) \ + ) + +# endif + +}}} // namespace boost::parameter::aux + +#endif // BOOST_PARAMETER_CAST_060902_HPP + diff --git a/cpp/BoostParts/boost/parameter/aux_/overloads.hpp b/cpp/BoostParts/boost/parameter/aux_/overloads.hpp new file mode 100644 index 00000000..dcc92d4d --- /dev/null +++ b/cpp/BoostParts/boost/parameter/aux_/overloads.hpp @@ -0,0 +1,88 @@ +// Copyright David Abrahams, Daniel Wallin 2003. Use, modification and +// distribution is subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This file generates overloads in this format: +// +// template +// typename mpl::apply_wrap1< +// aux::make_arg_list< +// PS0,A0 +// , aux::make_arg_list< +// PS1,A1 +// , mpl::identity +// > +// > +// , unnamed_list +// >::type +// operator()(A0 const& a0, A1 const& a1) const +// { +// typedef typename mpl::apply_wrap1< +// aux::make_arg_list< +// PS0,A0 +// , aux::make_arg_list< +// PS1,A1 +// , mpl::identity +// > +// > +// >::type arg_tuple; +// +// return arg_tuple( +// a0 +// , a1 +// , aux::void_() +// ... +// ); +// } +// + +#if !defined(BOOST_PP_IS_ITERATING) +# error Boost.Parameters - do not include this file! +#endif + +#define N BOOST_PP_ITERATION() + +#define BOOST_PARAMETER_open_list(z, n, text) \ + aux::item< \ + BOOST_PP_CAT(PS, n), BOOST_PP_CAT(A, n) + +#define BOOST_PARAMETER_close_list(z, n, text) > + +#define BOOST_PARAMETER_arg_list(n) \ + aux::make_arg_list< \ + BOOST_PP_ENUM(N, BOOST_PARAMETER_open_list, _) \ + , void_ \ + BOOST_PP_REPEAT(N, BOOST_PARAMETER_close_list, _) \ + , deduced_list \ + , aux::tag_keyword_arg \ + > + +#define BOOST_PARAMETER_arg_pack_init(z, n, limit) \ + BOOST_PP_CAT(a, BOOST_PP_SUB(limit,n)) + +template +typename mpl::first< + typename BOOST_PARAMETER_arg_list(N)::type +>::type +operator()(BOOST_PP_ENUM_BINARY_PARAMS(N, A, & a)) const +{ + typedef typename BOOST_PARAMETER_arg_list(N)::type result; + + typedef typename mpl::first::type result_type; + typedef typename mpl::second::type error; + error(); + + return result_type( + BOOST_PP_ENUM(N, BOOST_PARAMETER_arg_pack_init, BOOST_PP_DEC(N)) + BOOST_PP_ENUM_TRAILING_PARAMS( + BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, N) + , aux::void_reference() BOOST_PP_INTERCEPT + )); +} + +#undef BOOST_PARAMETER_arg_list +#undef BOOST_PARAMETER_open_list +#undef BOOST_PARAMETER_close_list +#undef N + diff --git a/cpp/BoostParts/boost/parameter/aux_/parenthesized_type.hpp b/cpp/BoostParts/boost/parameter/aux_/parenthesized_type.hpp new file mode 100644 index 00000000..c6ddd77f --- /dev/null +++ b/cpp/BoostParts/boost/parameter/aux_/parenthesized_type.hpp @@ -0,0 +1,119 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_PARAMETER_AUX_PARENTHESIZED_TYPE_DWA2006414_HPP +# define BOOST_PARAMETER_AUX_PARENTHESIZED_TYPE_DWA2006414_HPP + +# include +# include + +namespace boost { namespace parameter { namespace aux { + +// A macro that takes a parenthesized C++ type name (T) and transforms +// it into an un-parenthesized type expression equivalent to T. +# define BOOST_PARAMETER_PARENTHESIZED_TYPE(x) \ + boost::parameter::aux::unaryfunptr_arg_type< void(*)x >::type + +// A metafunction that transforms void(*)(T) -> T +template +struct unaryfunptr_arg_type; + +# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + +template +struct unaryfunptr_arg_type +{ + typedef Arg type; +}; + +# else + +// Use the "native typeof" bugfeatures of older versions of MSVC to +// accomplish what we'd normally do with partial specialization. This +// capability was discovered by Igor Chesnokov. + +# if BOOST_WORKAROUND(BOOST_MSVC, != 1300) + +// This version applies to VC6.5 and VC7.1 (except that we can just +// use partial specialization for the latter in this case). + +// This gets used as a base class. +template +struct msvc_type_memory +{ + // A nullary metafunction that will yield the Value type "stored" + // at this Address. + struct storage; +}; + +template +struct msvc_store_type : msvc_type_memory

+{ + // VC++ somehow lets us define the base's nested storage + // metafunction here, where we have the Value type we'd like to + // "store" in it. Later we can come back to the base class and + // extract the "stored type." + typedef msvc_type_memory
location; + struct location::storage + { + typedef Value type; + }; +}; + +# else + +// This slightly more complicated version of the same thing is +// required for msvc-7.0 +template +struct msvc_type_memory +{ + template + struct storage_impl; + + typedef storage_impl storage; +}; + +template +struct msvc_store_type : msvc_type_memory
+{ + // Rather than supplying a definition for the base class' nested + // class, we specialize the base class' nested template + template<> + struct storage_impl + { + typedef Value type; + }; +}; + +# endif + +// Function template argument deduction does many of the same things +// as type matching during partial specialization, so we call a +// function template to "store" T into the type memory addressed by +// void(*)(T). +template +msvc_store_type +msvc_store_argument_type(void(*)(T)); + +template +struct unaryfunptr_arg_type +{ + // We don't want the function to be evaluated, just instantiated, + // so protect it inside of sizeof. + enum { dummy = sizeof(msvc_store_argument_type((FunctionPointer)0)) }; + + // Now pull the type out of the instantiated base class + typedef typename msvc_type_memory::storage::type type; +}; + +# endif + +template <> +struct unaryfunptr_arg_type +{ + typedef void type; +}; + +}}} // namespace boost::parameter::aux + +#endif // BOOST_PARAMETER_AUX_PARENTHESIZED_TYPE_DWA2006414_HPP diff --git a/cpp/BoostParts/boost/parameter/aux_/preprocessor/flatten.hpp b/cpp/BoostParts/boost/parameter/aux_/preprocessor/flatten.hpp new file mode 100644 index 00000000..5d7615e3 --- /dev/null +++ b/cpp/BoostParts/boost/parameter/aux_/preprocessor/flatten.hpp @@ -0,0 +1,115 @@ +// Copyright Daniel Wallin 2005. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PARAMETER_FLATTEN_051217_HPP +# define BOOST_PARAMETER_FLATTEN_051217_HPP + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# define BOOST_PARAMETER_FLATTEN_SPLIT_required required, +# define BOOST_PARAMETER_FLATTEN_SPLIT_optional optional, +# define BOOST_PARAMETER_FLATTEN_SPLIT_deduced deduced, + +# define BOOST_PARAMETER_FLATTEN_SPLIT(sub) \ + BOOST_PP_CAT(BOOST_PARAMETER_FLATTEN_SPLIT_, sub) + +# define BOOST_PARAMETER_FLATTEN_QUALIFIER(sub) \ + BOOST_PP_SPLIT(0, BOOST_PARAMETER_FLATTEN_SPLIT(sub)) + +# define BOOST_PARAMETER_FLATTEN_ARGS(sub) \ + BOOST_PP_SPLIT(1, BOOST_PARAMETER_FLATTEN_SPLIT(sub)) + +# define BOOST_PARAMETER_FLATTEN_ARITY_optional(arities) \ + BOOST_PP_TUPLE_ELEM(3,0,arities) + +# define BOOST_PARAMETER_FLATTEN_ARITY_required(arities) \ + BOOST_PP_TUPLE_ELEM(3,1,arities) + +# define BOOST_PARAMETER_FLATTEN_SPEC0_DUMMY_ELEM(z, n, data) ~ +# define BOOST_PARAMETER_FLATTEN_SPEC0(r, n, elem, data) \ + (( \ + BOOST_PP_TUPLE_ELEM(3,2,data) \ + , BOOST_PP_TUPLE_REM(BOOST_PP_TUPLE_ELEM(3,0,data)) elem \ + BOOST_PP_ENUM_TRAILING( \ + BOOST_PP_SUB( \ + BOOST_PP_TUPLE_ELEM(3,1,data) \ + , BOOST_PP_TUPLE_ELEM(3,0,data) \ + ) \ + , BOOST_PARAMETER_FLATTEN_SPEC0_DUMMY_ELEM \ + , ~ \ + ) \ + )) + +# define BOOST_PARAMETER_FLATTEN_SPEC_AUX(r, arity, max_arity, spec, transform) \ + BOOST_PARAMETER_FOR_EACH_R( \ + r \ + , arity \ + , BOOST_PARAMETER_FLATTEN_ARGS(spec) \ + , (arity, max_arity, transform(BOOST_PARAMETER_FLATTEN_QUALIFIER(spec))) \ + , BOOST_PARAMETER_FLATTEN_SPEC0 \ + ) + +# define BOOST_PARAMETER_FLATTEN_IDENTITY(x) x + +# define BOOST_PARAMETER_FLATTEN_SPEC_optional(r, arities, spec) \ + BOOST_PARAMETER_FLATTEN_SPEC_AUX( \ + r \ + , BOOST_PP_CAT( \ + BOOST_PARAMETER_FLATTEN_ARITY_, BOOST_PARAMETER_FLATTEN_QUALIFIER(spec) \ + )(arities) \ + , BOOST_PP_TUPLE_ELEM(3,2,arities) \ + , spec \ + , BOOST_PARAMETER_FLATTEN_IDENTITY \ + ) + +# define BOOST_PARAMETER_FLATTEN_SPEC_required(r, arities, spec) \ + BOOST_PARAMETER_FLATTEN_SPEC_optional(r, arities, spec) + +# define BOOST_PARAMETER_FLATTEN_SPEC_AS_DEDUCED(x) BOOST_PP_CAT(deduced_,x) + +# define BOOST_PARAMETER_FLATTEN_SPEC_deduced_M(r, arities, n, spec) \ + BOOST_PARAMETER_FLATTEN_SPEC_AUX( \ + r \ + , BOOST_PP_CAT( \ + BOOST_PARAMETER_FLATTEN_ARITY_, BOOST_PARAMETER_FLATTEN_QUALIFIER(spec) \ + )(arities) \ + , BOOST_PP_TUPLE_ELEM(3,2,arities) \ + , spec \ + , BOOST_PARAMETER_FLATTEN_SPEC_AS_DEDUCED \ + ) + +# define BOOST_PARAMETER_FLATTEN_SPEC_deduced(r, arities, spec) \ + BOOST_PP_SEQ_FOR_EACH_I_R( \ + r \ + , BOOST_PARAMETER_FLATTEN_SPEC_deduced_M \ + , arities \ + , BOOST_PARAMETER_FLATTEN_ARGS(spec) \ + ) + +# define BOOST_PARAMETER_FLATTEN_SPEC(r, arities, spec) \ + BOOST_PP_CAT( \ + BOOST_PARAMETER_FLATTEN_SPEC_, BOOST_PARAMETER_FLATTEN_QUALIFIER(spec) \ + )(r, arities, spec) + +# define BOOST_PARAMETER_FLATTEN(optional_arity, required_arity, wanted_arity, specs) \ + BOOST_PP_SEQ_FOR_EACH( \ + BOOST_PARAMETER_FLATTEN_SPEC \ + , ( \ + optional_arity, required_arity \ + , wanted_arity \ + ) \ + , specs \ + ) + +#endif // BOOST_PARAMETER_FLATTEN_051217_HPP + diff --git a/cpp/BoostParts/boost/parameter/aux_/preprocessor/for_each.hpp b/cpp/BoostParts/boost/parameter/aux_/preprocessor/for_each.hpp new file mode 100644 index 00000000..0eb1f702 --- /dev/null +++ b/cpp/BoostParts/boost/parameter/aux_/preprocessor/for_each.hpp @@ -0,0 +1,103 @@ +// Copyright Daniel Wallin 2005. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PARAMETER_FOR_EACH_051217_HPP +# define BOOST_PARAMETER_FOR_EACH_051217_HPP + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# define BOOST_PARAMETER_FOR_EACH_head_aux2(x,y) (x,y), ~ +# define BOOST_PARAMETER_FOR_EACH_head_aux3(x,y,z) (x,y,z), ~ +# define BOOST_PARAMETER_FOR_EACH_head_aux4(x,y,z,u) (x,y,z,u), ~ +# define BOOST_PARAMETER_FOR_EACH_head(n,x) \ + BOOST_PP_SPLIT(0, BOOST_PP_CAT(BOOST_PARAMETER_FOR_EACH_head_aux,n) x) + +# define BOOST_PARAMETER_FOR_EACH_pred_aux_BOOST_PARAMETER_FOR_EACH_END_SENTINEL +# define BOOST_PARAMETER_FOR_EACH_pred_aux_check(x) \ + BOOST_PP_NOT(BOOST_PP_IS_EMPTY( \ + BOOST_PP_CAT(BOOST_PARAMETER_FOR_EACH_pred_aux_, x) \ + )), ~ + +# define BOOST_PARAMETER_FOR_EACH_pred_aux2(x,y) \ + BOOST_PARAMETER_FOR_EACH_pred_aux_check(x) +# define BOOST_PARAMETER_FOR_EACH_pred_aux3(x,y,z) \ + BOOST_PARAMETER_FOR_EACH_pred_aux_check(x) +# define BOOST_PARAMETER_FOR_EACH_pred_aux4(x,y,z,u) \ + BOOST_PARAMETER_FOR_EACH_pred_aux_check(x) + +# define BOOST_PARAMETER_FOR_EACH_pred_aux0(n,x) \ + BOOST_PP_CAT(BOOST_PARAMETER_FOR_EACH_pred_aux,n) x + +# if BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_MSVC() +# define BOOST_PARAMETER_FOR_EACH_pred_SPLIT_FIRST(x) \ + BOOST_PP_SPLIT(0, x) + +# define BOOST_PARAMETER_FOR_EACH_pred(r, state) \ + BOOST_PARAMETER_FOR_EACH_pred_SPLIT_FIRST( \ + BOOST_PARAMETER_FOR_EACH_pred_aux0( \ + BOOST_PP_TUPLE_ELEM(5,3,state) \ + , BOOST_PP_TUPLE_ELEM(5,0,state) \ + ) \ + ) +# else +# define BOOST_PARAMETER_FOR_EACH_pred(r, state) \ + BOOST_PP_SPLIT( \ + 0 \ + , BOOST_PARAMETER_FOR_EACH_pred_aux0( \ + BOOST_PP_TUPLE_ELEM(5,3,state) \ + , BOOST_PP_TUPLE_ELEM(5,0,state) \ + ) \ + ) +# endif + +# define BOOST_PARAMETER_FOR_EACH_op(r, state) \ + ( \ + BOOST_PP_TUPLE_EAT(BOOST_PP_TUPLE_ELEM(5,3,state)) \ + BOOST_PP_TUPLE_ELEM(5,0,state) \ + , BOOST_PP_TUPLE_ELEM(5,1,state) \ + , BOOST_PP_TUPLE_ELEM(5,2,state) \ + , BOOST_PP_TUPLE_ELEM(5,3,state) \ + , BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(5,4,state)) \ + ) + +# define BOOST_PARAMETER_FOR_EACH_macro(r, state) \ + BOOST_PP_TUPLE_ELEM(5,2,state)( \ + r \ + , BOOST_PP_TUPLE_ELEM(5,4,state) \ + , BOOST_PARAMETER_FOR_EACH_head( \ + BOOST_PP_TUPLE_ELEM(5,3,state) \ + , BOOST_PP_TUPLE_ELEM(5,0,state) \ + ) \ + , BOOST_PP_TUPLE_ELEM(5,1,state) \ + ) + +# define BOOST_PARAMETER_FOR_EACH_build_end_sentinel(z,n,text) \ + BOOST_PP_COMMA_IF(n) BOOST_PARAMETER_FOR_EACH_END_SENTINEL +# define BOOST_PARAMETER_FOR_EACH_build_end_sentinel_tuple(arity) \ + ( \ + BOOST_PP_REPEAT(arity, BOOST_PARAMETER_FOR_EACH_build_end_sentinel, _) \ + ) + +# define BOOST_PARAMETER_FOR_EACH_R(r, arity, list, data, macro) \ + BOOST_PP_CAT(BOOST_PP_FOR_, r)( \ + (list BOOST_PARAMETER_FOR_EACH_build_end_sentinel_tuple(arity), data, macro, arity, 0) \ + , BOOST_PARAMETER_FOR_EACH_pred \ + , BOOST_PARAMETER_FOR_EACH_op \ + , BOOST_PARAMETER_FOR_EACH_macro \ + ) + +# define BOOST_PARAMETER_FOR_EACH(arity, list, data, macro) \ + BOOST_PARAMETER_FOR_EACH_R(BOOST_PP_DEDUCE_R(), arity, list, data, macro) + +#endif // BOOST_PARAMETER_FOR_EACH_051217_HPP + diff --git a/cpp/BoostParts/boost/parameter/aux_/set.hpp b/cpp/BoostParts/boost/parameter/aux_/set.hpp new file mode 100644 index 00000000..1c4ccf5d --- /dev/null +++ b/cpp/BoostParts/boost/parameter/aux_/set.hpp @@ -0,0 +1,67 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PARAMETER_SET_060912_HPP +# define BOOST_PARAMETER_SET_060912_HPP + +# include + +# if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) \ + && !BOOST_WORKAROUND(__GNUC__, < 3) +# include +# include +# include + +namespace boost { namespace parameter { namespace aux { + +typedef mpl::set0<> set0; + +template +struct insert_ +{ + typedef typename mpl::insert::type type; +}; + +template +struct has_key_ +{ + typedef typename mpl::has_key::type type; +}; + +}}} // namespace boost::parameter::aux + +# else + +# include +# include +# include +# include +# include + +namespace boost { namespace parameter { namespace aux { + +typedef mpl::list0<> set0; + +template +struct insert_ +{ + typedef typename mpl::push_front::type type; +}; + +template +struct has_key_ +{ + typedef typename mpl::find::type iter; + typedef mpl::not_< + is_same::type> + > type; +}; + +}}} // namespace boost::parameter::aux + +# endif + + +#endif // BOOST_PARAMETER_SET_060912_HPP + diff --git a/cpp/BoostParts/boost/parameter/aux_/template_keyword.hpp b/cpp/BoostParts/boost/parameter/aux_/template_keyword.hpp new file mode 100644 index 00000000..5a02f008 --- /dev/null +++ b/cpp/BoostParts/boost/parameter/aux_/template_keyword.hpp @@ -0,0 +1,47 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PARAMETER_TEMPLATE_KEYWORD_060203_HPP +# define BOOST_PARAMETER_TEMPLATE_KEYWORD_060203_HPP + +# include +# include +# include +# include + +namespace boost { namespace parameter { + +namespace aux +{ + + struct template_keyword_tag {}; + + template + struct is_pointer_convertible + : is_convertible + {}; + + template + struct is_template_keyword + : mpl::and_< + mpl::not_ > + , is_pointer_convertible + > + {}; + +} // namespace aux + +template +struct template_keyword + : aux::template_keyword_tag +{ + typedef Tag key_type; + typedef T value_type; + typedef value_type reference; +}; + +}} // namespace boost::parameter + +#endif // BOOST_PARAMETER_TEMPLATE_KEYWORD_060203_HPP + diff --git a/cpp/BoostParts/boost/parameter/macros.hpp b/cpp/BoostParts/boost/parameter/macros.hpp new file mode 100644 index 00000000..83fbfb5a --- /dev/null +++ b/cpp/BoostParts/boost/parameter/macros.hpp @@ -0,0 +1,99 @@ +// Copyright David Abrahams, Daniel Wallin 2003. Use, modification and +// distribution is subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PARAMETER_MACROS_050412_HPP +#define BOOST_PARAMETER_MACROS_050412_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOOST_PARAMETER_FUN_TEMPLATE_HEAD1(n) \ + template + +#define BOOST_PARAMETER_FUN_TEMPLATE_HEAD0(n) + +#if ! defined(BOOST_NO_SFINAE) && ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x592)) + +# define BOOST_PARAMETER_MATCH_TYPE(n, param) \ + BOOST_PP_EXPR_IF(n, typename) param::match \ + < \ + BOOST_PP_ENUM_PARAMS(n, T) \ + >::type + +#else + +# define BOOST_PARAMETER_MATCH_TYPE(n, param) param + +#endif + +#define BOOST_PARAMETER_FUN_DECL(z, n, params) \ + \ + BOOST_PP_CAT(BOOST_PARAMETER_FUN_TEMPLATE_HEAD, BOOST_PP_BOOL(n))(n) \ + \ + BOOST_PP_TUPLE_ELEM(3, 0, params) \ + BOOST_PP_TUPLE_ELEM(3, 1, params)( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& p) \ + BOOST_PP_COMMA_IF(n) \ + BOOST_PARAMETER_MATCH_TYPE(n,BOOST_PP_TUPLE_ELEM(3, 2, params)) \ + kw = BOOST_PP_TUPLE_ELEM(3, 2, params)() \ + ) \ + { \ + return BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3, 1, params), _with_named_params)( \ + kw(BOOST_PP_ENUM_PARAMS(n, p)) \ + ); \ + } + +// Generates: +// +// template +// ret name ## _with_named_params(Params const&); +// +// template +// ret name(T0 const& p0, typename parameters::match::type kw = parameters()) +// { +// return name ## _with_named_params(kw(p0)); +// } +// +// template +// ret name(T0 const& p0, ..., TN const& PN +// , typename parameters::match::type kw = parameters()) +// { +// return name ## _with_named_params(kw(p0, ..., pN)); +// } +// +// template +// ret name ## _with_named_params(Params const&) +// +// lo and hi determines the min and max arity of the generated functions. + +#define BOOST_PARAMETER_FUN(ret, name, lo, hi, parameters) \ + \ + template \ + ret BOOST_PP_CAT(name, _with_named_params)(Params const& p); \ + \ + BOOST_PP_REPEAT_FROM_TO( \ + lo, BOOST_PP_INC(hi), BOOST_PARAMETER_FUN_DECL, (ret, name, parameters)) \ + \ + template \ + ret BOOST_PP_CAT(name, _with_named_params)(Params const& p) + +#define BOOST_PARAMETER_MEMFUN(ret, name, lo, hi, parameters) \ + \ + BOOST_PP_REPEAT_FROM_TO( \ + lo, BOOST_PP_INC(hi), BOOST_PARAMETER_FUN_DECL, (ret, name, parameters)) \ + \ + template \ + ret BOOST_PP_CAT(name, _with_named_params)(Params const& p) + +#endif // BOOST_PARAMETER_MACROS_050412_HPP + diff --git a/cpp/BoostParts/boost/parameter/match.hpp b/cpp/BoostParts/boost/parameter/match.hpp new file mode 100644 index 00000000..2fa3f175 --- /dev/null +++ b/cpp/BoostParts/boost/parameter/match.hpp @@ -0,0 +1,55 @@ +// Copyright David Abrahams 2005. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_PARAMETER_MATCH_DWA2005714_HPP +# define BOOST_PARAMETER_MATCH_DWA2005714_HPP + +# include +# include + +# if BOOST_WORKAROUND(__MWERKS__, <= 0x3003) +// Temporary version of BOOST_PP_SEQ_ENUM until Paul M. integrates the workaround. +# define BOOST_PARAMETER_SEQ_ENUM_I(size,seq) BOOST_PP_CAT(BOOST_PP_SEQ_ENUM_, size) seq +# define BOOST_PARAMETER_SEQ_ENUM(seq) BOOST_PARAMETER_SEQ_ENUM_I(BOOST_PP_SEQ_SIZE(seq), seq) +# else +# define BOOST_PARAMETER_SEQ_ENUM(seq) BOOST_PP_SEQ_ENUM(seq) +# endif + +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +# include +# include +# include +# include +# include + +# define BOOST_PARAMETER_MATCH_DEFAULTS(ArgTypes) \ + BOOST_PP_ENUM_TRAILING_PARAMS( \ + BOOST_PP_SUB( \ + BOOST_PARAMETER_MAX_ARITY \ + , BOOST_PP_SEQ_SIZE(ArgTypes) \ + ) \ + , ::boost::parameter::void_ BOOST_PP_INTERCEPT \ + ) + +# else + +# define BOOST_PARAMETER_MATCH_DEFAULTS(ArgTypes) + +# endif + +// +// Generates, e.g. +// +// typename dfs_params::match::type name = dfs_params() +// +// with workarounds for Borland compatibility. +// + +# define BOOST_PARAMETER_MATCH(ParameterSpec, ArgTypes, name) \ + typename ParameterSpec ::match< \ + BOOST_PARAMETER_SEQ_ENUM(ArgTypes) \ + BOOST_PARAMETER_MATCH_DEFAULTS(ArgTypes) \ + >::type name = ParameterSpec () + +#endif // BOOST_PARAMETER_MATCH_DWA2005714_HPP diff --git a/cpp/BoostParts/boost/parameter/parameters.hpp b/cpp/BoostParts/boost/parameter/parameters.hpp new file mode 100644 index 00000000..97e10243 --- /dev/null +++ b/cpp/BoostParts/boost/parameter/parameters.hpp @@ -0,0 +1,931 @@ +// Copyright David Abrahams, Daniel Wallin 2003. Use, modification and +// distribution is subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PARAMETERS_031014_HPP +#define BOOST_PARAMETERS_031014_HPP + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace parameter_ +{ + template + struct unmatched_argument + { + BOOST_MPL_ASSERT((boost::is_same)); + typedef int type; + }; +} // namespace parameter_ + +namespace boost { + +template class reference_wrapper; + +namespace parameter { + +namespace aux { struct use_default {}; } + +// These templates can be used to describe the treatment of particular +// named parameters for the purposes of overload elimination with +// SFINAE, by placing specializations in the parameters<...> list. In +// order for a treated function to participate in overload resolution: +// +// - all keyword tags wrapped in required<...> must have a matching +// actual argument +// +// - The actual argument type matched by every keyword tag +// associated with a predicate must satisfy that predicate +// +// If a keyword k is specified without an optional<...> or +// required<...>, wrapper, it is treated as though optional were +// specified. +// +// If a keyword k is specified with deduced<...>, that keyword +// will be automatically deduced from the argument list. +// +template +struct required +{ + typedef Tag key_type; + typedef Predicate predicate; +}; + +template +struct optional +{ + typedef Tag key_type; + typedef Predicate predicate; +}; + +template +struct deduced +{ + typedef Tag key_type; +}; + +namespace aux +{ + // Defines metafunctions, is_required and is_optional, that + // identify required<...>, optional<...> and deduced<...> specializations. + BOOST_DETAIL_IS_XXX_DEF(required, required, 2) + BOOST_DETAIL_IS_XXX_DEF(optional, optional, 2) + BOOST_DETAIL_IS_XXX_DEF(deduced_aux, deduced, 1) + + template + struct is_deduced0 + : is_deduced_aux< + typename S::key_type + >::type + {}; + + template + struct is_deduced + : mpl::eval_if< + mpl::or_< + is_optional, is_required + > + , is_deduced0 + , mpl::false_ + >::type + {}; + + // + // key_type, has_default, and predicate -- + // + // These metafunctions accept a ParameterSpec and extract the + // keyword tag, whether or not a default is supplied for the + // parameter, and the predicate that the corresponding actual + // argument type is required match. + // + // a ParameterSpec is a specialization of either keyword<...>, + // required<...>, optional<...> + // + + // helper for key_type<...>, below. + template + struct get_tag_type0 + { + typedef typename T::key_type type; + }; + + template + struct get_tag_type + : mpl::eval_if< + is_deduced_aux + , get_tag_type0 + , mpl::identity + > + {}; + + template + struct tag_type + : mpl::eval_if< + mpl::or_< + is_optional + , is_required + > + , get_tag_type + , mpl::identity + > + {}; + + template + struct has_default + : mpl::not_ > + {}; + + // helper for get_predicate<...>, below + template + struct get_predicate_or_default + { + typedef T type; + }; + + template <> + struct get_predicate_or_default + { + typedef mpl::always type; + }; + + // helper for predicate<...>, below + template + struct get_predicate + { + typedef typename + get_predicate_or_default::type + type; + }; + + template + struct predicate + : mpl::eval_if< + mpl::or_< + is_optional + , is_required + > + , get_predicate + , mpl::identity > + > + { + }; + + + // Converts a ParameterSpec into a specialization of + // parameter_requirements. We need to do this in order to get the + // tag_type into the type in a way that can be conveniently matched + // by a satisfies(...) member function in arg_list. + template + struct as_parameter_requirements + { + typedef parameter_requirements< + typename tag_type::type + , typename predicate::type + , typename has_default::type + > type; + }; + + template + struct is_named_argument + : mpl::or_< + is_template_keyword + , is_tagged_argument + > + {}; + + // Returns mpl::true_ iff the given ParameterRequirements are + // satisfied by ArgList. + template + struct satisfies + { +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) + // VC7.1 can't handle the sizeof() implementation below, + // so we use this instead. + typedef typename mpl::apply_wrap3< + typename ArgList::binding + , typename ParameterRequirements::keyword + , void_ + , mpl::false_ + >::type bound; + + typedef typename mpl::eval_if< + is_same + , typename ParameterRequirements::has_default + , mpl::apply_wrap2< + typename mpl::lambda< + typename ParameterRequirements::predicate, lambda_tag + >::type + , bound + , ArgList + > + >::type type; +#else + BOOST_STATIC_CONSTANT( + bool, value = ( + sizeof( + aux::to_yesno( + ArgList::satisfies((ParameterRequirements*)0, (ArgList*)0) + ) + ) == sizeof(yes_tag) + ) + ); + + typedef mpl::bool_ type; +#endif + }; + + // Returns mpl::true_ if the requirements of the given ParameterSpec + // are satisfied by ArgList. + template + struct satisfies_requirements_of + : satisfies< + ArgList + , typename as_parameter_requirements::type + > + {}; + + // Tags a deduced argument Arg with the keyword tag of Spec using TagFn. + // Returns the tagged argument and the mpl::set<> UsedArgs with the + // tag of Spec inserted. + template + struct tag_deduced + { + typedef mpl::pair< + typename mpl::apply_wrap2::type, Arg>::type + , typename aux::insert_::type>::type + > type; + }; + + template < + class Argument + , class ArgumentPack + , class DeducedArgs + , class UsedArgs + , class TagFn + > + struct deduce_tag; + + // Tag type passed to MPL lambda. + struct lambda_tag; + + // Helper for deduce_tag<> below. + template < + class Argument + , class ArgumentPack + , class DeducedArgs + , class UsedArgs + , class TagFn + > + struct deduce_tag0 + { + typedef typename DeducedArgs::spec spec; + + typedef typename mpl::apply_wrap2< + typename mpl::lambda< + typename spec::predicate, lambda_tag + >::type + , Argument + , ArgumentPack + >::type condition; + + // Deduced parameter matches several arguments. + + BOOST_MPL_ASSERT(( + mpl::not_::type> + > > + )); + + typedef typename mpl::eval_if< + condition + , tag_deduced + , deduce_tag + >::type type; + }; + + // Tries to deduced a keyword tag for a given Argument. + // Returns an mpl::pair<> consisting of the tagged_argument<>, + // and an mpl::set<> where the new tag has been inserted. + // + // Argument: The argument type to be tagged. + // + // ArgumentPack: The ArgumentPack built so far. + // + // DeducedArgs: A specialization of deduced_item<> (see below). + // A list containing only the deduced ParameterSpecs. + // + // UsedArgs: An mpl::set<> containing the keyword tags used so far. + // + // TagFn: A metafunction class used to tag positional or deduced + // arguments with a keyword tag. + + template < + class Argument + , class ArgumentPack + , class DeducedArgs + , class UsedArgs + , class TagFn + > + struct deduce_tag + { + typedef typename mpl::eval_if< + is_same + , mpl::pair + , deduce_tag0 + >::type type; + }; + + template < + class List + , class DeducedArgs + , class TagFn + , class Positional + , class UsedArgs + , class ArgumentPack + , class Error + > + struct make_arg_list_aux; + + // Inserts Tagged::key_type into the UserArgs set. + // Extra indirection to lazily evaluate Tagged::key_type. + template + struct insert_tagged + { + typedef typename aux::insert_< + UsedArgs, typename Tagged::key_type + >::type type; + }; + + // Borland needs the insane extra-indirection workaround below + // so that it doesn't magically drop the const qualifier from + // the argument type. + + template < + class List + , class DeducedArgs + , class TagFn + , class Positional + , class UsedArgs + , class ArgumentPack +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + , class argument +#endif + , class Error + > +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + struct make_arg_list00 +#else + struct make_arg_list0 +#endif + { +#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + typedef typename List::arg argument; +#endif + typedef typename List::spec parameter_spec; + typedef typename tag_type::type tag_; + + typedef is_named_argument is_tagged; + + // If this argument is either explicitly tagged or a deduced + // parameter, we turn off positional matching. + typedef mpl::and_< + mpl::not_< + mpl::or_, is_tagged> + > + , Positional + > positional; + + // If this parameter is explicitly tagged we add it to the + // used-parmeters set. We only really need to add parameters + // that are deduced, but we would need a way to check if + // a given tag corresponds to a deduced parameter spec. + typedef typename mpl::eval_if< + is_tagged + , insert_tagged + , mpl::identity + >::type used_args; + + // If this parameter is neither explicitly tagged, nor + // positionally matched; deduce the tag from the deduced + // parameter specs. + typedef typename mpl::eval_if< + mpl::or_ + , mpl::pair + , deduce_tag + >::type deduced_data; + + // If this parameter is explicitly tagged.. + typedef typename mpl::eval_if< + is_tagged + , mpl::identity // .. just use it + , mpl::eval_if< // .. else, if positional matching is turned on.. + positional + , mpl::apply_wrap2 // .. tag it positionally + , mpl::first // .. else, use the deduced tag + > + >::type tagged; + + // We build the arg_list incrementally as we go, prepending new + // nodes. + + typedef typename mpl::if_< + mpl::and_< + is_same + , is_same + > + , parameter_::unmatched_argument + , void_ + >::type error; + + typedef typename mpl::if_< + is_same + , ArgumentPack + , arg_list + >::type argument_pack; + + typedef typename make_arg_list_aux< + typename List::tail + , DeducedArgs + , TagFn + , positional + , typename deduced_data::second + , argument_pack + , error + >::type type; + }; + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + template < + class List + , class DeducedArgs + , class TagFn + , class Positional + , class UsedArgs + , class ArgumentPack + , class Error + > + struct make_arg_list0 + { + typedef typename mpl::eval_if< + typename List::is_arg_const + , make_arg_list00< + List + , DeducedArgs + , TagFn + , Positional + , UsedArgs + , ArgumentPack + , typename List::arg const + , Error + > + , make_arg_list00< + List + , DeducedArgs + , TagFn + , Positional + , UsedArgs + , ArgumentPack + , typename List::arg + , Error + > + >::type type; + }; +#endif + + // Returns an ArgumentPack where the list of arguments has + // been tagged with keyword tags. + // + // List: A specialization of item<> (see below). Contains + // both the ordered ParameterSpecs, and the given arguments. + // + // DeducedArgs: A specialization of deduced_item<> (see below). + // A list containing only the deduced ParameterSpecs. + // + // TagFn: A metafunction class used to tag positional or deduced + // arguments with a keyword tag. + // + // Position: An mpl::bool_<> specialization indicating if positional + // matching is to be performed. + // + // DeducedSet: An mpl::set<> containing the keyword tags used so far. + // + // ArgumentPack: The ArgumentPack built so far. This is initially an + // empty_arg_list and is built incrementally. + // + + template < + class List + , class DeducedArgs + , class TagFn + , class Positional + , class DeducedSet + , class ArgumentPack + , class Error + > + struct make_arg_list_aux + { + typedef typename mpl::eval_if< + is_same + , mpl::identity > + , make_arg_list0 + >::type type; + }; + + // VC6.5 was choking on the default parameters for make_arg_list_aux, so + // this just forwards to that adding in the defaults. + template < + class List + , class DeducedArgs + , class TagFn + , class EmitErrors = mpl::true_ + > + struct make_arg_list + { + typedef typename make_arg_list_aux< + List, DeducedArgs, TagFn, mpl::true_, aux::set0, empty_arg_list, void_ + >::type type; + }; + + // A parameter spec item typelist. + template + struct item + { + typedef Spec spec; + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + typedef is_const is_arg_const; +#endif + + typedef Arg arg; + typedef Tail tail; + }; + + template + struct make_item + { + typedef item type; + }; + + // Creates a item typelist. + template + struct make_items + { + typedef typename mpl::eval_if< + is_same + , mpl::identity + , make_item + >::type type; + }; + + // A typelist that stored deduced parameter specs. + template + struct deduced_item + { + typedef ParameterSpec spec; + typedef Tail tail; + }; + + // Evaluate Tail and construct deduced_item list. + template + struct make_deduced_item + { + typedef deduced_item type; + }; + + template + struct make_deduced_items + { + typedef typename mpl::eval_if< + is_same + , mpl::identity + , mpl::eval_if< + is_deduced + , make_deduced_item + , Tail + > + >::type type; + }; + + // Generates: + // + // make< + // parameter_spec#0, argument_type#0 + // , make< + // parameter_spec#1, argument_type#1 + // , ... mpl::identity + // ...> + // > +#define BOOST_PARAMETER_make_arg_list(z, n, names) \ + BOOST_PP_SEQ_ELEM(0,names)< \ + BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names), n), \ + BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(2,names), n), + +#define BOOST_PARAMETER_right_angle(z, n, text) > + +#define BOOST_PARAMETER_build_arg_list(n, make, parameter_spec, argument_type) \ + BOOST_PP_REPEAT( \ + n, BOOST_PARAMETER_make_arg_list, (make)(parameter_spec)(argument_type)) \ + mpl::identity \ + BOOST_PP_REPEAT(n, BOOST_PARAMETER_right_angle, _) + +#define BOOST_PARAMETER_make_deduced_list(z, n, names) \ + BOOST_PP_SEQ_ELEM(0,names)< \ + BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names), n), + +#define BOOST_PARAMETER_build_deduced_list(n, make, parameter_spec) \ + BOOST_PP_REPEAT( \ + n, BOOST_PARAMETER_make_deduced_list, (make)(parameter_spec)) \ + mpl::identity \ + BOOST_PP_REPEAT(n, BOOST_PARAMETER_right_angle, _) + + struct tag_keyword_arg + { + template + struct apply + : tag + {}; + }; + + struct tag_template_keyword_arg + { + template + struct apply + { + typedef template_keyword type; + }; + }; + +} // namespace aux + +#define BOOST_PARAMETER_FORWARD_TYPEDEF(z, i, names) \ + typedef BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0,names),i) BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(1,names),i); + +#define BOOST_PARAMETER_FORWARD_TYPEDEFS(n, src, dest) \ + BOOST_PP_REPEAT(n, BOOST_PARAMETER_FORWARD_TYPEDEF, (src)(dest)) + + +#define BOOST_PARAMETER_TEMPLATE_ARGS(z, n, text) class BOOST_PP_CAT(PS, n) = void_ + +template< + class PS0 + , BOOST_PP_ENUM_SHIFTED(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_TEMPLATE_ARGS, _) +> +struct parameters +{ +#undef BOOST_PARAMETER_TEMPLATE_ARGS + + typedef typename BOOST_PARAMETER_build_deduced_list( + BOOST_PARAMETER_MAX_ARITY, aux::make_deduced_items, PS + )::type deduced_list; + + // if the elements of NamedList match the criteria of overload + // resolution, returns a type which can be constructed from + // parameters. Otherwise, this is not a valid metafunction (no nested + // ::type). + + +#if ! defined(BOOST_NO_SFINAE) && ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x592)) + // If NamedList satisfies the PS0, PS1, ..., this is a + // metafunction returning parameters. Otherwise it + // has no nested ::type. + template + struct match_base + : mpl::if_< + // mpl::and_< + // aux::satisfies_requirements_of + // , mpl::and_< + // aux::satisfies_requirements_of... + // ..., mpl::true_ + // ...> > + +# define BOOST_PARAMETER_satisfies(z, n, text) \ + mpl::and_< \ + aux::satisfies_requirements_of< \ + typename mpl::first::type \ + , BOOST_PP_CAT(PS, n)> \ + , + mpl::and_< + is_same::type, void_> + , BOOST_PP_REPEAT(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_satisfies, _) + mpl::true_ + BOOST_PP_REPEAT(BOOST_PARAMETER_MAX_ARITY, BOOST_PARAMETER_right_angle, _) + > + +# undef BOOST_PARAMETER_satisfies + + , mpl::identity + , void_ + > + {}; +#endif + + // Specializations are to be used as an optional argument to + // eliminate overloads via SFINAE + template< +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + // Borland simply can't handle default arguments in member + // class templates. People wishing to write portable code can + // explicitly specify BOOST_PARAMETER_MAX_ARITY arguments + BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, class A) +#else + BOOST_PP_ENUM_BINARY_PARAMS( + BOOST_PARAMETER_MAX_ARITY, class A, = void_ BOOST_PP_INTERCEPT + ) +#endif + > + struct match +# if ! defined(BOOST_NO_SFINAE) && ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x592)) + : match_base< + typename aux::make_arg_list< + typename BOOST_PARAMETER_build_arg_list( + BOOST_PARAMETER_MAX_ARITY, aux::make_items, PS, A + )::type + , deduced_list + , aux::tag_keyword_arg + , mpl::false_ // Don't emit errors when doing SFINAE + >::type + >::type + {}; +# else + { + typedef parameters< + BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, PS) + > type; + }; +# endif + + // Metafunction that returns an ArgumentPack. + + // TODO, bind has to instantiate the error type in the result + // of make_arg_list. + + template < +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + // Borland simply can't handle default arguments in member + // class templates. People wishing to write portable code can + // explicitly specify BOOST_PARAMETER_MAX_ARITY arguments + BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, class A) +#else + BOOST_PP_ENUM_BINARY_PARAMS( + BOOST_PARAMETER_MAX_ARITY, class A, = void_ BOOST_PP_INTERCEPT + ) +#endif + > + struct bind + { + typedef typename aux::make_arg_list< + typename BOOST_PARAMETER_build_arg_list( + BOOST_PARAMETER_MAX_ARITY, aux::make_items, PS, A + )::type + , deduced_list + , aux::tag_template_keyword_arg + >::type result; + + typedef typename mpl::first::type type; + }; + + BOOST_PARAMETER_FORWARD_TYPEDEFS(BOOST_PARAMETER_MAX_ARITY, PS, parameter_spec) + + // + // The function call operator is used to build an arg_list that + // labels the positional parameters and maintains whatever other + // tags may have been specified by the caller. + // + // !!!NOTE!!! + // + // The make_arg_list<> produces a reversed arg_list, so + // we need to pass the arguments to its constructor + // reversed. + // + aux::empty_arg_list operator()() const + { + return aux::empty_arg_list(); + } + + template + typename mpl::first< + typename aux::make_arg_list< + aux::item< + PS0,A0 + > + , deduced_list + , aux::tag_keyword_arg + >::type + >::type + operator()(A0& a0) const + { + typedef typename aux::make_arg_list< + aux::item< + PS0,A0 + > + , deduced_list + , aux::tag_keyword_arg + >::type result; + + typedef typename mpl::first::type result_type; + typedef typename mpl::second::type error; + error(); + + return result_type( + a0 + // , void_(), void_(), void_() ... + BOOST_PP_ENUM_TRAILING_PARAMS( + BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, 1) + , aux::void_reference() BOOST_PP_INTERCEPT) + ); + } + + template + typename mpl::first< + typename aux::make_arg_list< + aux::item< + PS0,A0 + , aux::item< + PS1,A1 + > + > + , deduced_list + , aux::tag_keyword_arg + >::type + >::type + operator()(A0& a0, A1& a1) const + { + typedef typename aux::make_arg_list< + aux::item< + PS0,A0 + , aux::item< + PS1,A1 + > + > + , deduced_list + , aux::tag_keyword_arg + >::type result; + + typedef typename mpl::first::type result_type; + typedef typename mpl::second::type error; + error(); + + return result_type( + a1,a0 + // , void_(), void_() ... + BOOST_PP_ENUM_TRAILING_PARAMS( + BOOST_PP_SUB(BOOST_PARAMETER_MAX_ARITY, 2) + , aux::void_reference() BOOST_PP_INTERCEPT) + ); + } + + // Higher arities are handled by the preprocessor +#define BOOST_PP_ITERATION_PARAMS_1 (3,( \ + 3,BOOST_PARAMETER_MAX_ARITY, \ + )) +#include BOOST_PP_ITERATE() + +}; + +} // namespace parameter + +} // namespace boost + +#endif // BOOST_PARAMETERS_031014_HPP + diff --git a/cpp/BoostParts/boost/parameter/preprocessor.hpp b/cpp/BoostParts/boost/parameter/preprocessor.hpp new file mode 100644 index 00000000..f1bda87c --- /dev/null +++ b/cpp/BoostParts/boost/parameter/preprocessor.hpp @@ -0,0 +1,1178 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PARAMETER_PREPROCESSOR_060206_HPP +# define BOOST_PARAMETER_PREPROCESSOR_060206_HPP + +# include +# include +# include + +# include +# include +# include + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# include + +# include +# include + +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +# include +# endif + +namespace boost { namespace parameter { namespace aux { + +# if ! defined(BOOST_NO_SFINAE) && ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x592)) + +// Given Match, which is "void x" where x is an argument matching +// criterion, extract a corresponding MPL predicate. +template +struct unwrap_predicate; + +// Match anything +template <> +struct unwrap_predicate +{ + typedef mpl::always type; +}; + +#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) + +typedef void* voidstar; + +// A matching predicate is explicitly specified +template +struct unwrap_predicate +{ + typedef Predicate type; +}; + +#else + +// A matching predicate is explicitly specified +template +struct unwrap_predicate +{ + typedef Predicate type; +}; + +#endif + + +// A type to which the argument is supposed to be convertible is +// specified +template +struct unwrap_predicate +{ + typedef is_convertible type; +}; + +// Recast the ParameterSpec's nested match metafunction as a free metafunction +template < + class Parameters + , BOOST_PP_ENUM_BINARY_PARAMS( + BOOST_PARAMETER_MAX_ARITY, class A, = boost::parameter::void_ BOOST_PP_INTERCEPT + ) +> +struct match + : Parameters::template match< + BOOST_PP_ENUM_PARAMS(BOOST_PARAMETER_MAX_ARITY, A) + > +{}; +# endif + +# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) + +// Function template argument deduction does many of the same things +// as type matching during partial specialization, so we call a +// function template to "store" T into the type memory addressed by +// void(*)(T). +template +msvc_store_type +msvc_store_predicate_type(void*(*)(void**(T))); + +template +msvc_store_type,void*(*)(void*(T))> +msvc_store_predicate_type(void*(*)(void*(T))); + +template +struct unwrap_predicate +{ + static FunctionType f; + + // We don't want the function to be evaluated, just instantiated, + // so protect it inside of sizeof. + enum { dummy = sizeof(msvc_store_predicate_type(f)) }; + + // Now pull the type out of the instantiated base class + typedef typename msvc_type_memory::storage::type type; +}; + +template <> +struct unwrap_predicate +{ + typedef mpl::always type; +}; + +# endif + +# undef false_ + +template < + class Parameters + , BOOST_PP_ENUM_BINARY_PARAMS( + BOOST_PARAMETER_MAX_ARITY, class A, = boost::parameter::void_ BOOST_PP_INTERCEPT + ) +> +struct argument_pack +{ + typedef typename make_arg_list< + typename BOOST_PARAMETER_build_arg_list( + BOOST_PARAMETER_MAX_ARITY, make_items, typename Parameters::parameter_spec, A + )::type + , typename Parameters::deduced_list + , tag_keyword_arg + , mpl::false_ + >::type result; + typedef typename mpl::first::type type; +}; + +# if 1 //BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// Works around VC6 problem where it won't accept rvalues. +template +T& as_lvalue(T& value, long) +{ + return value; +} + +template +T const& as_lvalue(T const& value, int) +{ + return value; +} +# endif + + +# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) \ + || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +template +struct apply_predicate +{ + BOOST_MPL_ASSERT(( + mpl::and_ + )); + + typedef typename mpl::if_< + typename mpl::apply2::type + , char + , int + >::type type; +}; + +template +struct funptr_predicate +{ + static P p; + + template + static typename apply_predicate::type + check_predicate(type, Args*, void**(*)(P0)); + + template + static typename mpl::if_< + is_convertible + , char + , int + >::type check_predicate(type, Args*, void*(*)(P0)); + + template + struct apply + { + BOOST_STATIC_CONSTANT(bool, result = + sizeof(check_predicate(boost::type(), (Args*)0, &p)) == 1 + ); + + typedef mpl::bool_::result> type; + }; +}; + +template <> +struct funptr_predicate + : mpl::always +{}; + +# endif + +}}} // namespace boost::parameter::aux + +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +// From Paul Mensonides +# define BOOST_PARAMETER_IS_NULLARY(x) \ + BOOST_PP_SPLIT(1, BOOST_PARAMETER_IS_NULLARY_C x BOOST_PP_COMMA() 0) \ + /**/ +# define BOOST_PARAMETER_IS_NULLARY_C() \ + ~, 1 BOOST_PP_RPAREN() \ + BOOST_PP_TUPLE_EAT(2) BOOST_PP_LPAREN() ~ \ + /**/ +# else +# define BOOST_PARAMETER_IS_NULLARY(x) BOOST_PP_IS_NULLARY(x) +# endif + +# define BOOST_PARAMETER_MEMBER_FUNCTION_CHECK_STATIC_static () +# define BOOST_PARAMETER_MEMBER_FUNCTION_IS_STATIC(name) \ + BOOST_PARAMETER_IS_NULLARY( \ + BOOST_PP_CAT(BOOST_PARAMETER_MEMBER_FUNCTION_CHECK_STATIC_,name) \ + ) + +# if !defined(BOOST_MSVC) +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_static +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC(name) \ + BOOST_PP_CAT(BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_, name) +# else +// Workaround for MSVC preprocessor. +// +// When stripping static from "static f", msvc will produce +// " f". The leading whitespace doesn't go away when pasting +// the token with something else, so this thing is a hack to +// strip the whitespace. +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_static ( +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_AUX(name) \ + BOOST_PP_CAT(BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_, name)) +# define BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC(name) \ + BOOST_PP_SEQ_HEAD( \ + BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC_AUX(name) \ + ) +# endif + +# define BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(name) \ + BOOST_PP_EXPR_IF( \ + BOOST_PARAMETER_MEMBER_FUNCTION_IS_STATIC(name) \ + , static \ + ) + +# define BOOST_PARAMETER_MEMBER_FUNCTION_NAME(name) \ + BOOST_PP_IF( \ + BOOST_PARAMETER_MEMBER_FUNCTION_IS_STATIC(name) \ + , BOOST_PARAMETER_MEMBER_FUNCTION_STRIP_STATIC \ + , name BOOST_PP_TUPLE_EAT(1) \ + )(name) + +// Calculates [begin, end) arity range. + +# define BOOST_PARAMETER_ARITY_RANGE_M_optional(state) state +# define BOOST_PARAMETER_ARITY_RANGE_M_deduced_optional(state) state +# define BOOST_PARAMETER_ARITY_RANGE_M_required(state) BOOST_PP_INC(state) +# define BOOST_PARAMETER_ARITY_RANGE_M_deduced_required(state) BOOST_PP_INC(state) + +# define BOOST_PARAMETER_ARITY_RANGE_M(s, state, x) \ + BOOST_PP_CAT( \ + BOOST_PARAMETER_ARITY_RANGE_M_ \ + , BOOST_PARAMETER_FN_ARG_QUALIFIER(x) \ + )(state) +/**/ + +# define BOOST_PARAMETER_ARITY_RANGE(args) \ + ( \ + BOOST_PP_SEQ_FOLD_LEFT(BOOST_PARAMETER_ARITY_RANGE_M, 0, args) \ + , BOOST_PP_INC(BOOST_PP_SEQ_SIZE(args)) \ + ) +/**/ + +// Accessor macros for the argument specs tuple. +# define BOOST_PARAMETER_FN_ARG_QUALIFIER(x) \ + BOOST_PP_TUPLE_ELEM(4,0,x) +/**/ + +# define BOOST_PARAMETER_FN_ARG_NAME(x) \ + BOOST_PP_TUPLE_ELEM(4,1,x) +/**/ + +# define BOOST_PARAMETER_FN_ARG_PRED(x) \ + BOOST_PP_TUPLE_ELEM(4,2,x) +/**/ + +# define BOOST_PARAMETER_FN_ARG_DEFAULT(x) \ + BOOST_PP_TUPLE_ELEM(4,3,x) +/**/ + +# define BOOST_PARAMETETER_FUNCTION_EAT_KEYWORD_QUALIFIER_out(x) +# define BOOST_PARAMETETER_FUNCTION_EAT_KEYWORD_QUALIFIER_in_out(x) + +// Returns 1 if x is either "out(k)" or "in_out(k)". +# define BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER(x) \ + BOOST_PP_IS_EMPTY( \ + BOOST_PP_CAT(BOOST_PARAMETETER_FUNCTION_EAT_KEYWORD_QUALIFIER_, x) \ + ) \ +/**/ + +# define BOOST_PARAMETETER_FUNCTION_GET_KEYWORD_QUALIFIER_out(x) x +# define BOOST_PARAMETETER_FUNCTION_GET_KEYWORD_QUALIFIER_in_out(x) x +# define BOOST_PARAMETER_FUNCTION_KEYWORD_GET(x) \ + BOOST_PP_CAT(BOOST_PARAMETETER_FUNCTION_GET_KEYWORD_QUALIFIER_, x) +/**/ + +// Returns the keyword of x, where x is either a keyword qualifier +// or a keyword. +// +// k => k +// out(k) => k +// in_out(k) => k +// +# define BOOST_PARAMETER_FUNCTION_KEYWORD(x) \ + BOOST_PP_IF( \ + BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER(x) \ + , BOOST_PARAMETER_FUNCTION_KEYWORD_GET \ + , x BOOST_PP_TUPLE_EAT(1) \ + )(x) +/**/ + +# define BOOST_PARAMETER_FN_ARG_KEYWORD(x) \ + BOOST_PARAMETER_FUNCTION_KEYWORD( \ + BOOST_PARAMETER_FN_ARG_NAME(x) \ + ) + +// Builds forwarding functions. + +# define BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_TEMPLATE_Z(z, n) \ + template +/**/ + +# if ! defined(BOOST_NO_SFINAE) && ! BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x592)) +# define BOOST_PARAMETER_FUNCTION_FWD_MATCH_Z(z, name, parameters, n) \ + , typename boost::parameter::aux::match< \ + parameters, BOOST_PP_ENUM_PARAMS(n, ParameterArgumentType) \ + >::type = parameters() +# else +# define BOOST_PARAMETER_FUNCTION_FWD_MATCH_Z(z, name, parameters, n) +# endif +/**/ + +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(base) \ + BOOST_PP_CAT( \ + boost_param_parameters_ \ + , BOOST_PP_CAT(__LINE__, BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base)) \ + ) + +// Produce a name for a result type metafunction for the function +// named base +# define BOOST_PARAMETER_FUNCTION_RESULT_NAME(base) \ + BOOST_PP_CAT( \ + boost_param_result_ \ + , BOOST_PP_CAT(__LINE__,BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base)) \ + ) + +// Can't do boost_param_impl_ ## basee because base might start with an underscore +// daniel: what? how is that relevant? the reason for using CAT() is to make sure +// base is expanded. i'm not sure we need to here, but it's more stable to do it. +# define BOOST_PARAMETER_IMPL(base) \ + BOOST_PP_CAT(boost_param_impl,BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base)) + +# define BOOST_PARAMETER_FUNCTION_FWD_FUNCTION00(z, n, r, data, elem) \ + BOOST_PP_IF( \ + n \ + , BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_TEMPLATE_Z, BOOST_PP_TUPLE_EAT(2) \ + )(z,n) \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(BOOST_PP_TUPLE_ELEM(7,3,data)) \ + inline \ + BOOST_PP_EXPR_IF(n, typename) \ + BOOST_PARAMETER_FUNCTION_RESULT_NAME(BOOST_PP_TUPLE_ELEM(7,3,data))< \ + BOOST_PP_EXPR_IF(n, typename) \ + boost::parameter::aux::argument_pack< \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(BOOST_PP_TUPLE_ELEM(7,3,data)) \ + BOOST_PP_COMMA_IF(n) \ + BOOST_PP_IF( \ + n, BOOST_PP_SEQ_ENUM, BOOST_PP_TUPLE_EAT(1) \ + )(elem) \ + >::type \ + >::type \ + BOOST_PARAMETER_MEMBER_FUNCTION_NAME(BOOST_PP_TUPLE_ELEM(7,3,data))( \ + BOOST_PP_IF( \ + n \ + , BOOST_PP_SEQ_FOR_EACH_I_R \ + , BOOST_PP_TUPLE_EAT(4) \ + )( \ + r \ + , BOOST_PARAMETER_FUNCTION_ARGUMENT \ + , ~ \ + , elem \ + ) \ + BOOST_PP_IF(n, BOOST_PARAMETER_FUNCTION_FWD_MATCH_Z, BOOST_PP_TUPLE_EAT(4))( \ + z \ + , BOOST_PP_TUPLE_ELEM(7,3,data) \ + , BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(BOOST_PP_TUPLE_ELEM(7,3,data)) \ + , n \ + ) \ + ) BOOST_PP_EXPR_IF(BOOST_PP_TUPLE_ELEM(7,4,data), const) \ + { \ + return BOOST_PARAMETER_IMPL(BOOST_PP_TUPLE_ELEM(7,3,data))( \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(BOOST_PP_TUPLE_ELEM(7,3,data))()( \ + BOOST_PP_ENUM_PARAMS_Z(z, n, a) \ + ) \ + ); \ + } +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_FUNCTION0(r, data, elem) \ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTION00( \ + BOOST_PP_TUPLE_ELEM(7,0,data) \ + , BOOST_PP_TUPLE_ELEM(7,1,data) \ + , r \ + , data \ + , elem \ + ) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_ARITY_0(z, n, data) \ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTION00( \ + z, n, BOOST_PP_DEDUCE_R() \ + , (z, n, BOOST_PP_TUPLE_REM(5) data) \ + , ~ \ + ) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_ARITY_N(z, n, data) \ + BOOST_PP_SEQ_FOR_EACH( \ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTION0 \ + , (z, n, BOOST_PP_TUPLE_REM(5) data) \ + , BOOST_PP_SEQ_FOR_EACH_PRODUCT( \ + BOOST_PARAMETER_FUNCTION_FWD_PRODUCT \ + , BOOST_PP_SEQ_FIRST_N( \ + n, BOOST_PP_TUPLE_ELEM(5,3,data) \ + ) \ + ) \ + ) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_FUNCTION(z, n, data) \ + BOOST_PP_IF( \ + n \ + , BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_ARITY_N \ + , BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_ARITY_0 \ + )(z,n,data) \ +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS0( \ + result,name,args,const_,combinations,range \ +) \ + BOOST_PP_REPEAT_FROM_TO( \ + BOOST_PP_TUPLE_ELEM(2,0,range), BOOST_PP_TUPLE_ELEM(2,1,range) \ + , BOOST_PARAMETER_FUNCTION_FWD_FUNCTION \ + , (result,name,const_,combinations,BOOST_PP_TUPLE_ELEM(2,1,range)) \ + ) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS(result,name,args, const_, combinations) \ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS0( \ + result, name, args, const_, combinations, BOOST_PARAMETER_ARITY_RANGE(args) \ + ) +/**/ + +// Builds boost::parameter::parameters<> specialization +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_optional(tag) \ + optional + +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_deduced_required(tag) \ + required + +# if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) && !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +# if BOOST_WORKAROUND(BOOST_MSVC, == 1300) +# define BOOST_PARAMETER_PREDICATE_TYPE(p) void*(*) (void* p) +# else +# define BOOST_PARAMETER_PREDICATE_TYPE(p) void p +# endif + +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ + BOOST_PP_COMMA_IF(i) \ + boost::parameter::BOOST_PP_CAT( \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_ \ + , BOOST_PARAMETER_FN_ARG_QUALIFIER(elem) \ + )( \ + tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ + BOOST_PARAMETER_FN_ARG_KEYWORD(elem) \ + ) \ + ) \ + , typename boost::parameter::aux::unwrap_predicate< \ + BOOST_PARAMETER_PREDICATE_TYPE(BOOST_PARAMETER_FN_ARG_PRED(elem)) \ + >::type \ + > +# elif BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ + BOOST_PP_COMMA_IF(i) \ + boost::parameter::BOOST_PP_CAT( \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_ \ + , BOOST_PARAMETER_FN_ARG_QUALIFIER(elem) \ + )( \ + tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ + BOOST_PARAMETER_FN_ARG_KEYWORD(elem) \ + ) \ + ) \ + , boost::parameter::aux::funptr_predicate< \ + void* BOOST_PARAMETER_FN_ARG_PRED(elem) \ + > \ + > +# elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# define BOOST_PARAMETER_FUNCTION_PARAMETERS_M(r,tag_namespace,i,elem) \ + BOOST_PP_COMMA_IF(i) \ + boost::parameter::BOOST_PP_CAT( \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_QUALIFIER_ \ + , BOOST_PARAMETER_FN_ARG_QUALIFIER(elem) \ + )( \ + tag_namespace::BOOST_PARAMETER_FUNCTION_KEYWORD( \ + BOOST_PARAMETER_FN_ARG_KEYWORD(elem) \ + ) \ + ) \ + , boost::mpl::always \ + > +# endif + +# define BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, base, args) \ + template \ + struct BOOST_PP_CAT( \ + BOOST_PP_CAT(boost_param_params_, __LINE__) \ + , BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base) \ + ) : boost::parameter::parameters< \ + BOOST_PP_SEQ_FOR_EACH_I( \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_M, tag_namespace, args \ + ) \ + > \ + {}; \ + \ + typedef BOOST_PP_CAT( \ + BOOST_PP_CAT(boost_param_params_, __LINE__) \ + , BOOST_PARAMETER_MEMBER_FUNCTION_NAME(base) \ + ) + +// Defines result type metafunction +# define BOOST_PARAMETER_FUNCTION_RESULT_ARG(z, _, i, x) \ + BOOST_PP_COMMA_IF(i) class BOOST_PP_TUPLE_ELEM(3,1,x) +/**/ + +# define BOOST_PARAMETER_FUNCTION_RESULT_(result, name, args) \ + template \ + struct BOOST_PARAMETER_FUNCTION_RESULT_NAME(name) \ + { \ + typedef typename BOOST_PARAMETER_PARENTHESIZED_TYPE(result) type; \ + }; + +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + +# define BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ + BOOST_PARAMETER_FUNCTION_RESULT_(result, name, args) \ + template <> \ + struct BOOST_PARAMETER_FUNCTION_RESULT_NAME(name) \ + { typedef int type; }; + +# else + +# define BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ + BOOST_PARAMETER_FUNCTION_RESULT_(result, name, args) + +# endif + +// Defines implementation function +# define BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) \ + template \ + typename BOOST_PARAMETER_FUNCTION_RESULT_NAME(name)< \ + Args \ + >::type BOOST_PARAMETER_IMPL(name)(Args const& args) + +# define BOOST_PARAMETER_FUNCTION_IMPL_FWD(name) \ + BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name); +/**/ + +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_required(state, arg) \ + ( \ + BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4, 0, state)) \ + , BOOST_PP_SEQ_PUSH_BACK(BOOST_PP_TUPLE_ELEM(4, 1, state), arg) \ + , BOOST_PP_TUPLE_ELEM(4, 2, state) \ + , BOOST_PP_TUPLE_ELEM(4, 3, state) \ + ) + +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_deduced_required(state, arg) \ + BOOST_PARAMETER_FUNCTION_SPLIT_ARG_required(state, arg) + +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_optional(state, arg) \ + ( \ + BOOST_PP_TUPLE_ELEM(4, 0, state) \ + , BOOST_PP_TUPLE_ELEM(4, 1, state) \ + , BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4, 2, state)) \ + , BOOST_PP_SEQ_PUSH_BACK(BOOST_PP_TUPLE_ELEM(4, 3, state), arg) \ + ) + +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG_deduced_optional(state, arg) \ + BOOST_PARAMETER_FUNCTION_SPLIT_ARG_optional(state, arg) + +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARG(s, state, arg) \ + BOOST_PP_CAT( \ + BOOST_PARAMETER_FUNCTION_SPLIT_ARG_ \ + , BOOST_PARAMETER_FN_ARG_QUALIFIER(arg) \ + )(state, arg) + +// Returns (required_count, required, optional_count, optionals) tuple +# define BOOST_PARAMETER_FUNCTION_SPLIT_ARGS(args) \ + BOOST_PP_SEQ_FOLD_LEFT( \ + BOOST_PARAMETER_FUNCTION_SPLIT_ARG \ + , (0,BOOST_PP_SEQ_NIL, 0,BOOST_PP_SEQ_NIL) \ + , args \ + ) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG_NAME(keyword) \ + BOOST_PP_CAT(BOOST_PP_CAT(keyword,_),type) + +// Helpers used as parameters to BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_TEMPLATE_ARG(r, _, arg) \ + , class BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG_NAME( \ + BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ + ) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG(r, _, arg) \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG_NAME( \ + BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ + )& BOOST_PARAMETER_FN_ARG_KEYWORD(arg) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_PARAMETER(r, _, arg) \ + , BOOST_PARAMETER_FN_ARG_KEYWORD(arg) + +// Produces a name for the dispatch functions. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name) \ + BOOST_PP_CAT( \ + boost_param_default_ \ + , BOOST_PP_CAT(__LINE__, BOOST_PARAMETER_MEMBER_FUNCTION_NAME(name)) \ + ) + +// Helper macro used below to produce lists based on the keyword argument +// names. macro is applied to every element. n is the number of +// optional arguments that should be included. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS(macro, n, split_args) \ + BOOST_PP_SEQ_FOR_EACH( \ + macro \ + , ~ \ + , BOOST_PP_TUPLE_ELEM(4,1,split_args) \ + ) \ + BOOST_PP_SEQ_FOR_EACH( \ + macro \ + , ~ \ + , BOOST_PP_SEQ_FIRST_N( \ + BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(4,2,split_args), n) \ + , BOOST_PP_TUPLE_ELEM(4,3,split_args) \ + ) \ + ) + +// Generates a keyword | default expression. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT(arg, tag_namespace) \ + boost::parameter::keyword< \ + tag_namespace::BOOST_PARAMETER_FN_ARG_KEYWORD(arg) \ + >::instance | boost::parameter::aux::use_default_tag() + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_GET_ARG(arg, tag_ns) \ + BOOST_PARAMETER_FUNCTION_CAST( \ + args[ \ + BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT( \ + arg, tag_ns \ + ) \ + ] \ + , BOOST_PARAMETER_FN_ARG_PRED(arg) \ + , Args \ + ) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_BODY(name, n, split_args, tag_namespace) \ + { \ + return BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ + (ResultType(*)())0 \ + , args \ + , 0L \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_PARAMETER \ + , n \ + , split_args \ + ) \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_GET_ARG( \ + BOOST_PP_SEQ_ELEM( \ + BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(4,2,split_args), n) \ + , BOOST_PP_TUPLE_ELEM(4,3,split_args) \ + ) \ + , tag_namespace \ + ) \ + ); \ + } + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_ACTUAL_DEFAULT(arg) \ + BOOST_PARAMETER_FUNCTION_CAST( \ + boost::parameter::aux::as_lvalue(BOOST_PARAMETER_FN_ARG_DEFAULT(arg), 0L) \ + , BOOST_PARAMETER_FN_ARG_PRED(arg) \ + , Args \ + ) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT_BODY(name, n, split_args, tag_ns, const_) \ + template < \ + class ResultType \ + , class Args \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_TEMPLATE_ARG \ + , BOOST_PP_INC(n) \ + , split_args \ + ) \ + > \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(name) \ + ResultType BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ + ResultType(*)() \ + , Args const& args \ + , long \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG \ + , BOOST_PP_INC(n) \ + , split_args \ + ) \ + , boost::parameter::aux::use_default_tag \ + ) BOOST_PP_EXPR_IF(const_, const) \ + { \ + return BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ + (ResultType(*)())0 \ + , args \ + , 0L \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_PARAMETER \ + , BOOST_PP_INC(n) \ + , split_args \ + ) \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_ACTUAL_DEFAULT( \ + BOOST_PP_SEQ_ELEM( \ + BOOST_PP_SUB(BOOST_PP_TUPLE_ELEM(4,2,split_args), BOOST_PP_INC(n)) \ + , BOOST_PP_TUPLE_ELEM(4,3,split_args) \ + ) \ + ) \ + ); \ + } + +// Produces a forwarding layer in the default evaluation machine. +// +// data is a tuple: +// +// (name, split_args) +// +// Where name is the base name of the function, and split_args is a tuple: +// +// (required_count, required_args, optional_count, required_args) +// + + +// defines the actual function body for BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION below. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION0(z, n, data) \ + template < \ + class ResultType \ + , class Args \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_TEMPLATE_ARG \ + , n \ + , BOOST_PP_TUPLE_ELEM(5,1,data) \ + ) \ + > \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(BOOST_PP_TUPLE_ELEM(5,0,data)) \ + ResultType BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(BOOST_PP_TUPLE_ELEM(5,0,data))( \ + ResultType(*)() \ + , Args const& args \ + , int \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG \ + , n \ + , BOOST_PP_TUPLE_ELEM(5,1,data) \ + ) \ + ) BOOST_PP_EXPR_IF(BOOST_PP_TUPLE_ELEM(5,2,data), const) \ + BOOST_PP_IF( \ + n \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_BODY \ + , ; BOOST_PP_TUPLE_EAT(4) \ + )( \ + BOOST_PP_TUPLE_ELEM(5,0,data) \ + , n \ + , BOOST_PP_TUPLE_ELEM(5,1,data) \ + , BOOST_PP_TUPLE_ELEM(5,3,data) \ + ) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION(z, n, data) \ + BOOST_PP_IF( \ + BOOST_PP_AND( \ + BOOST_PP_NOT(n) \ + , BOOST_PP_TUPLE_ELEM(5,4,data) \ + ) \ + , BOOST_PP_TUPLE_EAT(3) \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION0 \ + )(z, n, data) \ + BOOST_PP_IF( \ + BOOST_PP_EQUAL(n, BOOST_PP_TUPLE_ELEM(4,2,BOOST_PP_TUPLE_ELEM(5,1,data))) \ + , BOOST_PP_TUPLE_EAT(5) \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_EVAL_DEFAULT_BODY \ + )( \ + BOOST_PP_TUPLE_ELEM(5,0,data) \ + , n \ + , BOOST_PP_TUPLE_ELEM(5,1,data) \ + , BOOST_PP_TUPLE_ELEM(5,3,data) \ + , BOOST_PP_TUPLE_ELEM(5,2,data) \ + ) + +# define BOOST_PARAMETER_FUNCTION_DEFAULT_GET_ARG(r, tag_ns, arg) \ + , BOOST_PARAMETER_FUNCTION_CAST( \ + args[ \ + boost::parameter::keyword::instance \ + ] \ + , BOOST_PARAMETER_FN_ARG_PRED(arg) \ + , Args \ + ) + +// Generates the function template that recives a ArgumentPack, and then +// goes on to call the layers of overloads generated by +// BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER. +# define BOOST_PARAMETER_FUNCTION_INITIAL_DISPATCH_FUNCTION(name, split_args, const_, tag_ns) \ + template \ + typename BOOST_PARAMETER_FUNCTION_RESULT_NAME(name)::type \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(name) \ + BOOST_PARAMETER_IMPL(name)(Args const& args) BOOST_PP_EXPR_IF(const_, const) \ + { \ + return BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ + (typename BOOST_PARAMETER_FUNCTION_RESULT_NAME(name)::type(*)())0 \ + , args \ + , 0L \ + \ + BOOST_PP_SEQ_FOR_EACH( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_GET_ARG \ + , tag_ns \ + , BOOST_PP_TUPLE_ELEM(4,1,split_args) \ + ) \ + \ + ); \ + } + +// Helper for BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER below. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER_AUX( \ + name, split_args, skip_fwd_decl, const_, tag_namespace \ + ) \ + BOOST_PP_REPEAT_FROM_TO( \ + 0 \ + , BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4, 2, split_args)) \ + , BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION \ + , (name, split_args, const_, tag_namespace, skip_fwd_decl) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_INITIAL_DISPATCH_FUNCTION(name, split_args, const_, tag_namespace) \ +\ + template < \ + class ResultType \ + , class Args \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_TEMPLATE_ARG \ + , 0 \ + , split_args \ + ) \ + > \ + BOOST_PARAMETER_MEMBER_FUNCTION_STATIC(name) \ + ResultType BOOST_PARAMETER_FUNCTION_DEFAULT_NAME(name)( \ + ResultType(*)() \ + , Args const& args \ + , int \ + BOOST_PARAMETER_FUNCTION_DEFAULT_ARGUMENTS( \ + BOOST_PARAMETER_FUNCTION_DEFAULT_FUNCTION_ARG \ + , 0 \ + , split_args \ + ) \ + ) BOOST_PP_EXPR_IF(const_, const) + +// Generates a bunch of forwarding functions that each extract +// one more argument. +# define BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, skip_fwd_decl, const_, tag_ns) \ + BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER_AUX( \ + name, BOOST_PARAMETER_FUNCTION_SPLIT_ARGS(args), skip_fwd_decl, const_, tag_ns \ + ) +/**/ + +// Defines the result metafunction and the parameters specialization. +# define BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_RESULT(result, name, args) \ + \ + BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, name, args) \ + BOOST_PARAMETER_FUNCTION_PARAMETERS_NAME(name); \ + +// Helper for BOOST_PARAMETER_FUNCTION below. +# define BOOST_PARAMETER_FUNCTION_AUX(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name); \ +\ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ + result, name, args, 0 \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, 0, 0, tag_namespace) + +// Defines a Boost.Parameter enabled function with the new syntax. +# define BOOST_PARAMETER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_AUX( \ + result, name, tag_namespace \ + , BOOST_PARAMETER_FLATTEN(3, 2, 3, args) \ + ) \ +/**/ + +// Defines a Boost.Parameter enabled function. +# define BOOST_PARAMETER_BASIC_FUNCTION_AUX(result, name, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ + \ + BOOST_PARAMETER_FUNCTION_IMPL_FWD(name) \ + \ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ + result, name, args, 0 \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) + +# define BOOST_PARAMETER_BASIC_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_BASIC_FUNCTION_AUX( \ + result, name, tag_namespace \ + , BOOST_PARAMETER_FLATTEN(2, 2, 3, args) \ + ) \ +/**/ + +// Defines a Boost.Parameter enabled member function. +# define BOOST_PARAMETER_BASIC_MEMBER_FUNCTION_AUX(result, name, tag_namespace, args, const_) \ + BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ + \ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ + result, name, args, const_ \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_IMPL_HEAD(name) BOOST_PP_EXPR_IF(const_, const) \ +/**/ + +# define BOOST_PARAMETER_BASIC_MEMBER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION_AUX( \ + result, name, tag_namespace \ + , BOOST_PARAMETER_FLATTEN(2, 2, 3, args) \ + , 0 \ + ) +/**/ + +# define BOOST_PARAMETER_BASIC_CONST_MEMBER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_BASIC_MEMBER_FUNCTION_AUX( \ + result, name, tag_namespace \ + , BOOST_PARAMETER_FLATTEN(2, 2, 3, args) \ + , 1 \ + ) +/**/ + + + +# define BOOST_PARAMETER_MEMBER_FUNCTION_AUX(result, name, tag_namespace, const_, args) \ + BOOST_PARAMETER_FUNCTION_HEAD(result, name, tag_namespace, args) \ +\ + BOOST_PARAMETER_FUNCTION_FWD_FUNCTIONS( \ + result, name, args, const_ \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ + \ + BOOST_PARAMETER_FUNCTION_DEFAULT_LAYER(name, args, 1, const_, tag_namespace) + +// Defines a Boost.Parameter enabled function with the new syntax. +# define BOOST_PARAMETER_MEMBER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_MEMBER_FUNCTION_AUX( \ + result, name, tag_namespace, 0 \ + , BOOST_PARAMETER_FLATTEN(3, 2, 3, args) \ + ) \ +/**/ + +# define BOOST_PARAMETER_CONST_MEMBER_FUNCTION(result, name, tag_namespace, args) \ + BOOST_PARAMETER_MEMBER_FUNCTION_AUX( \ + result, name, tag_namespace, 1 \ + , BOOST_PARAMETER_FLATTEN(3, 2, 3, args) \ + ) \ +/**/ + +// Defines a Boost.Parameter enabled constructor. + +# define BOOST_PARAMETER_FUNCTION_ARGUMENT(r, _, i, elem) \ + BOOST_PP_COMMA_IF(i) elem& BOOST_PP_CAT(a, i) +/**/ + +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + +// Older MSVC can't do what's necessary to handle commas in base names; just +// use a typedef instead if you have a base name that contains commas. +# define BOOST_PARAMETER_PARENTHESIZED_BASE(x) BOOST_PP_SEQ_HEAD(x) + +# else + +# define BOOST_PARAMETER_PARENTHESIZED_BASE(x) BOOST_PARAMETER_PARENTHESIZED_TYPE(x) + +# endif + +# define BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR00(z, n, r, data, elem) \ + BOOST_PP_IF( \ + n \ + , BOOST_PARAMETER_FUNCTION_FWD_FUNCTION_TEMPLATE_Z, BOOST_PP_TUPLE_EAT(2) \ + )(z, n) \ + BOOST_PP_EXPR_IF(BOOST_PP_EQUAL(n,1), explicit) \ + BOOST_PP_TUPLE_ELEM(6,2,data)( \ + BOOST_PP_IF( \ + n \ + , BOOST_PP_SEQ_FOR_EACH_I_R \ + , BOOST_PP_TUPLE_EAT(4) \ + )( \ + r \ + , BOOST_PARAMETER_FUNCTION_ARGUMENT \ + , ~ \ + , elem \ + ) \ + BOOST_PP_IF(n, BOOST_PARAMETER_FUNCTION_FWD_MATCH_Z, BOOST_PP_TUPLE_EAT(4))( \ + z \ + , BOOST_PP_TUPLE_ELEM(6,3,data) \ + , BOOST_PP_CAT(constructor_parameters, __LINE__) \ + , n \ + ) \ + ) \ + : BOOST_PARAMETER_PARENTHESIZED_BASE(BOOST_PP_TUPLE_ELEM(6,3,data)) ( \ + BOOST_PP_CAT(constructor_parameters, __LINE__)()( \ + BOOST_PP_ENUM_PARAMS_Z(z, n, a) \ + ) \ + ) \ + {} +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR0(r, data, elem) \ + BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR00( \ + BOOST_PP_TUPLE_ELEM(6,0,data) \ + , BOOST_PP_TUPLE_ELEM(6,1,data) \ + , r \ + , data \ + , elem \ + ) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_PRODUCT(r, product) \ + (product) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR_ARITY_0(z, n, data) \ + BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR00( \ + z, n, BOOST_PP_DEDUCE_R() \ + , (z, n, BOOST_PP_TUPLE_REM(4) data) \ + , ~ \ + ) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR_ARITY_N(z, n, data) \ + BOOST_PP_SEQ_FOR_EACH( \ + BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR0 \ + , (z, n, BOOST_PP_TUPLE_REM(4) data) \ + , BOOST_PP_SEQ_FOR_EACH_PRODUCT( \ + BOOST_PARAMETER_FUNCTION_FWD_PRODUCT \ + , BOOST_PP_SEQ_FIRST_N( \ + n, BOOST_PP_TUPLE_ELEM(4,2,data) \ + ) \ + ) \ + ) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR(z, n, data) \ + BOOST_PP_IF( \ + n \ + , BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR_ARITY_N \ + , BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR_ARITY_0 \ + )(z,n,data) \ +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTORS0(class_,base,args,combinations,range) \ + BOOST_PP_REPEAT_FROM_TO( \ + BOOST_PP_TUPLE_ELEM(2,0,range), BOOST_PP_TUPLE_ELEM(2,1,range) \ + , BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTOR \ + , (class_,base,combinations,BOOST_PP_TUPLE_ELEM(2,1,range)) \ + ) +/**/ + +# define BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTORS(class_,base,args,combinations) \ + BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTORS0( \ + class_, base, args, combinations, BOOST_PARAMETER_ARITY_RANGE(args) \ + ) +/**/ + +# define BOOST_PARAMETER_CONSTRUCTOR_AUX(class_, base, tag_namespace, args) \ + BOOST_PARAMETER_FUNCTION_PARAMETERS(tag_namespace, ctor, args) \ + BOOST_PP_CAT(constructor_parameters, __LINE__); \ +\ + BOOST_PARAMETER_FUNCTION_FWD_CONSTRUCTORS( \ + class_, base, args \ + , BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + ) \ +/**/ + +# define BOOST_PARAMETER_CONSTRUCTOR(class_, base, tag_namespace, args) \ + BOOST_PARAMETER_CONSTRUCTOR_AUX( \ + class_, base, tag_namespace \ + , BOOST_PARAMETER_FLATTEN(2, 2, 3, args) \ + ) +/**/ + +# ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +# define BOOST_PARAMETER_FUNCTION_FWD_COMBINATION(r, _, i, elem) \ + (BOOST_PP_IF( \ + BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER( \ + BOOST_PARAMETER_FN_ARG_NAME(elem) \ + ) \ + , (const ParameterArgumentType ## i)(ParameterArgumentType ## i) \ + , (const ParameterArgumentType ## i) \ + )) +// MSVC6.5 lets us bind rvalues to T&. +# elif BOOST_WORKAROUND(BOOST_MSVC, < 1300) +# define BOOST_PARAMETER_FUNCTION_FWD_COMBINATION(r, _, i, elem) \ + (BOOST_PP_IF( \ + BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER( \ + BOOST_PARAMETER_FN_ARG_NAME(elem) \ + ) \ + , (ParameterArgumentType ## i) \ + , (const ParameterArgumentType ## i) \ + )) +// No partial ordering. This feature doesn't work. +// This is exactly the same as for VC6.5, but we might change it later. +# else +# define BOOST_PARAMETER_FUNCTION_FWD_COMBINATION(r, _, i, elem) \ + (BOOST_PP_IF( \ + BOOST_PARAMETER_FUNCTION_IS_KEYWORD_QUALIFIER( \ + BOOST_PARAMETER_FN_ARG_NAME(elem) \ + ) \ + , (ParameterArgumentType ## i) \ + , (const ParameterArgumentType ## i) \ + )) +# endif + +# define BOOST_PARAMETER_FUNCTION_FWD_COMBINATIONS(args) \ + BOOST_PP_SEQ_FOR_EACH_I(BOOST_PARAMETER_FUNCTION_FWD_COMBINATION, ~, args) + +#endif // BOOST_PARAMETER_PREPROCESSOR_060206_HPP + diff --git a/cpp/BoostParts/boost/preprocessor/detail/is_nullary.hpp b/cpp/BoostParts/boost/preprocessor/detail/is_nullary.hpp new file mode 100644 index 00000000..dee4075a --- /dev/null +++ b/cpp/BoostParts/boost/preprocessor/detail/is_nullary.hpp @@ -0,0 +1,30 @@ +# /* ************************************************************************** +# * * +# * (C) Copyright Paul Mensonides 2002. +# * Distributed under the Boost Software License, Version 1.0. (See +# * accompanying file LICENSE_1_0.txt or copy at +# * http://www.boost.org/LICENSE_1_0.txt) +# * * +# ************************************************************************** */ +# +# /* See http://www.boost.org for most recent version. */ +# +# ifndef BOOST_PREPROCESSOR_DETAIL_IS_NULLARY_HPP +# define BOOST_PREPROCESSOR_DETAIL_IS_NULLARY_HPP +# +# include +# include +# +# /* BOOST_PP_IS_NULLARY */ +# +# if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_EDG() +# define BOOST_PP_IS_NULLARY(x) BOOST_PP_CHECK(x, BOOST_PP_IS_NULLARY_CHECK) +# else +# define BOOST_PP_IS_NULLARY(x) BOOST_PP_IS_NULLARY_I(x) +# define BOOST_PP_IS_NULLARY_I(x) BOOST_PP_CHECK(x, BOOST_PP_IS_NULLARY_CHECK) +# endif +# +# define BOOST_PP_IS_NULLARY_CHECK() 1 +# define BOOST_PP_CHECK_RESULT_BOOST_PP_IS_NULLARY_CHECK 0, BOOST_PP_NIL +# +# endif diff --git a/cpp/BoostParts/boost/preprocessor/facilities/is_empty.hpp b/cpp/BoostParts/boost/preprocessor/facilities/is_empty.hpp new file mode 100644 index 00000000..638265c5 --- /dev/null +++ b/cpp/BoostParts/boost/preprocessor/facilities/is_empty.hpp @@ -0,0 +1,43 @@ +# /* ************************************************************************** +# * * +# * (C) Copyright Paul Mensonides 2003. +# * Distributed under the Boost Software License, Version 1.0. (See +# * accompanying file LICENSE_1_0.txt or copy at +# * http://www.boost.org/LICENSE_1_0.txt) +# * * +# ************************************************************************** */ +# +# /* See http://www.boost.org for most recent version. */ +# +# ifndef BOOST_PREPROCESSOR_FACILITIES_IS_EMPTY_HPP +# define BOOST_PREPROCESSOR_FACILITIES_IS_EMPTY_HPP +# +# include +# include +# include +# include +# include +# +# /* BOOST_PP_IS_EMPTY */ +# +# if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_MSVC() && ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_MWCC() +# define BOOST_PP_IS_EMPTY(x) BOOST_PP_IS_EMPTY_I(x BOOST_PP_IS_EMPTY_HELPER) +# define BOOST_PP_IS_EMPTY_I(contents) BOOST_PP_TUPLE_ELEM(2, 1, (BOOST_PP_IS_EMPTY_DEF_ ## contents())) +# define BOOST_PP_IS_EMPTY_DEF_BOOST_PP_IS_EMPTY_HELPER 1, 1 BOOST_PP_EMPTY +# define BOOST_PP_IS_EMPTY_HELPER() , 0 +# else +# if BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_MSVC() +# define BOOST_PP_IS_EMPTY(x) BOOST_PP_IS_EMPTY_I(BOOST_PP_IS_EMPTY_HELPER x ()) +# define BOOST_PP_IS_EMPTY_I(test) BOOST_PP_IS_EMPTY_II(BOOST_PP_SPLIT(0, BOOST_PP_CAT(BOOST_PP_IS_EMPTY_DEF_, test))) +# define BOOST_PP_IS_EMPTY_II(id) id +# else +# define BOOST_PP_IS_EMPTY(x) BOOST_PP_IS_EMPTY_I((BOOST_PP_IS_EMPTY_HELPER x ())) +# define BOOST_PP_IS_EMPTY_I(par) BOOST_PP_IS_EMPTY_II ## par +# define BOOST_PP_IS_EMPTY_II(test) BOOST_PP_SPLIT(0, BOOST_PP_CAT(BOOST_PP_IS_EMPTY_DEF_, test)) +# endif +# define BOOST_PP_IS_EMPTY_HELPER() 1 +# define BOOST_PP_IS_EMPTY_DEF_1 1, BOOST_PP_NIL +# define BOOST_PP_IS_EMPTY_DEF_BOOST_PP_IS_EMPTY_HELPER 0, BOOST_PP_NIL +# endif +# +# endif diff --git a/cpp/BoostParts/boost/preprocessor/for.hpp b/cpp/BoostParts/boost/preprocessor/for.hpp new file mode 100644 index 00000000..9ec9cee6 --- /dev/null +++ b/cpp/BoostParts/boost/preprocessor/for.hpp @@ -0,0 +1,17 @@ +# /* ************************************************************************** +# * * +# * (C) Copyright Paul Mensonides 2002. +# * Distributed under the Boost Software License, Version 1.0. (See +# * accompanying file LICENSE_1_0.txt or copy at +# * http://www.boost.org/LICENSE_1_0.txt) +# * * +# ************************************************************************** */ +# +# /* See http://www.boost.org for most recent version. */ +# +# ifndef BOOST_PREPROCESSOR_FOR_HPP +# define BOOST_PREPROCESSOR_FOR_HPP +# +# include +# +# endif diff --git a/cpp/BoostParts/boost/progress.hpp b/cpp/BoostParts/boost/progress.hpp new file mode 100644 index 00000000..fbbf04a7 --- /dev/null +++ b/cpp/BoostParts/boost/progress.hpp @@ -0,0 +1,143 @@ +// boost progress.hpp header file ------------------------------------------// + +// Copyright Beman Dawes 1994-99. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/timer for documentation. + +// Revision History +// 1 Dec 01 Add leading progress display strings (suggested by Toon Knapen) +// 20 May 01 Introduce several static_casts<> to eliminate warning messages +// (Fixed by Beman, reported by Herve Bronnimann) +// 12 Jan 01 Change to inline implementation to allow use without library +// builds. See docs for more rationale. (Beman Dawes) +// 22 Jul 99 Name changed to .hpp +// 16 Jul 99 Second beta +// 6 Jul 99 Initial boost version + +#ifndef BOOST_PROGRESS_HPP +#define BOOST_PROGRESS_HPP + +#include +#include // for noncopyable +#include // for uintmax_t +#include // for ostream, cout, etc +#include // for string + +namespace boost { + +// progress_timer ----------------------------------------------------------// + +// A progress_timer behaves like a timer except that the destructor displays +// an elapsed time message at an appropriate place in an appropriate form. + +class progress_timer : public timer, private noncopyable +{ + + public: + explicit progress_timer( std::ostream & os = std::cout ) + // os is hint; implementation may ignore, particularly in embedded systems + : m_os(os) {} + ~progress_timer() + { + // A) Throwing an exception from a destructor is a Bad Thing. + // B) The progress_timer destructor does output which may throw. + // C) A progress_timer is usually not critical to the application. + // Therefore, wrap the I/O in a try block, catch and ignore all exceptions. + try + { + // use istream instead of ios_base to workaround GNU problem (Greg Chicares) + std::istream::fmtflags old_flags = m_os.setf( std::istream::fixed, + std::istream::floatfield ); + std::streamsize old_prec = m_os.precision( 2 ); + m_os << elapsed() << " s\n" // "s" is System International d'Unites std + << std::endl; + m_os.flags( old_flags ); + m_os.precision( old_prec ); + } + + catch (...) {} // eat any exceptions + } // ~progress_timer + + private: + std::ostream & m_os; +}; + + +// progress_display --------------------------------------------------------// + +// progress_display displays an appropriate indication of +// progress at an appropriate place in an appropriate form. + +// NOTE: (Jan 12, 2001) Tried to change unsigned long to boost::uintmax_t, but +// found some compilers couldn't handle the required conversion to double. +// Reverted to unsigned long until the compilers catch up. + +class progress_display : private noncopyable +{ + public: + explicit progress_display( unsigned long expected_count, + std::ostream & os = std::cout, + const std::string & s1 = "\n", //leading strings + const std::string & s2 = "", + const std::string & s3 = "" ) + // os is hint; implementation may ignore, particularly in embedded systems + : m_os(os), m_s1(s1), m_s2(s2), m_s3(s3) { restart(expected_count); } + + void restart( unsigned long expected_count ) + // Effects: display appropriate scale + // Postconditions: count()==0, expected_count()==expected_count + { + _count = _next_tic_count = _tic = 0; + _expected_count = expected_count; + + m_os << m_s1 << "0% 10 20 30 40 50 60 70 80 90 100%\n" + << m_s2 << "|----|----|----|----|----|----|----|----|----|----|" + << std::endl // endl implies flush, which ensures display + << m_s3; + if ( !_expected_count ) _expected_count = 1; // prevent divide by zero + } // restart + + unsigned long operator+=( unsigned long increment ) + // Effects: Display appropriate progress tic if needed. + // Postconditions: count()== original count() + increment + // Returns: count(). + { + if ( (_count += increment) >= _next_tic_count ) { display_tic(); } + return _count; + } + + unsigned long operator++() { return operator+=( 1 ); } + unsigned long count() const { return _count; } + unsigned long expected_count() const { return _expected_count; } + + private: + std::ostream & m_os; // may not be present in all imps + const std::string m_s1; // string is more general, safer than + const std::string m_s2; // const char *, and efficiency or size are + const std::string m_s3; // not issues + + unsigned long _count, _expected_count, _next_tic_count; + unsigned int _tic; + void display_tic() + { + // use of floating point ensures that both large and small counts + // work correctly. static_cast<>() is also used several places + // to suppress spurious compiler warnings. + unsigned int tics_needed = + static_cast( + (static_cast(_count)/_expected_count)*50.0 ); + do { m_os << '*' << std::flush; } while ( ++_tic < tics_needed ); + _next_tic_count = + static_cast((_tic/50.0)*_expected_count); + if ( _count == _expected_count ) { + if ( _tic < 51 ) m_os << '*'; + m_os << std::endl; + } + } // display_tic +}; + +} // namespace boost + +#endif // BOOST_PROGRESS_HPP diff --git a/cpp/BoostParts/boost/test/debug.hpp b/cpp/BoostParts/boost/test/debug.hpp new file mode 100644 index 00000000..cf3313d0 --- /dev/null +++ b/cpp/BoostParts/boost/test/debug.hpp @@ -0,0 +1,101 @@ +// (C) Copyright Gennadiy Rozental 2006-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines portable debug interfaces +// *************************************************************************** + +#ifndef BOOST_TEST_DEBUG_API_HPP_112006GER +#define BOOST_TEST_DEBUG_API_HPP_112006GER + +// Boost.Test +#include +#include +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace debug { + +// ************************************************************************** // +// ************** check if program is running under debugger ************** // +// ************************************************************************** // + +bool BOOST_TEST_DECL under_debugger(); + +// ************************************************************************** // +// ************** cause program to break execution ************** // +// ************** in debugger at call point ************** // +// ************************************************************************** // + +void BOOST_TEST_DECL debugger_break(); + +// ************************************************************************** // +// ************** gui debugger setup ************** // +// ************************************************************************** // + +struct dbg_startup_info { + long pid; + bool break_or_continue; + unit_test::const_string binary_path; + unit_test::const_string display; + unit_test::const_string init_done_lock; +}; + +typedef unit_test::callback1 dbg_starter; + +// ************************************************************************** // +// ************** debugger setup ************** // +// ************************************************************************** // + +#if BOOST_WORKAROUND( BOOST_MSVC, <1300) + +std::string BOOST_TEST_DECL set_debugger( unit_test::const_string dbg_id ); + +#else + +std::string BOOST_TEST_DECL set_debugger( unit_test::const_string dbg_id, dbg_starter s = dbg_starter() ); + +#endif + + +// ************************************************************************** // +// ************** attach debugger to the current process ************** // +// ************************************************************************** // + +bool BOOST_TEST_DECL attach_debugger( bool break_or_continue = true ); + +// ************************************************************************** // +// ************** switch on/off detect memory leaks feature ************** // +// ************************************************************************** // + +void BOOST_TEST_DECL detect_memory_leaks( bool on_off ); + +// ************************************************************************** // +// ************** cause program to break execution in ************** // +// ************** debugger at specific allocation point ************** // +// ************************************************************************** // + +void BOOST_TEST_DECL break_memory_alloc( long mem_alloc_order_num ); + +} // namespace debug + +} // namespace boost + +#include + +#endif diff --git a/cpp/BoostParts/boost/test/debug_config.hpp b/cpp/BoostParts/boost/test/debug_config.hpp new file mode 100644 index 00000000..54c21e9d --- /dev/null +++ b/cpp/BoostParts/boost/test/debug_config.hpp @@ -0,0 +1,24 @@ +// (C) Copyright Gennadiy Rozental 2006-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : user's config for Boost.Test debugging support +// *************************************************************************** + +#ifndef BOOST_TEST_DEBUG_CONFIG_HPP_112006GER +#define BOOST_TEST_DEBUG_CONFIG_HPP_112006GER + +// ';' separated list of supported debuggers +// #define BOOST_TEST_DBG_LIST gdb;dbx + +// maximum size of /proc/pid/stat file +// #define BOOST_TEST_STAT_LINE_MAX + +#endif diff --git a/cpp/BoostParts/boost/test/detail/config.hpp b/cpp/BoostParts/boost/test/detail/config.hpp new file mode 100644 index 00000000..54557927 --- /dev/null +++ b/cpp/BoostParts/boost/test/detail/config.hpp @@ -0,0 +1,104 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 63441 $ +// +// Description : as a central place for global configuration switches +// *************************************************************************** + +#ifndef BOOST_TEST_CONFIG_HPP_071894GER +#define BOOST_TEST_CONFIG_HPP_071894GER + +// Boost +#include // compilers workarounds +#include + +//____________________________________________________________________________// + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x570)) || \ + BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ + (defined __sgi && BOOST_WORKAROUND(_COMPILER_VERSION, BOOST_TESTED_AT(730))) +# define BOOST_TEST_SHIFTED_LINE +#endif + +//____________________________________________________________________________// + +#if defined(BOOST_MSVC) || (defined(__BORLANDC__) && !defined(BOOST_DISABLE_WIN32)) +# define BOOST_TEST_CALL_DECL __cdecl +#else +# define BOOST_TEST_CALL_DECL /**/ +#endif + +//____________________________________________________________________________// + +#if !defined(BOOST_NO_STD_LOCALE) && \ + !BOOST_WORKAROUND(BOOST_MSVC, < 1310) && \ + !defined(__MWERKS__) +# define BOOST_TEST_USE_STD_LOCALE 1 +#endif + +//____________________________________________________________________________// + +#if BOOST_WORKAROUND(__BORLANDC__, <= 0x570) || \ + BOOST_WORKAROUND( __COMO__, <= 0x433 ) || \ + BOOST_WORKAROUND( __INTEL_COMPILER, <= 800 ) || \ + defined(__sgi) && _COMPILER_VERSION <= 730 || \ + BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ + defined(__DECCXX) || \ + defined(__DMC__) +# define BOOST_TEST_NO_PROTECTED_USING +#endif + +//____________________________________________________________________________// + +#if defined(__GNUC__) || BOOST_WORKAROUND(BOOST_MSVC, == 1400) +#define BOOST_TEST_PROTECTED_VIRTUAL virtual +#else +#define BOOST_TEST_PROTECTED_VIRTUAL +#endif + +//____________________________________________________________________________// + +#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) && \ + !BOOST_WORKAROUND(BOOST_MSVC, <1310) && \ + !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x530)) +# define BOOST_TEST_SUPPORT_INTERACTION_TESTING 1 +#endif + +//____________________________________________________________________________// + +#if defined(BOOST_ALL_DYN_LINK) && !defined(BOOST_TEST_DYN_LINK) +# define BOOST_TEST_DYN_LINK +#endif + +#if defined(BOOST_TEST_INCLUDED) +# undef BOOST_TEST_DYN_LINK +#endif + +#if defined(BOOST_TEST_DYN_LINK) +# define BOOST_TEST_ALTERNATIVE_INIT_API + +# ifdef BOOST_TEST_SOURCE +# define BOOST_TEST_DECL BOOST_SYMBOL_EXPORT +# else +# define BOOST_TEST_DECL BOOST_SYMBOL_IMPORT +# endif // BOOST_TEST_SOURCE +#else +# define BOOST_TEST_DECL +#endif + +#if !defined(BOOST_TEST_MAIN) && defined(BOOST_AUTO_TEST_MAIN) +#define BOOST_TEST_MAIN BOOST_AUTO_TEST_MAIN +#endif + +#if !defined(BOOST_TEST_MAIN) && defined(BOOST_TEST_MODULE) +#define BOOST_TEST_MAIN BOOST_TEST_MODULE +#endif + +#endif // BOOST_TEST_CONFIG_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/detail/enable_warnings.hpp b/cpp/BoostParts/boost/test/detail/enable_warnings.hpp new file mode 100644 index 00000000..2d67fb0b --- /dev/null +++ b/cpp/BoostParts/boost/test/detail/enable_warnings.hpp @@ -0,0 +1,30 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : enable previosly suppressed warnings +// *************************************************************************** + +#ifdef BOOST_MSVC +# pragma warning(default: 4511) // copy constructor can't not be generated +# pragma warning(default: 4512) // assignment operator can't not be generated +# pragma warning(default: 4100) // unreferenced formal parameter +# pragma warning(default: 4996) // was declared deprecated +# pragma warning(default: 4355) // 'this' : used in base member initializer list +# pragma warning(default: 4706) // assignment within conditional expression +# pragma warning(default: 4251) // class 'A' needs to have dll-interface to be used by clients of class 'B' +# pragma warning(default: 4127) // conditional expression is constant +# pragma warning(default: 4290) // C++ exception specification ignored except to ... +# pragma warning(default: 4180) // qualifier applied to function type has no meaning; ignored +# pragma warning(default: 4275) // non dll-interface class ... used as base for dll-interface class ... +# pragma warning(default: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data +# pragma warning(default: 4511) // 'class' : copy constructor could not be generated +# pragma warning(pop) +#endif diff --git a/cpp/BoostParts/boost/test/detail/fwd_decl.hpp b/cpp/BoostParts/boost/test/detail/fwd_decl.hpp new file mode 100644 index 00000000..8ffba82b --- /dev/null +++ b/cpp/BoostParts/boost/test/detail/fwd_decl.hpp @@ -0,0 +1,48 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : contains forward eclarations for Boost.Test data types +// *************************************************************************** + +#ifndef BOOST_TEST_FWD_DECL_HPP_011605GER +#define BOOST_TEST_FWD_DECL_HPP_011605GER + +namespace boost { + +class execution_monitor; +class execution_exception; + +namespace unit_test { + +class test_unit; +class test_case; +class test_suite; +class master_test_suite_t; + +class test_tree_visitor; +class test_observer; + +// singletons +class unit_test_monitor_t; +class unit_test_log_t; + +class unit_test_log_formatter; +struct log_entry_data; +struct log_checkpoint_data; + +class lazy_ostream; + +} // namespace unit_test + +} // namespace boost + +#endif // BOOST_TEST_FWD_DECL_HPP_011605GER + diff --git a/cpp/BoostParts/boost/test/detail/global_typedef.hpp b/cpp/BoostParts/boost/test/detail/global_typedef.hpp new file mode 100644 index 00000000..b2d81868 --- /dev/null +++ b/cpp/BoostParts/boost/test/detail/global_typedef.hpp @@ -0,0 +1,88 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : some trivial global typedefs +// *************************************************************************** + +#ifndef BOOST_TEST_GLOBAL_TYPEDEF_HPP_021005GER +#define BOOST_TEST_GLOBAL_TYPEDEF_HPP_021005GER + +#include +#define BOOST_TEST_L( s ) boost::unit_test::const_string( s, sizeof( s ) - 1 ) +#define BOOST_TEST_STRINGIZE( s ) BOOST_TEST_L( BOOST_STRINGIZE( s ) ) +#define BOOST_TEST_EMPTY_STRING BOOST_TEST_L( "" ) + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +typedef unsigned long counter_t; + +//____________________________________________________________________________// + +enum report_level { INV_REPORT_LEVEL, CONFIRMATION_REPORT, SHORT_REPORT, DETAILED_REPORT, NO_REPORT }; + +//____________________________________________________________________________// + +enum output_format { INV_OF, CLF /* compiler log format */, XML /* XML */ }; + +//____________________________________________________________________________// + +enum test_unit_type { tut_case = 0x01, tut_suite = 0x10, tut_any = 0x11 }; + +//____________________________________________________________________________// + +typedef unsigned long test_unit_id; + +const test_unit_id INV_TEST_UNIT_ID = 0xFFFFFFFF; +const test_unit_id MAX_TEST_CASE_ID = 0xFFFFFFFE; +const test_unit_id MIN_TEST_CASE_ID = 0x00010000; +const test_unit_id MAX_TEST_SUITE_ID = 0x0000FF00; +const test_unit_id MIN_TEST_SUITE_ID = 0x00000001; + +//____________________________________________________________________________// + +namespace ut_detail { + +inline test_unit_type +test_id_2_unit_type( test_unit_id id ) +{ + return (id & 0xFFFF0000) != 0 ? tut_case : tut_suite; +} + +//____________________________________________________________________________// + +// helper templates to prevent ODR violations +template +struct static_constant { + static T value; +}; + +template +T static_constant::value; + +//____________________________________________________________________________// + +} // namespace ut_detail + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_GLOBAL_TYPEDEF_HPP_021005GER diff --git a/cpp/BoostParts/boost/test/detail/log_level.hpp b/cpp/BoostParts/boost/test/detail/log_level.hpp new file mode 100644 index 00000000..3fecd4fb --- /dev/null +++ b/cpp/BoostParts/boost/test/detail/log_level.hpp @@ -0,0 +1,43 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : shared definition for unit test log levels +// *************************************************************************** + +#ifndef BOOST_TEST_LOG_LEVEL_HPP_011605GER +#define BOOST_TEST_LOG_LEVEL_HPP_011605GER + +namespace boost { +namespace unit_test { + +// ************************************************************************** // +// ************** log levels ************** // +// ************************************************************************** // + +// each log level includes all subsequent higher loging levels +enum log_level { + invalid_log_level = -1, + log_successful_tests = 0, + log_test_units = 1, + log_messages = 2, + log_warnings = 3, + log_all_errors = 4, // reported by unit test macros + log_cpp_exception_errors = 5, // uncaught C++ exceptions + log_system_errors = 6, // including timeouts, signals, traps + log_fatal_errors = 7, // including unit test macros or + // fatal system errors + log_nothing = 8 +}; + +} // namespace unit_test +} // namespace boost + +#endif // BOOST_TEST_LOG_LEVEL_HPP_011605GER diff --git a/cpp/BoostParts/boost/test/detail/suppress_warnings.hpp b/cpp/BoostParts/boost/test/detail/suppress_warnings.hpp new file mode 100644 index 00000000..2471226b --- /dev/null +++ b/cpp/BoostParts/boost/test/detail/suppress_warnings.hpp @@ -0,0 +1,31 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : suppress some warnings +// *************************************************************************** + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4511) // copy constructor can't not be generated +# pragma warning(disable: 4512) // assignment operator can't not be generated +# pragma warning(disable: 4100) // unreferenced formal parameter +# pragma warning(disable: 4996) // was declared deprecated +# pragma warning(disable: 4355) // 'this' : used in base member initializer list +# pragma warning(disable: 4706) // assignment within conditional expression +# pragma warning(disable: 4251) // class 'A' needs to have dll-interface to be used by clients of class 'B' +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4290) // C++ exception specification ignored except to ... +# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored +# pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ... +# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data +# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated +#endif + diff --git a/cpp/BoostParts/boost/test/detail/unit_test_parameters.hpp b/cpp/BoostParts/boost/test/detail/unit_test_parameters.hpp new file mode 100644 index 00000000..391dfc3b --- /dev/null +++ b/cpp/BoostParts/boost/test/detail/unit_test_parameters.hpp @@ -0,0 +1,69 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : storage for unit test framework parameters information +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_PARAMETERS_HPP_071894GER +#define BOOST_TEST_UNIT_TEST_PARAMETERS_HPP_071894GER + +#include +#include + +#include + +// STL +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** runtime_config ************** // +// ************************************************************************** // + +namespace runtime_config { + +BOOST_TEST_DECL void init( int& argc, char** argv ); + +BOOST_TEST_DECL unit_test::log_level log_level(); +BOOST_TEST_DECL bool no_result_code(); +BOOST_TEST_DECL unit_test::report_level report_level(); +BOOST_TEST_DECL const_string test_to_run(); +BOOST_TEST_DECL const_string break_exec_path(); +BOOST_TEST_DECL bool save_pattern(); +BOOST_TEST_DECL bool show_build_info(); +BOOST_TEST_DECL bool show_progress(); +BOOST_TEST_DECL bool catch_sys_errors(); +BOOST_TEST_DECL bool auto_start_dbg(); +BOOST_TEST_DECL bool use_alt_stack(); +BOOST_TEST_DECL bool detect_fp_exceptions(); +BOOST_TEST_DECL output_format report_format(); +BOOST_TEST_DECL output_format log_format(); +BOOST_TEST_DECL std::ostream* report_sink(); +BOOST_TEST_DECL std::ostream* log_sink(); +BOOST_TEST_DECL long detect_memory_leaks(); +BOOST_TEST_DECL int random_seed(); + +} // namespace runtime_config + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_PARAMETERS_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/detail/workaround.hpp b/cpp/BoostParts/boost/test/detail/workaround.hpp new file mode 100644 index 00000000..8c284602 --- /dev/null +++ b/cpp/BoostParts/boost/test/detail/workaround.hpp @@ -0,0 +1,65 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : contains mics. workarounds +// *************************************************************************** + +#ifndef BOOST_TEST_WORKAROUND_HPP_021005GER +#define BOOST_TEST_WORKAROUND_HPP_021005GER + +// Boost +#include // compilers workarounds and std::ptrdiff_t + +// STL +#include // for std::distance + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace ut_detail { + +#ifdef BOOST_NO_STD_DISTANCE +template +std::ptrdiff_t distance( T const& x_, T const& y_ ) +{ + std::ptrdiff_t res = 0; + + std::distance( x_, y_, res ); + + return res; +} + +//____________________________________________________________________________// + +#else +using std::distance; +#endif + +template inline void ignore_unused_variable_warning(const T&) {} + +} // namespace ut_detail + +} // namespace unit_test + +namespace unit_test_framework = unit_test; + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_WORKAROUND_HPP_021005GER diff --git a/cpp/BoostParts/boost/test/execution_monitor.hpp b/cpp/BoostParts/boost/test/execution_monitor.hpp new file mode 100644 index 00000000..e8461527 --- /dev/null +++ b/cpp/BoostParts/boost/test/execution_monitor.hpp @@ -0,0 +1,263 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Beman Dawes 2001. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : defines abstract monitor interfaces and implements execution exception +// The original Boost Test Library included an implementation detail function +// named catch_exceptions() which caught otherwise uncaught C++ exceptions. +// It was derived from an existing test framework by Beman Dawes. The +// intent was to expand later to catch other detectable but platform dependent +// error events like Unix signals or Windows structured C exceptions. +// +// Requests from early adopters of the Boost Test Library included +// configurable levels of error message detail, elimination of templates, +// separation of error reporting, and making the catch_exceptions() facilities +// available as a public interface. Support for unit testing also stretched +// the function based design. Implementation within the header became less +// attractive due to the need to include many huge system dependent headers, +// although still preferable in certain cases. +// +// All those issues have been addressed by introducing the class-based +// design presented here. +// *************************************************************************** + +#ifndef BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER +#define BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER + +// Boost.Test +#include +#include +#include +#include + +// Boost +#include +#include +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace detail { + +// ************************************************************************** // +// ************** detail::translate_exception_base ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL translate_exception_base { +public: + // Constructor + explicit translate_exception_base( boost::scoped_ptr& next ) + { + next.swap( m_next ); + } + + // Destructor + virtual ~translate_exception_base() {} + + virtual int operator()( unit_test::callback0 const& F ) = 0; + +protected: + // Data members + boost::scoped_ptr m_next; +}; + +} // namespace detail + +// ************************************************************************** // +// ************** execution_exception ************** // +// ************************************************************************** // + +// design rationale: fear of being out (or nearly out) of memory. + +class BOOST_TEST_DECL execution_exception { + typedef boost::unit_test::const_string const_string; +public: + enum error_code { + // These values are sometimes used as program return codes. + // The particular values have been chosen to avoid conflicts with + // commonly used program return codes: values < 100 are often user + // assigned, values > 255 are sometimes used to report system errors. + // Gaps in values allow for orderly expansion. + + no_error = 0, // for completeness only; never returned + user_error = 200, // user reported non-fatal error + cpp_exception_error = 205, // see note (1) below + system_error = 210, // see note (2) below + timeout_error = 215, // only detectable on certain platforms + user_fatal_error = 220, // user reported fatal error + system_fatal_error = 225 // see note (2) below + + // Note 1: Only uncaught C++ exceptions are treated as errors. + // If the application catches a C++ exception, it will never reach + // the execution_monitor. + + // Note 2: These errors include Unix signals and Windows structured + // exceptions. They are often initiated by hardware traps. + // + // The implementation decides what is a fatal_system_exception and what is + // just a system_exception. Fatal errors are so likely to have corrupted + // machine state (like a stack overflow or addressing exception) that it + // is unreasonable to continue execution. + }; + + struct BOOST_TEST_DECL location { + explicit location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 ); + + const_string m_file_name; + size_t m_line_num; + const_string m_function; + }; + + // Constructor + execution_exception( error_code ec_, const_string what_msg_, location const& location_ ); // max length 256 inc '\0' + + // Access methods + error_code code() const { return m_error_code; } + const_string what() const { return m_what; } + location const& where() const { return m_location; } + +private: + // Data members + error_code m_error_code; + const_string m_what; + location m_location; +}; // execution_exception + +// ************************************************************************** // +// ************** execution_monitor ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL execution_monitor { +public: + // Constructor + execution_monitor() + : p_catch_system_errors( true ) + , p_auto_start_dbg( false ) + , p_timeout( 0 ) + , p_use_alt_stack( true ) + , p_detect_fp_exceptions( false ) + {} + + // Public properties + + // The p_catch_system_errors parameter specifies whether the monitor should + // try to catch system errors/exceptions that would cause program to crash + // in regular case + unit_test::readwrite_property p_catch_system_errors; + // The p_auto_start_dbg parameter specifies whether the monitor should + // try to attach debugger in case of caught system error + unit_test::readwrite_property p_auto_start_dbg; + // The p_timeout parameter specifies the seconds that elapse before + // a timer_error occurs. May be ignored on some platforms. + unit_test::readwrite_property p_timeout; + // The p_use_alt_stack parameter specifies whether the monitor should + // use alternative stack for the signal catching + unit_test::readwrite_property p_use_alt_stack; + // The p_detect_fp_exceptions parameter specifies whether the monitor should + // try to detect hardware floating point exceptions + unit_test::readwrite_property p_detect_fp_exceptions; + + int execute( unit_test::callback0 const& F ); + // Returns: Value returned by function call F(). + // + // Effects: Calls executes supplied function F inside a try/catch block which also may + // include other unspecified platform dependent error detection code. + // + // Throws: execution_exception on an uncaught C++ exception, + // a hardware or software signal, trap, or other exception. + // + // Note: execute() doesn't consider it an error for F to return a non-zero value. + + // register custom (user supplied) exception translator + template + void register_exception_translator( ExceptionTranslator const& tr, boost::type* = 0 ); + +private: + // implementation helpers + int catch_signals( unit_test::callback0 const& F ); + + // Data members + boost::scoped_ptr m_custom_translators; + boost::scoped_array m_alt_stack; +}; // execution_monitor + +namespace detail { + +// ************************************************************************** // +// ************** detail::translate_exception ************** // +// ************************************************************************** // + +template +class translate_exception : public translate_exception_base +{ + typedef boost::scoped_ptr base_ptr; +public: + explicit translate_exception( ExceptionTranslator const& tr, base_ptr& next ) + : translate_exception_base( next ), m_translator( tr ) {} + + int operator()( unit_test::callback0 const& F ) + { + try { + return m_next ? (*m_next)( F ) : F(); + } catch( Exception const& e ) { + m_translator( e ); + return boost::exit_exception_failure; + } + } + +private: + // Data members + ExceptionTranslator m_translator; +}; + +} // namespace detail + +template +void +execution_monitor::register_exception_translator( ExceptionTranslator const& tr, boost::type* ) +{ + m_custom_translators.reset( + new detail::translate_exception( tr,m_custom_translators ) ); +} + +// ************************************************************************** // +// ************** execution_aborted ************** // +// ************************************************************************** // + +struct execution_aborted {}; + +// ************************************************************************** // +// ************** system_error ************** // +// ************************************************************************** // + +class system_error { +public: + // Constructor + explicit system_error( char const* exp ); + + unit_test::readonly_property p_errno; + unit_test::readonly_property p_failed_exp; +}; + +#define BOOST_TEST_SYS_ASSERT( exp ) if( (exp) ) ; else throw ::boost::system_error( BOOST_STRINGIZE( exp ) ) + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif diff --git a/cpp/BoostParts/boost/test/floating_point_comparison.hpp b/cpp/BoostParts/boost/test/floating_point_comparison.hpp new file mode 100644 index 00000000..5446adac --- /dev/null +++ b/cpp/BoostParts/boost/test/floating_point_comparison.hpp @@ -0,0 +1,286 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : defines algoirthms for comparing 2 floating point values +// *************************************************************************** + +#ifndef BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER +#define BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER + +// Boost.Test +#include +#include +#include + +// Boost +#include // for std::numeric_limits +#include // for numeric::conversion_traits +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace test_tools { + +using unit_test::readonly_property; + +// ************************************************************************** // +// ************** floating_point_comparison_type ************** // +// ************************************************************************** // + +enum floating_point_comparison_type { + FPC_STRONG, // "Very close" - equation 1' in docs, the default + FPC_WEAK // "Close enough" - equation 2' in docs. + +}; + +// ************************************************************************** // +// ************** details ************** // +// ************************************************************************** // + +namespace tt_detail { + +// FPT is Floating-Point Type: float, double, long double or User-Defined. +template +inline FPT +fpt_abs( FPT fpv ) +{ + return fpv < static_cast(0) ? -fpv : fpv; +} + +//____________________________________________________________________________// + +template +struct fpt_limits { + static FPT min_value() + { + return std::numeric_limits::is_specialized + ? (std::numeric_limits::min)() + : 0; + } + static FPT max_value() + { + return std::numeric_limits::is_specialized + ? (std::numeric_limits::max)() + : static_cast(1000000); // for the our purpuses it doesn't really matter what value is returned here + } +}; + +//____________________________________________________________________________// + +// both f1 and f2 are unsigned here +template +inline FPT +safe_fpt_division( FPT f1, FPT f2 ) +{ + // Avoid overflow. + if( (f2 < static_cast(1)) && (f1 > f2*fpt_limits::max_value()) ) + return fpt_limits::max_value(); + + // Avoid underflow. + if( (f1 == static_cast(0)) || + ((f2 > static_cast(1)) && (f1 < f2*fpt_limits::min_value())) ) + return static_cast(0); + + return f1/f2; +} + +//____________________________________________________________________________// + +} // namespace tt_detail + +// ************************************************************************** // +// ************** tolerance presentation types ************** // +// ************************************************************************** // + +template +struct percent_tolerance_t { + explicit percent_tolerance_t( FPT v ) : m_value( v ) {} + + FPT m_value; +}; + +//____________________________________________________________________________// + +template +Out& operator<<( Out& out, percent_tolerance_t t ) +{ + return out << t.m_value; +} + +//____________________________________________________________________________// + +template +inline percent_tolerance_t +percent_tolerance( FPT v ) +{ + return percent_tolerance_t( v ); +} + +//____________________________________________________________________________// + +template +struct fraction_tolerance_t { + explicit fraction_tolerance_t( FPT v ) : m_value( v ) {} + + FPT m_value; +}; + +//____________________________________________________________________________// + +template +Out& operator<<( Out& out, fraction_tolerance_t t ) +{ + return out << t.m_value; +} + +//____________________________________________________________________________// + +template +inline fraction_tolerance_t +fraction_tolerance( FPT v ) +{ + return fraction_tolerance_t( v ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** close_at_tolerance ************** // +// ************************************************************************** // + +template +class close_at_tolerance { +public: + // Public typedefs + typedef bool result_type; + + // Constructor + template + explicit close_at_tolerance( percent_tolerance_t tolerance, + floating_point_comparison_type fpc_type = FPC_STRONG ) + : p_fraction_tolerance( tt_detail::fpt_abs( static_cast(0.01)*tolerance.m_value ) ) + , p_strong_or_weak( fpc_type == FPC_STRONG ) + , m_report_modifier( 100. ) + {} + template + explicit close_at_tolerance( fraction_tolerance_t tolerance, + floating_point_comparison_type fpc_type = FPC_STRONG ) + : p_fraction_tolerance( tt_detail::fpt_abs( tolerance.m_value ) ) + , p_strong_or_weak( fpc_type == FPC_STRONG ) + , m_report_modifier( 1. ) + {} + + predicate_result operator()( FPT left, FPT right ) const + { + FPT diff = tt_detail::fpt_abs( left - right ); + FPT d1 = tt_detail::safe_fpt_division( diff, tt_detail::fpt_abs( right ) ); + FPT d2 = tt_detail::safe_fpt_division( diff, tt_detail::fpt_abs( left ) ); + + predicate_result res( p_strong_or_weak + ? (d1 <= p_fraction_tolerance.get() && d2 <= p_fraction_tolerance.get()) + : (d1 <= p_fraction_tolerance.get() || d2 <= p_fraction_tolerance.get()) ); + + if( !res ) + res.message() << (( d1 <= p_fraction_tolerance.get() ? d2 : d1 ) * m_report_modifier); + + return res; + } + + // Public properties + readonly_property p_fraction_tolerance; + readonly_property p_strong_or_weak; +private: + // Data members + FPT m_report_modifier; +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** check_is_close ************** // +// ************************************************************************** // + +struct BOOST_TEST_DECL check_is_close_t { + // Public typedefs + typedef bool result_type; + + template + predicate_result + operator()( FPT1 left, FPT2 right, percent_tolerance_t tolerance, + floating_point_comparison_type fpc_type = FPC_STRONG ) const + { + // deduce "better" type from types of arguments being compared + // if one type is floating and the second integral we use floating type and + // value of integral type is promoted to the floating. The same for float and double + // But we don't want to compare two values of integral types using this tool. + typedef typename numeric::conversion_traits::supertype FPT; + BOOST_STATIC_ASSERT( !is_integral::value ); + + close_at_tolerance pred( tolerance, fpc_type ); + + return pred( left, right ); + } + template + predicate_result + operator()( FPT1 left, FPT2 right, fraction_tolerance_t tolerance, + floating_point_comparison_type fpc_type = FPC_STRONG ) const + { + // same as in a comment above + typedef typename numeric::conversion_traits::supertype FPT; + BOOST_STATIC_ASSERT( !is_integral::value ); + + close_at_tolerance pred( tolerance, fpc_type ); + + return pred( left, right ); + } +}; + +namespace { +check_is_close_t const& check_is_close = unit_test::ut_detail::static_constant::value; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** check_is_small ************** // +// ************************************************************************** // + +struct BOOST_TEST_DECL check_is_small_t { + // Public typedefs + typedef bool result_type; + + template + bool + operator()( FPT fpv, FPT tolerance ) const + { + return tt_detail::fpt_abs( fpv ) < tt_detail::fpt_abs( tolerance ); + } +}; + +namespace { +check_is_small_t const& check_is_small = unit_test::ut_detail::static_constant::value; +} + +//____________________________________________________________________________// + +} // namespace test_tools + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_FLOATING_POINT_COMAPARISON_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/framework.hpp b/cpp/BoostParts/boost/test/framework.hpp new file mode 100644 index 00000000..54d4b527 --- /dev/null +++ b/cpp/BoostParts/boost/test/framework.hpp @@ -0,0 +1,112 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : defines framework interface +// *************************************************************************** + +#ifndef BOOST_TEST_FRAMEWORK_HPP_020805GER +#define BOOST_TEST_FRAMEWORK_HPP_020805GER + +// Boost.Test +#include +#include +#include + +#include + +// STL +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** init_unit_test_func ************** // +// ************************************************************************** // + +#ifdef BOOST_TEST_ALTERNATIVE_INIT_API +typedef bool (*init_unit_test_func)(); +#else +typedef test_suite* (*init_unit_test_func)( int, char* [] ); +#endif + +// ************************************************************************** // +// ************** framework ************** // +// ************************************************************************** // + +namespace framework { + +// initialization +BOOST_TEST_DECL void init( init_unit_test_func init_func, int argc, char* argv[] ); +BOOST_TEST_DECL bool is_initialized(); + +// mutation access methods +BOOST_TEST_DECL void register_test_unit( test_case* tc ); +BOOST_TEST_DECL void register_test_unit( test_suite* ts ); +BOOST_TEST_DECL void deregister_test_unit( test_unit* tu ); +BOOST_TEST_DECL void clear(); + +BOOST_TEST_DECL void register_observer( test_observer& ); +BOOST_TEST_DECL void deregister_observer( test_observer& ); +BOOST_TEST_DECL void reset_observers(); + +BOOST_TEST_DECL master_test_suite_t& master_test_suite(); + +// constant access methods +BOOST_TEST_DECL test_case const& current_test_case(); + +BOOST_TEST_DECL test_unit& get( test_unit_id, test_unit_type ); +template +UnitType& get( test_unit_id id ) +{ + return static_cast( get( id, static_cast(UnitType::type) ) ); +} + +// test initiation +BOOST_TEST_DECL void run( test_unit_id = INV_TEST_UNIT_ID, bool continue_test = true ); +BOOST_TEST_DECL void run( test_unit const*, bool continue_test = true ); + +// public test events dispatchers +BOOST_TEST_DECL void assertion_result( bool passed ); +BOOST_TEST_DECL void exception_caught( execution_exception const& ); +BOOST_TEST_DECL void test_unit_aborted( test_unit const& ); + +// ************************************************************************** // +// ************** framework errors ************** // +// ************************************************************************** // + +struct internal_error : std::runtime_error { + internal_error( const_string m ) : std::runtime_error( std::string( m.begin(), m.size() ) ) {} +}; + +struct setup_error : std::runtime_error { + setup_error( const_string m ) : std::runtime_error( std::string( m.begin(), m.size() ) ) {} +}; + +#define BOOST_TEST_SETUP_ASSERT( cond, msg ) if( cond ) {} else throw unit_test::framework::setup_error( msg ) + +struct nothing_to_test {}; // not really an error + +} // namespace framework + +} // unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_FRAMEWORK_HPP_020805GER + diff --git a/cpp/BoostParts/boost/test/impl/compiler_log_formatter.ipp b/cpp/BoostParts/boost/test/impl/compiler_log_formatter.ipp new file mode 100644 index 00000000..d49c2f8f --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/compiler_log_formatter.ipp @@ -0,0 +1,222 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : implements compiler like Log formatter +// *************************************************************************** + +#ifndef BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER +#define BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER + +// Boost.Test +#include +#include +#include +#include +#include + +// Boost +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace output { + +// ************************************************************************** // +// ************** compiler_log_formatter ************** // +// ************************************************************************** // + +namespace { + +const_string +test_phase_identifier() +{ + return framework::is_initialized() + ? const_string( framework::current_test_case().p_name.get() ) + : BOOST_TEST_L( "Test setup" ); +} + +} // local namespace + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_start( std::ostream& output, counter_t test_cases_amount ) +{ + if( test_cases_amount > 0 ) + output << "Running " << test_cases_amount << " test " + << (test_cases_amount > 1 ? "cases" : "case") << "...\n"; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_finish( std::ostream& ostr ) +{ + ostr.flush(); +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_build_info( std::ostream& output ) +{ + output << "Platform: " << BOOST_PLATFORM << '\n' + << "Compiler: " << BOOST_COMPILER << '\n' + << "STL : " << BOOST_STDLIB << '\n' + << "Boost : " << BOOST_VERSION/100000 << "." + << BOOST_VERSION/100 % 1000 << "." + << BOOST_VERSION % 100 << std::endl; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::test_unit_start( std::ostream& output, test_unit const& tu ) +{ + output << "Entering test " << tu.p_type_name << " \"" << tu.p_name << "\"" << std::endl; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::test_unit_finish( std::ostream& output, test_unit const& tu, unsigned long elapsed ) +{ + output << "Leaving test " << tu.p_type_name << " \"" << tu.p_name << "\""; + + if( elapsed > 0 ) { + output << "; testing time: "; + if( elapsed % 1000 == 0 ) + output << elapsed/1000 << "ms"; + else + output << elapsed << "mks"; + } + + output << std::endl; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::test_unit_skipped( std::ostream& output, test_unit const& tu ) +{ + output << "Test " << tu.p_type_name << " \"" << tu.p_name << "\"" << "is skipped" << std::endl; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_exception( std::ostream& output, log_checkpoint_data const& checkpoint_data, execution_exception const& ex ) +{ + execution_exception::location const& loc = ex.where(); + print_prefix( output, loc.m_file_name, loc.m_line_num ); + + output << "fatal error in \"" << (loc.m_function.is_empty() ? test_phase_identifier() : loc.m_function ) << "\": "; + + output << ex.what(); + + if( !checkpoint_data.m_file_name.is_empty() ) { + output << '\n'; + print_prefix( output, checkpoint_data.m_file_name, checkpoint_data.m_line_num ); + output << "last checkpoint"; + if( !checkpoint_data.m_message.empty() ) + output << ": " << checkpoint_data.m_message; + } + + output << std::endl; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_entry_start( std::ostream& output, log_entry_data const& entry_data, log_entry_types let ) +{ + switch( let ) { + case BOOST_UTL_ET_INFO: + print_prefix( output, entry_data.m_file_name, entry_data.m_line_num ); + output << "info: "; + break; + case BOOST_UTL_ET_MESSAGE: + break; + case BOOST_UTL_ET_WARNING: + print_prefix( output, entry_data.m_file_name, entry_data.m_line_num ); + output << "warning in \"" << test_phase_identifier() << "\": "; + break; + case BOOST_UTL_ET_ERROR: + print_prefix( output, entry_data.m_file_name, entry_data.m_line_num ); + output << "error in \"" << test_phase_identifier() << "\": "; + break; + case BOOST_UTL_ET_FATAL_ERROR: + print_prefix( output, entry_data.m_file_name, entry_data.m_line_num ); + output << "fatal error in \"" << test_phase_identifier() << "\": "; + break; + } +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_entry_value( std::ostream& output, const_string value ) +{ + output << value; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_entry_value( std::ostream& output, lazy_ostream const& value ) +{ + output << value; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::log_entry_finish( std::ostream& output ) +{ + output << std::endl; +} + +//____________________________________________________________________________// + +void +compiler_log_formatter::print_prefix( std::ostream& output, const_string file, std::size_t line ) +{ +#ifdef __APPLE_CC__ + // Xcode-compatible logging format, idea by Richard Dingwall at + // . + output << file << ':' << line << ": "; +#else + output << file << '(' << line << "): "; +#endif +} + +//____________________________________________________________________________// + +} // namespace output + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_COMPILER_LOG_FORMATTER_IPP_020105GER diff --git a/cpp/BoostParts/boost/test/impl/cpp_main.ipp b/cpp/BoostParts/boost/test/impl/cpp_main.ipp new file mode 100644 index 00000000..e5156e49 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/cpp_main.ipp @@ -0,0 +1,139 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Beman Dawes 1995-2001. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : main function implementation for Program Executon Monitor +// *************************************************************************** + +#ifndef BOOST_TEST_CPP_MAIN_IPP_012205GER +#define BOOST_TEST_CPP_MAIN_IPP_012205GER + +// Boost.Test +#include +#include +#include + +// Boost +#include // for exit codes +#include // for workarounds + +// STL +#include +#include // std::getenv +#include // std::strerror + +#include + +//____________________________________________________________________________// + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::getenv; using ::strerror; } +#endif + +namespace { + +struct cpp_main_caller { + cpp_main_caller( int (*cpp_main_func)( int argc, char* argv[] ), int argc, char** argv ) + : m_cpp_main_func( cpp_main_func ) + , m_argc( argc ) + , m_argv( argv ) {} + + int operator()() { return (*m_cpp_main_func)( m_argc, m_argv ); } + +private: + // Data members + int (*m_cpp_main_func)( int argc, char* argv[] ); + int m_argc; + char** m_argv; +}; + +} // local namespace + +// ************************************************************************** // +// ************** prg_exec_monitor_main ************** // +// ************************************************************************** // + +namespace boost { + +int BOOST_TEST_DECL +prg_exec_monitor_main( int (*cpp_main)( int argc, char* argv[] ), int argc, char* argv[] ) +{ + int result = 0; + + try { + boost::unit_test::const_string p( std::getenv( "BOOST_TEST_CATCH_SYSTEM_ERRORS" ) ); + ::boost::execution_monitor ex_mon; + + ex_mon.p_catch_system_errors.value = p != "no"; + + result = ex_mon.execute( + ::boost::unit_test::callback0( cpp_main_caller( cpp_main, argc, argv ) ) ); + + if( result == 0 ) + result = ::boost::exit_success; + else if( result != ::boost::exit_success ) { + std::cout << "\n**** error return code: " << result << std::endl; + result = ::boost::exit_failure; + } + } + catch( ::boost::execution_exception const& exex ) { + std::cout << "\n**** exception(" << exex.code() << "): " << exex.what() << std::endl; + result = ::boost::exit_exception_failure; + } + catch( ::boost::system_error const& ex ) { + std::cout << "\n**** failed to initialize execution monitor." + << "\n**** expression at fault: " << ex.p_failed_exp + << "\n**** error(" << ex.p_errno << "): " << std::strerror( ex.p_errno ) << std::endl; + result = ::boost::exit_exception_failure; + } + + if( result != ::boost::exit_success ) { + std::cerr << "******** errors detected; see standard output for details ********" << std::endl; + } + else { + // Some prefer a confirming message when all is well, while others don't + // like the clutter. Use an environment variable to avoid command + // line argument modifications; for use in production programs + // that's a no-no in some organizations. + ::boost::unit_test::const_string p( std::getenv( "BOOST_PRG_MON_CONFIRM" ) ); + if( p != "no" ) { + std::cerr << std::flush << "no errors detected" << std::endl; + } + } + + return result; +} + +} // namespace boost + +#if !defined(BOOST_TEST_DYN_LINK) && !defined(BOOST_TEST_NO_MAIN) + +// ************************************************************************** // +// ************** main function for tests using lib ************** // +// ************************************************************************** // + +int cpp_main( int argc, char* argv[] ); // prototype for user's cpp_main() + +int BOOST_TEST_CALL_DECL +main( int argc, char* argv[] ) +{ + return ::boost::prg_exec_monitor_main( &cpp_main, argc, argv ); +} + +//____________________________________________________________________________// + +#endif // !BOOST_TEST_DYN_LINK && !BOOST_TEST_NO_MAIN + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_CPP_MAIN_IPP_012205GER diff --git a/cpp/BoostParts/boost/test/impl/debug.ipp b/cpp/BoostParts/boost/test/impl/debug.ipp new file mode 100644 index 00000000..d351271f --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/debug.ipp @@ -0,0 +1,970 @@ +// (C) Copyright Gennadiy Rozental 2006-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : debug interfaces implementation +// *************************************************************************** + +#ifndef BOOST_TEST_DEBUG_API_IPP_112006GER +#define BOOST_TEST_DEBUG_API_IPP_112006GER + +// Boost.Test +#include +#include +#include + +#include +#include + +// Implementation on Windows +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(BOOST_DISABLE_WIN32) // ******* WIN32 + +# define BOOST_WIN32_BASED_DEBUG + +// SYSTEM API +# include +# include +# include +# include + +# if !defined(NDEBUG) && defined(_MSC_VER) +# define BOOST_MS_CRT_BASED_DEBUG +# include +# endif + + +# if BOOST_WORKAROUND( BOOST_MSVC, <1300) +# define snprintf _snprintf +# endif + +# ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::memset; using ::sprintf; } +# endif + +#elif defined(unix) || defined(__unix) // ********************* UNIX + +# define BOOST_UNIX_BASED_DEBUG + +// Boost.Test +#include +#include + +// STL +#include // std::memcpy +#include +#include +#include // !! ?? cstdarg + +// SYSTEM API +# include +# include +# include + +# include +# include +# include +# include +# include +# include + +# if defined(sun) || defined(__sun) + +# define BOOST_SUN_BASED_DEBUG + +# ifndef BOOST_TEST_DBG_LIST +# define BOOST_TEST_DBG_LIST dbx;gdb +# endif + +# define BOOST_TEST_CNL_DBG dbx +# define BOOST_TEST_GUI_DBG dbx-ddd + +# include + +# elif defined(linux) || defined(__linux) + +# define BOOST_LINUX_BASED_DEBUG + +# include + +# ifndef BOOST_TEST_STAT_LINE_MAX +# define BOOST_TEST_STAT_LINE_MAX 500 +# endif + +# ifndef BOOST_TEST_DBG_LIST +# define BOOST_TEST_DBG_LIST gdb +# endif + +# define BOOST_TEST_CNL_DBG gdb +# define BOOST_TEST_GUI_DBG gdb-xterm + +# endif + +#endif + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace debug { + +using unit_test::const_string; + +// ************************************************************************** // +// ************** debug::info_t ************** // +// ************************************************************************** // + +namespace { + +#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32 + +template +inline void +dyn_symbol( T& res, char const* module_name, char const* symbol_name ) +{ + HMODULE m = ::GetModuleHandleA( module_name ); + + if( !m ) + m = ::LoadLibraryA( module_name ); + + res = reinterpret_cast( ::GetProcAddress( m, symbol_name ) ); +} + +//____________________________________________________________________________// + +static struct info_t { + typedef BOOL (WINAPI* IsDebuggerPresentT)(); + typedef LONG (WINAPI* RegQueryValueExT)( HKEY, char const* /*LPTSTR*/, LPDWORD, LPDWORD, LPBYTE, LPDWORD ); + typedef LONG (WINAPI* RegOpenKeyT)( HKEY, char const* /*LPCTSTR*/, PHKEY ); + typedef LONG (WINAPI* RegCloseKeyT)( HKEY ); + + info_t(); + + IsDebuggerPresentT m_is_debugger_present; + RegOpenKeyT m_reg_open_key; + RegQueryValueExT m_reg_query_value; + RegCloseKeyT m_reg_close_key; + +} s_info; + +//____________________________________________________________________________// + +info_t::info_t() +{ + dyn_symbol( m_is_debugger_present, "kernel32", "IsDebuggerPresent" ); + dyn_symbol( m_reg_open_key, "advapi32", "RegOpenKeyA" ); + dyn_symbol( m_reg_query_value, "advapi32", "RegQueryValueExA" ); + dyn_symbol( m_reg_close_key, "advapi32", "RegCloseKey" ); +} + +//____________________________________________________________________________// + +#elif defined(BOOST_UNIX_BASED_DEBUG) + +// ************************************************************************** // +// ************** fd_holder ************** // +// ************************************************************************** // + +struct fd_holder { + explicit fd_holder( int fd ) : m_fd( fd ) {} + ~fd_holder() + { + if( m_fd != -1 ) + ::close( m_fd ); + } + + operator int() { return m_fd; } + +private: + // Data members + int m_fd; +}; + + +// ************************************************************************** // +// ************** process_info ************** // +// ************************************************************************** // + +struct process_info { + // Constructor + explicit process_info( int pid ); + + // access methods + int parent_pid() const { return m_parent_pid; } + const_string binary_name() const { return m_binary_name; } + const_string binary_path() const { return m_binary_path; } + +private: + // Data members + int m_parent_pid; + const_string m_binary_name; + const_string m_binary_path; + +#if defined(BOOST_SUN_BASED_DEBUG) + struct psinfo m_psi; +#elif defined(BOOST_LINUX_BASED_DEBUG) + char m_stat_line[BOOST_TEST_STAT_LINE_MAX+1]; +#endif + char m_binary_path_buff[500+1]; // !! ?? +}; + +//____________________________________________________________________________// + +process_info::process_info( int pid ) +: m_parent_pid( 0 ) +{ +#if defined(BOOST_SUN_BASED_DEBUG) + char fname_buff[30]; + + ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/psinfo", pid ); + + fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) ); + + if( psinfo_fd == -1 ) + return; + + if( ::read( psinfo_fd, &m_psi, sizeof(m_psi) ) == -1 ) + return; + + m_parent_pid = m_psi.pr_ppid; + + m_binary_name.assign( m_psi.pr_fname ); + + //-------------------------- // + + ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/as", pid ); + + fd_holder as_fd( ::open( fname_buff, O_RDONLY ) ); + uintptr_t binary_name_pos; + + // !! ?? could we avoid reading whole m_binary_path_buff? + if( as_fd == -1 || + ::lseek( as_fd, m_psi.pr_argv, SEEK_SET ) == -1 || + ::read ( as_fd, &binary_name_pos, sizeof(binary_name_pos) ) == -1 || + ::lseek( as_fd, binary_name_pos, SEEK_SET ) == -1 || + ::read ( as_fd, m_binary_path_buff, sizeof(m_binary_path_buff) ) == -1 ) + return; + + m_binary_path.assign( m_binary_path_buff ); + +#elif defined(BOOST_LINUX_BASED_DEBUG) + char fname_buff[30]; + + ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/stat", pid ); + + fd_holder psinfo_fd( ::open( fname_buff, O_RDONLY ) ); + + if( psinfo_fd == -1 ) + return; + + ssize_t num_read = ::read( psinfo_fd, m_stat_line, sizeof(m_stat_line)-1 ); + if( num_read == -1 ) + return; + + m_stat_line[num_read] = 0; + + char const* name_beg = m_stat_line; + while( *name_beg && *name_beg != '(' ) + ++name_beg; + + char const* name_end = name_beg+1; + while( *name_end && *name_end != ')' ) + ++name_end; + + std::sscanf( name_end+1, "%*s%d", &m_parent_pid ); + + m_binary_name.assign( name_beg+1, name_end ); + + ::snprintf( fname_buff, sizeof(fname_buff), "/proc/%d/exe", pid ); + num_read = ::readlink( fname_buff, m_binary_path_buff, sizeof(m_binary_path_buff)-1 ); + + if( num_read == -1 ) + return; + + m_binary_path_buff[num_read] = 0; + m_binary_path.assign( m_binary_path_buff, num_read ); +#endif +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** prepare_window_title ************** // +// ************************************************************************** // + +static char* +prepare_window_title( dbg_startup_info const& dsi ) +{ + typedef unit_test::const_string str_t; + + static char title_str[50]; + + str_t path_sep( "\\/" ); + + str_t::iterator it = unit_test::find_last_of( dsi.binary_path.begin(), dsi.binary_path.end(), + path_sep.begin(), path_sep.end() ); + + if( it == dsi.binary_path.end() ) + it = dsi.binary_path.begin(); + else + ++it; + + ::snprintf( title_str, sizeof(title_str), "%*s %ld", (int)(dsi.binary_path.end()-it), it, dsi.pid ); + + return title_str; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** save_execlp ************** // +// ************************************************************************** // + +typedef unit_test::basic_cstring mbuffer; + +inline char* +copy_arg( mbuffer& dest, const_string arg ) +{ + if( dest.size() < arg.size()+1 ) + return 0; + + char* res = dest.begin(); + + std::memcpy( res, arg.begin(), arg.size()+1 ); + + dest.trim_left( arg.size()+1 ); + + return res; +} + +//____________________________________________________________________________// + +bool +safe_execlp( char const* file, ... ) +{ + static char* argv_buff[200]; + + va_list args; + char const* arg; + + // first calculate actual number of arguments + int num_args = 2; // file name and 0 at least + + va_start( args, file ); + while( !!(arg = va_arg( args, char const* )) ) + num_args++; + va_end( args ); + + // reserve space for the argument pointers array + char** argv_it = argv_buff; + mbuffer work_buff( reinterpret_cast(argv_buff), sizeof(argv_buff) ); + work_buff.trim_left( num_args * sizeof(char*) ); + + // copy all the argument values into local storage + if( !(*argv_it++ = copy_arg( work_buff, file )) ) + return false; + + printf( "!! %s\n", file ); + + va_start( args, file ); + while( !!(arg = va_arg( args, char const* )) ) { + printf( "!! %s\n", arg ); + if( !(*argv_it++ = copy_arg( work_buff, arg )) ) + return false; + } + va_end( args ); + + *argv_it = 0; + + return ::execvp( file, argv_buff ) != -1; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** start_debugger_in_emacs ************** // +// ************************************************************************** // + +static void +start_debugger_in_emacs( dbg_startup_info const& dsi, char const* emacs_name, char const* dbg_command ) +{ + char const* title = prepare_window_title( dsi ); + + if( !title ) + return; + + dsi.display.is_empty() + ? safe_execlp( emacs_name, "-title", title, "--eval", dbg_command, 0 ) + : safe_execlp( emacs_name, "-title", title, "-display", dsi.display.begin(), "--eval", dbg_command, 0 ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** gdb starters ************** // +// ************************************************************************** // + +static char const* +prepare_gdb_cmnd_file( dbg_startup_info const& dsi ) +{ + // prepare pid value + char pid_buff[16]; + ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid ); + unit_test::const_string pid_str( pid_buff ); + + static char cmd_file_name[] = "/tmp/btl_gdb_cmd_XXXXXX"; // !! ?? + + // prepare commands + fd_holder cmd_fd( ::mkstemp( cmd_file_name ) ); + + if( cmd_fd == -1 ) + return 0; + +#define WRITE_STR( str ) if( ::write( cmd_fd, str.begin(), str.size() ) == -1 ) return 0; +#define WRITE_CSTR( str ) if( ::write( cmd_fd, str, sizeof( str )-1 ) == -1 ) return 0; + + WRITE_CSTR( "file " ); + WRITE_STR( dsi.binary_path ); + WRITE_CSTR( "\nattach " ); + WRITE_STR( pid_str ); + WRITE_CSTR( "\nshell unlink " ); + WRITE_STR( dsi.init_done_lock ); + WRITE_CSTR( "\ncont" ); + if( dsi.break_or_continue ) + WRITE_CSTR( "\nup 4" ); + + WRITE_CSTR( "\necho \\n" ); // !! ?? + WRITE_CSTR( "\nlist -" ); + WRITE_CSTR( "\nlist" ); + WRITE_CSTR( "\nshell unlink " ); + WRITE_CSTR( cmd_file_name ); + + return cmd_file_name; +} + +//____________________________________________________________________________// + +static void +start_gdb_in_console( dbg_startup_info const& dsi ) +{ + char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi ); + + if( !cmnd_file_name ) + return; + + safe_execlp( "gdb", "-q", "-x", cmnd_file_name, 0 ); +} + +//____________________________________________________________________________// + +static void +start_gdb_in_xterm( dbg_startup_info const& dsi ) +{ + char const* title = prepare_window_title( dsi ); + char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi ); + + if( !title || !cmnd_file_name ) + return; + + safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(), + "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e", + "gdb", "-q", "-x", cmnd_file_name, 0 ); +} + +//____________________________________________________________________________// + +static void +start_gdb_in_emacs( dbg_startup_info const& dsi ) +{ + char const* cmnd_file_name = prepare_gdb_cmnd_file( dsi ); + if( !cmnd_file_name ) + return; + + char dbg_cmd_buff[500]; // !! ?? + ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (gdb \"gdb -q -x %s\"))", cmnd_file_name ); + + start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff ); +} + +//____________________________________________________________________________// + +static void +start_gdb_in_xemacs( dbg_startup_info const& ) +{ + // !! ?? +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** dbx starters ************** // +// ************************************************************************** // + +static char const* +prepare_dbx_cmd_line( dbg_startup_info const& dsi, bool list_source = true ) +{ + static char cmd_line_buff[500]; // !! ?? + + ::snprintf( cmd_line_buff, sizeof(cmd_line_buff), "unlink %s;cont;%s%s", + dsi.init_done_lock.begin(), + dsi.break_or_continue ? "up 2;": "", + list_source ? "echo \" \";list -w3;" : "" ); + + return cmd_line_buff; +} + +//____________________________________________________________________________// + +static void +start_dbx_in_console( dbg_startup_info const& dsi ) +{ + char pid_buff[16]; + ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid ); + + safe_execlp( "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 ); +} + +//____________________________________________________________________________// + +static void +start_dbx_in_xterm( dbg_startup_info const& dsi ) +{ + char const* title = prepare_window_title( dsi ); + if( !title ) + return; + + char pid_buff[16]; // !! ?? + ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid ); + + safe_execlp( "xterm", "-T", title, "-display", dsi.display.begin(), + "-bg", "black", "-fg", "white", "-geometry", "88x30+10+10", "-fn", "9x15", "-e", + "dbx", "-q", "-c", prepare_dbx_cmd_line( dsi ), dsi.binary_path.begin(), pid_buff, 0 ); +} + +//____________________________________________________________________________// + +static void +start_dbx_in_emacs( dbg_startup_info const& /*dsi*/ ) +{ +// char dbg_cmd_buff[500]; // !! ?? +// +// ::snprintf( dbg_cmd_buff, sizeof(dbg_cmd_buff), "(progn (dbx \"dbx -q -c cont %s %ld\"))", dsi.binary_path.begin(), dsi.pid ); + +// start_debugger_in_emacs( dsi, "emacs", dbg_cmd_buff ); +} + +//____________________________________________________________________________// + +static void +start_dbx_in_xemacs( dbg_startup_info const& ) +{ + // !! ?? +} + +//____________________________________________________________________________// + +static void +start_dbx_in_ddd( dbg_startup_info const& dsi ) +{ + char const* title = prepare_window_title( dsi ); + if( !title ) + return; + + char pid_buff[16]; // !! ?? + ::snprintf( pid_buff, sizeof(pid_buff), "%ld", dsi.pid ); + + safe_execlp( "ddd", "-display", dsi.display.begin(), + "--dbx", "-q", "-c", prepare_dbx_cmd_line( dsi, false ), dsi.binary_path.begin(), pid_buff, 0 ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** debug::info_t ************** // +// ************************************************************************** // + +static struct info_t { + // Constructor + info_t(); + + // Public properties + unit_test::readwrite_property p_dbg; + + // Data members + std::map m_dbg_starter_reg; +} s_info; + +//____________________________________________________________________________// + +info_t::info_t() +{ + p_dbg.value = ::getenv( "DISPLAY" ) + ? std::string( BOOST_STRINGIZE( BOOST_TEST_GUI_DBG ) ) + : std::string( BOOST_STRINGIZE( BOOST_TEST_CNL_DBG ) ); + + m_dbg_starter_reg[std::string("gdb")] = &start_gdb_in_console; + m_dbg_starter_reg[std::string("gdb-emacs")] = &start_gdb_in_emacs; + m_dbg_starter_reg[std::string("gdb-xterm")] = &start_gdb_in_xterm; + m_dbg_starter_reg[std::string("gdb-xemacs")] = &start_gdb_in_xemacs; + + m_dbg_starter_reg[std::string("dbx")] = &start_dbx_in_console; + m_dbg_starter_reg[std::string("dbx-emacs")] = &start_dbx_in_emacs; + m_dbg_starter_reg[std::string("dbx-xterm")] = &start_dbx_in_xterm; + m_dbg_starter_reg[std::string("dbx-xemacs")] = &start_dbx_in_xemacs; + m_dbg_starter_reg[std::string("dbx-ddd")] = &start_dbx_in_ddd; +} + +//____________________________________________________________________________// + +#endif + +} // local namespace + +// ************************************************************************** // +// ************** check if program is running under debugger ************** // +// ************************************************************************** // + +bool +under_debugger() +{ +#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32 + + return !!s_info.m_is_debugger_present && s_info.m_is_debugger_present(); + +#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX + + // !! ?? could/should we cache the result somehow? + const_string dbg_list = BOOST_TEST_STRINGIZE( BOOST_TEST_DBG_LIST ); + + pid_t pid = ::getpid(); + + while( pid != 0 ) { + process_info pi( pid ); + + // !! ?? should we use tokenizer here instead? + if( dbg_list.find( pi.binary_name() ) != const_string::npos ) + return true; + + pid = (pi.parent_pid() == pid ? 0 : pi.parent_pid()); + } + + return false; + +#else // ****************************************************** default + + return false; + +#endif +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** cause program to break execution ************** // +// ************** in debugger at call point ************** // +// ************************************************************************** // + +void +debugger_break() +{ + // !! ?? auto-start debugger? + +#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32 + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1300) || \ + BOOST_WORKAROUND(__GNUC__, >= 3) && !defined(__MINGW32__) || \ + defined(__INTEL_COMPILER) +# define BOOST_DEBUG_BREAK __debugbreak +#else +# define BOOST_DEBUG_BREAK DebugBreak +#endif + +#ifndef __MINGW32__ + if( !under_debugger() ) { + __try { + __try { + BOOST_DEBUG_BREAK(); + } + __except( UnhandledExceptionFilter(GetExceptionInformation()) ) + { + // User opted to ignore the breakpoint + return; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + // If we got here, the user has pushed Debug. Debugger is already attached to our process and we + // continue to let the another BOOST_DEBUG_BREAK to be called. + } + } +#endif + + BOOST_DEBUG_BREAK(); + +#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX + + ::kill( ::getpid(), SIGTRAP ); + +#else // ****************************************************** default + +#endif +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** console debugger setup ************** // +// ************************************************************************** // + +#if defined(BOOST_UNIX_BASED_DEBUG) // ************************ UNIX + +std::string +set_debugger( unit_test::const_string dbg_id, dbg_starter s ) +{ + std::string old = s_info.p_dbg; + + assign_op( s_info.p_dbg.value, dbg_id, 0 ); + + if( !!s ) + s_info.m_dbg_starter_reg[s_info.p_dbg] = s; + + return old; +} + +#else // ***************************************************** default + +std::string +set_debugger( unit_test::const_string, dbg_starter ) +{ + return std::string(); +} + +#endif + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** attach debugger to the current process ************** // +// ************************************************************************** // + +bool +attach_debugger( bool break_or_continue ) +{ + if( under_debugger() ) + return false; + +#if defined(BOOST_WIN32_BASED_DEBUG) // *********************** WIN32 + + const int MAX_CMD_LINE = 200; + + // *************************************************** // + // Debugger "ready" event + + SECURITY_ATTRIBUTES attr; + attr.nLength = sizeof(attr); + attr.lpSecurityDescriptor = NULL; + attr.bInheritHandle = true; + + // manual resettable, initially non signaled, unnamed event, + // that will signal me that debugger initialization is done + HANDLE dbg_init_done_ev = ::CreateEvent( + &attr, // pointer to security attributes + true, // flag for manual-reset event + false, // flag for initial state + NULL // pointer to event-object name + ); + + if( !dbg_init_done_ev ) + return false; + + // *************************************************** // + // Debugger command line format + + HKEY reg_key; + + if( !s_info.m_reg_open_key || (*s_info.m_reg_open_key)( + HKEY_LOCAL_MACHINE, // handle of open key + "Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", // name of subkey to open + ®_key ) != ERROR_SUCCESS ) // address of handle of open key + return false; + + char format[MAX_CMD_LINE]; + DWORD format_size = MAX_CMD_LINE; + DWORD type = REG_SZ; + + if( !s_info.m_reg_query_value || (*s_info.m_reg_query_value)( + reg_key, // handle of open key + "Debugger", // name of subkey to query + 0, // reserved + &type, // value type + (LPBYTE)format, // buffer for returned string + &format_size ) != ERROR_SUCCESS ) // in: buffer size; out: actual size of returned string + return false; + + if( !s_info.m_reg_close_key || (*s_info.m_reg_close_key)( reg_key ) != ERROR_SUCCESS ) + return false; + + // *************************************************** // + // Debugger command line + + char cmd_line[MAX_CMD_LINE]; + std::sprintf( cmd_line, format, ::GetCurrentProcessId(), dbg_init_done_ev ); + + // *************************************************** // + // Debugger window parameters + + STARTUPINFOA startup_info; + std::memset( &startup_info, 0, sizeof(startup_info) ); + + startup_info.cb = sizeof(startup_info); + startup_info.dwFlags = STARTF_USESHOWWINDOW; + startup_info.wShowWindow = SW_SHOWNORMAL; + + // debugger process s_info + PROCESS_INFORMATION debugger_info; + + bool created = !!::CreateProcessA( + NULL, // pointer to name of executable module; NULL - use the one in command line + cmd_line, // pointer to command line string + NULL, // pointer to process security attributes; NULL - debugger's handle can't be inherited + NULL, // pointer to thread security attributes; NULL - debugger's handle can't be inherited + true, // debugger inherit opened handles + 0, // priority flags; 0 - normal priority + NULL, // pointer to new environment block; NULL - use this process environment + NULL, // pointer to current directory name; NULL - use this process correct directory + &startup_info, // pointer to STARTUPINFO that specifies main window appearance + &debugger_info // pointer to PROCESS_INFORMATION that will contain the new process identification + ); + + if( created ) + ::WaitForSingleObject( dbg_init_done_ev, INFINITE ); + + ::CloseHandle( dbg_init_done_ev ); + + if( !created ) + return false; + + if( break_or_continue ) + debugger_break(); + + return true; + +#elif defined(BOOST_UNIX_BASED_DEBUG) // ********************** UNIX + + char init_done_lock_fn[] = "/tmp/btl_dbg_init_done_XXXXXX"; + fd_holder init_done_lock_fd( ::mkstemp( init_done_lock_fn ) ); + + if( init_done_lock_fd == -1 ) + return false; + + pid_t child_pid = fork(); + + if( child_pid == -1 ) + return false; + + if( child_pid != 0 ) { // parent process - here we will start the debugger + dbg_startup_info dsi; + + process_info pi( child_pid ); + if( pi.binary_path().is_empty() ) + ::exit( -1 ); + + dsi.pid = child_pid; + dsi.break_or_continue = break_or_continue; + dsi.binary_path = pi.binary_path(); + dsi.display = ::getenv( "DISPLAY" ); + dsi.init_done_lock = init_done_lock_fn; + + dbg_starter starter = s_info.m_dbg_starter_reg[s_info.p_dbg]; + if( !!starter ) + starter( dsi ); + + ::perror( "Boost.Test execution monitor failed to start a debugger:" ); + + ::exit( -1 ); + } + + // child process - here we will continue our test module execution ; // !! ?? should it be vice versa + + while( ::access( init_done_lock_fn, F_OK ) == 0 ) { + struct timeval to = { 0, 100 }; + + ::select( 0, 0, 0, 0, &to ); + } + +// char dummy; +// while( ::read( init_done_lock_fd, &dummy, sizeof(char) ) == 0 ); + + if( break_or_continue ) + debugger_break(); + + return true; + +#else // ****************************************************** default + + return false; + +#endif +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** switch on/off detect memory leaks feature ************** // +// ************************************************************************** // + +void +detect_memory_leaks( bool on_off ) +{ + unit_test::ut_detail::ignore_unused_variable_warning( on_off ); + +#ifdef BOOST_MS_CRT_BASED_DEBUG + int flags = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); + + if( !on_off ) + flags &= ~_CRTDBG_LEAK_CHECK_DF; + else { + flags |= _CRTDBG_LEAK_CHECK_DF; + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); + } + + _CrtSetDbgFlag ( flags ); +#endif // BOOST_MS_CRT_BASED_DEBUG +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** cause program to break execution in ************** // +// ************** debugger at specific allocation point ************** // +// ************************************************************************** // + +void +break_memory_alloc( long mem_alloc_order_num ) +{ + unit_test::ut_detail::ignore_unused_variable_warning( mem_alloc_order_num ); + +#ifdef BOOST_MS_CRT_BASED_DEBUG + _CrtSetBreakAlloc( mem_alloc_order_num ); +#endif // BOOST_MS_CRT_BASED_DEBUG +} + +} // namespace debug + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_DEBUG_API_IPP_112006GER + diff --git a/cpp/BoostParts/boost/test/impl/exception_safety.ipp b/cpp/BoostParts/boost/test/impl/exception_safety.ipp new file mode 100644 index 00000000..e2d529a8 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/exception_safety.ipp @@ -0,0 +1,537 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : Facilities to perform exception safety tests +// *************************************************************************** + +#ifndef BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER +#define BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER + +// Boost.Test +#include + +#if BOOST_TEST_SUPPORT_INTERACTION_TESTING + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +// Boost +#include + +// STL +#include +#include +#include +#include +#include +#include + +//____________________________________________________________________________// + +namespace boost { + +using namespace ::boost::unit_test; + +namespace itest { + +// ************************************************************************** // +// ************** execution_path_point ************** // +// ************************************************************************** // + +enum exec_path_point_type { EPP_SCOPE, EPP_EXCEPT, EPP_DECISION, EPP_ALLOC }; + +struct execution_path_point { + execution_path_point( exec_path_point_type t, const_string file, std::size_t line_num ) + : m_type( t ) + , m_file_name( file ) + , m_line_num( line_num ) + {} + + exec_path_point_type m_type; + const_string m_file_name; + std::size_t m_line_num; + + // Execution path point specific + struct decision_data { + bool value; + unsigned forced_exception_point; + }; + struct scope_data { + unsigned size; + char const* name; + }; + struct except_data { + char const* description; + }; + struct alloc_data { + void* ptr; + std::size_t size; + }; + + union { + struct decision_data m_decision; + struct scope_data m_scope; + struct except_data m_except; + struct alloc_data m_alloc; + }; +}; + +// ************************************************************************** // +// ************** exception safety test implementation ************** // +// ************************************************************************** // + +struct exception_safety_tester : itest::manager, test_observer { + // helpers types + struct unique_exception {}; + + // Constructor + explicit exception_safety_tester( const_string test_name ); + ~exception_safety_tester(); + + // check last run and prepare for next + bool next_execution_path(); + + // memory tracking + + // manager interface implementation + virtual void exception_point( const_string file, std::size_t line_num, const_string description ); + virtual bool decision_point( const_string file, std::size_t line_num ); + virtual unsigned enter_scope( const_string file, std::size_t line_num, const_string scope_name ); + virtual void leave_scope( unsigned enter_scope_point ); + virtual void allocated( const_string file, std::size_t line_num, void* p, std::size_t s ); + virtual void freed( void* p ); + + // test observer interface + virtual void assertion_result( bool passed ); + virtual int priority() { return (std::numeric_limits::max)(); } // we want this observer to run the last + +private: + void failure_point(); + void report_error(); + + typedef std::vector exec_path; + typedef std::map registry; + + // Data members + bool m_internal_activity; + + unsigned m_exception_point_counter; + unsigned m_forced_exception_point; + + unsigned m_exec_path_point; + exec_path m_execution_path; + + unsigned m_exec_path_counter; + unsigned m_break_exec_path; + + bool m_invairant_failed; + registry m_memory_in_use; +}; + +//____________________________________________________________________________// + +struct activity_guard { + bool& m_v; + + activity_guard( bool& v ) : m_v( v ) { m_v = true; } + ~activity_guard() { m_v = false; } +}; + +//____________________________________________________________________________// + +exception_safety_tester::exception_safety_tester( const_string test_name ) +: m_internal_activity( true ) +, m_exception_point_counter( 0 ) +, m_forced_exception_point( 1 ) +, m_exec_path_point( 0 ) +, m_exec_path_counter( 1 ) +, m_break_exec_path( static_cast(-1) ) +, m_invairant_failed( false ) +{ + framework::register_observer( *this ); + + if( !runtime_config::break_exec_path().is_empty() ) { + using namespace unit_test; + + string_token_iterator tit( runtime_config::break_exec_path(), + (dropped_delimeters = ":",kept_delimeters = " ") ); + + const_string test_to_break = *tit; + + if( test_to_break == test_name ) { + ++tit; + + m_break_exec_path = lexical_cast( *tit ); + } + } + + m_internal_activity = false; +} + +//____________________________________________________________________________// + +exception_safety_tester::~exception_safety_tester() +{ + m_internal_activity = true; + + framework::deregister_observer( *this ); +} + +//____________________________________________________________________________// + +bool +exception_safety_tester::next_execution_path() +{ + activity_guard ag( m_internal_activity ); + + // check memory usage + if( m_execution_path.size() > 0 ) { + bool errors_detected = m_invairant_failed || (m_memory_in_use.size() != 0); + framework::assertion_result( !errors_detected ); + + if( errors_detected ) + report_error(); + + m_memory_in_use.clear(); + } + + m_exec_path_point = 0; + m_exception_point_counter = 0; + m_invairant_failed = false; + ++m_exec_path_counter; + + while( m_execution_path.size() > 0 ) { + switch( m_execution_path.back().m_type ) { + case EPP_SCOPE: + case EPP_ALLOC: + m_execution_path.pop_back(); + break; + + case EPP_DECISION: + if( !m_execution_path.back().m_decision.value ) { + m_execution_path.pop_back(); + break; + } + + m_execution_path.back().m_decision.value = false; + m_forced_exception_point = m_execution_path.back().m_decision.forced_exception_point; + return true; + + case EPP_EXCEPT: + m_execution_path.pop_back(); + ++m_forced_exception_point; + return true; + } + } + + BOOST_TEST_MESSAGE( "Total tested " << --m_exec_path_counter << " execution path" ); + + return false; +} + +//____________________________________________________________________________// + +void +exception_safety_tester::exception_point( const_string file, std::size_t line_num, const_string description ) +{ + activity_guard ag( m_internal_activity ); + + if( ++m_exception_point_counter == m_forced_exception_point ) { + m_execution_path.push_back( + execution_path_point( EPP_EXCEPT, file, line_num ) ); + + m_execution_path.back().m_except.description = description.begin(); + + ++m_exec_path_point; + + failure_point(); + } +} + +//____________________________________________________________________________// + +bool +exception_safety_tester::decision_point( const_string file, std::size_t line_num ) +{ + activity_guard ag( m_internal_activity ); + + if( m_exec_path_point < m_execution_path.size() ) { + BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_DECISION && + m_execution_path[m_exec_path_point].m_file_name == file && + m_execution_path[m_exec_path_point].m_line_num == line_num, + "Function under test exibit non-deterministic behavior" ); + } + else { + m_execution_path.push_back( + execution_path_point( EPP_DECISION, file, line_num ) ); + + m_execution_path.back().m_decision.value = true; + m_execution_path.back().m_decision.forced_exception_point = m_forced_exception_point; + } + + return m_execution_path[m_exec_path_point++].m_decision.value; +} + +//____________________________________________________________________________// + +unsigned +exception_safety_tester::enter_scope( const_string file, std::size_t line_num, const_string scope_name ) +{ + activity_guard ag( m_internal_activity ); + + if( m_exec_path_point < m_execution_path.size() ) { + BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_SCOPE && + m_execution_path[m_exec_path_point].m_file_name == file && + m_execution_path[m_exec_path_point].m_line_num == line_num, + "Function under test exibit non-deterministic behavior" ); + } + else { + m_execution_path.push_back( + execution_path_point( EPP_SCOPE, file, line_num ) ); + } + + m_execution_path[m_exec_path_point].m_scope.size = 0; + m_execution_path[m_exec_path_point].m_scope.name = scope_name.begin(); + + return m_exec_path_point++; +} + +//____________________________________________________________________________// + +void +exception_safety_tester::leave_scope( unsigned enter_scope_point ) +{ + activity_guard ag( m_internal_activity ); + + BOOST_REQUIRE_MESSAGE( m_execution_path[enter_scope_point].m_type == EPP_SCOPE, + "Function under test exibit non-deterministic behavior" ); + + m_execution_path[enter_scope_point].m_scope.size = m_exec_path_point - enter_scope_point; +} + +//____________________________________________________________________________// + +void +exception_safety_tester::allocated( const_string file, std::size_t line_num, void* p, std::size_t s ) +{ + if( m_internal_activity ) + return; + + activity_guard ag( m_internal_activity ); + + if( m_exec_path_point < m_execution_path.size() ) + BOOST_REQUIRE_MESSAGE( m_execution_path[m_exec_path_point].m_type == EPP_ALLOC, + "Function under test exibit non-deterministic behavior" ); + else + m_execution_path.push_back( + execution_path_point( EPP_ALLOC, file, line_num ) ); + + m_execution_path[m_exec_path_point].m_alloc.ptr = p; + m_execution_path[m_exec_path_point].m_alloc.size = s; + + m_memory_in_use.insert( std::make_pair( p, m_exec_path_point++ ) ); +} + +//____________________________________________________________________________// + +void +exception_safety_tester::freed( void* p ) +{ + if( m_internal_activity ) + return; + + activity_guard ag( m_internal_activity ); + + registry::iterator it = m_memory_in_use.find( p ); + if( it != m_memory_in_use.end() ) { + m_execution_path[it->second].m_alloc.ptr = 0; + m_memory_in_use.erase( it ); + } +} + +//____________________________________________________________________________// + +void +exception_safety_tester::assertion_result( bool passed ) +{ + if( !m_internal_activity && !passed ) { + m_invairant_failed = true; + + failure_point(); + } +} + +//____________________________________________________________________________// + +void +exception_safety_tester::failure_point() +{ + if( m_exec_path_counter == m_break_exec_path ) + debug::debugger_break(); + + throw unique_exception(); +} + +//____________________________________________________________________________// + +namespace { + +inline void +format_location( wrap_stringstream& formatter, execution_path_point const& /*p*/, unsigned indent ) +{ + if( indent ) + formatter << std::left << std::setw( indent ) << ""; + +// !! ?? optional if( p.m_file_name ) +// formatter << p.m_file_name << '(' << p.m_line_num << "): "; +} + +//____________________________________________________________________________// + +template +inline void +format_execution_path( wrap_stringstream& formatter, ExecPathIt it, ExecPathIt end, unsigned indent = 0 ) +{ + while( it != end ) { + switch( it->m_type ) { + case EPP_SCOPE: + format_location( formatter, *it, indent ); + formatter << "> \"" << it->m_scope.name << "\"\n"; + format_execution_path( formatter, it+1, it + it->m_scope.size, indent + 2 ); + format_location( formatter, *it, indent ); + formatter << "< \"" << it->m_scope.name << "\"\n"; + it += it->m_scope.size; + break; + + case EPP_DECISION: + format_location( formatter, *it, indent ); + formatter << "Decision made as " << std::boolalpha << it->m_decision.value << '\n'; + ++it; + break; + + case EPP_EXCEPT: + format_location( formatter, *it, indent ); + formatter << "Forced failure"; + if( it->m_except.description ) + formatter << ": " << it->m_except.description; + formatter << "\n"; + ++it; + break; + + case EPP_ALLOC: + if( it->m_alloc.ptr ) { + format_location( formatter, *it, indent ); + formatter << "Allocated memory block 0x" << std::uppercase << it->m_alloc.ptr + << ", " << it->m_alloc.size << " bytes long: <"; + + unsigned i; + for( i = 0; i < std::min( it->m_alloc.size, 8 ); i++ ) { + unsigned char c = static_cast(it->m_alloc.ptr)[i]; + if( (std::isprint)( c ) ) + formatter << c; + else + formatter << '.'; + } + + formatter << "> "; + + for( i = 0; i < std::min( it->m_alloc.size, 8 ); i++ ) { + unsigned c = static_cast(it->m_alloc.ptr)[i]; + formatter << std::hex << std::uppercase << c << ' '; + } + + formatter << "\n"; + } + ++it; + break; + } + } +} + +//____________________________________________________________________________// + +} // local namespace + +void +exception_safety_tester::report_error() +{ + activity_guard ag( m_internal_activity ); + + unit_test_log << unit_test::log::begin( m_execution_path.back().m_file_name, + m_execution_path.back().m_line_num ) + << log_all_errors; + + wrap_stringstream formatter; + + if( m_invairant_failed ) + formatter << "Failed invariant"; + + if( m_memory_in_use.size() != 0 ) { + if( m_invairant_failed ) + formatter << " and "; + + formatter << static_cast(m_memory_in_use.size()) << " memory leak"; + if( m_memory_in_use.size() > 1 ) + formatter << 's'; + } + formatter << " detected in the execution path " << m_exec_path_counter << ":\n"; + + format_execution_path( formatter, m_execution_path.begin(), m_execution_path.end() ); + + unit_test_log << const_string( formatter.str() ) << unit_test::log::end(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** exception safety test ************** // +// ************************************************************************** // + +void BOOST_TEST_DECL +exception_safety( callback0<> const& F, const_string test_name ) +{ + exception_safety_tester est( test_name ); + + do { + try { + F(); + } + catch( exception_safety_tester::unique_exception const& ) {} + + } while( est.next_execution_path() ); +} + +//____________________________________________________________________________// + +} // namespace itest + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // non-ancient compiler + +#endif // BOOST_TEST_EXECUTION_SAFETY_IPP_112005GER diff --git a/cpp/BoostParts/boost/test/impl/execution_monitor.ipp b/cpp/BoostParts/boost/test/impl/execution_monitor.ipp new file mode 100644 index 00000000..d9d5b6a3 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/execution_monitor.ipp @@ -0,0 +1,1367 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Beman Dawes and Ullrich Koethe 1995-2001. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : provides execution monitor implementation for all supported +// configurations, including Microsoft structured exception based, unix signals +// based and special workarounds for borland +// +// Note that when testing requirements or user wishes preclude use of this +// file as a separate compilation unit, it may be included as a header file. +// +// Header dependencies are deliberately restricted to reduce coupling to other +// boost libraries. +// *************************************************************************** + +#ifndef BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER +#define BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER + +// Boost.Test +#include +#include +#include +#include + +// Boost +#include // for exit codes +#include // for workarounds +#include // for get_error_info +#include // for current_exception_cast + +// STL +#include // for std::string +#include // for std::bad_alloc +#include // for std::bad_cast, std::bad_typeid +#include // for std::exception, std::bad_exception +#include // for std exception hierarchy +#include // for C string API +#include // for assert +#include // for NULL +#include // for vsnprintf +#include // for varargs + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::strerror; using ::strlen; using ::strncat; } +#endif + +// to use vsnprintf +#if defined(__SUNPRO_CC) || defined(__SunOS) +# include +# include +using std::va_list; +#endif + +// to use vsnprintf +#if defined(__QNXNTO__) +# include +#endif + +#if defined(_WIN32) && !defined(BOOST_DISABLE_WIN32) && \ + (!defined(__COMO__) && !defined(__MWERKS__) && !defined(__GNUC__) || \ + BOOST_WORKAROUND(__MWERKS__, >= 0x3000)) + +# define BOOST_SEH_BASED_SIGNAL_HANDLING + +# include + +# if defined(__MWERKS__) || (defined(_MSC_VER) && !defined(UNDER_CE)) +# include +# endif + +# if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 || defined(__MWERKS__) +# include +# endif + +# if defined(__BORLANDC__) && __BORLANDC__ < 0x560 + typedef unsigned uintptr_t; +# endif + +# if BOOST_WORKAROUND(_MSC_VER, < 1300 ) || defined(UNDER_CE) +typedef void* uintptr_t; +# endif + +// for the FP control routines +#include + +#ifndef EM_INVALID +#define EM_INVALID _EM_INVALID +#endif + +#ifndef EM_DENORMAL +#define EM_DENORMAL _EM_DENORMAL +#endif + +#ifndef EM_ZERODIVIDE +#define EM_ZERODIVIDE _EM_ZERODIVIDE +#endif + +#ifndef EM_OVERFLOW +#define EM_OVERFLOW _EM_OVERFLOW +#endif + +#ifndef EM_UNDERFLOW +#define EM_UNDERFLOW _EM_UNDERFLOW +#endif + +#ifndef MCW_EM +#define MCW_EM _MCW_EM +#endif + +# if !defined(NDEBUG) && defined(_MSC_VER) && !defined(UNDER_CE) +# include +# define BOOST_TEST_CRT_HOOK_TYPE _CRT_REPORT_HOOK +# define BOOST_TEST_CRT_ASSERT _CRT_ASSERT +# define BOOST_TEST_CRT_ERROR _CRT_ERROR +# define BOOST_TEST_CRT_SET_HOOK(H) _CrtSetReportHook(H) +# else +# define BOOST_TEST_CRT_HOOK_TYPE void* +# define BOOST_TEST_CRT_ASSERT 2 +# define BOOST_TEST_CRT_ERROR 1 +# define BOOST_TEST_CRT_SET_HOOK(H) (void*)(H) +# endif + +# if !BOOST_WORKAROUND(_MSC_VER, >= 1400 ) || defined(UNDER_CE) + +typedef void* _invalid_parameter_handler; + +inline _invalid_parameter_handler +_set_invalid_parameter_handler( _invalid_parameter_handler arg ) +{ + return arg; +} + +# endif + +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) || defined(UNDER_CE) + +namespace { void _set_se_translator( void* ) {} } + +# endif + +#elif defined(BOOST_HAS_SIGACTION) + +# define BOOST_SIGACTION_BASED_SIGNAL_HANDLING + +# include +# include +# include + +# if defined(__FreeBSD__) + +# ifndef SIGPOLL +# define SIGPOLL SIGIO +# endif + +# if (__FreeBSD_version < 70100) + +# define ILL_ILLADR 0 // ILL_RESAD_FAULT +# define ILL_PRVOPC ILL_PRIVIN_FAULT +# define ILL_ILLOPN 2 // ILL_RESOP_FAULT +# define ILL_COPROC ILL_FPOP_FAULT + +# define BOOST_TEST_LIMITED_SIGNAL_DETAILS +# define BOOST_TEST_IGNORE_SIGCHLD + +# endif +# endif + +# if !defined(__CYGWIN__) && !defined(__QNXNTO__) +# define BOOST_TEST_USE_ALT_STACK +# endif + +# if defined(SIGPOLL) && !defined(__CYGWIN__) && \ + !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && \ + !defined(__NetBSD__) && \ + !defined(__QNXNTO__) +# define BOOST_TEST_CATCH_SIGPOLL +# endif + +# ifdef BOOST_TEST_USE_ALT_STACK +# define BOOST_TEST_ALT_STACK_SIZE SIGSTKSZ +# endif + +#else + +# define BOOST_NO_SIGNAL_HANDLING + +#endif + +#ifndef UNDER_CE +#include +#endif + +#include + +//____________________________________________________________________________// + +namespace boost { + +// ************************************************************************** // +// ************** report_error ************** // +// ************************************************************************** // + +namespace detail { + +#ifdef __BORLANDC__ +# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) std::vsnprintf( (a1), (a2), (a3), (a4) ) +#elif BOOST_WORKAROUND(_MSC_VER, <= 1310) || \ + BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3000)) || \ + defined(UNDER_CE) +# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) _vsnprintf( (a1), (a2), (a3), (a4) ) +#else +# define BOOST_TEST_VSNPRINTF( a1, a2, a3, a4 ) vsnprintf( (a1), (a2), (a3), (a4) ) +#endif + +template +typename ErrorInfo::value_type +extract( boost::exception const* ex ) +{ + if( !ex ) + return 0; + + typename ErrorInfo::value_type const * val = boost::get_error_info( *ex ); + + return val ? *val : 0; +} + +//____________________________________________________________________________// + +static void +report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, va_list* args ) +{ + static const int REPORT_ERROR_BUFFER_SIZE = 512; + static char buf[REPORT_ERROR_BUFFER_SIZE]; + + BOOST_TEST_VSNPRINTF( buf, sizeof(buf)-1, format, *args ); + buf[sizeof(buf)-1] = 0; + + va_end( *args ); + + throw execution_exception( ec, buf, execution_exception::location( extract( be ), + extract( be ), + extract( be ) ) ); +} + +//____________________________________________________________________________// + +static void +report_error( execution_exception::error_code ec, char const* format, ... ) +{ + va_list args; + va_start( args, format ); + + report_error( ec, 0, format, &args ); +} + +//____________________________________________________________________________// + +static void +report_error( execution_exception::error_code ec, boost::exception const* be, char const* format, ... ) +{ + va_list args; + va_start( args, format ); + + report_error( ec, be, format, &args ); +} + +//____________________________________________________________________________// + +template +inline int +do_invoke( Tr const& tr, Functor const& F ) +{ + return tr ? (*tr)( F ) : F(); +} + +//____________________________________________________________________________// + +} // namespace detail + +#if defined(BOOST_SIGACTION_BASED_SIGNAL_HANDLING) + +// ************************************************************************** // +// ************** Sigaction based signal handling ************** // +// ************************************************************************** // + +namespace detail { + +// ************************************************************************** // +// ************** boost::detail::system_signal_exception ************** // +// ************************************************************************** // + +class system_signal_exception { +public: + // Constructor + system_signal_exception() + : m_sig_info( 0 ) + , m_context( 0 ) + {} + + // Access methods + void operator()( siginfo_t* i, void* c ) + { + m_sig_info = i; + m_context = c; + } + void report() const; + +private: + // Data members + siginfo_t* m_sig_info; // system signal detailed info + void* m_context; // signal context +}; + +//____________________________________________________________________________// + +void +system_signal_exception::report() const +{ + if( !m_sig_info ) + return; // no error actually occur? + + switch( m_sig_info->si_code ) { + case SI_USER: + report_error( execution_exception::system_error, + "signal: generated by kill() (or family); uid=%d; pid=%d", + (int)m_sig_info->si_uid, (int)m_sig_info->si_pid ); + break; + case SI_QUEUE: + report_error( execution_exception::system_error, + "signal: sent by sigqueue()" ); + break; + case SI_TIMER: + report_error( execution_exception::system_error, + "signal: the expiration of a timer set by timer_settimer()" ); + break; + case SI_ASYNCIO: + report_error( execution_exception::system_error, + "signal: generated by the completion of an asynchronous I/O request" ); + break; + case SI_MESGQ: + report_error( execution_exception::system_error, + "signal: generated by the the arrival of a message on an empty message queue" ); + break; + default: + break; + } + + switch( m_sig_info->si_signo ) { + case SIGILL: + switch( m_sig_info->si_code ) { +#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS + case ILL_ILLOPC: + report_error( execution_exception::system_fatal_error, + "signal: illegal opcode; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case ILL_ILLTRP: + report_error( execution_exception::system_fatal_error, + "signal: illegal trap; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case ILL_PRVREG: + report_error( execution_exception::system_fatal_error, + "signal: privileged register; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case ILL_BADSTK: + report_error( execution_exception::system_fatal_error, + "signal: internal stack error; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; +#endif + case ILL_ILLOPN: + report_error( execution_exception::system_fatal_error, + "signal: illegal operand; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case ILL_ILLADR: + report_error( execution_exception::system_fatal_error, + "signal: illegal addressing mode; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case ILL_PRVOPC: + report_error( execution_exception::system_fatal_error, + "signal: privileged opcode; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case ILL_COPROC: + report_error( execution_exception::system_fatal_error, + "signal: co-processor error; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + default: + report_error( execution_exception::system_fatal_error, + "signal: SIGILL, si_code: %d (illegal instruction; address of failing instruction: 0x%08lx)", + m_sig_info->si_addr, m_sig_info->si_code ); + break; + } + break; + + case SIGFPE: + switch( m_sig_info->si_code ) { + case FPE_INTDIV: + report_error( execution_exception::system_error, + "signal: integer divide by zero; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case FPE_INTOVF: + report_error( execution_exception::system_error, + "signal: integer overflow; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case FPE_FLTDIV: + report_error( execution_exception::system_error, + "signal: floating point divide by zero; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case FPE_FLTOVF: + report_error( execution_exception::system_error, + "signal: floating point overflow; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case FPE_FLTUND: + report_error( execution_exception::system_error, + "signal: floating point underflow; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case FPE_FLTRES: + report_error( execution_exception::system_error, + "signal: floating point inexact result; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case FPE_FLTINV: + report_error( execution_exception::system_error, + "signal: invalid floating point operation; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + case FPE_FLTSUB: + report_error( execution_exception::system_error, + "signal: subscript out of range; address of failing instruction: 0x%08lx", + m_sig_info->si_addr ); + break; + default: + report_error( execution_exception::system_error, + "signal: SIGFPE, si_code: %d (errnoneous arithmetic operations; address of failing instruction: 0x%08lx)", + m_sig_info->si_addr, m_sig_info->si_code ); + break; + } + break; + + case SIGSEGV: + switch( m_sig_info->si_code ) { +#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS + case SEGV_MAPERR: + report_error( execution_exception::system_fatal_error, + "memory access violation at address: 0x%08lx: no mapping at fault address", + m_sig_info->si_addr ); + break; + case SEGV_ACCERR: + report_error( execution_exception::system_fatal_error, + "memory access violation at address: 0x%08lx: invalid permissions", + m_sig_info->si_addr ); + break; +#endif + default: + report_error( execution_exception::system_fatal_error, + "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)", + m_sig_info->si_addr, m_sig_info->si_code ); + break; + } + break; + + case SIGBUS: + switch( m_sig_info->si_code ) { +#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS + case BUS_ADRALN: + report_error( execution_exception::system_fatal_error, + "memory access violation at address: 0x%08lx: invalid address alignment", + m_sig_info->si_addr ); + break; + case BUS_ADRERR: + report_error( execution_exception::system_fatal_error, + "memory access violation at address: 0x%08lx: non-existent physical address", + m_sig_info->si_addr ); + break; + case BUS_OBJERR: + report_error( execution_exception::system_fatal_error, + "memory access violation at address: 0x%08lx: object specific hardware error", + m_sig_info->si_addr ); + break; +#endif + default: + report_error( execution_exception::system_fatal_error, + "signal: SIGSEGV, si_code: %d (memory access violation at address: 0x%08lx)", + m_sig_info->si_addr, m_sig_info->si_code ); + break; + } + break; + + case SIGCHLD: + switch( m_sig_info->si_code ) { +#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS + case CLD_EXITED: + report_error( execution_exception::system_error, + "child has exited; pid: %d; uid: %d; exit value: %d", + (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); + break; + case CLD_KILLED: + report_error( execution_exception::system_error, + "child was killed; pid: %d; uid: %d; exit value: %d", + (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); + break; + case CLD_DUMPED: + report_error( execution_exception::system_error, + "child terminated abnormally; pid: %d; uid: %d; exit value: %d", + (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); + break; + case CLD_TRAPPED: + report_error( execution_exception::system_error, + "traced child has trapped; pid: %d; uid: %d; exit value: %d", + (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); + break; + case CLD_STOPPED: + report_error( execution_exception::system_error, + "child has stopped; pid: %d; uid: %d; exit value: %d", + (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); + break; + case CLD_CONTINUED: + report_error( execution_exception::system_error, + "stopped child had continued; pid: %d; uid: %d; exit value: %d", + (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status ); + break; +#endif + default: + report_error( execution_exception::system_error, + "signal: SIGCHLD, si_code: %d (child process has terminated; pid: %d; uid: %d; exit value: %d)", + (int)m_sig_info->si_pid, (int)m_sig_info->si_uid, (int)m_sig_info->si_status, m_sig_info->si_code ); + break; + } + break; + +#if defined(BOOST_TEST_CATCH_SIGPOLL) + + case SIGPOLL: + switch( m_sig_info->si_code ) { +#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS + case POLL_IN: + report_error( execution_exception::system_error, + "data input available; band event %d", + (int)m_sig_info->si_band ); + break; + case POLL_OUT: + report_error( execution_exception::system_error, + "output buffers available; band event %d", + (int)m_sig_info->si_band ); + break; + case POLL_MSG: + report_error( execution_exception::system_error, + "input message available; band event %d", + (int)m_sig_info->si_band ); + break; + case POLL_ERR: + report_error( execution_exception::system_error, + "i/o error; band event %d", + (int)m_sig_info->si_band ); + break; + case POLL_PRI: + report_error( execution_exception::system_error, + "high priority input available; band event %d", + (int)m_sig_info->si_band ); + break; +#if defined(POLL_ERR) && defined(POLL_HUP) && (POLL_ERR - POLL_HUP) + case POLL_HUP: + report_error( execution_exception::system_error, + "device disconnected; band event %d", + (int)m_sig_info->si_band ); + break; +#endif +#endif + default: + report_error( execution_exception::system_error, + "signal: SIGPOLL, si_code: %d (asynchronous I/O event occured; band event %d)", + (int)m_sig_info->si_band, m_sig_info->si_code ); + break; + } + break; + +#endif + + case SIGABRT: + report_error( execution_exception::system_error, + "signal: SIGABRT (application abort requested)" ); + break; + + case SIGALRM: + report_error( execution_exception::timeout_error, + "signal: SIGALRM (timeout while executing function)" ); + break; + + default: + report_error( execution_exception::system_error, "unrecognized signal" ); + } +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** boost::detail::signal_action ************** // +// ************************************************************************** // + +// Forward declaration +extern "C" { +static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ); +static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ); +} + +class signal_action { + typedef struct sigaction* sigaction_ptr; +public: + //Constructor + signal_action(); + signal_action( int sig, bool install, bool attach_dbg, char* alt_stack ); + ~signal_action(); + +private: + // Data members + int m_sig; + bool m_installed; + struct sigaction m_new_action; + struct sigaction m_old_action; +}; + +//____________________________________________________________________________// + +signal_action::signal_action() +: m_installed( false ) +{} + +//____________________________________________________________________________// + +signal_action::signal_action( int sig, bool install, bool attach_dbg, char* alt_stack ) +: m_sig( sig ) +, m_installed( install ) +{ + if( !install ) + return; + + std::memset( &m_new_action, 0, sizeof(struct sigaction) ); + + BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig , sigaction_ptr(), &m_new_action ) != -1 ); + + if( m_new_action.sa_sigaction || m_new_action.sa_handler ) { + m_installed = false; + return; + } + + m_new_action.sa_flags |= SA_SIGINFO; + m_new_action.sa_sigaction = attach_dbg ? &execution_monitor_attaching_signal_handler + : &execution_monitor_jumping_signal_handler; + BOOST_TEST_SYS_ASSERT( sigemptyset( &m_new_action.sa_mask ) != -1 ); + +#ifdef BOOST_TEST_USE_ALT_STACK + if( alt_stack ) + m_new_action.sa_flags |= SA_ONSTACK; +#endif + + BOOST_TEST_SYS_ASSERT( ::sigaction( m_sig, &m_new_action, &m_old_action ) != -1 ); +} + +//____________________________________________________________________________// + +signal_action::~signal_action() +{ + if( m_installed ) + ::sigaction( m_sig, &m_old_action , sigaction_ptr() ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** boost::detail::signal_handler ************** // +// ************************************************************************** // + +class signal_handler { +public: + // Constructor + explicit signal_handler( bool catch_system_errors, int timeout, bool attach_dbg, char* alt_stack ); + + // Destructor + ~signal_handler(); + + // access methods + static sigjmp_buf& jump_buffer() + { + assert( !!s_active_handler ); + + return s_active_handler->m_sigjmp_buf; + } + + static system_signal_exception& sys_sig() + { + assert( !!s_active_handler ); + + return s_active_handler->m_sys_sig; + } + +private: + // Data members + signal_handler* m_prev_handler; + int m_timeout; + + signal_action m_ILL_action; + signal_action m_FPE_action; + signal_action m_SEGV_action; + signal_action m_BUS_action; + signal_action m_CHLD_action; + signal_action m_POLL_action; + signal_action m_ABRT_action; + signal_action m_ALRM_action; + + sigjmp_buf m_sigjmp_buf; + system_signal_exception m_sys_sig; + + static signal_handler* s_active_handler; +}; + +// !! need to be placed in thread specific storage +typedef signal_handler* signal_handler_ptr; +signal_handler* signal_handler::s_active_handler = signal_handler_ptr(); + +//____________________________________________________________________________// + +signal_handler::signal_handler( bool catch_system_errors, int timeout, bool attach_dbg, char* alt_stack ) +: m_prev_handler( s_active_handler ) +, m_timeout( timeout ) +, m_ILL_action ( SIGILL , catch_system_errors, attach_dbg, alt_stack ) +, m_FPE_action ( SIGFPE , catch_system_errors, attach_dbg, alt_stack ) +, m_SEGV_action( SIGSEGV, catch_system_errors, attach_dbg, alt_stack ) +, m_BUS_action ( SIGBUS , catch_system_errors, attach_dbg, alt_stack ) +#ifndef BOOST_TEST_IGNORE_SIGCHLD +, m_CHLD_action( SIGCHLD, catch_system_errors, attach_dbg, alt_stack ) +#endif +#ifdef BOOST_TEST_CATCH_SIGPOLL +, m_POLL_action( SIGPOLL, catch_system_errors, attach_dbg, alt_stack ) +#endif +, m_ABRT_action( SIGABRT, catch_system_errors, attach_dbg, alt_stack ) +, m_ALRM_action( SIGALRM, timeout > 0 , attach_dbg, alt_stack ) +{ + s_active_handler = this; + + if( m_timeout > 0 ) { + ::alarm( 0 ); + ::alarm( timeout ); + } + +#ifdef BOOST_TEST_USE_ALT_STACK + if( alt_stack ) { + stack_t sigstk; + std::memset( &sigstk, 0, sizeof(stack_t) ); + + BOOST_TEST_SYS_ASSERT( ::sigaltstack( 0, &sigstk ) != -1 ); + + if( sigstk.ss_flags & SS_DISABLE ) { + sigstk.ss_sp = alt_stack; + sigstk.ss_size = BOOST_TEST_ALT_STACK_SIZE; + sigstk.ss_flags = 0; + BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 ); + } + } +#endif +} + +//____________________________________________________________________________// + +signal_handler::~signal_handler() +{ + assert( s_active_handler == this ); + + if( m_timeout > 0 ) + ::alarm( 0 ); + +#ifdef BOOST_TEST_USE_ALT_STACK +#ifdef __GNUC__ + // We shouldn't need to explicitly initialize all the members here, + // but gcc warns if we don't, so add initializers for each of the + // members specified in the POSIX std: + stack_t sigstk = { 0, 0, 0 }; +#else + stack_t sigstk = { }; +#endif + + sigstk.ss_size = MINSIGSTKSZ; + sigstk.ss_flags = SS_DISABLE; + BOOST_TEST_SYS_ASSERT( ::sigaltstack( &sigstk, 0 ) != -1 ); +#endif + + s_active_handler = m_prev_handler; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** execution_monitor_signal_handler ************** // +// ************************************************************************** // + +extern "C" { + +static bool ignore_sigchild( siginfo_t* info ) +{ + return info->si_signo == SIGCHLD +#ifndef BOOST_TEST_LIMITED_SIGNAL_DETAILS + && info->si_code == CLD_EXITED +#endif +#ifdef BOOST_TEST_IGNORE_NON_ZERO_CHILD_CODE + ; +#else + && (int)info->si_status == 0; +#endif +} + +//____________________________________________________________________________// + +static void execution_monitor_jumping_signal_handler( int sig, siginfo_t* info, void* context ) +{ + if( ignore_sigchild( info ) ) + return; + + signal_handler::sys_sig()( info, context ); + + siglongjmp( signal_handler::jump_buffer(), sig ); +} + +//____________________________________________________________________________// + +static void execution_monitor_attaching_signal_handler( int sig, siginfo_t* info, void* context ) +{ + if( ignore_sigchild( info ) ) + return; + + if( !debug::attach_debugger( false ) ) + execution_monitor_jumping_signal_handler( sig, info, context ); + + // debugger attached; it will handle the signal + BOOST_TEST_SYS_ASSERT( ::signal( sig, SIG_DFL ) != SIG_ERR ); +} + +//____________________________________________________________________________// + +} + +} // namespace detail + +// ************************************************************************** // +// ************** execution_monitor::catch_signals ************** // +// ************************************************************************** // + +int +execution_monitor::catch_signals( unit_test::callback0 const& F ) +{ + using namespace detail; + +#if defined(__CYGWIN__) + p_catch_system_errors.value = false; +#endif + +#ifdef BOOST_TEST_USE_ALT_STACK + if( !!p_use_alt_stack && !m_alt_stack ) + m_alt_stack.reset( new char[BOOST_TEST_ALT_STACK_SIZE] ); +#else + p_use_alt_stack.value = false; +#endif + + signal_handler local_signal_handler( p_catch_system_errors, p_timeout, p_auto_start_dbg, + !p_use_alt_stack ? 0 : m_alt_stack.get() ); + + if( !sigsetjmp( signal_handler::jump_buffer(), 1 ) ) + return detail::do_invoke( m_custom_translators , F ); + else + throw local_signal_handler.sys_sig(); +} + +//____________________________________________________________________________// + +#elif defined(BOOST_SEH_BASED_SIGNAL_HANDLING) + +// ************************************************************************** // +// ************** Microsoft structured exception handling ************** // +// ************************************************************************** // + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) +namespace { void _set_se_translator( void* ) {} } +#endif + +namespace detail { + +// ************************************************************************** // +// ************** boost::detail::system_signal_exception ************** // +// ************************************************************************** // + +class system_signal_exception { +public: + // Constructor + explicit system_signal_exception( execution_monitor* em ) + : m_em( em ) + , m_se_id( 0 ) + , m_fault_address( 0 ) + , m_dir( false ) + {} + + void report() const; + int operator()( unsigned int id, _EXCEPTION_POINTERS* exps ); + +private: + // Data members + execution_monitor* m_em; + + unsigned int m_se_id; + void* m_fault_address; + bool m_dir; +}; + +static void +seh_catch_preventer( unsigned int /* id */, _EXCEPTION_POINTERS* /* exps */ ) +{ + throw; +} + +//____________________________________________________________________________// + +int +system_signal_exception::operator()( unsigned int id, _EXCEPTION_POINTERS* exps ) +{ + const unsigned int MSFT_CPP_EXCEPT = 0xE06d7363; // EMSC + + if( !m_em->p_catch_system_errors || (id == MSFT_CPP_EXCEPT) ) + return EXCEPTION_CONTINUE_SEARCH; + + if( !!m_em->p_auto_start_dbg && debug::attach_debugger( false ) ) { + m_em->p_catch_system_errors.value = false; + _set_se_translator( &seh_catch_preventer ); + + return EXCEPTION_CONTINUE_EXECUTION; + } + + m_se_id = id; + if( m_se_id == EXCEPTION_ACCESS_VIOLATION && exps->ExceptionRecord->NumberParameters == 2 ) { + m_fault_address = (void*)exps->ExceptionRecord->ExceptionInformation[1]; + m_dir = exps->ExceptionRecord->ExceptionInformation[0] == 0; + } + + return EXCEPTION_EXECUTE_HANDLER; +} + +//____________________________________________________________________________// + +void +system_signal_exception::report() const +{ + switch( m_se_id ) { + // cases classified as system_fatal_error + case EXCEPTION_ACCESS_VIOLATION: { + if( !m_fault_address ) + detail::report_error( execution_exception::system_fatal_error, "memory access violation" ); + else + detail::report_error( + execution_exception::system_fatal_error, + "memory access violation occurred at address 0x%08lx, while attempting to %s", + m_fault_address, + m_dir ? " read inaccessible data" + : " write to an inaccessible (or protected) address" + ); + break; + } + + case EXCEPTION_ILLEGAL_INSTRUCTION: + detail::report_error( execution_exception::system_fatal_error, "illegal instruction" ); + break; + + case EXCEPTION_PRIV_INSTRUCTION: + detail::report_error( execution_exception::system_fatal_error, "tried to execute an instruction whose operation is not allowed in the current machine mode" ); + break; + + case EXCEPTION_IN_PAGE_ERROR: + detail::report_error( execution_exception::system_fatal_error, "access to a memory page that is not present" ); + break; + + case EXCEPTION_STACK_OVERFLOW: + detail::report_error( execution_exception::system_fatal_error, "stack overflow" ); + break; + + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + detail::report_error( execution_exception::system_fatal_error, "tried to continue execution after a non continuable exception occurred" ); + break; + + // cases classified as (non-fatal) system_trap + case EXCEPTION_DATATYPE_MISALIGNMENT: + detail::report_error( execution_exception::system_error, "data misalignment" ); + break; + + case EXCEPTION_INT_DIVIDE_BY_ZERO: + detail::report_error( execution_exception::system_error, "integer divide by zero" ); + break; + + case EXCEPTION_INT_OVERFLOW: + detail::report_error( execution_exception::system_error, "integer overflow" ); + break; + + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + detail::report_error( execution_exception::system_error, "array bounds exceeded" ); + break; + + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + detail::report_error( execution_exception::system_error, "floating point divide by zero" ); + break; + + case EXCEPTION_FLT_STACK_CHECK: + detail::report_error( execution_exception::system_error, + "stack overflowed or underflowed as the result of a floating-point operation" ); + break; + + case EXCEPTION_FLT_DENORMAL_OPERAND: + detail::report_error( execution_exception::system_error, + "operand of floating point operation is denormal" ); + break; + +# if 0 // !! ?? + case EXCEPTION_FLT_INEXACT_RESULT: + detail::report_error( execution_exception::system_error, + "result of a floating-point operation cannot be represented exactly" ); + break; +#endif + + case EXCEPTION_FLT_OVERFLOW: + detail::report_error( execution_exception::system_error, + "exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type" ); + break; + + case EXCEPTION_FLT_UNDERFLOW: + detail::report_error( execution_exception::system_error, + "exponent of a floating-point operation is less than the magnitude allowed by the corresponding type" ); + break; + + case EXCEPTION_FLT_INVALID_OPERATION: + detail::report_error( execution_exception::system_error, "floating point error" ); + break; + + case EXCEPTION_BREAKPOINT: + detail::report_error( execution_exception::system_error, "breakpoint encountered" ); + break; + + default: + detail::report_error( execution_exception::system_error, "unrecognized exception. Id: 0x%08lx", m_se_id ); + break; + } +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** assert_reporting_function ************** // +// ************************************************************************** // + +int BOOST_TEST_CALL_DECL +assert_reporting_function( int reportType, char* userMessage, int* ) +{ + switch( reportType ) { + case BOOST_TEST_CRT_ASSERT: + detail::report_error( execution_exception::user_error, userMessage ); + + return 1; // return value and retVal are not important since we never reach this line + case BOOST_TEST_CRT_ERROR: + detail::report_error( execution_exception::system_error, userMessage ); + + return 1; // return value and retVal are not important since we never reach this line + default: + return 0; // use usual reporting method + } +} // assert_reporting_function + +//____________________________________________________________________________// + +void BOOST_TEST_CALL_DECL +invalid_param_handler( wchar_t const* /* expr */, + wchar_t const* /* func */, + wchar_t const* /* file */, + unsigned int /* line */, + uintptr_t /* reserved */) +{ + detail::report_error( execution_exception::user_error, + "Invalid parameter detected by C runtime library" ); +} + +//____________________________________________________________________________// + +void BOOST_TEST_CALL_DECL +switch_fp_exceptions( bool on_off ) +{ + if( !on_off ) + _clearfp(); + + int cw = ::_controlfp( 0, 0 ); + + int exceptions_mask = EM_INVALID|EM_DENORMAL|EM_ZERODIVIDE|EM_OVERFLOW|EM_UNDERFLOW; + + if( on_off ) + cw &= ~exceptions_mask; // Set the exception masks on, turn exceptions off + else + cw |= exceptions_mask; // Set the exception masks off, turn exceptions on + + if( on_off ) + _clearfp(); + + // Set the control word + ::_controlfp( cw, MCW_EM ); +} + +//____________________________________________________________________________// + +} // namespace detail + +// ************************************************************************** // +// ************** execution_monitor::catch_signals ************** // +// ************************************************************************** // + +int +execution_monitor::catch_signals( unit_test::callback0 const& F ) +{ + _invalid_parameter_handler old_iph = _invalid_parameter_handler(); + BOOST_TEST_CRT_HOOK_TYPE old_crt_hook = 0; + + if( !p_catch_system_errors ) + _set_se_translator( &detail::seh_catch_preventer ); + else { + if( !!p_detect_fp_exceptions ) + detail::switch_fp_exceptions( true ); + + old_crt_hook = BOOST_TEST_CRT_SET_HOOK( &detail::assert_reporting_function ); + + old_iph = _set_invalid_parameter_handler( + reinterpret_cast<_invalid_parameter_handler>( &detail::invalid_param_handler ) ); + } + + detail::system_signal_exception SSE( this ); + + int ret_val = 0; + + __try { + __try { + ret_val = detail::do_invoke( m_custom_translators, F ); + } + __except( SSE( GetExceptionCode(), GetExceptionInformation() ) ) { + throw SSE; + } + } + __finally { + if( !!p_catch_system_errors ) { + if( !!p_detect_fp_exceptions ) + detail::switch_fp_exceptions( false ); + + BOOST_TEST_CRT_SET_HOOK( old_crt_hook ); + + _set_invalid_parameter_handler( old_iph ); + } + } + + return ret_val; +} + +//____________________________________________________________________________// + +#else // default signal handler + +namespace detail { + +class system_signal_exception { +public: + void report() const {} +}; + +} // namespace detail + +int +execution_monitor::catch_signals( unit_test::callback0 const& F ) +{ + return detail::do_invoke( m_custom_translators , F ); +} + +//____________________________________________________________________________// + +#endif // choose signal handler + +// ************************************************************************** // +// ************** execution_monitor::execute ************** // +// ************************************************************************** // + +int +execution_monitor::execute( unit_test::callback0 const& F ) +{ + if( debug::under_debugger() ) + p_catch_system_errors.value = false; + + try { + return catch_signals( F ); + } + + // Catch-clause reference arguments are a bit different from function + // arguments (ISO 15.3 paragraphs 18 & 19). Apparently const isn't + // required. Programmers ask for const anyhow, so we supply it. That's + // easier than answering questions about non-const usage. + + catch( char const* ex ) + { detail::report_error( execution_exception::cpp_exception_error, + "C string: %s", ex ); } + catch( std::string const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + "std::string: %s", ex.c_str() ); } + + // std:: exceptions + + catch( std::bad_alloc const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::bad_alloc: %s", ex.what() ); } + +#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) + catch( std::bad_cast const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::bad_cast" ); } + catch( std::bad_typeid const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::bad_typeid" ); } +#else + catch( std::bad_cast const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::bad_cast: %s", ex.what() ); } + catch( std::bad_typeid const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::bad_typeid: %s", ex.what() ); } +#endif + + catch( std::bad_exception const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::bad_exception: %s", ex.what() ); } + catch( std::domain_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::domain_error: %s", ex.what() ); } + catch( std::invalid_argument const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::invalid_argument: %s", ex.what() ); } + catch( std::length_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::length_error: %s", ex.what() ); } + catch( std::out_of_range const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::out_of_range: %s", ex.what() ); } + catch( std::range_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::range_error: %s", ex.what() ); } + catch( std::overflow_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::overflow_error: %s", ex.what() ); } + catch( std::underflow_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::underflow_error: %s", ex.what() ); } + catch( std::logic_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::logic_error: %s", ex.what() ); } + catch( std::runtime_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::runtime_error: %s", ex.what() ); } + catch( std::exception const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + current_exception_cast(), + "std::exception: %s", ex.what() ); } + + catch( boost::exception const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + &ex, + "unknown boost::exception" ); } + + // system errors + catch( system_error const& ex ) + { detail::report_error( execution_exception::cpp_exception_error, + "system_error produced by: %s: %s", ex.p_failed_exp.get(), std::strerror( ex.p_errno ) ); } + catch( detail::system_signal_exception const& ex ) + { ex.report(); } + + // not an error + catch( execution_aborted const& ) + { return 0; } + + // just forward + catch( execution_exception const& ) + { throw; } + + // unknown error + catch( ... ) + { detail::report_error( execution_exception::cpp_exception_error, "unknown type" ); } + + return 0; // never reached; supplied to quiet compiler warnings +} // execute + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** system_error ************** // +// ************************************************************************** // + +system_error::system_error( char const* exp ) +#ifdef UNDER_CE +: p_errno( GetLastError() ) +#else +: p_errno( errno ) +#endif +, p_failed_exp( exp ) +{} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** execution_exception ************** // +// ************************************************************************** // + +execution_exception::execution_exception( error_code ec_, const_string what_msg_, location const& location_ ) +: m_error_code( ec_ ) +, m_what( what_msg_.empty() ? BOOST_TEST_L( "uncaught exception, system error or abort requested" ) : what_msg_ ) +, m_location( location_ ) +{} + +//____________________________________________________________________________// + +execution_exception::location::location( char const* file_name, size_t line_num, char const* func ) +: m_file_name( file_name ? file_name : "unknown location" ) +, m_line_num( line_num ) +, m_function( func ) +{} + +//____________________________________________________________________________// + +} // namespace boost + +#include + +#endif // BOOST_TEST_EXECUTION_MONITOR_IPP_012205GER + diff --git a/cpp/BoostParts/boost/test/impl/framework.ipp b/cpp/BoostParts/boost/test/impl/framework.ipp new file mode 100644 index 00000000..1fbcffc0 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/framework.ipp @@ -0,0 +1,503 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57991 $ +// +// Description : implements framework API - main driver for the test +// *************************************************************************** + +#ifndef BOOST_TEST_FRAMEWORK_IPP_021005GER +#define BOOST_TEST_FRAMEWORK_IPP_021005GER + +// Boost.Test +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +// Boost +#include + +// STL +#include +#include +#include +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::time; using ::srand; } +#endif + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** test_start calls wrapper ************** // +// ************************************************************************** // + +namespace ut_detail { + +struct test_start_caller { + test_start_caller( test_observer* to, counter_t tc_amount ) + : m_to( to ) + , m_tc_amount( tc_amount ) + {} + + int operator()() + { + m_to->test_start( m_tc_amount ); + return 0; + } + +private: + // Data members + test_observer* m_to; + counter_t m_tc_amount; +}; + +//____________________________________________________________________________// + +struct test_init_caller { + explicit test_init_caller( init_unit_test_func init_func ) + : m_init_func( init_func ) + {} + int operator()() + { +#ifdef BOOST_TEST_ALTERNATIVE_INIT_API + if( !(*m_init_func)() ) + throw std::runtime_error( "test module initialization failed" ); +#else + test_suite* manual_test_units = (*m_init_func)( framework::master_test_suite().argc, framework::master_test_suite().argv ); + + if( manual_test_units ) + framework::master_test_suite().add( manual_test_units ); +#endif + return 0; + } + + // Data members + init_unit_test_func m_init_func; +}; + +} + +// ************************************************************************** // +// ************** framework ************** // +// ************************************************************************** // + +class framework_impl : public test_tree_visitor { +public: + framework_impl() + : m_master_test_suite( 0 ) + , m_curr_test_case( INV_TEST_UNIT_ID ) + , m_next_test_case_id( MIN_TEST_CASE_ID ) + , m_next_test_suite_id( MIN_TEST_SUITE_ID ) + , m_is_initialized( false ) + , m_test_in_progress( false ) + {} + + ~framework_impl() { clear(); } + + void clear() + { + while( !m_test_units.empty() ) { + test_unit_store::value_type const& tu = *m_test_units.begin(); + test_unit* tu_ptr = tu.second; + + // the delete will erase this element from map + if( ut_detail::test_id_2_unit_type( tu.second->p_id ) == tut_suite ) + delete (test_suite const*)tu_ptr; + else + delete (test_case const*)tu_ptr; + } + } + + void set_tu_id( test_unit& tu, test_unit_id id ) { tu.p_id.value = id; } + + // test_tree_visitor interface implementation + void visit( test_case const& tc ) + { + if( !tc.check_dependencies() ) { + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_unit_skipped( tc ); + + return; + } + + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_unit_start( tc ); + + boost::timer tc_timer; + test_unit_id bkup = m_curr_test_case; + m_curr_test_case = tc.p_id; + unit_test_monitor_t::error_level run_result = unit_test_monitor.execute_and_translate( tc ); + + unsigned long elapsed = static_cast( tc_timer.elapsed() * 1e6 ); + + if( unit_test_monitor.is_critical_error( run_result ) ) { + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_aborted(); + } + + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_unit_finish( tc, elapsed ); + + m_curr_test_case = bkup; + + if( unit_test_monitor.is_critical_error( run_result ) ) + throw test_being_aborted(); + } + + bool test_suite_start( test_suite const& ts ) + { + if( !ts.check_dependencies() ) { + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_unit_skipped( ts ); + + return false; + } + + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_unit_start( ts ); + + return true; + } + + void test_suite_finish( test_suite const& ts ) + { + BOOST_TEST_FOREACH( test_observer*, to, m_observers ) + to->test_unit_finish( ts, 0 ); + } + + ////////////////////////////////////////////////////////////////// + struct priority_order { + bool operator()( test_observer* lhs, test_observer* rhs ) const + { + return (lhs->priority() < rhs->priority()) || ((lhs->priority() == rhs->priority()) && (lhs < rhs)); + } + }; + + typedef std::map test_unit_store; + typedef std::set observer_store; + + master_test_suite_t* m_master_test_suite; + test_unit_id m_curr_test_case; + test_unit_store m_test_units; + + test_unit_id m_next_test_case_id; + test_unit_id m_next_test_suite_id; + + bool m_is_initialized; + bool m_test_in_progress; + + observer_store m_observers; +}; + +//____________________________________________________________________________// + +namespace { + +#if defined(__CYGWIN__) +framework_impl& s_frk_impl() { static framework_impl* the_inst = 0; if(!the_inst) the_inst = new framework_impl; return *the_inst; } +#else +framework_impl& s_frk_impl() { static framework_impl the_inst; return the_inst; } +#endif + +} // local namespace + +//____________________________________________________________________________// + +namespace framework { + +void +init( init_unit_test_func init_func, int argc, char* argv[] ) +{ + runtime_config::init( argc, argv ); + + // set the log level and format + unit_test_log.set_threshold_level( runtime_config::log_level() ); + unit_test_log.set_format( runtime_config::log_format() ); + + // set the report level and format + results_reporter::set_level( runtime_config::report_level() ); + results_reporter::set_format( runtime_config::report_format() ); + + register_observer( results_collector ); + register_observer( unit_test_log ); + + if( runtime_config::show_progress() ) + register_observer( progress_monitor ); + + if( runtime_config::detect_memory_leaks() > 0 ) { + debug::detect_memory_leaks( true ); + debug::break_memory_alloc( runtime_config::detect_memory_leaks() ); + } + + // init master unit test suite + master_test_suite().argc = argc; + master_test_suite().argv = argv; + + try { + boost::execution_monitor em; + + ut_detail::test_init_caller tic( init_func ); + + em.execute( tic ); + } + catch( execution_exception const& ex ) { + throw setup_error( ex.what() ); + } + + s_frk_impl().m_is_initialized = true; +} + +//____________________________________________________________________________// + +bool +is_initialized() +{ + return s_frk_impl().m_is_initialized; +} + +//____________________________________________________________________________// + +void +register_test_unit( test_case* tc ) +{ + BOOST_TEST_SETUP_ASSERT( tc->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test case already registered" ) ); + + test_unit_id new_id = s_frk_impl().m_next_test_case_id; + + BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_CASE_ID, BOOST_TEST_L( "too many test cases" ) ); + + typedef framework_impl::test_unit_store::value_type map_value_type; + + s_frk_impl().m_test_units.insert( map_value_type( new_id, tc ) ); + s_frk_impl().m_next_test_case_id++; + + s_frk_impl().set_tu_id( *tc, new_id ); +} + +//____________________________________________________________________________// + +void +register_test_unit( test_suite* ts ) +{ + BOOST_TEST_SETUP_ASSERT( ts->p_id == INV_TEST_UNIT_ID, BOOST_TEST_L( "test suite already registered" ) ); + + test_unit_id new_id = s_frk_impl().m_next_test_suite_id; + + BOOST_TEST_SETUP_ASSERT( new_id != MAX_TEST_SUITE_ID, BOOST_TEST_L( "too many test suites" ) ); + + typedef framework_impl::test_unit_store::value_type map_value_type; + s_frk_impl().m_test_units.insert( map_value_type( new_id, ts ) ); + s_frk_impl().m_next_test_suite_id++; + + s_frk_impl().set_tu_id( *ts, new_id ); +} + +//____________________________________________________________________________// + +void +deregister_test_unit( test_unit* tu ) +{ + s_frk_impl().m_test_units.erase( tu->p_id ); +} + +//____________________________________________________________________________// + +void +clear() +{ + s_frk_impl().clear(); +} + +//____________________________________________________________________________// + +void +register_observer( test_observer& to ) +{ + s_frk_impl().m_observers.insert( &to ); +} + +//____________________________________________________________________________// + +void +deregister_observer( test_observer& to ) +{ + s_frk_impl().m_observers.erase( &to ); +} + +//____________________________________________________________________________// + +void +reset_observers() +{ + s_frk_impl().m_observers.clear(); +} + +//____________________________________________________________________________// + +master_test_suite_t& +master_test_suite() +{ + if( !s_frk_impl().m_master_test_suite ) + s_frk_impl().m_master_test_suite = new master_test_suite_t; + + return *s_frk_impl().m_master_test_suite; +} + +//____________________________________________________________________________// + +test_case const& +current_test_case() +{ + return get( s_frk_impl().m_curr_test_case ); +} + +//____________________________________________________________________________// + +test_unit& +get( test_unit_id id, test_unit_type t ) +{ + test_unit* res = s_frk_impl().m_test_units[id]; + + if( (res->p_type & t) == 0 ) + throw internal_error( "Invalid test unit type" ); + + return *res; +} + +//____________________________________________________________________________// + +void +run( test_unit_id id, bool continue_test ) +{ + if( id == INV_TEST_UNIT_ID ) + id = master_test_suite().p_id; + + test_case_counter tcc; + traverse_test_tree( id, tcc ); + + BOOST_TEST_SETUP_ASSERT( tcc.p_count != 0 , runtime_config::test_to_run().is_empty() + ? BOOST_TEST_L( "test tree is empty" ) + : BOOST_TEST_L( "no test cases matching filter" ) ); + + bool call_start_finish = !continue_test || !s_frk_impl().m_test_in_progress; + bool was_in_progress = s_frk_impl().m_test_in_progress; + + s_frk_impl().m_test_in_progress = true; + + if( call_start_finish ) { + BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) { + boost::execution_monitor em; + + try { + em.execute( ut_detail::test_start_caller( to, tcc.p_count ) ); + } + catch( execution_exception const& ex ) { + throw setup_error( ex.what() ); + } + } + } + + switch( runtime_config::random_seed() ) { + case 0: + break; + case 1: { + unsigned int seed = static_cast( std::time( 0 ) ); + BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << seed ); + std::srand( seed ); + break; + } + default: + BOOST_TEST_MESSAGE( "Test cases order is shuffled using seed: " << runtime_config::random_seed() ); + std::srand( runtime_config::random_seed() ); + } + + try { + traverse_test_tree( id, s_frk_impl() ); + } + catch( test_being_aborted const& ) { + // abort already reported + } + + if( call_start_finish ) { + BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) + to->test_finish(); + } + + s_frk_impl().m_test_in_progress = was_in_progress; +} + +//____________________________________________________________________________// + +void +run( test_unit const* tu, bool continue_test ) +{ + run( tu->p_id, continue_test ); +} + +//____________________________________________________________________________// + +void +assertion_result( bool passed ) +{ + BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) + to->assertion_result( passed ); +} + +//____________________________________________________________________________// + +void +exception_caught( execution_exception const& ex ) +{ + BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) + to->exception_caught( ex ); +} + +//____________________________________________________________________________// + +void +test_unit_aborted( test_unit const& tu ) +{ + BOOST_TEST_FOREACH( test_observer*, to, s_frk_impl().m_observers ) + to->test_unit_aborted( tu ); +} + +//____________________________________________________________________________// + +} // namespace framework + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_FRAMEWORK_IPP_021005GER diff --git a/cpp/BoostParts/boost/test/impl/interaction_based.ipp b/cpp/BoostParts/boost/test/impl/interaction_based.ipp new file mode 100644 index 00000000..56bb8672 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/interaction_based.ipp @@ -0,0 +1,90 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : Facilities to perform interaction-based testing +// *************************************************************************** + +#ifndef BOOST_TEST_INTERACTION_BASED_IPP_112105GER +#define BOOST_TEST_INTERACTION_BASED_IPP_112105GER + +// Boost.Test +#include + +#if BOOST_TEST_SUPPORT_INTERACTION_TESTING + +// Boost.Test +#include +#include +#include +#include +#include // for setup_error + +#include + +// STL +#include +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace itest { // interaction-based testing + +// ************************************************************************** // +// ************** manager ************** // +// ************************************************************************** // + +manager::manager() +{ + instance_ptr( true, this ); +} + +//____________________________________________________________________________// + +manager::~manager() +{ + instance_ptr( true ); +} + +//____________________________________________________________________________// + +manager* +manager::instance_ptr( bool reset, manager* new_ptr ) +{ + static manager dummy( 0 ); + + static manager* ptr = &dummy; + + if( reset ) { + if( new_ptr ) { + BOOST_TEST_SETUP_ASSERT( ptr == &dummy, BOOST_TEST_L( "Can't run two interation based test the same time" ) ); + + ptr = new_ptr; + } + else + ptr = &dummy; + } + + return ptr; +} + +} // namespace itest + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // not ancient compiler + +#endif // BOOST_TEST_INTERACTION_BASED_IPP_112105GER diff --git a/cpp/BoostParts/boost/test/impl/logged_expectations.ipp b/cpp/BoostParts/boost/test/impl/logged_expectations.ipp new file mode 100644 index 00000000..2df790c6 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/logged_expectations.ipp @@ -0,0 +1,246 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, ELOG_VER 1.0. (See accompanying file +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : Facilities to perform interaction based testng of logged expectations +// *************************************************************************** + +#ifndef BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER +#define BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER + +// Boost.Test +#include + +#if BOOST_TEST_SUPPORT_INTERACTION_TESTING + +#include + +#include +#include + +#include +#include + +#include + +// Boost +#include + +// STL +#include + +//____________________________________________________________________________// + +namespace boost { + +using namespace ::boost::unit_test; + +namespace itest { + +// ************************************************************************** // +// ************** logged expectation test implementation ************** // +// ************************************************************************** // + +struct expectations_logger : itest::manager { + // Constructor + expectations_logger( const_string log_file_name, bool test_or_log ); + + virtual bool decision_point( const_string, std::size_t ); + virtual unsigned enter_scope( const_string, std::size_t, const_string scope_name ); + virtual void allocated( const_string, std::size_t, void*, std::size_t s ); + virtual void data_flow( const_string d ); + virtual std::string return_value( const_string default_value ); + +private: + // Data members + bool m_test_or_log; + std::fstream m_log_file; +}; + +literal_string ELOG_VER = "1.0"; +literal_string CLMN_SEP = "|"; +static const char LINE_SEP = '\n'; + +literal_string FILE_SIG = "ELOG"; +literal_string SCOPE_SIG = "SCOPE"; +literal_string ALLOC_SIG = "ALLOC"; +literal_string DP_SIG = "SWITCH"; +literal_string DATA_SIG = "DATA"; +literal_string RETURN_SIG = "RETURN"; + +//____________________________________________________________________________// + +expectations_logger::expectations_logger( const_string log_file_name, bool test_or_log ) +: m_test_or_log( test_or_log ) +{ + BOOST_REQUIRE_MESSAGE( !log_file_name.is_empty(), "Empty expectations log file name" ); + + m_log_file.open( log_file_name.begin(), test_or_log ? std::ios::in : std::ios::out ); + + BOOST_REQUIRE_MESSAGE( m_log_file.is_open(), + "Can't open expectations log file " << log_file_name + << " for " << ( m_test_or_log ? "reading" : "writing") ); + + if( m_test_or_log ) { + std::string line; + + std::getline( m_log_file, line, LINE_SEP ); + + const_string cline( line ); + string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); + + BOOST_CHECK_EQUAL( *tit, FILE_SIG ); + ++tit; + BOOST_CHECK_EQUAL( *tit, ELOG_VER ); + } + else { + m_log_file << FILE_SIG << CLMN_SEP << ELOG_VER << LINE_SEP; + } +} + +//____________________________________________________________________________// + +bool +expectations_logger::decision_point( const_string, std::size_t ) +{ + if( m_test_or_log ) { + std::string line; + + std::getline( m_log_file, line, LINE_SEP ); + + const_string cline( line ); + string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); + + BOOST_CHECK_EQUAL( *tit, DP_SIG ); ++tit; + return lexical_cast( *tit ); + } + else { + m_log_file << DP_SIG << CLMN_SEP << std::boolalpha << true << LINE_SEP; + + return true; + } +} + +//____________________________________________________________________________// + +unsigned +expectations_logger::enter_scope( const_string, std::size_t, const_string scope_name ) +{ + if( m_test_or_log ) { + std::string line; + + std::getline( m_log_file, line, LINE_SEP ); + + const_string cline( line ); + string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); + + BOOST_CHECK_EQUAL( *tit, SCOPE_SIG ); ++tit; + BOOST_CHECK_EQUAL( *tit, scope_name ); + } + else { + m_log_file << SCOPE_SIG << CLMN_SEP << scope_name << LINE_SEP; + } + + return 0; +} + +//____________________________________________________________________________// + +void +expectations_logger::allocated( const_string, std::size_t, void*, std::size_t s ) +{ + if( m_test_or_log ) { + std::string line; + + std::getline( m_log_file, line, LINE_SEP ); + + const_string cline( line ); + string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); + + BOOST_CHECK_EQUAL( *tit, ALLOC_SIG ); ++tit; + BOOST_CHECK_EQUAL( lexical_cast( *tit ), s ); + } + else { + m_log_file << ALLOC_SIG << CLMN_SEP << s << LINE_SEP; + } +} + +//____________________________________________________________________________// + +void +expectations_logger::data_flow( const_string d ) +{ + if( m_test_or_log ) { + std::string line; + + std::getline( m_log_file, line, LINE_SEP ); + + const_string cline( line ); + string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); + + BOOST_CHECK_EQUAL( *tit, DATA_SIG ); ++tit; + BOOST_CHECK_EQUAL( *tit, d ); + } + else { + m_log_file << DATA_SIG << CLMN_SEP << d << LINE_SEP; + } +} + +//____________________________________________________________________________// + +std::string +expectations_logger::return_value( const_string default_value ) +{ + if( m_test_or_log ) { + std::string line; + + std::getline( m_log_file, line, LINE_SEP ); + + const_string cline( line ); + string_token_iterator tit( cline, (dropped_delimeters = CLMN_SEP, kept_delimeters = dt_none)); + + BOOST_CHECK_EQUAL( *tit, RETURN_SIG ); ++tit; + + return std::string( tit->begin(), tit->size() ); + } + else { + m_log_file << RETURN_SIG << CLMN_SEP << default_value << LINE_SEP; + + return std::string(); + } +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** logged expectations test ************** // +// ************************************************************************** // + +void BOOST_TEST_DECL +logged_expectations( callback0<> const& F, const_string log_file_name, bool test_or_log ) +{ + expectations_logger el( log_file_name, test_or_log ); + + F(); +} + +//____________________________________________________________________________// + +} // namespace itest + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // not ancient compiler + +#endif // BOOST_TEST_LOGGED_EXPECTATIONS_IPP_120905GER diff --git a/cpp/BoostParts/boost/test/impl/plain_report_formatter.ipp b/cpp/BoostParts/boost/test/impl/plain_report_formatter.ipp new file mode 100644 index 00000000..d901b8ea --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/plain_report_formatter.ipp @@ -0,0 +1,198 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : plain report formatter definition +// *************************************************************************** + +#ifndef BOOST_TEST_PLAIN_REPORT_FORMATTER_IPP_020105GER +#define BOOST_TEST_PLAIN_REPORT_FORMATTER_IPP_020105GER + +// Boost.Test +#include +#include +#include +#include + +#include + +// STL +#include +#include +#include + +#include + +# ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::log10; } +# endif + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace output { + +namespace { + +typedef custom_manip quote; + +template +inline std::ostream& +operator<<( custom_printer const& p, T const& value ) +{ + *p << '"' << value << '"'; + + return *p; +} + +//____________________________________________________________________________// + +void +print_stat_value( std::ostream& ostr, counter_t v, counter_t indent, counter_t total, + const_string name, const_string res ) +{ + if( v > 0 ) { + ostr << std::setw( indent ) << "" + << v << ' ' << name << ( v != 1 ? "s" : "" ); + if( total > 0 ) + ostr << " out of " << total; + + ostr << ' ' << res << '\n'; + } +} + +//____________________________________________________________________________// + +} // local namespace + +// ************************************************************************** // +// ************** plain_report_formatter ************** // +// ************************************************************************** // + +void +plain_report_formatter::results_report_start( std::ostream& ostr ) +{ + m_indent = 0; + ostr << '\n'; +} + +//____________________________________________________________________________// + +void +plain_report_formatter::results_report_finish( std::ostream& ostr ) +{ + ostr.flush(); +} + +//____________________________________________________________________________// + +void +plain_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream& ostr ) +{ + test_results const& tr = results_collector.results( tu.p_id ); + + const_string descr; + + if( tr.passed() ) + descr = "passed"; + else if( tr.p_skipped ) + descr = "skipped"; + else if( tr.p_aborted ) + descr = "aborted"; + else + descr = "failed"; + + ostr << std::setw( m_indent ) << "" + << "Test " << (tu.p_type == tut_case ? "case " : "suite " ) << quote() << tu.p_name << ' ' << descr; + + if( tr.p_skipped ) { + ostr << " due to " << (tu.check_dependencies() ? "test aborting\n" : "failed dependancy\n" ); + m_indent += 2; + return; + } + + counter_t total_assertions = tr.p_assertions_passed + tr.p_assertions_failed; + counter_t total_tc = tr.p_test_cases_passed + tr.p_test_cases_failed + tr.p_test_cases_skipped; + + if( total_assertions > 0 || total_tc > 0 ) + ostr << " with:"; + + ostr << '\n'; + m_indent += 2; + + print_stat_value( ostr, tr.p_assertions_passed, m_indent, total_assertions, "assertion", "passed" ); + print_stat_value( ostr, tr.p_assertions_failed, m_indent, total_assertions, "assertion", "failed" ); + print_stat_value( ostr, tr.p_expected_failures, m_indent, 0 , "failure" , "expected" ); + print_stat_value( ostr, tr.p_test_cases_passed, m_indent, total_tc , "test case", "passed" ); + print_stat_value( ostr, tr.p_test_cases_failed, m_indent, total_tc , "test case", "failed" ); + print_stat_value( ostr, tr.p_test_cases_skipped, m_indent, total_tc , "test case", "skipped" ); + print_stat_value( ostr, tr.p_test_cases_aborted, m_indent, total_tc , "test case", "aborted" ); + + ostr << '\n'; +} + +//____________________________________________________________________________// + +void +plain_report_formatter::test_unit_report_finish( test_unit const&, std::ostream& ) +{ + m_indent -= 2; +} + +//____________________________________________________________________________// + +void +plain_report_formatter::do_confirmation_report( test_unit const& tu, std::ostream& ostr ) +{ + test_results const& tr = results_collector.results( tu.p_id ); + + if( tr.passed() ) { + ostr << "*** No errors detected\n"; + return; + } + + if( tr.p_skipped ) { + ostr << "*** Test " << tu.p_type_name << " skipped due to " + << (tu.check_dependencies() ? "test aborting\n" : "failed dependancy\n" ); + return; + } + + if( tr.p_assertions_failed == 0 ) { + ostr << "*** errors detected in test " << tu.p_type_name << " " << quote() << tu.p_name + << "; see standard output for details\n"; + return; + } + + counter_t num_failures = tr.p_assertions_failed; + + ostr << "*** " << num_failures << " failure" << ( num_failures != 1 ? "s" : "" ) << " detected"; + + if( tr.p_expected_failures > 0 ) + ostr << " (" << tr.p_expected_failures << " failure" << ( tr.p_expected_failures != 1 ? "s" : "" ) << " expected)"; + + ostr << " in test " << tu.p_type_name << " " << quote() << tu.p_name << "\n"; +} + +//____________________________________________________________________________// + +} // namespace output + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_PLAIN_REPORT_FORMATTER_IPP_020105GER diff --git a/cpp/BoostParts/boost/test/impl/progress_monitor.ipp b/cpp/BoostParts/boost/test/impl/progress_monitor.ipp new file mode 100644 index 00000000..d245aa61 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/progress_monitor.ipp @@ -0,0 +1,110 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : implements simple text based progress monitor +// *************************************************************************** + +#ifndef BOOST_TEST_PROGRESS_MONITOR_IPP_020105GER +#define BOOST_TEST_PROGRESS_MONITOR_IPP_020105GER + +// Boost.Test +#include +#include + +#include + +// Boost +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** progress_monitor ************** // +// ************************************************************************** // + +namespace { + +struct progress_monitor_impl { + // Constructor + progress_monitor_impl() + : m_stream( runtime_config::log_sink() ) + {} + + std::ostream* m_stream; + scoped_ptr m_progress_display; +}; + +progress_monitor_impl& s_pm_impl() { static progress_monitor_impl the_inst; return the_inst; } + +} // local namespace + +//____________________________________________________________________________// + +void +progress_monitor_t::test_start( counter_t test_cases_amount ) +{ + s_pm_impl().m_progress_display.reset( new progress_display( test_cases_amount, *s_pm_impl().m_stream ) ); +} + +//____________________________________________________________________________// + +void +progress_monitor_t::test_aborted() +{ + (*s_pm_impl().m_progress_display) += s_pm_impl().m_progress_display->count(); +} + +//____________________________________________________________________________// + +void +progress_monitor_t::test_unit_finish( test_unit const& tu, unsigned long ) +{ + if( tu.p_type == tut_case ) + ++(*s_pm_impl().m_progress_display); +} + +//____________________________________________________________________________// + +void +progress_monitor_t::test_unit_skipped( test_unit const& tu ) +{ + test_case_counter tcc; + traverse_test_tree( tu, tcc ); + + (*s_pm_impl().m_progress_display) += tcc.p_count; +} + +//____________________________________________________________________________// + +void +progress_monitor_t::set_stream( std::ostream& ostr ) +{ + s_pm_impl().m_stream = &ostr; +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_PROGRESS_MONITOR_IPP_020105GER diff --git a/cpp/BoostParts/boost/test/impl/results_collector.ipp b/cpp/BoostParts/boost/test/impl/results_collector.ipp new file mode 100644 index 00000000..e85528ba --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/results_collector.ipp @@ -0,0 +1,294 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : implements Unit Test results collecting facility. +// *************************************************************************** + +#ifndef BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER +#define BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER + +// Boost.Test +#include +#include +#include +#include + +// Boost +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** test_results ************** // +// ************************************************************************** // + +test_results::test_results() +{ + clear(); +} + +//____________________________________________________________________________// + +bool +test_results::passed() const +{ + return !p_skipped && + p_test_cases_failed == 0 && + p_assertions_failed <= p_expected_failures && + !p_aborted; +} + +//____________________________________________________________________________// + +int +test_results::result_code() const +{ + return passed() ? exit_success + : ( (p_assertions_failed > p_expected_failures || p_skipped ) + ? exit_test_failure + : exit_exception_failure ); +} + +//____________________________________________________________________________// + +void +test_results::operator+=( test_results const& tr ) +{ + p_assertions_passed.value += tr.p_assertions_passed; + p_assertions_failed.value += tr.p_assertions_failed; + p_test_cases_passed.value += tr.p_test_cases_passed; + p_test_cases_failed.value += tr.p_test_cases_failed; + p_test_cases_skipped.value += tr.p_test_cases_skipped; + p_test_cases_aborted.value += tr.p_test_cases_aborted; +} + +//____________________________________________________________________________// + +void +test_results::clear() +{ + p_assertions_passed.value = 0; + p_assertions_failed.value = 0; + p_expected_failures.value = 0; + p_test_cases_passed.value = 0; + p_test_cases_failed.value = 0; + p_test_cases_skipped.value = 0; + p_test_cases_aborted.value = 0; + p_aborted.value = false; + p_skipped.value = true; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** results_collector ************** // +// ************************************************************************** // + +#if !BOOST_WORKAROUND(BOOST_MSVC, <1300) + +namespace { + +struct results_collector_impl { + std::map m_results_store; +}; + +results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; return the_inst; } + +} // local namespace + +#else + +struct results_collector_impl { + std::map m_results_store; +}; + +static results_collector_impl& s_rc_impl() { static results_collector_impl the_inst; return the_inst; } + +#endif + +//____________________________________________________________________________// + +void +results_collector_t::test_start( counter_t ) +{ + s_rc_impl().m_results_store.clear(); +} + +//____________________________________________________________________________// + +void +results_collector_t::test_finish() +{ + // do nothing +} + +//____________________________________________________________________________// + +void +results_collector_t::test_aborted() +{ + // do nothing +} + +//____________________________________________________________________________// + +void +results_collector_t::test_unit_start( test_unit const& tu ) +{ + // init test_results entry + test_results& tr = s_rc_impl().m_results_store[tu.p_id]; + + tr.clear(); + + tr.p_expected_failures.value = tu.p_expected_failures; + tr.p_skipped.value = false; +} + +//____________________________________________________________________________// + +class results_collect_helper : public test_tree_visitor { +public: + explicit results_collect_helper( test_results& tr, test_unit const& ts ) : m_tr( tr ), m_ts( ts ) {} + + void visit( test_case const& tc ) + { + test_results const& tr = results_collector.results( tc.p_id ); + m_tr += tr; + + if( tr.passed() ) + m_tr.p_test_cases_passed.value++; + else if( tr.p_skipped ) + m_tr.p_test_cases_skipped.value++; + else { + if( tr.p_aborted ) + m_tr.p_test_cases_aborted.value++; + m_tr.p_test_cases_failed.value++; + } + } + bool test_suite_start( test_suite const& ts ) + { + if( m_ts.p_id == ts.p_id ) + return true; + else { + m_tr += results_collector.results( ts.p_id ); + return false; + } + } + +private: + // Data members + test_results& m_tr; + test_unit const& m_ts; +}; + +//____________________________________________________________________________// + +void +results_collector_t::test_unit_finish( test_unit const& tu, unsigned long ) +{ + if( tu.p_type == tut_suite ) { + results_collect_helper ch( s_rc_impl().m_results_store[tu.p_id], tu ); + + traverse_test_tree( tu, ch ); + } + else { + test_results const& tr = s_rc_impl().m_results_store[tu.p_id]; + + bool num_failures_match = tr.p_aborted || tr.p_assertions_failed >= tr.p_expected_failures; + if( !num_failures_match ) + BOOST_TEST_MESSAGE( "Test case " << tu.p_name << " has fewer failures than expected" ); + + bool check_any_assertions = tr.p_aborted || (tr.p_assertions_failed != 0) || (tr.p_assertions_passed != 0); + if( !check_any_assertions ) + BOOST_TEST_MESSAGE( "Test case " << tu.p_name << " did not check any assertions" ); + } +} + +//____________________________________________________________________________// + +void +results_collector_t::test_unit_skipped( test_unit const& tu ) +{ + if( tu.p_type == tut_suite ) { + test_case_counter tcc; + traverse_test_tree( tu, tcc ); + + test_results& tr = s_rc_impl().m_results_store[tu.p_id]; + + tr.clear(); + + tr.p_skipped.value = true; + tr.p_test_cases_skipped.value = tcc.p_count; + } +} + +//____________________________________________________________________________// + +void +results_collector_t::assertion_result( bool passed ) +{ + test_results& tr = s_rc_impl().m_results_store[framework::current_test_case().p_id]; + + if( passed ) + tr.p_assertions_passed.value++; + else + tr.p_assertions_failed.value++; + + if( tr.p_assertions_failed == 1 ) + first_failed_assertion(); +} + +//____________________________________________________________________________// + +void +results_collector_t::exception_caught( execution_exception const& ) +{ + test_results& tr = s_rc_impl().m_results_store[framework::current_test_case().p_id]; + + tr.p_assertions_failed.value++; +} + +//____________________________________________________________________________// + +void +results_collector_t::test_unit_aborted( test_unit const& tu ) +{ + s_rc_impl().m_results_store[tu.p_id].p_aborted.value = true; +} + +//____________________________________________________________________________// + +test_results const& +results_collector_t::results( test_unit_id id ) const +{ + return s_rc_impl().m_results_store[id]; +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_RESULTS_COLLECTOR_IPP_021105GER diff --git a/cpp/BoostParts/boost/test/impl/results_reporter.ipp b/cpp/BoostParts/boost/test/impl/results_reporter.ipp new file mode 100644 index 00000000..71a0f66f --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/results_reporter.ipp @@ -0,0 +1,202 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : result reporting facilties +// *************************************************************************** + +#ifndef BOOST_TEST_RESULTS_REPORTER_IPP_020105GER +#define BOOST_TEST_RESULTS_REPORTER_IPP_020105GER + +// Boost.Test +#include +#include +#include +#include +#include +#include + +#include + +// Boost +#include +#include +typedef ::boost::io::ios_base_all_saver io_saver_type; + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace results_reporter { + +// ************************************************************************** // +// ************** result reporter implementation ************** // +// ************************************************************************** // + +namespace { + +struct results_reporter_impl : test_tree_visitor { + // Constructor + results_reporter_impl() + : m_output( runtime_config::report_sink() ) + , m_stream_state_saver( new io_saver_type( *m_output ) ) + , m_report_level( CONFIRMATION_REPORT ) + , m_formatter( new output::plain_report_formatter ) + {} + + // test tree visitor interface implementation + void visit( test_case const& tc ) + { + m_formatter->test_unit_report_start( tc, *m_output ); + m_formatter->test_unit_report_finish( tc, *m_output ); + } + bool test_suite_start( test_suite const& ts ) + { + m_formatter->test_unit_report_start( ts, *m_output ); + + if( m_report_level == DETAILED_REPORT && !results_collector.results( ts.p_id ).p_skipped ) + return true; + + m_formatter->test_unit_report_finish( ts, *m_output ); + return false; + } + void test_suite_finish( test_suite const& ts ) + { + m_formatter->test_unit_report_finish( ts, *m_output ); + } + + typedef scoped_ptr saver_ptr; + + // Data members + std::ostream* m_output; + saver_ptr m_stream_state_saver; + report_level m_report_level; + scoped_ptr m_formatter; +}; + +results_reporter_impl& s_rr_impl() { static results_reporter_impl the_inst; return the_inst; } + +} // local namespace + +// ************************************************************************** // +// ************** report configuration ************** // +// ************************************************************************** // + +void +set_level( report_level l ) +{ + if( l != INV_REPORT_LEVEL ) + s_rr_impl().m_report_level = l; +} + +//____________________________________________________________________________// + +void +set_stream( std::ostream& ostr ) +{ + s_rr_impl().m_output = &ostr; + s_rr_impl().m_stream_state_saver.reset( new io_saver_type( ostr ) ); +} + +//____________________________________________________________________________// + +std::ostream& +get_stream() +{ + return *s_rr_impl().m_output; +} + +//____________________________________________________________________________// + +void +set_format( output_format rf ) +{ + switch( rf ) { + case CLF: + set_format( new output::plain_report_formatter ); + break; + case XML: + set_format( new output::xml_report_formatter ); + break; + default: + break; + } +} + +//____________________________________________________________________________// + +void +set_format( results_reporter::format* f ) +{ + if( f ) + s_rr_impl().m_formatter.reset( f ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** report initiation ************** // +// ************************************************************************** // + +void +make_report( report_level l, test_unit_id id ) +{ + if( l == INV_REPORT_LEVEL ) + l = s_rr_impl().m_report_level; + + if( l == NO_REPORT ) + return; + + if( id == INV_TEST_UNIT_ID ) + id = framework::master_test_suite().p_id; + + s_rr_impl().m_stream_state_saver->restore(); + + report_level bkup = s_rr_impl().m_report_level; + s_rr_impl().m_report_level = l; + + s_rr_impl().m_formatter->results_report_start( *s_rr_impl().m_output ); + + switch( l ) { + case CONFIRMATION_REPORT: + s_rr_impl().m_formatter->do_confirmation_report( framework::get( id ), *s_rr_impl().m_output ); + break; + case SHORT_REPORT: + case DETAILED_REPORT: + traverse_test_tree( id, s_rr_impl() ); + break; + default: + break; + } + + s_rr_impl().m_formatter->results_report_finish( *s_rr_impl().m_output ); + s_rr_impl().m_report_level = bkup; +} + +//____________________________________________________________________________// + +} // namespace results_reporter + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_RESULTS_REPORTER_IPP_020105GER diff --git a/cpp/BoostParts/boost/test/impl/test_main.ipp b/cpp/BoostParts/boost/test/impl/test_main.ipp new file mode 100644 index 00000000..6c41ceea --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/test_main.ipp @@ -0,0 +1,68 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// (C) Copyright Beman Dawes 1995-2001. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $$Revision: 49312 $ +// +// Description : implements main function for Test Execution Monitor. +// *************************************************************************** + +#ifndef BOOST_TEST_TEST_MAIN_IPP_012205GER +#define BOOST_TEST_TEST_MAIN_IPP_012205GER + +// Boost.Test +#include +#include +#include + +// Boost +#include + +#include + +//____________________________________________________________________________// + +extern int test_main( int argc, char* argv[] ); // prototype for user's test_main() + +struct test_main_caller { + test_main_caller( int argc, char** argv ) : m_argc( argc ), m_argv( argv ) {} + + void operator()() { + int test_main_result = test_main( m_argc, m_argv ); + + // translate a test_main non-success return into a test error + BOOST_CHECK( test_main_result == 0 || test_main_result == boost::exit_success ); + } + +private: + // Data members + int m_argc; + char** m_argv; +}; + +// ************************************************************************** // +// ************** test main ************** // +// ************************************************************************** // + +::boost::unit_test::test_suite* +init_unit_test_suite( int argc, char* argv[] ) { + using namespace ::boost::unit_test; + + framework::master_test_suite().p_name.value = "Test Program"; + + framework::master_test_suite().add( BOOST_TEST_CASE( test_main_caller( argc, argv ) ) ); + + return 0; +} + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_TEST_MAIN_IPP_012205GER diff --git a/cpp/BoostParts/boost/test/impl/test_tools.ipp b/cpp/BoostParts/boost/test/impl/test_tools.ipp new file mode 100644 index 00000000..67fb25dc --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/test_tools.ipp @@ -0,0 +1,628 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : supplies offline implementation for the Test Tools +// *************************************************************************** + +#ifndef BOOST_TEST_TEST_TOOLS_IPP_012205GER +#define BOOST_TEST_TEST_TOOLS_IPP_012205GER + +// Boost.Test +#include +#include +#include +#include +#include // execution_aborted +#include + +// Boost +#include + +// STL +#include +#include +#include +#include +#include +#include +#include + +// !! should we use #include +#include + +#include + +//____________________________________________________________________________// + +# ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::strcmp; using ::strlen; using ::isprint; } +#if !defined( BOOST_NO_CWCHAR ) +namespace std { using ::wcscmp; } +#endif +# endif + +namespace boost { + +namespace test_tools { + +// ************************************************************************** // +// ************** print_log_value ************** // +// ************************************************************************** // + +void +print_log_value::operator()( std::ostream& ostr, char t ) +{ + if( (std::isprint)( static_cast(t) ) ) + ostr << '\'' << t << '\''; + else + ostr << std::hex +#if BOOST_TEST_USE_STD_LOCALE + << std::showbase +#else + << "0x" +#endif + << static_cast(t); +} + +//____________________________________________________________________________// + +void +print_log_value::operator()( std::ostream& ostr, unsigned char t ) +{ + ostr << std::hex + // showbase is only available for new style streams: +#if BOOST_TEST_USE_STD_LOCALE + << std::showbase +#else + << "0x" +#endif + << static_cast(t); +} + +//____________________________________________________________________________// + +void +print_log_value::operator()( std::ostream& ostr, char const* t ) +{ + ostr << ( t ? t : "null string" ); +} + +//____________________________________________________________________________// + +void +print_log_value::operator()( std::ostream& ostr, wchar_t const* t ) +{ + ostr << ( t ? t : L"null string" ); +} + +//____________________________________________________________________________// + +namespace tt_detail { + +// ************************************************************************** // +// ************** TOOL BOX Implementation ************** // +// ************************************************************************** // + +using ::boost::unit_test::lazy_ostream; + +bool +check_impl( predicate_result const& pr, lazy_ostream const& check_descr, + const_string file_name, std::size_t line_num, + tool_level tl, check_type ct, + std::size_t num_of_args, ... ) +{ + using namespace unit_test; + + if( !framework::is_initialized() ) + throw std::runtime_error( "can't use testing tools before framework is initialized" ); + + if( !!pr ) + tl = PASS; + + log_level ll; + char const* prefix; + char const* suffix; + + switch( tl ) { + case PASS: + ll = log_successful_tests; + prefix = "check "; + suffix = " passed"; + break; + case WARN: + ll = log_warnings; + prefix = "condition "; + suffix = " is not satisfied"; + break; + case CHECK: + ll = log_all_errors; + prefix = "check "; + suffix = " failed"; + break; + case REQUIRE: + ll = log_fatal_errors; + prefix = "critical check "; + suffix = " failed"; + break; + default: + return true; + } + + switch( ct ) { + case CHECK_PRED: + unit_test_log << unit_test::log::begin( file_name, line_num ) + << ll << prefix << check_descr << suffix; + + if( !pr.has_empty_message() ) + unit_test_log << ". " << pr.message(); + + unit_test_log << unit_test::log::end(); + break; + + case CHECK_MSG: + unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; + + if( tl == PASS ) + unit_test_log << prefix << "'" << check_descr << "'" << suffix; + else + unit_test_log << check_descr; + + if( !pr.has_empty_message() ) + unit_test_log << ". " << pr.message(); + + unit_test_log << unit_test::log::end(); + break; + + case CHECK_EQUAL: + case CHECK_NE: + case CHECK_LT: + case CHECK_LE: + case CHECK_GT: + case CHECK_GE: { + static char const* check_str [] = { " == ", " != ", " < " , " <= ", " > " , " >= " }; + static char const* rever_str [] = { " != ", " == ", " >= ", " > " , " <= ", " < " }; + + va_list args; + + va_start( args, num_of_args ); + char const* arg1_descr = va_arg( args, char const* ); + lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); + char const* arg2_descr = va_arg( args, char const* ); + lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* ); + + unit_test_log << unit_test::log::begin( file_name, line_num ) + << ll << prefix << arg1_descr << check_str[ct-CHECK_EQUAL] << arg2_descr << suffix; + + if( tl != PASS ) + unit_test_log << " [" << *arg1_val << rever_str[ct-CHECK_EQUAL] << *arg2_val << "]" ; + + va_end( args ); + + if( !pr.has_empty_message() ) + unit_test_log << ". " << pr.message(); + + unit_test_log << unit_test::log::end(); + break; + } + + case CHECK_CLOSE: + case CHECK_CLOSE_FRACTION: { + va_list args; + + va_start( args, num_of_args ); + char const* arg1_descr = va_arg( args, char const* ); + lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); + char const* arg2_descr = va_arg( args, char const* ); + lazy_ostream const* arg2_val = va_arg( args, lazy_ostream const* ); + /* toler_descr = */ va_arg( args, char const* ); + lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* ); + + unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; + + unit_test_log << "difference{" << pr.message() << (ct == CHECK_CLOSE ? "%" : "") + << "} between " << arg1_descr << "{" << *arg1_val + << "} and " << arg2_descr << "{" << *arg2_val + << ( tl == PASS ? "} doesn't exceed " : "} exceeds " ) + << *toler_val; + if( ct == CHECK_CLOSE ) + unit_test_log << "%"; + + va_end( args ); + + unit_test_log << unit_test::log::end(); + break; + } + case CHECK_SMALL: { + va_list args; + + va_start( args, num_of_args ); + char const* arg1_descr = va_arg( args, char const* ); + lazy_ostream const* arg1_val = va_arg( args, lazy_ostream const* ); + /* toler_descr = */ va_arg( args, char const* ); + lazy_ostream const* toler_val = va_arg( args, lazy_ostream const* ); + + unit_test_log << unit_test::log::begin( file_name, line_num ) << ll; + + unit_test_log << "absolute value of " << arg1_descr << "{" << *arg1_val << "}" + << ( tl == PASS ? " doesn't exceed " : " exceeds " ) + << *toler_val; + + va_end( args ); + + if( !pr.has_empty_message() ) + unit_test_log << ". " << pr.message(); + + unit_test_log << unit_test::log::end(); + break; + } + + case CHECK_PRED_WITH_ARGS: { + unit_test_log << unit_test::log::begin( file_name, line_num ) + << ll << prefix << check_descr; + + // print predicate call description + { + va_list args; + va_start( args, num_of_args ); + + unit_test_log << "( "; + for( std::size_t i = 0; i < num_of_args; ++i ) { + unit_test_log << va_arg( args, char const* ); + va_arg( args, lazy_ostream const* ); // skip argument value; + + if( i != num_of_args-1 ) + unit_test_log << ", "; + } + unit_test_log << " )" << suffix; + va_end( args ); + } + + if( tl != PASS ) { + va_list args; + va_start( args, num_of_args ); + + unit_test_log << " for ( "; + for( std::size_t i = 0; i < num_of_args; ++i ) { + va_arg( args, char const* ); // skip argument description; + unit_test_log << *va_arg( args, lazy_ostream const* ); + + if( i != num_of_args-1 ) + unit_test_log << ", "; + } + unit_test_log << " )"; + va_end( args ); + } + + if( !pr.has_empty_message() ) + unit_test_log << ". " << pr.message(); + + unit_test_log << unit_test::log::end(); + break; + } + + case CHECK_EQUAL_COLL: { + va_list args; + + va_start( args, num_of_args ); + char const* left_begin_descr = va_arg( args, char const* ); + char const* left_end_descr = va_arg( args, char const* ); + char const* right_begin_descr = va_arg( args, char const* ); + char const* right_end_descr = va_arg( args, char const* ); + + unit_test_log << unit_test::log::begin( file_name, line_num ) + << ll << prefix + << "{ " << left_begin_descr << ", " << left_end_descr << " } == { " + << right_begin_descr << ", " << right_end_descr << " }" + << suffix; + + va_end( args ); + + if( !pr.has_empty_message() ) + unit_test_log << ". " << pr.message(); + + unit_test_log << unit_test::log::end(); + break; + } + + case CHECK_BITWISE_EQUAL: { + va_list args; + + va_start( args, num_of_args ); + char const* left_descr = va_arg( args, char const* ); + char const* right_descr = va_arg( args, char const* ); + + unit_test_log << unit_test::log::begin( file_name, line_num ) + << ll << prefix << left_descr << " =.= " << right_descr << suffix; + + va_end( args ); + + if( !pr.has_empty_message() ) + unit_test_log << ". " << pr.message(); + + unit_test_log << unit_test::log::end(); + break; + } + } + + switch( tl ) { + case PASS: + framework::assertion_result( true ); + return true; + + case WARN: + return false; + + case CHECK: + framework::assertion_result( false ); + return false; + + case REQUIRE: + framework::assertion_result( false ); + + framework::test_unit_aborted( framework::current_test_case() ); + + throw execution_aborted(); + } + + return true; +} + +//____________________________________________________________________________// + +predicate_result +equal_impl( char const* left, char const* right ) +{ + return (left && right) ? std::strcmp( left, right ) == 0 : (left == right); +} + +//____________________________________________________________________________// + +#if !defined( BOOST_NO_CWCHAR ) + +predicate_result +equal_impl( wchar_t const* left, wchar_t const* right ) +{ + return (left && right) ? std::wcscmp( left, right ) == 0 : (left == right); +} + +#endif // !defined( BOOST_NO_CWCHAR ) + +//____________________________________________________________________________// + +bool +is_defined_impl( const_string symbol_name, const_string symbol_value ) +{ + symbol_value.trim_left( 2 ); + return symbol_name != symbol_value; +} + +//____________________________________________________________________________// + +} // namespace tt_detail + +// ************************************************************************** // +// ************** output_test_stream ************** // +// ************************************************************************** // + +struct output_test_stream::Impl +{ + std::fstream m_pattern; + bool m_match_or_save; + bool m_text_or_binary; + std::string m_synced_string; + + char get_char() + { + char res; + do { + m_pattern.get( res ); + } while( m_text_or_binary && res == '\r' && !m_pattern.fail() && !m_pattern.eof() ); + + return res; + } + + void check_and_fill( predicate_result& res ) + { + if( !res.p_predicate_value ) + res.message() << "Output content: \"" << m_synced_string << '\"'; + } +}; + +//____________________________________________________________________________// + +output_test_stream::output_test_stream( const_string pattern_file_name, bool match_or_save, bool text_or_binary ) +: m_pimpl( new Impl ) +{ + if( !pattern_file_name.is_empty() ) { + std::ios::openmode m = match_or_save ? std::ios::in : std::ios::out; + if( !text_or_binary ) + m |= std::ios::binary; + + m_pimpl->m_pattern.open( pattern_file_name.begin(), m ); + + BOOST_WARN_MESSAGE( m_pimpl->m_pattern.is_open(), + "Can't open pattern file " << pattern_file_name + << " for " << (match_or_save ? "reading" : "writing") ); + } + + m_pimpl->m_match_or_save = match_or_save; + m_pimpl->m_text_or_binary = text_or_binary; +} + +//____________________________________________________________________________// + +output_test_stream::~output_test_stream() +{ + delete m_pimpl; +} + +//____________________________________________________________________________// + +predicate_result +output_test_stream::is_empty( bool flush_stream ) +{ + sync(); + + result_type res( m_pimpl->m_synced_string.empty() ); + + m_pimpl->check_and_fill( res ); + + if( flush_stream ) + flush(); + + return res; +} + +//____________________________________________________________________________// + +predicate_result +output_test_stream::check_length( std::size_t length_, bool flush_stream ) +{ + sync(); + + result_type res( m_pimpl->m_synced_string.length() == length_ ); + + m_pimpl->check_and_fill( res ); + + if( flush_stream ) + flush(); + + return res; +} + +//____________________________________________________________________________// + +predicate_result +output_test_stream::is_equal( const_string arg, bool flush_stream ) +{ + sync(); + + result_type res( const_string( m_pimpl->m_synced_string ) == arg ); + + m_pimpl->check_and_fill( res ); + + if( flush_stream ) + flush(); + + return res; +} + +//____________________________________________________________________________// + +predicate_result +output_test_stream::match_pattern( bool flush_stream ) +{ + sync(); + + result_type result( true ); + + if( !m_pimpl->m_pattern.is_open() ) { + result = false; + result.message() << "Pattern file can't be opened!"; + } + else { + if( m_pimpl->m_match_or_save ) { + for ( std::string::size_type i = 0; i < m_pimpl->m_synced_string.length(); ++i ) { + char c = m_pimpl->get_char(); + + result = !m_pimpl->m_pattern.fail() && + !m_pimpl->m_pattern.eof() && + (m_pimpl->m_synced_string[i] == c); + + if( !result ) { + std::string::size_type suffix_size = (std::min)( m_pimpl->m_synced_string.length() - i, + static_cast(5) ); + + // try to log area around the mismatch + result.message() << "Mismatch at position " << i << '\n' + << "..." << m_pimpl->m_synced_string.substr( i, suffix_size ) << "..." << '\n' + << "..." << c; + + std::string::size_type counter = suffix_size; + while( --counter ) { + char c = m_pimpl->get_char(); + + if( m_pimpl->m_pattern.fail() || m_pimpl->m_pattern.eof() ) + break; + + result.message() << c; + } + + result.message() << "..."; + + // skip rest of the bytes. May help for further matching + m_pimpl->m_pattern.ignore( + static_cast( m_pimpl->m_synced_string.length() - i - suffix_size) ); + break; + } + } + } + else { + m_pimpl->m_pattern.write( m_pimpl->m_synced_string.c_str(), + static_cast( m_pimpl->m_synced_string.length() ) ); + m_pimpl->m_pattern.flush(); + } + } + + if( flush_stream ) + flush(); + + return result; +} + +//____________________________________________________________________________// + +void +output_test_stream::flush() +{ + m_pimpl->m_synced_string.erase(); + +#ifndef BOOST_NO_STRINGSTREAM + str( std::string() ); +#else + seekp( 0, std::ios::beg ); +#endif +} + +//____________________________________________________________________________// + +std::size_t +output_test_stream::length() +{ + sync(); + + return m_pimpl->m_synced_string.length(); +} + +//____________________________________________________________________________// + +void +output_test_stream::sync() +{ +#ifdef BOOST_NO_STRINGSTREAM + m_pimpl->m_synced_string.assign( str(), pcount() ); + freeze( false ); +#else + m_pimpl->m_synced_string = str(); +#endif +} + +//____________________________________________________________________________// + +} // namespace test_tools + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_TEST_TOOLS_IPP_012205GER diff --git a/cpp/BoostParts/boost/test/impl/unit_test_log.ipp b/cpp/BoostParts/boost/test/impl/unit_test_log.ipp new file mode 100644 index 00000000..dbe40155 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/unit_test_log.ipp @@ -0,0 +1,444 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : implemets Unit Test Log +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER +#define BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER + +// Boost.Test +#include +#include +#include +#include + +#include + +#include + +#include +#include + +// Boost +#include +#include +typedef ::boost::io::ios_base_all_saver io_saver_type; + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** entry_value_collector ************** // +// ************************************************************************** // + +namespace ut_detail { + +entry_value_collector const& +entry_value_collector::operator<<( lazy_ostream const& v ) const +{ + unit_test_log << v; + + return *this; +} + +//____________________________________________________________________________// + +entry_value_collector const& +entry_value_collector::operator<<( const_string v ) const +{ + unit_test_log << v; + + return *this; +} + +//____________________________________________________________________________// + +entry_value_collector::~entry_value_collector() +{ + if( m_last ) + unit_test_log << log::end(); +} + +//____________________________________________________________________________// + +} // namespace ut_detail + +// ************************************************************************** // +// ************** unit_test_log ************** // +// ************************************************************************** // + +namespace { + +struct unit_test_log_impl { + // Constructor + unit_test_log_impl() + : m_stream( runtime_config::log_sink() ) + , m_stream_state_saver( new io_saver_type( *m_stream ) ) + , m_threshold_level( log_all_errors ) + , m_log_formatter( new output::compiler_log_formatter ) + { + } + + // log data + typedef scoped_ptr formatter_ptr; + typedef scoped_ptr saver_ptr; + + std::ostream* m_stream; + saver_ptr m_stream_state_saver; + log_level m_threshold_level; + formatter_ptr m_log_formatter; + + // entry data + bool m_entry_in_progress; + bool m_entry_started; + log_entry_data m_entry_data; + + // check point data + log_checkpoint_data m_checkpoint_data; + + // helper functions + std::ostream& stream() { return *m_stream; } + void set_checkpoint( const_string file, std::size_t line_num, const_string msg ) + { + assign_op( m_checkpoint_data.m_message, msg, 0 ); + m_checkpoint_data.m_file_name = file; + m_checkpoint_data.m_line_num = line_num; + } +}; + +unit_test_log_impl& s_log_impl() { static unit_test_log_impl the_inst; return the_inst; } + +} // local namespace + +//____________________________________________________________________________// + +void +unit_test_log_t::test_start( counter_t test_cases_amount ) +{ + if( s_log_impl().m_threshold_level == log_nothing ) + return; + + s_log_impl().m_log_formatter->log_start( s_log_impl().stream(), test_cases_amount ); + + if( runtime_config::show_build_info() ) + s_log_impl().m_log_formatter->log_build_info( s_log_impl().stream() ); + + s_log_impl().m_entry_in_progress = false; +} + +//____________________________________________________________________________// + +void +unit_test_log_t::test_finish() +{ + if( s_log_impl().m_threshold_level == log_nothing ) + return; + + s_log_impl().m_log_formatter->log_finish( s_log_impl().stream() ); + + s_log_impl().stream().flush(); +} + +//____________________________________________________________________________// + +void +unit_test_log_t::test_aborted() +{ + BOOST_TEST_LOG_ENTRY( log_messages ) << "Test is aborted"; +} + +//____________________________________________________________________________// + +void +unit_test_log_t::test_unit_start( test_unit const& tu ) +{ + if( s_log_impl().m_threshold_level > log_test_units ) + return; + + if( s_log_impl().m_entry_in_progress ) + *this << log::end(); + + s_log_impl().m_log_formatter->test_unit_start( s_log_impl().stream(), tu ); +} + +//____________________________________________________________________________// + +void +unit_test_log_t::test_unit_finish( test_unit const& tu, unsigned long elapsed ) +{ + if( s_log_impl().m_threshold_level > log_test_units ) + return; + + s_log_impl().m_checkpoint_data.clear(); + + if( s_log_impl().m_entry_in_progress ) + *this << log::end(); + + s_log_impl().m_log_formatter->test_unit_finish( s_log_impl().stream(), tu, elapsed ); +} + +//____________________________________________________________________________// + +void +unit_test_log_t::test_unit_skipped( test_unit const& tu ) +{ + if( s_log_impl().m_threshold_level > log_test_units ) + return; + + if( s_log_impl().m_entry_in_progress ) + *this << log::end(); + + s_log_impl().m_log_formatter->test_unit_skipped( s_log_impl().stream(), tu ); +} + +//____________________________________________________________________________// + +void +unit_test_log_t::test_unit_aborted( test_unit const& ) +{ + // do nothing +} + +//____________________________________________________________________________// + +void +unit_test_log_t::assertion_result( bool ) +{ + // do nothing +} + +//____________________________________________________________________________// + +void +unit_test_log_t::exception_caught( execution_exception const& ex ) +{ + log_level l = + ex.code() <= execution_exception::cpp_exception_error ? log_cpp_exception_errors : + (ex.code() <= execution_exception::timeout_error ? log_system_errors + : log_fatal_errors ); + + if( l >= s_log_impl().m_threshold_level ) { + if( s_log_impl().m_entry_in_progress ) + *this << log::end(); + + s_log_impl().m_log_formatter->log_exception( s_log_impl().stream(), s_log_impl().m_checkpoint_data, ex ); + } +} + +//____________________________________________________________________________// + +void +unit_test_log_t::set_checkpoint( const_string file, std::size_t line_num, const_string msg ) +{ + s_log_impl().set_checkpoint( file, line_num, msg ); +} + +//____________________________________________________________________________// + +char +set_unix_slash( char in ) +{ + return in == '\\' ? '/' : in; +} + +unit_test_log_t& +unit_test_log_t::operator<<( log::begin const& b ) +{ + if( s_log_impl().m_entry_in_progress ) + *this << log::end(); + + s_log_impl().m_stream_state_saver->restore(); + + s_log_impl().m_entry_data.clear(); + + assign_op( s_log_impl().m_entry_data.m_file_name, b.m_file_name, 0 ); + + // normalize file name + std::transform( s_log_impl().m_entry_data.m_file_name.begin(), s_log_impl().m_entry_data.m_file_name.end(), + s_log_impl().m_entry_data.m_file_name.begin(), + &set_unix_slash ); + + s_log_impl().m_entry_data.m_line_num = b.m_line_num; + + return *this; +} + +//____________________________________________________________________________// + +unit_test_log_t& +unit_test_log_t::operator<<( log::end const& ) +{ + if( s_log_impl().m_entry_in_progress ) + s_log_impl().m_log_formatter->log_entry_finish( s_log_impl().stream() ); + + s_log_impl().m_entry_in_progress = false; + + return *this; +} + +//____________________________________________________________________________// + +unit_test_log_t& +unit_test_log_t::operator<<( log_level l ) +{ + s_log_impl().m_entry_data.m_level = l; + + return *this; +} + +//____________________________________________________________________________// + +ut_detail::entry_value_collector +unit_test_log_t::operator()( log_level l ) +{ + *this << l; + + return ut_detail::entry_value_collector(); +} + +//____________________________________________________________________________// + +bool +unit_test_log_t::log_entry_start() +{ + if( s_log_impl().m_entry_in_progress ) + return true; + + switch( s_log_impl().m_entry_data.m_level ) { + case log_successful_tests: + s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data, + unit_test_log_formatter::BOOST_UTL_ET_INFO ); + break; + case log_messages: + s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data, + unit_test_log_formatter::BOOST_UTL_ET_MESSAGE ); + break; + case log_warnings: + s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data, + unit_test_log_formatter::BOOST_UTL_ET_WARNING ); + break; + case log_all_errors: + case log_cpp_exception_errors: + case log_system_errors: + s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data, + unit_test_log_formatter::BOOST_UTL_ET_ERROR ); + break; + case log_fatal_errors: + s_log_impl().m_log_formatter->log_entry_start( s_log_impl().stream(), s_log_impl().m_entry_data, + unit_test_log_formatter::BOOST_UTL_ET_FATAL_ERROR ); + break; + case log_nothing: + case log_test_units: + case invalid_log_level: + return false; + } + + s_log_impl().m_entry_in_progress = true; + + return true; +} + +//____________________________________________________________________________// + +unit_test_log_t& +unit_test_log_t::operator<<( const_string value ) +{ + if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level && !value.empty() && log_entry_start() ) + s_log_impl().m_log_formatter->log_entry_value( s_log_impl().stream(), value ); + + return *this; +} + +//____________________________________________________________________________// + +unit_test_log_t& +unit_test_log_t::operator<<( lazy_ostream const& value ) +{ + if( s_log_impl().m_entry_data.m_level >= s_log_impl().m_threshold_level && !value.empty() && log_entry_start() ) + s_log_impl().m_log_formatter->log_entry_value( s_log_impl().stream(), value ); + + return *this; +} + +//____________________________________________________________________________// + +void +unit_test_log_t::set_stream( std::ostream& str ) +{ + if( s_log_impl().m_entry_in_progress ) + return; + + s_log_impl().m_stream = &str; + s_log_impl().m_stream_state_saver.reset( new io_saver_type( str ) ); +} + +//____________________________________________________________________________// + +void +unit_test_log_t::set_threshold_level( log_level lev ) +{ + if( s_log_impl().m_entry_in_progress || lev == invalid_log_level ) + return; + + s_log_impl().m_threshold_level = lev; +} + +//____________________________________________________________________________// + +void +unit_test_log_t::set_format( output_format log_format ) +{ + if( s_log_impl().m_entry_in_progress ) + return; + + if( log_format == CLF ) + set_formatter( new output::compiler_log_formatter ); + else + set_formatter( new output::xml_log_formatter ); +} + +//____________________________________________________________________________// + +void +unit_test_log_t::set_formatter( unit_test_log_formatter* the_formatter ) +{ + s_log_impl().m_log_formatter.reset( the_formatter ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** unit_test_log_formatter ************** // +// ************************************************************************** // + +void +unit_test_log_formatter::log_entry_value( std::ostream& ostr, lazy_ostream const& value ) +{ + log_entry_value( ostr, (wrap_stringstream().ref() << value).str() ); +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_LOG_IPP_012205GER diff --git a/cpp/BoostParts/boost/test/impl/unit_test_main.ipp b/cpp/BoostParts/boost/test/impl/unit_test_main.ipp new file mode 100644 index 00000000..9874c69a --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/unit_test_main.ipp @@ -0,0 +1,246 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : main function implementation for Unit Test Framework +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER +#define BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER + +// Boost.Test +#include +#include +#include +#include + +#include + +#if !defined(__BORLANDC__) && !BOOST_WORKAROUND( BOOST_MSVC, < 1300 ) && !BOOST_WORKAROUND( __SUNPRO_CC, < 0x5100 ) +#define BOOST_TEST_SUPPORT_RUN_BY_NAME +#include +#endif + +// Boost +#include +#include + +// STL +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** test_case_filter ************** // +// ************************************************************************** // + +class test_case_filter : public test_tree_visitor { +public: + struct single_filter { + single_filter( const_string in ) + { + if( in == "*" ) + m_kind = SFK_ALL; + else if( first_char( in ) == '*' && last_char( in ) == '*' ) { + m_kind = SFK_SUBSTR; + m_value = in.substr( 1, in.size()-1 ); + } + else if( first_char( in ) == '*' ) { + m_kind = SFK_TRAILING; + m_value = in.substr( 1 ); + } + else if( last_char( in ) == '*' ) { + m_kind = SFK_LEADING; + m_value = in.substr( 0, in.size()-1 ); + } + else { + m_kind = SFK_MATCH; + m_value = in; + } + }; + + bool pass( test_unit const& tu ) const + { + const_string name( tu.p_name ); + + switch( m_kind ) { + default: + case SFK_ALL: + return true; + + case SFK_LEADING: + return name.substr( 0, m_value.size() ) == m_value; + + case SFK_TRAILING: + return name.size() >= m_value.size() && name.substr( name.size() - m_value.size() ) == m_value; + + case SFK_SUBSTR: + return name.find( m_value ) != const_string::npos; + + case SFK_MATCH: + return m_value == tu.p_name.get(); + } + } + enum kind { SFK_ALL, SFK_LEADING, SFK_TRAILING, SFK_SUBSTR, SFK_MATCH }; + + kind m_kind; + const_string m_value; + }; + // Constructor +#ifndef BOOST_TEST_SUPPORT_RUN_BY_NAME + explicit test_case_filter( const_string ) : m_depth( 0 ) {} +#else + explicit test_case_filter( const_string tc_to_run ) + : m_depth( 0 ) + { + string_token_iterator tit( tc_to_run, (dropped_delimeters = "/", kept_delimeters = dt_none) ); + + while( tit != string_token_iterator() ) { + m_filters.push_back( + std::vector( string_token_iterator( *tit, (dropped_delimeters = ",", kept_delimeters = dt_none) ), + string_token_iterator() ) ); + + ++tit; + } + } +#endif + + void filter_unit( test_unit const& tu ) + { + if( (++m_depth - 1) > m_filters.size() ) { + tu.p_enabled.value = true; + return; + } + + if( m_depth == 1 ) + return; + + std::vector const& filters = m_filters[m_depth-2]; + + tu.p_enabled.value = + std::find_if( filters.begin(), filters.end(), bind( &single_filter::pass, _1, boost::ref(tu) ) ) != filters.end(); + } + + // test tree visitor interface + virtual void visit( test_case const& tc ) + { + if( m_depth < m_filters.size() ) { + tc.p_enabled.value = false; + return; + } + + filter_unit( tc ); + + --m_depth; + } + + virtual bool test_suite_start( test_suite const& ts ) + { + filter_unit( ts ); + + if( !ts.p_enabled ) + --m_depth; + + return ts.p_enabled; + } + + virtual void test_suite_finish( test_suite const& ) { --m_depth; } + +private: + // Data members + std::vector > m_filters; + unsigned m_depth; +}; + +// ************************************************************************** // +// ************** unit_test_main ************** // +// ************************************************************************** // + +int BOOST_TEST_DECL +unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ) +{ + try { + framework::init( init_func, argc, argv ); + + if( !runtime_config::test_to_run().is_empty() ) { + test_case_filter filter( runtime_config::test_to_run() ); + + traverse_test_tree( framework::master_test_suite().p_id, filter ); + } + + framework::run(); + + results_reporter::make_report(); + + return runtime_config::no_result_code() + ? boost::exit_success + : results_collector.results( framework::master_test_suite().p_id ).result_code(); + } + catch( framework::nothing_to_test const& ) { + return boost::exit_success; + } + catch( framework::internal_error const& ex ) { + results_reporter::get_stream() << "Boost.Test framework internal error: " << ex.what() << std::endl; + + return boost::exit_exception_failure; + } + catch( framework::setup_error const& ex ) { + results_reporter::get_stream() << "Test setup error: " << ex.what() << std::endl; + + return boost::exit_exception_failure; + } + catch( ... ) { + results_reporter::get_stream() << "Boost.Test framework internal error: unknown reason" << std::endl; + + return boost::exit_exception_failure; + } +} + +} // namespace unit_test + +} // namespace boost + +#if !defined(BOOST_TEST_DYN_LINK) && !defined(BOOST_TEST_NO_MAIN) + +// ************************************************************************** // +// ************** main function for tests using lib ************** // +// ************************************************************************** // + +int BOOST_TEST_CALL_DECL +main( int argc, char* argv[] ) +{ + // prototype for user's unit test init function +#ifdef BOOST_TEST_ALTERNATIVE_INIT_API + extern bool init_unit_test(); + + boost::unit_test::init_unit_test_func init_func = &init_unit_test; +#else + extern ::boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ); + + boost::unit_test::init_unit_test_func init_func = &init_unit_test_suite; +#endif + + return ::boost::unit_test::unit_test_main( init_func, argc, argv ); +} + +#endif // !BOOST_TEST_DYN_LINK && !BOOST_TEST_NO_MAIN + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_MAIN_IPP_012205GER diff --git a/cpp/BoostParts/boost/test/impl/unit_test_monitor.ipp b/cpp/BoostParts/boost/test/impl/unit_test_monitor.ipp new file mode 100644 index 00000000..b162ad92 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/unit_test_monitor.ipp @@ -0,0 +1,101 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : implements specific subclass of Executon Monitor used by Unit +// Test Framework to monitor test cases run. +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_MONITOR_IPP_012205GER +#define BOOST_TEST_UNIT_TEST_MONITOR_IPP_012205GER + +// Boost.Test +#include +#include +#include +#include + +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace { + +template +struct zero_return_wrapper_t { + explicit zero_return_wrapper_t( F const& f ) : m_f( f ) {} + + int operator()() { m_f(); return 0; } + + F const& m_f; +}; + +template +zero_return_wrapper_t +zero_return_wrapper( F const& f ) +{ + return zero_return_wrapper_t( f ); +} + +} + +// ************************************************************************** // +// ************** unit_test_monitor ************** // +// ************************************************************************** // + +unit_test_monitor_t::error_level +unit_test_monitor_t::execute_and_translate( test_case const& tc ) +{ + try { + p_catch_system_errors.value = runtime_config::catch_sys_errors(); + p_timeout.value = tc.p_timeout.get(); + p_auto_start_dbg.value = runtime_config::auto_start_dbg(); + p_use_alt_stack.value = runtime_config::use_alt_stack(); + p_detect_fp_exceptions.value = runtime_config::detect_fp_exceptions(); + + execute( callback0( zero_return_wrapper( tc.test_func() ) ) ); + } + catch( execution_exception const& ex ) { + framework::exception_caught( ex ); + framework::test_unit_aborted( framework::current_test_case() ); + + // translate execution_exception::error_code to error_level + switch( ex.code() ) { + case execution_exception::no_error: return test_ok; + case execution_exception::user_error: return unexpected_exception; + case execution_exception::cpp_exception_error: return unexpected_exception; + case execution_exception::system_error: return os_exception; + case execution_exception::timeout_error: return os_timeout; + case execution_exception::user_fatal_error: + case execution_exception::system_fatal_error: return fatal_error; + default: return unexpected_exception; + } + } + + return test_ok; +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_MONITOR_IPP_012205GER diff --git a/cpp/BoostParts/boost/test/impl/unit_test_parameters.ipp b/cpp/BoostParts/boost/test/impl/unit_test_parameters.ipp new file mode 100644 index 00000000..fd8e1ade --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/unit_test_parameters.ipp @@ -0,0 +1,527 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 63640 $ +// +// Description : simple implementation for Unit Test Framework parameter +// handling routines. May be rewritten in future to use some kind of +// command-line arguments parsing facility and environment variable handling +// facility +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER +#define BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER + +// Boost.Test +#include +#include +#include +#include +#include +#include +#include + +// Boost.Runtime.Param +#include +#include + +namespace rt = boost::runtime; +namespace cla = rt::cla; + + +#ifndef UNDER_CE +#include + +namespace env = rt::env; +#endif + + +// Boost +#include +#include +#include +#include + +// STL +#include +#include +#include +#include + +#include + +//____________________________________________________________________________// + +# ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::getenv; using ::strncmp; using ::strcmp; } +# endif + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** input operations for unit_test's enums ************** // +// ************************************************************************** // + +std::istream& +operator>>( std::istream& in, unit_test::log_level& ll ) +{ + static fixed_mapping > log_level_name( + "all" , log_successful_tests, + "success" , log_successful_tests, + "test_suite" , log_test_units, + "unit_scope" , log_test_units, + "message" , log_messages, + "warning" , log_warnings, + "error" , log_all_errors, + "cpp_exception" , log_cpp_exception_errors, + "system_error" , log_system_errors, + "fatal_error" , log_fatal_errors, + "nothing" , log_nothing, + + invalid_log_level + ); + + std::string val; + in >> val; + + ll = log_level_name[val]; + BOOST_TEST_SETUP_ASSERT( ll != unit_test::invalid_log_level, "invalid log level " + val ); + + return in; +} + +//____________________________________________________________________________// + +std::istream& +operator>>( std::istream& in, unit_test::report_level& rl ) +{ + fixed_mapping > report_level_name ( + "confirm", CONFIRMATION_REPORT, + "short", SHORT_REPORT, + "detailed", DETAILED_REPORT, + "no", NO_REPORT, + + INV_REPORT_LEVEL + ); + + std::string val; + in >> val; + + rl = report_level_name[val]; + BOOST_TEST_SETUP_ASSERT( rl != INV_REPORT_LEVEL, "invalid report level " + val ); + + return in; +} + +//____________________________________________________________________________// + +std::istream& +operator>>( std::istream& in, unit_test::output_format& of ) +{ + fixed_mapping > output_format_name ( + "HRF", unit_test::CLF, + "CLF", unit_test::CLF, + "XML", unit_test::XML, + + unit_test::INV_OF + ); + + std::string val; + in >> val; + + of = output_format_name[val]; + BOOST_TEST_SETUP_ASSERT( of != unit_test::INV_OF, "invalid output format " + val ); + + return in; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** runtime_config ************** // +// ************************************************************************** // + +namespace runtime_config { + +namespace { + +// framework parameters and corresponding command-line arguments +std::string AUTO_START_DBG = "auto_start_dbg"; +std::string BREAK_EXEC_PATH = "break_exec_path"; +std::string BUILD_INFO = "build_info"; +std::string CATCH_SYS_ERRORS = "catch_system_errors"; +std::string DETECT_FP_EXCEPT = "detect_fp_exceptions"; +std::string DETECT_MEM_LEAKS = "detect_memory_leaks"; +std::string LOG_FORMAT = "log_format"; +std::string LOG_LEVEL = "log_level"; +std::string LOG_SINK = "log_sink"; +std::string OUTPUT_FORMAT = "output_format"; +std::string RANDOM_SEED = "random"; +std::string REPORT_FORMAT = "report_format"; +std::string REPORT_LEVEL = "report_level"; +std::string REPORT_SINK = "report_sink"; +std::string RESULT_CODE = "result_code"; +std::string TESTS_TO_RUN = "run_test"; +std::string SAVE_TEST_PATTERN = "save_pattern"; +std::string SHOW_PROGRESS = "show_progress"; +std::string USE_ALT_STACK = "use_alt_stack"; + +fixed_mapping parameter_2_env_var( + AUTO_START_DBG , "BOOST_TEST_AUTO_START_DBG", + BREAK_EXEC_PATH , "BOOST_TEST_BREAK_EXEC_PATH", + BUILD_INFO , "BOOST_TEST_BUILD_INFO", + CATCH_SYS_ERRORS , "BOOST_TEST_CATCH_SYSTEM_ERRORS", + DETECT_FP_EXCEPT , "BOOST_TEST_DETECT_FP_EXCEPTIONS", + DETECT_MEM_LEAKS , "BOOST_TEST_DETECT_MEMORY_LEAK", + LOG_FORMAT , "BOOST_TEST_LOG_FORMAT", + LOG_LEVEL , "BOOST_TEST_LOG_LEVEL", + LOG_SINK , "BOOST_TEST_LOG_SINK", + OUTPUT_FORMAT , "BOOST_TEST_OUTPUT_FORMAT", + RANDOM_SEED , "BOOST_TEST_RANDOM", + REPORT_FORMAT , "BOOST_TEST_REPORT_FORMAT", + REPORT_LEVEL , "BOOST_TEST_REPORT_LEVEL", + REPORT_SINK , "BOOST_TEST_REPORT_SINK", + RESULT_CODE , "BOOST_TEST_RESULT_CODE", + TESTS_TO_RUN , "BOOST_TESTS_TO_RUN", + SAVE_TEST_PATTERN , "BOOST_TEST_SAVE_PATTERN", + SHOW_PROGRESS , "BOOST_TEST_SHOW_PROGRESS", + USE_ALT_STACK , "BOOST_TEST_USE_ALT_STACK", + + "" +); + +//____________________________________________________________________________// + +// storage for the CLAs +cla::parser s_cla_parser; +std::string s_empty; + +output_format s_report_format; +output_format s_log_format; + +//____________________________________________________________________________// + +template +T +retrieve_parameter( const_string parameter_name, cla::parser const& s_cla_parser, T const& default_value = T(), T const& optional_value = T() ) +{ + rt::const_argument_ptr arg = s_cla_parser[parameter_name]; + if( arg ) { + if( rtti::type_id() == rtti::type_id() || + !static_cast( arg->p_formal_parameter.get() ).p_optional_value ) + return s_cla_parser.get( parameter_name ); + + optional val = s_cla_parser.get >( parameter_name ); + if( val ) + return *val; + else + return optional_value; + } + + boost::optional v; + +#ifndef UNDER_CE + env::get( parameter_2_env_var[parameter_name], v ); +#endif + + if( v ) + return *v; + else + return default_value; +} + +//____________________________________________________________________________// + +} // local namespace + +void +init( int& argc, char** argv ) +{ + using namespace cla; + + try { + s_cla_parser - cla::ignore_mismatch + << cla::dual_name_parameter( AUTO_START_DBG + "|d" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Automatically starts debugger if system level error (signal) occurs") + << cla::named_parameter( BREAK_EXEC_PATH ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "For the exception safety testing allows to break at specific execution path") + << cla::dual_name_parameter( BUILD_INFO + "|i" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Shows library build information" ) + << cla::dual_name_parameter( CATCH_SYS_ERRORS + "|s" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Allows to switch between catching and ignoring system errors (signals)") + << cla::named_parameter( DETECT_FP_EXCEPT ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "Allows to switch between catching and ignoring floating point exceptions") + << cla::named_parameter( DETECT_MEM_LEAKS ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "Allows to switch between catching and ignoring memory leaks") + << cla::dual_name_parameter( LOG_FORMAT + "|f" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies log format") + << cla::dual_name_parameter( LOG_LEVEL + "|l" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies log level") + << cla::dual_name_parameter( LOG_SINK + "|k" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies log sink:stdout(default),stderr or file name") + << cla::dual_name_parameter( OUTPUT_FORMAT + "|o" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies output format (both log and report)") + << cla::dual_name_parameter( RANDOM_SEED + "|a" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional,cla::optional_value, + cla::description = "Allows to switch between sequential and random order of test units execution.\n" + "Optionally allows to specify concrete seed for random number generator") + << cla::dual_name_parameter( REPORT_FORMAT + "|m" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies report format") + << cla::dual_name_parameter(REPORT_LEVEL + "|r") + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies report level") + << cla::dual_name_parameter( REPORT_SINK + "|e" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Specifies report sink:stderr(default),stdout or file name") + << cla::dual_name_parameter( RESULT_CODE + "|c" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Allows to disable test modules's result code generation") + << cla::dual_name_parameter( TESTS_TO_RUN + "|t" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Allows to filter which test units to run") + << cla::named_parameter( SAVE_TEST_PATTERN ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "Allows to switch between saving and matching against test pattern file") + << cla::dual_name_parameter( SHOW_PROGRESS + "|p" ) + - (cla::prefix = "--|-",cla::separator = "=| ",cla::guess_name,cla::optional, + cla::description = "Turns on progress display") + << cla::named_parameter( USE_ALT_STACK ) + - (cla::prefix = "--",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "Turns on/off usage of an alternative stack for signal handling") + + << cla::dual_name_parameter( "help|?" ) + - (cla::prefix = "--|-",cla::separator = "=",cla::guess_name,cla::optional, + cla::description = "this help message") + ; + + s_cla_parser.parse( argc, argv ); + + if( s_cla_parser["help"] ) { + s_cla_parser.help( std::cout ); + throw framework::nothing_to_test(); + } + + s_report_format = retrieve_parameter( REPORT_FORMAT, s_cla_parser, unit_test::CLF ); + s_log_format = retrieve_parameter( LOG_FORMAT, s_cla_parser, unit_test::CLF ); + + unit_test::output_format of = retrieve_parameter( OUTPUT_FORMAT, s_cla_parser, unit_test::INV_OF ); + + if( of != unit_test::INV_OF ) + s_report_format = s_log_format = of; + } + catch( rt::logic_error const& ex ) { + std::ostringstream err; + + err << "Fail to process runtime parameters: " << ex.msg() << std::endl; + s_cla_parser.usage( err ); + + throw framework::setup_error( err.str() ); + } +} + +//____________________________________________________________________________// + +unit_test::log_level +log_level() +{ + return retrieve_parameter( LOG_LEVEL, s_cla_parser, unit_test::log_all_errors ); +} + +//____________________________________________________________________________// + +bool +no_result_code() +{ + return !retrieve_parameter( RESULT_CODE, s_cla_parser, true ); +} + +//____________________________________________________________________________// + +unit_test::report_level +report_level() +{ + return retrieve_parameter( REPORT_LEVEL, s_cla_parser, unit_test::CONFIRMATION_REPORT ); +} + +//____________________________________________________________________________// + +const_string +test_to_run() +{ + static std::string s_test_to_run = retrieve_parameter( TESTS_TO_RUN, s_cla_parser, s_empty ); + + return s_test_to_run; +} + +//____________________________________________________________________________// + +const_string +break_exec_path() +{ + static std::string s_break_exec_path = retrieve_parameter( BREAK_EXEC_PATH, s_cla_parser, s_empty ); + + return s_break_exec_path; +} + +//____________________________________________________________________________// + +bool +save_pattern() +{ + return retrieve_parameter( SAVE_TEST_PATTERN, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +bool +show_progress() +{ + return retrieve_parameter( SHOW_PROGRESS, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +bool +show_build_info() +{ + return retrieve_parameter( BUILD_INFO, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +bool +catch_sys_errors() +{ + return retrieve_parameter( CATCH_SYS_ERRORS, s_cla_parser, +#ifdef BOOST_TEST_DEFAULTS_TO_CORE_DUMP + false +#else + true +#endif + ); +} + +//____________________________________________________________________________// + +bool +auto_start_dbg() +{ + // !! set debugger as an option + return retrieve_parameter( AUTO_START_DBG, s_cla_parser, false ); +; +} + +//____________________________________________________________________________// + +bool +use_alt_stack() +{ + return retrieve_parameter( USE_ALT_STACK, s_cla_parser, true ); +} + +//____________________________________________________________________________// + +bool +detect_fp_exceptions() +{ + return retrieve_parameter( DETECT_FP_EXCEPT, s_cla_parser, false ); +} + +//____________________________________________________________________________// + +output_format +report_format() +{ + return s_report_format; +} + +//____________________________________________________________________________// + +output_format +log_format() +{ + return s_log_format; +} + +//____________________________________________________________________________// + +std::ostream* +report_sink() +{ + std::string sink_name = retrieve_parameter( REPORT_SINK, s_cla_parser, s_empty ); + + if( sink_name.empty() || sink_name == "stderr" ) + return &std::cerr; + + if( sink_name == "stdout" ) + return &std::cout; + + static std::ofstream log_file( sink_name.c_str() ); + return &log_file; +} + +//____________________________________________________________________________// + +std::ostream* +log_sink() +{ + std::string sink_name = retrieve_parameter( LOG_SINK, s_cla_parser, s_empty ); + + if( sink_name.empty() || sink_name == "stdout" ) + return &std::cout; + + if( sink_name == "stderr" ) + return &std::cerr; + + static std::ofstream report_file( sink_name.c_str() ); + return &report_file; +} + +//____________________________________________________________________________// + +long +detect_memory_leaks() +{ + return retrieve_parameter( DETECT_MEM_LEAKS, s_cla_parser, static_cast(1) ); +} + +//____________________________________________________________________________// + +int +random_seed() +{ + return retrieve_parameter( RANDOM_SEED, s_cla_parser, 0, 1 ); +} + +//____________________________________________________________________________// + +} // namespace runtime_config + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_PARAMETERS_IPP_012205GER diff --git a/cpp/BoostParts/boost/test/impl/unit_test_suite.ipp b/cpp/BoostParts/boost/test/impl/unit_test_suite.ipp new file mode 100644 index 00000000..859a0b56 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/unit_test_suite.ipp @@ -0,0 +1,346 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : privides core implementation for Unit Test Framework. +// Extensions can be provided in separate files +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER +#define BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER + +// Boost.Test +#include +#include +#include +#include +#include +#include + +// Boost +#include + +// STL +#include +#include + +#include + +#if BOOST_WORKAROUND(__BORLANDC__, < 0x600) && \ + BOOST_WORKAROUND(_STLPORT_VERSION, <= 0x450) \ + /**/ + using std::rand; // rand is in std and random_shuffle is in _STL +#endif + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** test_unit ************** // +// ************************************************************************** // + +test_unit::test_unit( const_string name, test_unit_type t ) +: p_type( t ) +, p_type_name( t == tut_case ? "case" : "suite" ) +, p_id( INV_TEST_UNIT_ID ) +, p_name( std::string( name.begin(), name.size() ) ) +, p_enabled( true ) +{ +} + +//____________________________________________________________________________// + +test_unit::~test_unit() +{ + framework::deregister_test_unit( this ); +} + +//____________________________________________________________________________// + +void +test_unit::depends_on( test_unit* tu ) +{ + m_dependencies.push_back( tu->p_id ); +} + +//____________________________________________________________________________// + +bool +test_unit::check_dependencies() const +{ + BOOST_TEST_FOREACH( test_unit_id, tu_id, m_dependencies ) { + if( !unit_test::results_collector.results( tu_id ).passed() ) + return false; + } + + return true; +} + +//____________________________________________________________________________// + +void +test_unit::increase_exp_fail( unsigned num ) +{ + p_expected_failures.value += num; + + if( p_parent_id != 0 ) + framework::get( p_parent_id ).increase_exp_fail( num ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** test_case ************** // +// ************************************************************************** // + +test_case::test_case( const_string name, callback0<> const& test_func ) +: test_unit( name, static_cast(type) ) +, m_test_func( test_func ) +{ + // !! weirdest MSVC BUG; try to remove this statement; looks like it eats first token of next statement +#if BOOST_WORKAROUND(BOOST_MSVC,<1300) + 0; +#endif + framework::register_test_unit( this ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** test_suite ************** // +// ************************************************************************** // + +//____________________________________________________________________________// + +test_suite::test_suite( const_string name ) +: test_unit( name, static_cast(type) ) +{ + framework::register_test_unit( this ); +} + +//____________________________________________________________________________// + +void +test_suite::add( test_unit* tu, counter_t expected_failures, unsigned timeout ) +{ + if( timeout != 0 ) + tu->p_timeout.value = timeout; + + m_members.push_back( tu->p_id ); + tu->p_parent_id.value = p_id; + + if( tu->p_expected_failures ) + increase_exp_fail( tu->p_expected_failures ); + + if( expected_failures ) + tu->increase_exp_fail( expected_failures ); +} + +//____________________________________________________________________________// + +void +test_suite::add( test_unit_generator const& gen, unsigned timeout ) +{ + test_unit* tu; + while((tu = gen.next(), tu)) + add( tu, 0, timeout ); +} + +//____________________________________________________________________________// + +void +test_suite::remove( test_unit_id id ) +{ + std::vector::iterator it = std::find( m_members.begin(), m_members.end(), id ); + + if( it != m_members.end() ) + m_members.erase( it ); +} + +//____________________________________________________________________________// + +test_unit_id +test_suite::get( const_string tu_name ) const +{ + BOOST_TEST_FOREACH( test_unit_id, id, m_members ) { + if( tu_name == framework::get( id, ut_detail::test_id_2_unit_type( id ) ).p_name.get() ) + return id; + } + + return INV_TEST_UNIT_ID; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** traverse_test_tree ************** // +// ************************************************************************** // + +void +traverse_test_tree( test_case const& tc, test_tree_visitor& V ) +{ + if( tc.p_enabled ) + V.visit( tc ); +} + +//____________________________________________________________________________// + +void +traverse_test_tree( test_suite const& suite, test_tree_visitor& V ) +{ + if( !suite.p_enabled || !V.test_suite_start( suite ) ) + return; + + try { + if( runtime_config::random_seed() == 0 ) { + BOOST_TEST_FOREACH( test_unit_id, id, suite.m_members ) + traverse_test_tree( id, V ); + } + else { + std::vector members( suite.m_members ); + std::random_shuffle( members.begin(), members.end() ); + BOOST_TEST_FOREACH( test_unit_id, id, members ) + traverse_test_tree( id, V ); + } + + } catch( test_being_aborted const& ) { + V.test_suite_finish( suite ); + framework::test_unit_aborted( suite ); + + throw; + } + + V.test_suite_finish( suite ); +} + +//____________________________________________________________________________// + +void +traverse_test_tree( test_unit_id id, test_tree_visitor& V ) +{ + if( ut_detail::test_id_2_unit_type( id ) == tut_case ) + traverse_test_tree( framework::get( id ), V ); + else + traverse_test_tree( framework::get( id ), V ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** test_case_counter ************** // +// ************************************************************************** // + +void +test_case_counter::visit( test_case const& tc ) +{ + if( tc.p_enabled ) + ++p_count.value; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** object generators ************** // +// ************************************************************************** // + +namespace ut_detail { + +std::string +normalize_test_case_name( const_string name ) +{ + return ( name[0] == '&' + ? std::string( name.begin()+1, name.size()-1 ) + : std::string( name.begin(), name.size() ) ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** auto_test_unit_registrar ************** // +// ************************************************************************** // + +auto_test_unit_registrar::auto_test_unit_registrar( test_case* tc, counter_t exp_fail ) +{ + curr_ts_store().back()->add( tc, exp_fail ); +} + +//____________________________________________________________________________// + +auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name ) +{ + test_unit_id id = curr_ts_store().back()->get( ts_name ); + + test_suite* ts; + + if( id != INV_TEST_UNIT_ID ) { + ts = &framework::get( id ); // !! test for invalid tu type + BOOST_ASSERT( ts->p_parent_id == curr_ts_store().back()->p_id ); + } + else { + ts = new test_suite( ts_name ); + curr_ts_store().back()->add( ts ); + } + + curr_ts_store().push_back( ts ); +} + +//____________________________________________________________________________// + +auto_test_unit_registrar::auto_test_unit_registrar( test_unit_generator const& tc_gen ) +{ + curr_ts_store().back()->add( tc_gen ); +} + +//____________________________________________________________________________// + +auto_test_unit_registrar::auto_test_unit_registrar( int ) +{ + if( curr_ts_store().size() == 0 ) + return; // report error? + + curr_ts_store().pop_back(); +} + +//____________________________________________________________________________// + +std::list& +auto_test_unit_registrar::curr_ts_store() +{ + static std::list inst( 1, &framework::master_test_suite() ); + return inst; +} + +//____________________________________________________________________________// + +} // namespace ut_detail + +// ************************************************************************** // +// ************** global_fixture ************** // +// ************************************************************************** // + +global_fixture::global_fixture() +{ + framework::register_observer( *this ); +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_SUITE_IPP_012205GER diff --git a/cpp/BoostParts/boost/test/impl/xml_log_formatter.ipp b/cpp/BoostParts/boost/test/impl/xml_log_formatter.ipp new file mode 100644 index 00000000..8322e0b7 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/xml_log_formatter.ipp @@ -0,0 +1,180 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : implements XML Log formatter +// *************************************************************************** + +#ifndef BOOST_TEST_XML_LOG_FORMATTER_IPP_020105GER +#define BOOST_TEST_XML_LOG_FORMATTER_IPP_020105GER + +// Boost.Test +#include +#include +#include +#include + +#include + +// Boost +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace output { + +static const_string tu_type_name( test_unit const& tu ) +{ + return tu.p_type == tut_case ? "TestCase" : "TestSuite"; +} + +// ************************************************************************** // +// ************** xml_log_formatter ************** // +// ************************************************************************** // + +void +xml_log_formatter::log_start( std::ostream& ostr, counter_t ) +{ + ostr << ""; +} + +//____________________________________________________________________________// + +void +xml_log_formatter::log_finish( std::ostream& ostr ) +{ + ostr << ""; +} + +//____________________________________________________________________________// + +void +xml_log_formatter::log_build_info( std::ostream& ostr ) +{ + ostr << ""; +} + +//____________________________________________________________________________// + +void +xml_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu ) +{ + ostr << "<" << tu_type_name( tu ) << " name" << attr_value() << tu.p_name.get() << ">"; +} + +//____________________________________________________________________________// + +void +xml_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, unsigned long elapsed ) +{ + if( tu.p_type == tut_case ) + ostr << "" << elapsed << ""; + + ostr << ""; +} + +//____________________________________________________________________________// + +void +xml_log_formatter::test_unit_skipped( std::ostream& ostr, test_unit const& tu ) +{ + ostr << "<" << tu_type_name( tu ) + << " name" << attr_value() << tu.p_name.get() + << " skipped" << attr_value() << "yes" + << "/>"; +} + +//____________________________________________________________________________// + +void +xml_log_formatter::log_exception( std::ostream& ostr, log_checkpoint_data const& checkpoint_data, execution_exception const& ex ) +{ + execution_exception::location const& loc = ex.where(); + + ostr << "" << cdata() << ex.what(); + + if( !checkpoint_data.m_file_name.is_empty() ) { + ostr << "" + << cdata() << checkpoint_data.m_message + << ""; + } + + ostr << ""; +} + +//____________________________________________________________________________// + +void +xml_log_formatter::log_entry_start( std::ostream& ostr, log_entry_data const& entry_data, log_entry_types let ) +{ + static literal_string xml_tags[] = { "Info", "Message", "Warning", "Error", "FatalError" }; + + m_curr_tag = xml_tags[let]; + ostr << '<' << m_curr_tag + << BOOST_TEST_L( " file" ) << attr_value() << entry_data.m_file_name + << BOOST_TEST_L( " line" ) << attr_value() << entry_data.m_line_num + << BOOST_TEST_L( ">" ); + + m_curr_tag.clear(); +} + +//____________________________________________________________________________// + +} // namespace output + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_XML_LOG_FORMATTER_IPP_020105GER diff --git a/cpp/BoostParts/boost/test/impl/xml_report_formatter.ipp b/cpp/BoostParts/boost/test/impl/xml_report_formatter.ipp new file mode 100644 index 00000000..0a512857 --- /dev/null +++ b/cpp/BoostParts/boost/test/impl/xml_report_formatter.ipp @@ -0,0 +1,115 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : XML report formatter +// *************************************************************************** + +#ifndef BOOST_TEST_XML_REPORT_FORMATTER_IPP_020105GER +#define BOOST_TEST_XML_REPORT_FORMATTER_IPP_020105GER + +// Boost.Test +#include +#include +#include + +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace output { + +void +xml_report_formatter::results_report_start( std::ostream& ostr ) +{ + ostr << ""; +} + +//____________________________________________________________________________// + +void +xml_report_formatter::results_report_finish( std::ostream& ostr ) +{ + ostr << ""; +} + + +//____________________________________________________________________________// + +void +xml_report_formatter::test_unit_report_start( test_unit const& tu, std::ostream& ostr ) +{ + test_results const& tr = results_collector.results( tu.p_id ); + + const_string descr; + + if( tr.passed() ) + descr = "passed"; + else if( tr.p_skipped ) + descr = "skipped"; + else if( tr.p_aborted ) + descr = "aborted"; + else + descr = "failed"; + + ostr << '<' << ( tu.p_type == tut_case ? "TestCase" : "TestSuite" ) + << " name" << attr_value() << tu.p_name.get() + << " result" << attr_value() << descr + << " assertions_passed" << attr_value() << tr.p_assertions_passed + << " assertions_failed" << attr_value() << tr.p_assertions_failed + << " expected_failures" << attr_value() << tr.p_expected_failures; + + if( tu.p_type == tut_suite ) + ostr << " test_cases_passed" << attr_value() << tr.p_test_cases_passed + << " test_cases_failed" << attr_value() << tr.p_test_cases_failed + << " test_cases_skipped" << attr_value() << tr.p_test_cases_skipped + << " test_cases_aborted" << attr_value() << tr.p_test_cases_aborted; + + + ostr << '>'; +} + +//____________________________________________________________________________// + +void +xml_report_formatter::test_unit_report_finish( test_unit const& tu, std::ostream& ostr ) +{ + ostr << "'; +} + +//____________________________________________________________________________// + +void +xml_report_formatter::do_confirmation_report( test_unit const& tu, std::ostream& ostr ) +{ + test_unit_report_start( tu, ostr ); + test_unit_report_finish( tu, ostr ); +} + +//____________________________________________________________________________// + +} // namespace output + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_XML_REPORT_FORMATTER_IPP_020105GER diff --git a/cpp/BoostParts/boost/test/included/test_exec_monitor.hpp b/cpp/BoostParts/boost/test/included/test_exec_monitor.hpp new file mode 100644 index 00000000..9d79480e --- /dev/null +++ b/cpp/BoostParts/boost/test/included/test_exec_monitor.hpp @@ -0,0 +1,39 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : included (vs. linked) version of Test Execution Monitor +// *************************************************************************** + +#ifndef BOOST_INCLUDED_TEST_EXEC_MONITOR_HPP_071894GER +#define BOOST_INCLUDED_TEST_EXEC_MONITOR_HPP_071894GER + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOOST_TEST_INCLUDED +#include + +#endif // BOOST_INCLUDED_TEST_EXEC_MONITOR_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/included/unit_test.hpp b/cpp/BoostParts/boost/test/included/unit_test.hpp new file mode 100644 index 00000000..c3c1c711 --- /dev/null +++ b/cpp/BoostParts/boost/test/included/unit_test.hpp @@ -0,0 +1,41 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : included (vs. linked) version of Unit Test Framework +// *************************************************************************** + +#ifndef BOOST_INCLUDED_UNIT_TEST_FRAMEWORK_HPP_071894GER +#define BOOST_INCLUDED_UNIT_TEST_FRAMEWORK_HPP_071894GER + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOOST_TEST_INCLUDED +#include + +#endif // BOOST_INCLUDED_UNIT_TEST_FRAMEWORK_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/interaction_based.hpp b/cpp/BoostParts/boost/test/interaction_based.hpp new file mode 100644 index 00000000..7a85cce6 --- /dev/null +++ b/cpp/BoostParts/boost/test/interaction_based.hpp @@ -0,0 +1,262 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : Facilities to perform interaction-based testing +// *************************************************************************** + +#ifndef BOOST_TEST_INTERACTION_BASED_HPP_112105GER +#define BOOST_TEST_INTERACTION_BASED_HPP_112105GER + +// Boost.Test +#include +#include + +#include + +#include + +// Boost +#include + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** BOOST_ITEST_EPOINT ************** // +// ************************************************************************** // + +#define BOOST_ITEST_EPOINT( description ) \ + ::boost::itest::manager::instance().exception_point( BOOST_TEST_L(__FILE__), __LINE__, description ) +/**/ + +// ************************************************************************** // +// ************** BOOST_ITEST_DPOINT ************** // +// ************************************************************************** // + +#define BOOST_ITEST_DPOINT() \ + ::boost::itest::manager::instance().decision_point( BOOST_TEST_L(__FILE__), __LINE__ ) +/**/ + +// ************************************************************************** // +// ************** BOOST_ITEST_SCOPE ************** // +// ************************************************************************** // + +#define BOOST_ITEST_SCOPE( scope_name ) \ + ::boost::itest::scope_guard itest_scope_guard ## __LINE__( BOOST_TEST_L(__FILE__), __LINE__, BOOST_STRINGIZE(scope_name) ) +/**/ + +// ************************************************************************** // +// ************** BOOST_ITEST_NEW ************** // +// ************************************************************************** // + +#define BOOST_ITEST_NEW( type_name ) \ + new ( ::boost::itest::location( BOOST_TEST_L(__FILE__), __LINE__ ) ) type_name +/**/ + +// ************************************************************************** // +// ************** BOOST_ITEST_DATA_FLOW ************** // +// ************************************************************************** // + +#define BOOST_ITEST_DATA_FLOW( v ) \ + ::boost::itest::manager::instance().generic_data_flow( v ) +/**/ + +// ************************************************************************** // +// ************** BOOST_ITEST_RETURN ************** // +// ************************************************************************** // + +#define BOOST_ITEST_RETURN( type, default_value ) \ + ::boost::itest::manager::instance().generic_return( default_value ) +/**/ + +// ************************************************************************** // +// ************** BOOST_ITEST_MOCK_FUNC ************** // +// ************************************************************************** // + +#define BOOST_ITEST_MOCK_FUNC( function_name ) \ + BOOST_ITEST_SCOPE( function_name ); \ + BOOST_ITEST_EPOINT( 0 ); \ + return ::boost::itest::mock_object<>::prototype(); \ +/**/ + +namespace boost { + +namespace itest { // interaction-based testing + +using unit_test::const_string; + +// ************************************************************************** // +// ************** manager ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL manager { +public: + // instance access + static manager& instance() { return *instance_ptr(); } + + // Mock objects interface hooks + virtual void exception_point( const_string /*file*/, + std::size_t /*line_num*/, + const_string /*descr*/ ){} + virtual bool decision_point( const_string /*file*/, + std::size_t /*line_num*/ ) { return true; } + virtual unsigned enter_scope( const_string /*file*/, + std::size_t /*line_num*/, + const_string /*scope_name*/){ return 0; } + virtual void leave_scope( unsigned ) {} + virtual void allocated( const_string /*file*/, + std::size_t /*line_num*/, + void* /*p*/, std::size_t /*s*/ ) {} + virtual void freed( void* /*p*/ ) {} + virtual void data_flow( const_string /*d*/ ) {} + virtual std::string return_value( const_string /*default_value */ ) { return ""; } + + template + void generic_data_flow( T const& t ) + { + wrap_stringstream ws; + + data_flow( (ws << t).str() ); + } + template + T generic_return( DefaultValueType const& dv ) + { + wrap_stringstream ws; + + std::string const& res = return_value( (ws << dv).str() ); + + if( res.empty() ) + return dv; + + return lexical_cast( res ); + } + +protected: + manager(); +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +public: +#endif + BOOST_TEST_PROTECTED_VIRTUAL ~manager(); + +private: + struct dummy_constr{}; + explicit manager( dummy_constr* ) {} + + static manager* instance_ptr( bool reset = false, manager* ptr = 0 ); +}; // manager + +// ************************************************************************** // +// ************** scope_guard ************** // +// ************************************************************************** // + +class scope_guard { +public: + // Constructor + scope_guard( const_string file, std::size_t line_num, const_string scope_name ) + { + m_scope_index = manager::instance().enter_scope( file, line_num, scope_name ); + } + ~scope_guard() + { + manager::instance().leave_scope( m_scope_index ); + } + + unsigned m_scope_index; +}; + +// ************************************************************************** // +// ************** location ************** // +// ************************************************************************** // + +struct location { + location( const_string file, std::size_t line ) + : m_file_name( file ) + , m_line_num( line ) + {} + + const_string m_file_name; + std::size_t m_line_num; +}; + +} // namespace itest + +} // namespace boost + +// ************************************************************************** // +// ************** operator new overload ************** // +// ************************************************************************** // + +#if !defined(BOOST_ITEST_NO_NEW_OVERLOADS) + +// STL +#include + +# ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::malloc; using ::free; } +# endif +# ifdef _CRTDBG_MAP_ALLOC +namespace std { using ::_malloc_dbg; using ::_free_dbg; } +# endif + +inline void* +operator new( std::size_t s, ::boost::itest::location const& l ) +{ + void* res = std::malloc(s ? s : 1); + + if( res ) + ::boost::itest::manager::instance().allocated( l.m_file_name, l.m_line_num, res, s ); + else + throw std::bad_alloc(); + + return res; +} + +//____________________________________________________________________________// + +inline void* +operator new[]( std::size_t s, ::boost::itest::location const& l ) +{ + void* res = std::malloc(s ? s : 1); + + if( res ) + ::boost::itest::manager::instance().allocated( l.m_file_name, l.m_line_num, res, s ); + else + throw std::bad_alloc(); + + return res; +} + +//____________________________________________________________________________// + +inline void +operator delete( void* p, ::boost::itest::location const& ) +{ + ::boost::itest::manager::instance().freed( p ); + + std::free( p ); +} + +//____________________________________________________________________________// + +inline void +operator delete[]( void* p, ::boost::itest::location const& ) +{ + ::boost::itest::manager::instance().freed( p ); + + std::free( p ); +} + +//____________________________________________________________________________// + +#endif + +#include + +#endif // BOOST_TEST_INTERACTION_BASED_HPP_112105GER diff --git a/cpp/BoostParts/boost/test/minimal.hpp b/cpp/BoostParts/boost/test/minimal.hpp new file mode 100644 index 00000000..30701995 --- /dev/null +++ b/cpp/BoostParts/boost/test/minimal.hpp @@ -0,0 +1,143 @@ +// (C) Copyright Gennadiy Rozental 2002-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : simple minimal testing definitions and implementation +// *************************************************************************** + +#ifndef BOOST_TEST_MINIMAL_HPP_071894GER +#define BOOST_TEST_MINIMAL_HPP_071894GER + +#define BOOST_CHECK(exp) \ + ( (exp) \ + ? static_cast(0) \ + : boost::minimal_test::report_error(#exp,__FILE__,__LINE__, BOOST_CURRENT_FUNCTION) ) + +#define BOOST_REQUIRE(exp) \ + ( (exp) \ + ? static_cast(0) \ + : boost::minimal_test::report_critical_error(#exp,__FILE__,__LINE__,BOOST_CURRENT_FUNCTION)) + +#define BOOST_ERROR( msg_ ) \ + boost::minimal_test::report_error( (msg_),__FILE__,__LINE__, BOOST_CURRENT_FUNCTION, true ) +#define BOOST_FAIL( msg_ ) \ + boost::minimal_test::report_critical_error( (msg_),__FILE__,__LINE__, BOOST_CURRENT_FUNCTION, true ) + +//____________________________________________________________________________// + +// Boost.Test +#include +#include +#include +#include +#include + +// Boost +#include // for exit codes#include // for exit codes +#include // for BOOST_CURRENT_FUNCTION + +// STL +#include // std::cerr, std::endl +#include // std::string + +#include + +//____________________________________________________________________________// + +int test_main( int argc, char* argv[] ); // prototype for users test_main() + +namespace boost { +namespace minimal_test { + +typedef boost::unit_test::const_string const_string; + +inline unit_test::counter_t& errors_counter() { static unit_test::counter_t ec = 0; return ec; } + +inline void +report_error( const char* msg, const char* file, int line, const_string func_name, bool is_msg = false ) +{ + ++errors_counter(); + std::cerr << file << "(" << line << "): "; + + if( is_msg ) + std::cerr << msg; + else + std::cerr << "test " << msg << " failed"; + + if( func_name != "(unknown)" ) + std::cerr << " in function: '" << func_name << "'"; + + std::cerr << std::endl; +} + +inline void +report_critical_error( const char* msg, const char* file, int line, const_string func_name, bool is_msg = false ) +{ + report_error( msg, file, line, func_name, is_msg ); + + throw boost::execution_aborted(); +} + +class caller { +public: + // constructor + caller( int argc, char** argv ) + : m_argc( argc ), m_argv( argv ) {} + + // execution monitor hook implementation + int operator()() { return test_main( m_argc, m_argv ); } + +private: + // Data members + int m_argc; + char** m_argv; +}; // monitor + +} // namespace minimal_test + +} // namespace boost + +//____________________________________________________________________________// + +int BOOST_TEST_CALL_DECL main( int argc, char* argv[] ) +{ + using namespace boost::minimal_test; + + try { + ::boost::execution_monitor ex_mon; + int run_result = ex_mon.execute( caller( argc, argv ) ); + + BOOST_CHECK( run_result == 0 || run_result == boost::exit_success ); + } + catch( boost::execution_exception const& exex ) { + if( exex.code() != boost::execution_exception::no_error ) + BOOST_ERROR( (std::string( "exception \"" ). + append( exex.what().begin(), exex.what().end() ). + append( "\" caught" ) ).c_str() ); + std::cerr << "\n**** Testing aborted."; + } + + if( boost::minimal_test::errors_counter() != 0 ) { + std::cerr << "\n**** " << errors_counter() + << " error" << (errors_counter() > 1 ? "s" : "" ) << " detected\n"; + + return boost::exit_test_failure; + } + + std::cout << "\n**** no errors detected\n"; + + return boost::exit_success; +} + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_MINIMAL_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/mock_object.hpp b/cpp/BoostParts/boost/test/mock_object.hpp new file mode 100644 index 00000000..e2a436a1 --- /dev/null +++ b/cpp/BoostParts/boost/test/mock_object.hpp @@ -0,0 +1,328 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : Facilities to perform exception safety_tests +// *************************************************************************** + +#ifndef BOOST_TEST_MOCK_OBJECT_HPP_112205GER +#define BOOST_TEST_MOCK_OBJECT_HPP_112205GER + +// Boost.Test +#include +#include + +// Boost +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace itest { + +// ************************************************************************** // +// ************** mock_object_base ************** // +// ************************************************************************** // + +class mock_object_base { +public: + mock_object_base() {} + + template + mock_object_base( T1 const& ) {} + + template + mock_object_base( T1 const&, T2 const& ) {} + + template + mock_object_base( T1 const&, T2 const&, T3 const& ) {} + + template + mock_object_base( T1 const&, T2 const&, T3 const&, T4 const& ) {} + + template + mock_object_base( T1 const&, T2 const&, T3 const&, T4 const&, T5 const& ) {} +}; + +// ************************************************************************** // +// ************** mock_object implementation helpers ************** // +// ************************************************************************** // + +#define MO_OP_IMPL( op, descr, ret ) \ + BOOST_ITEST_SCOPE( mock_object::operator op ); \ + BOOST_ITEST_EPOINT( descr ); \ + return ret \ +/**/ + +#define MO_UNARY_OP( op, descr ) \ +self_type const& operator op() const \ +{ \ + MO_OP_IMPL( op, descr, prototype() ); \ +} \ +/**/ + +#define MO_UNARY_BOOL_OP( op, descr ) \ +bool operator op() const \ +{ \ + MO_OP_IMPL( op, descr, (!!BOOST_ITEST_DPOINT()) ); \ +} \ +/**/ + +#define MO_BINARY_OP( op, descr ) \ +template \ +inline mock_object const& \ +operator op( mock_object const& mo, \ + mock_object const& ) \ +{ \ + MO_OP_IMPL( op, descr, mo ); \ +} \ + \ +template \ +inline mock_object const& \ +operator op( mock_object const& mo, T const& ) \ +{ \ + MO_OP_IMPL( op, descr, mo ); \ +} \ + \ +template \ +inline mock_object const& \ +operator op( T const&, mock_object const& mo ) \ +{ \ + MO_OP_IMPL( op, descr, mo ); \ +} \ +/**/ + +#define MO_BINARY_BOOL_OP( op, descr ) \ +template \ +inline bool \ +operator op( mock_object const&, \ + mock_object const& ) \ +{ \ + MO_OP_IMPL( op, descr, BOOST_ITEST_DPOINT() ); \ +} \ + \ +template \ +inline bool \ +operator op( mock_object const&, T const& ) \ +{ \ + MO_OP_IMPL( op, descr, BOOST_ITEST_DPOINT() ); \ +} \ + \ +template \ +inline bool \ +operator op( T const&, mock_object const& ) \ +{ \ + MO_OP_IMPL( op, descr, BOOST_ITEST_DPOINT() ); \ +} \ +/**/ + +// ************************************************************************** // +// ************** mock_object ************** // +// ************************************************************************** // + +template +class mock_object; + +template +class mock_object : public Base { + // Private typeefs + typedef mock_object self_type; + struct dummy { void nonnull() {}; }; + typedef void (dummy::*safe_bool)(); + + // prototype constructor + mock_object( dummy* ) {} + +public: + static mock_object& prototype() + { + static mock_object p( reinterpret_cast(0) ); + return p; + } + + // Constructors + mock_object() + { + BOOST_ITEST_SCOPE( mock_object::mock_object ); + BOOST_ITEST_EPOINT( "Mock object default constructor" ); + } + + template + mock_object( T1 const& arg1 ) + : mock_object_base( arg1 ) + { + BOOST_ITEST_SCOPE( mock_object::mock_object ); + BOOST_ITEST_EPOINT( "Mock object constructor" ); + } + + template + mock_object( T1 const& arg1, T2 const& arg2 ) + : mock_object_base( arg1, arg2 ) + { + BOOST_ITEST_SCOPE( mock_object::mock_object ); + BOOST_ITEST_EPOINT( "Mock object constructor" ); + } + + template + mock_object( T1 const& arg1, T2 const& arg2, T3 const& arg3 ) + : mock_object_base( arg1, arg2, arg3 ) + { + BOOST_ITEST_SCOPE( mock_object::mock_object ); + BOOST_ITEST_EPOINT( "Mock object constructor" ); + } + + template + mock_object( T1 const& arg1, T2 const& arg2, T3 const& arg3, T4 const& arg4 ) + : mock_object_base( arg1, arg2, arg3, arg4 ) + { + BOOST_ITEST_SCOPE( mock_object::mock_object ); + BOOST_ITEST_EPOINT( "Mock object constructor" ); + } + + template + mock_object( T1 const& arg1, T2 const& arg2, T3 const& arg3, T4 const& arg4, T5 const& arg5 ) + : mock_object_base( arg1, arg2, arg3, arg4, arg5 ) + { + BOOST_ITEST_SCOPE( mock_object::mock_object ); + BOOST_ITEST_EPOINT( "Mock object constructor" ); + } + + mock_object( mock_object const& ) + { + BOOST_ITEST_SCOPE( mock_object::mock_object ); + BOOST_ITEST_EPOINT( "Mock object copy constructor" ); + } + + // assignment + self_type const& operator =( mock_object const& ) const + { + MO_OP_IMPL( =, "Copy assignment", prototype() ); + } + + template + self_type const& operator =( T const& ) const + { + MO_OP_IMPL( =, "Copy assignment", prototype() ); + } + + // Unary operators + MO_UNARY_BOOL_OP( !, "Logical NOT operator" ) + MO_UNARY_OP( &, "Address-of operator" ) + MO_UNARY_OP( ~, "One's complement operator" ) + MO_UNARY_OP( *, "Pointer dereference" ) + MO_UNARY_OP( +, "Unary plus" ) + + // Increment and Decrement + MO_UNARY_OP( ++, "Prefix increment" ) + MO_UNARY_OP( --, "Prefix decrement" ) + self_type const& operator ++(int) const + { + MO_OP_IMPL( ++, "Postfix increment", prototype() ); + } + self_type const& operator --(int) const + { + MO_OP_IMPL( --, "Postfix decrement", prototype() ); + } + + // Bool context convertion + operator safe_bool() const + { + MO_OP_IMPL( safe_bool, "Bool context conversion", + (BOOST_ITEST_DPOINT() ? 0 : &dummy::nonnull) ); + } + + // Function-call operators + self_type const& operator ()() const + { + MO_OP_IMPL( (), "0-arity function-call", prototype() ); + } + template + self_type const& operator ()( T1 const& arg1 ) const + { + MO_OP_IMPL( (), "1-arity function-call", prototype() ); + } + template + self_type const& operator ()( T1 const&, T2 const& ) const + { + MO_OP_IMPL( (), "2-arity function-call", prototype() ); + } + template + self_type const& operator ()( T1 const&, T2 const&, T3 const& ) const + { + MO_OP_IMPL( (), "3-arity function-call", prototype() ); + } + template + self_type const& operator ()( T1 const&, T2 const&, T3 const&, T4 const& ) const + { + MO_OP_IMPL( (), "4-arity function-call", prototype() ); + } + template + self_type const& operator ()( T1 const&, T2 const&, T3 const&, T4 const&, T5 const& ) const + { + MO_OP_IMPL( (), "5-arity function-call", prototype() ); + } + + // Substripting + template + self_type const& operator []( T const& ) const + { + MO_OP_IMPL( [], "Substripting", prototype() ); + } + + // Class member access + self_type const* operator->() const + { + MO_OP_IMPL( ->, "Class member access", this ); + } +}; + +// !! MO_BINARY_OP( BOOST_PP_COMMA(), "Comma operator" ) + +MO_BINARY_BOOL_OP( !=, "Inequality" ) +MO_BINARY_OP( %, "Modulus" ) +MO_BINARY_OP( %=, "Modulus/assignment" ) +MO_BINARY_OP( &, "Bitwise AND" ) +MO_BINARY_BOOL_OP( &&, "Logical AND" ) +MO_BINARY_OP( &=, "Bitwise AND/assignment" ) +MO_BINARY_OP( *, "Multiplication" ) +MO_BINARY_OP( *=, "Multiplication/assignment" ) +MO_BINARY_OP( +, "Addition" ) +MO_BINARY_OP( +=, "Addition/assignment" ) +//MO_BINARY_OP( -, "Subtraction" ) +MO_BINARY_OP( -=, "Subtraction/assignment" ) +MO_BINARY_OP( ->*, "Pointer-to-member selection" ) +MO_BINARY_OP( /, "Division" ) +MO_BINARY_OP( /=, "Division/assignment" ) +MO_BINARY_BOOL_OP( <, "Less than" ) +MO_BINARY_OP( <<=, "Left shift/assignment" ) +MO_BINARY_BOOL_OP( <=, "Less than or equal to" ) +MO_BINARY_BOOL_OP( ==, "Equality" ) +MO_BINARY_BOOL_OP( >, "Greater than" ) +MO_BINARY_BOOL_OP( >=, "Greater than or equal to" ) +MO_BINARY_OP( >>=, "Right shift/assignment" ) +MO_BINARY_OP( ^, "Exclusive OR" ) +MO_BINARY_OP( ^=, "Exclusive OR/assignment" ) +MO_BINARY_OP( |, "Bitwise inclusive OR" ) +MO_BINARY_OP( |=, "Bitwise inclusive OR/assignment" ) +MO_BINARY_BOOL_OP( ||, "Logical OR" ) + +MO_BINARY_OP( <<, "Left shift" ) +MO_BINARY_OP( >>, "Right shift" ) + +} // namespace itest + +} // namespace boost + +#include + +#endif // BOOST_TEST_MOCK_OBJECT_HPP_112205GER diff --git a/cpp/BoostParts/boost/test/output/compiler_log_formatter.hpp b/cpp/BoostParts/boost/test/output/compiler_log_formatter.hpp new file mode 100644 index 00000000..3abb2d57 --- /dev/null +++ b/cpp/BoostParts/boost/test/output/compiler_log_formatter.hpp @@ -0,0 +1,68 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : contains compiler like Log formatter definition +// *************************************************************************** + +#ifndef BOOST_TEST_COMPILER_LOG_FORMATTER_HPP_020105GER +#define BOOST_TEST_COMPILER_LOG_FORMATTER_HPP_020105GER + +// Boost.Test +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace output { + +// ************************************************************************** // +// ************** compiler_log_formatter ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL compiler_log_formatter : public unit_test_log_formatter { +public: + // Formatter interface + void log_start( std::ostream&, counter_t test_cases_amount ); + void log_finish( std::ostream& ); + void log_build_info( std::ostream& ); + + void test_unit_start( std::ostream&, test_unit const& tu ); + void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ); + void test_unit_skipped( std::ostream&, test_unit const& tu ); + + void log_exception( std::ostream&, log_checkpoint_data const&, execution_exception const& ex ); + + void log_entry_start( std::ostream&, log_entry_data const&, log_entry_types let ); + void log_entry_value( std::ostream&, const_string value ); + void log_entry_value( std::ostream&, lazy_ostream const& value ); + void log_entry_finish( std::ostream& ); + +protected: + virtual void print_prefix( std::ostream&, const_string file, std::size_t line ); +}; + +} // namespace output + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_COMPILER_LOG_FORMATTER_HPP_020105GER diff --git a/cpp/BoostParts/boost/test/output/plain_report_formatter.hpp b/cpp/BoostParts/boost/test/output/plain_report_formatter.hpp new file mode 100644 index 00000000..49eb7dc7 --- /dev/null +++ b/cpp/BoostParts/boost/test/output/plain_report_formatter.hpp @@ -0,0 +1,62 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : plain report formatter implementation +// *************************************************************************** + +#ifndef BOOST_TEST_PLAIN_REPORT_FORMATTER_HPP_020105GER +#define BOOST_TEST_PLAIN_REPORT_FORMATTER_HPP_020105GER + +// Boost.Test +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace output { + +// ************************************************************************** // +// ************** plain_report_formatter ************** // +// ************************************************************************** // + +class plain_report_formatter : public results_reporter::format { +public: + // Formatter interface + void results_report_start( std::ostream& ostr ); + void results_report_finish( std::ostream& ostr ); + + void test_unit_report_start( test_unit const&, std::ostream& ostr ); + void test_unit_report_finish( test_unit const&, std::ostream& ostr ); + + void do_confirmation_report( test_unit const&, std::ostream& ostr ); + +private: + // Data members + counter_t m_indent; +}; + +} // namespace output + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_PLAIN_REPORT_FORMATTER_HPP_020105GER diff --git a/cpp/BoostParts/boost/test/output/xml_log_formatter.hpp b/cpp/BoostParts/boost/test/output/xml_log_formatter.hpp new file mode 100644 index 00000000..93ee2fe8 --- /dev/null +++ b/cpp/BoostParts/boost/test/output/xml_log_formatter.hpp @@ -0,0 +1,72 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : contains XML Log formatter definition +// *************************************************************************** + +#ifndef BOOST_TEST_XML_LOG_FORMATTER_020105GER +#define BOOST_TEST_XML_LOG_FORMATTER_020105GER + +// Boost.Test +#include +#include + +// STL +#include // std::size_t + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace output { + +// ************************************************************************** // +// ************** xml_log_formatter ************** // +// ************************************************************************** // + +class xml_log_formatter : public unit_test_log_formatter { +public: + // Formatter interface + void log_start( std::ostream&, counter_t test_cases_amount ); + void log_finish( std::ostream& ); + void log_build_info( std::ostream& ); + + void test_unit_start( std::ostream&, test_unit const& tu ); + void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ); + void test_unit_skipped( std::ostream&, test_unit const& tu ); + + void log_exception( std::ostream&, log_checkpoint_data const&, execution_exception const& ex ); + + void log_entry_start( std::ostream&, log_entry_data const&, log_entry_types let ); + using unit_test_log_formatter::log_entry_value; // bring base class functions into overload set + void log_entry_value( std::ostream&, const_string value ); + void log_entry_finish( std::ostream& ); + +private: + // Data members + const_string m_curr_tag; +}; + +} // namespace output + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_XML_LOG_FORMATTER_020105GER diff --git a/cpp/BoostParts/boost/test/output/xml_report_formatter.hpp b/cpp/BoostParts/boost/test/output/xml_report_formatter.hpp new file mode 100644 index 00000000..6c413d9a --- /dev/null +++ b/cpp/BoostParts/boost/test/output/xml_report_formatter.hpp @@ -0,0 +1,58 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : XML report formatter implementation +// *************************************************************************** + +#ifndef BOOST_TEST_XML_REPORT_FORMATTER_HPP_020105GER +#define BOOST_TEST_XML_REPORT_FORMATTER_HPP_020105GER + +// Boost.Test +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace output { + +// ************************************************************************** // +// ************** xml_report_formatter ************** // +// ************************************************************************** // + +class xml_report_formatter : public results_reporter::format { +public: + // Formatter interface + void results_report_start( std::ostream& ostr ); + void results_report_finish( std::ostream& ostr ); + + void test_unit_report_start( test_unit const&, std::ostream& ostr ); + void test_unit_report_finish( test_unit const&, std::ostream& ostr ); + + void do_confirmation_report( test_unit const&, std::ostream& ostr ); +}; + +} // namespace output + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_XML_REPORT_FORMATTER_HPP_020105GER diff --git a/cpp/BoostParts/boost/test/output_test_stream.hpp b/cpp/BoostParts/boost/test/output_test_stream.hpp new file mode 100644 index 00000000..295c2380 --- /dev/null +++ b/cpp/BoostParts/boost/test/output_test_stream.hpp @@ -0,0 +1,78 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : output_test_stream class definition +// *************************************************************************** + +#ifndef BOOST_TEST_OUTPUT_TEST_STREAM_HPP_012705GER +#define BOOST_TEST_OUTPUT_TEST_STREAM_HPP_012705GER + +// Boost.Test +#include +#include +#include + +// STL +#include // for std::size_t + +#include + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** output_test_stream ************** // +// ************************************************************************** // + +// class to be used to simplify testing of ostream-based output operations + +namespace boost { + +namespace test_tools { + +class BOOST_TEST_DECL output_test_stream : public wrap_stringstream::wrapped_stream { + typedef unit_test::const_string const_string; + typedef predicate_result result_type; +public: + // Constructor + explicit output_test_stream( const_string pattern_file_name = const_string(), + bool match_or_save = true, + bool text_or_binary = true ); + + // Destructor + ~output_test_stream(); + + // checking function + result_type is_empty( bool flush_stream = true ); + result_type check_length( std::size_t length, bool flush_stream = true ); + result_type is_equal( const_string arg_, bool flush_stream = true ); + result_type match_pattern( bool flush_stream = true ); + + // explicit flush + void flush(); + +private: + // helper functions + std::size_t length(); + void sync(); + + struct Impl; + Impl* m_pimpl; +}; + +} // namespace test_tools + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_OUTPUT_TEST_STREAM_HPP_012705GER diff --git a/cpp/BoostParts/boost/test/predicate_result.hpp b/cpp/BoostParts/boost/test/predicate_result.hpp new file mode 100644 index 00000000..16ae4882 --- /dev/null +++ b/cpp/BoostParts/boost/test/predicate_result.hpp @@ -0,0 +1,88 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : enhanced result for test predicate that include message explaining failure +// *************************************************************************** + +#ifndef BOOST_TEST_PREDICATE_RESULT_HPP_012705GER +#define BOOST_TEST_PREDICATE_RESULT_HPP_012705GER + +// Boost.Test +#include +#include +#include + +// Boost +#include +#include + +// STL +#include // for std::size_t + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace test_tools { + +// ************************************************************************** // +// ************** predicate_result ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL predicate_result { + typedef unit_test::const_string const_string; + struct dummy { void nonnull() {}; }; + typedef void (dummy::*safe_bool)(); + +public: + // Constructor + predicate_result( bool pv_ ) + : p_predicate_value( pv_ ) + {} + + template + predicate_result( BoolConvertable const& pv_ ) : p_predicate_value( !!pv_ ) {} + + // Access methods + bool operator!() const { return !p_predicate_value; } + void operator=( bool pv_ ) { p_predicate_value.value = pv_; } + operator safe_bool() const { return !!p_predicate_value ? &dummy::nonnull : 0; } + + // Public properties + BOOST_READONLY_PROPERTY( bool, (predicate_result) ) p_predicate_value; + + // Access methods + bool has_empty_message() const { return !m_message; } + wrap_stringstream& message() + { + if( !m_message ) + m_message.reset( new wrap_stringstream ); + + return *m_message; + } + const_string message() const { return !m_message ? const_string() : const_string( m_message->str() ); } + +private: + // Data members + shared_ptr m_message; +}; + +} // namespace test_tools + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_PREDICATE_RESULT_HPP_012705GER diff --git a/cpp/BoostParts/boost/test/progress_monitor.hpp b/cpp/BoostParts/boost/test/progress_monitor.hpp new file mode 100644 index 00000000..f4c99d5d --- /dev/null +++ b/cpp/BoostParts/boost/test/progress_monitor.hpp @@ -0,0 +1,70 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines simple text based progress monitor +// *************************************************************************** + +#ifndef BOOST_TEST_PROGRESS_MONITOR_HPP_020105GER +#define BOOST_TEST_PROGRESS_MONITOR_HPP_020105GER + +// Boost.Test +#include +#include + +// STL +#include // for std::ostream& + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** progress_monitor ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL progress_monitor_t : public test_observer, public singleton { +public: + // test observer interface + void test_start( counter_t test_cases_amount ); + void test_finish() {} + void test_aborted(); + + void test_unit_start( test_unit const& ) {} + void test_unit_finish( test_unit const&, unsigned long ); + void test_unit_skipped( test_unit const& ); + void test_unit_aborted( test_unit const& ) {} + + void assertion_result( bool ) {} + void exception_caught( execution_exception const& ) {} + + // configuration + void set_stream( std::ostream& ); + +private: + BOOST_TEST_SINGLETON_CONS( progress_monitor_t ); +}; // progress_monitor_t + +BOOST_TEST_SINGLETON_INST( progress_monitor ) + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_PROGRESS_MONITOR_HPP_020105GER + diff --git a/cpp/BoostParts/boost/test/results_collector.hpp b/cpp/BoostParts/boost/test/results_collector.hpp new file mode 100644 index 00000000..a56b4dbf --- /dev/null +++ b/cpp/BoostParts/boost/test/results_collector.hpp @@ -0,0 +1,112 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines class unit_test_result that is responsible for +// gathering test results and presenting this information to end-user +// *************************************************************************** + +#ifndef BOOST_TEST_RESULTS_COLLECTOR_HPP_071894GER +#define BOOST_TEST_RESULTS_COLLECTOR_HPP_071894GER + +// Boost.Test +#include + +#include +#include + +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** first failed assertion debugger hook ************** // +// ************************************************************************** // + +namespace { +inline void first_failed_assertion() {} +} + +// ************************************************************************** // +// ************** test_results ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL test_results { +public: + test_results(); + + typedef BOOST_READONLY_PROPERTY( counter_t, (results_collector_t)(test_results)(results_collect_helper) ) counter_prop; + typedef BOOST_READONLY_PROPERTY( bool, (results_collector_t)(test_results)(results_collect_helper) ) bool_prop; + + counter_prop p_assertions_passed; + counter_prop p_assertions_failed; + counter_prop p_expected_failures; + counter_prop p_test_cases_passed; + counter_prop p_test_cases_failed; + counter_prop p_test_cases_skipped; + counter_prop p_test_cases_aborted; + bool_prop p_aborted; + bool_prop p_skipped; + + // "conclusion" methods + bool passed() const; + int result_code() const; + + // collection helper + void operator+=( test_results const& ); + + void clear(); +}; + +// ************************************************************************** // +// ************** results_collector ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL results_collector_t : public test_observer, public singleton { +public: + // test_observer interface implementation + void test_start( counter_t test_cases_amount ); + void test_finish(); + void test_aborted(); + + void test_unit_start( test_unit const& ); + void test_unit_finish( test_unit const&, unsigned long elapsed ); + void test_unit_skipped( test_unit const& ); + void test_unit_aborted( test_unit const& ); + + void assertion_result( bool passed ); + void exception_caught( execution_exception const& ); + + // results access + test_results const& results( test_unit_id ) const; + +private: + BOOST_TEST_SINGLETON_CONS( results_collector_t ); +}; + +BOOST_TEST_SINGLETON_INST( results_collector ) + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_RESULTS_COLLECTOR_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/results_reporter.hpp b/cpp/BoostParts/boost/test/results_reporter.hpp new file mode 100644 index 00000000..16f622a2 --- /dev/null +++ b/cpp/BoostParts/boost/test/results_reporter.hpp @@ -0,0 +1,88 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines class unit_test_result that is responsible for +// gathering test results and presenting this information to end-user +// *************************************************************************** + +#ifndef BOOST_TEST_RESULTS_REPORTER_HPP_021205GER +#define BOOST_TEST_RESULTS_REPORTER_HPP_021205GER + +// Boost.Test +#include +#include + +// STL +#include // for std::ostream& + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace results_reporter { + +// ************************************************************************** // +// ************** formatter interface ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL format { +public: + // Destructor + virtual ~format() {} + + virtual void results_report_start( std::ostream& ostr ) = 0; + virtual void results_report_finish( std::ostream& ostr ) = 0; + + virtual void test_unit_report_start( test_unit const&, std::ostream& ostr ) = 0; + virtual void test_unit_report_finish( test_unit const&, std::ostream& ostr ) = 0; + + virtual void do_confirmation_report( test_unit const&, std::ostream& ostr ) = 0; +}; + +// ************************************************************************** // +// ************** report configuration ************** // +// ************************************************************************** // + +BOOST_TEST_DECL void set_level( report_level ); +BOOST_TEST_DECL void set_stream( std::ostream& ); +BOOST_TEST_DECL void set_format( output_format ); +BOOST_TEST_DECL void set_format( results_reporter::format* ); + +BOOST_TEST_DECL std::ostream& get_stream(); + +// ************************************************************************** // +// ************** report initiation ************** // +// ************************************************************************** // + +BOOST_TEST_DECL void make_report( report_level l = INV_REPORT_LEVEL, test_unit_id = INV_TEST_UNIT_ID ); +inline void confirmation_report( test_unit_id id = INV_TEST_UNIT_ID ) +{ make_report( CONFIRMATION_REPORT, id ); } +inline void short_report( test_unit_id id = INV_TEST_UNIT_ID ) +{ make_report( SHORT_REPORT, id ); } +inline void detailed_report( test_unit_id id = INV_TEST_UNIT_ID ) +{ make_report( DETAILED_REPORT, id ); } + +} // namespace results_reporter + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_RESULTS_REPORTER_HPP_021205GER + diff --git a/cpp/BoostParts/boost/test/test_exec_monitor.hpp b/cpp/BoostParts/boost/test/test_exec_monitor.hpp new file mode 100644 index 00000000..348370c8 --- /dev/null +++ b/cpp/BoostParts/boost/test/test_exec_monitor.hpp @@ -0,0 +1,36 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : Entry point for the end user into the Test Execution Monitor. +// *************************************************************************** + +#ifndef BOOST_TEST_EXEC_MONITOR_HPP_071894GER +#define BOOST_TEST_EXEC_MONITOR_HPP_071894GER + +// Boost.Test +#include + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** Auto Linking ************** // +// ************************************************************************** // + +// Automatically link to the correct build variant where possible. +#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_TEST_NO_LIB) && \ + !defined(BOOST_TEST_SOURCE) && !defined(BOOST_TEST_INCLUDED) + +# define BOOST_LIB_NAME boost_test_exec_monitor +# include + +#endif // auto-linking disabled + +#endif // BOOST_TEST_EXEC_MONITOR_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/test_observer.hpp b/cpp/BoostParts/boost/test/test_observer.hpp new file mode 100644 index 00000000..0c252a11 --- /dev/null +++ b/cpp/BoostParts/boost/test/test_observer.hpp @@ -0,0 +1,65 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines abstract interface for test observer +// *************************************************************************** + +#ifndef BOOST_TEST_TEST_OBSERVER_HPP_021005GER +#define BOOST_TEST_TEST_OBSERVER_HPP_021005GER + +// Boost.Test +#include +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** test_observer ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL test_observer { +public: + // test observer interface + virtual void test_start( counter_t /* test_cases_amount */ ) {} + virtual void test_finish() {} + virtual void test_aborted() {} + + virtual void test_unit_start( test_unit const& ) {} + virtual void test_unit_finish( test_unit const&, unsigned long /* elapsed */ ) {} + virtual void test_unit_skipped( test_unit const& ) {} + virtual void test_unit_aborted( test_unit const& ) {} + + virtual void assertion_result( bool /* passed */ ) {} + virtual void exception_caught( execution_exception const& ) {} + + virtual int priority() { return 0; } + +protected: + BOOST_TEST_PROTECTED_VIRTUAL ~test_observer() {} +}; + +} // unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_TEST_OBSERVER_HPP_021005GER + diff --git a/cpp/BoostParts/boost/test/test_tools.hpp b/cpp/BoostParts/boost/test/test_tools.hpp new file mode 100644 index 00000000..b2ee9e37 --- /dev/null +++ b/cpp/BoostParts/boost/test/test_tools.hpp @@ -0,0 +1,719 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : contains definition for all test tools in test toolbox +// *************************************************************************** + +#ifndef BOOST_TEST_TEST_TOOLS_HPP_012705GER +#define BOOST_TEST_TEST_TOOLS_HPP_012705GER + +// Boost.Test +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +// Boost +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +// STL +#include // for std::size_t +#include +#include // for std::boolalpha +#include // for CHAR_BIT + +#ifdef BOOST_MSVC +# pragma warning(disable: 4127) // conditional expression is constant +#endif + +#include + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** TOOL BOX ************** // +// ************************************************************************** // + +// In macros below following argument abbreviations are used: +// P - predicate +// M - message +// S - statement +// E - exception +// L - left argument +// R - right argument +// TL - tool level +// CT - check type +// ARGS - arguments list + +#define BOOST_TEST_TOOL_IMPL( func, P, check_descr, TL, CT ) \ + ::boost::test_tools::tt_detail::func( \ + P, \ + ::boost::unit_test::lazy_ostream::instance() << check_descr, \ + BOOST_TEST_L(__FILE__), \ + static_cast(__LINE__), \ + ::boost::test_tools::tt_detail::TL, \ + ::boost::test_tools::tt_detail::CT \ +/**/ + +//____________________________________________________________________________// + +#define BOOST_CHECK_IMPL( P, check_descr, TL, CT ) \ +do { \ + BOOST_TEST_PASSPOINT(); \ + BOOST_TEST_TOOL_IMPL( check_impl, P, check_descr, TL, CT ), 0 );\ +} while( ::boost::test_tools::dummy_cond ) \ +/**/ + +//____________________________________________________________________________// + +#define BOOST_TEST_PASS_ARG_INFO( r, data, arg ) , arg, BOOST_STRINGIZE( arg ) + +#define BOOST_CHECK_WITH_ARGS_IMPL( P, check_descr, TL, CT, ARGS ) \ +do { \ + BOOST_TEST_PASSPOINT(); \ + BOOST_TEST_TOOL_IMPL( check_frwd, P, check_descr, TL, CT ) \ + BOOST_PP_SEQ_FOR_EACH( BOOST_TEST_PASS_ARG_INFO, '_', ARGS ) ); \ +} while( ::boost::test_tools::dummy_cond ) \ +/**/ + +//____________________________________________________________________________// + +#define BOOST_WARN( P ) BOOST_CHECK_IMPL( (P), BOOST_TEST_STRINGIZE( P ), WARN, CHECK_PRED ) +#define BOOST_CHECK( P ) BOOST_CHECK_IMPL( (P), BOOST_TEST_STRINGIZE( P ), CHECK, CHECK_PRED ) +#define BOOST_REQUIRE( P ) BOOST_CHECK_IMPL( (P), BOOST_TEST_STRINGIZE( P ), REQUIRE, CHECK_PRED ) + +//____________________________________________________________________________// + +#define BOOST_WARN_MESSAGE( P, M ) BOOST_CHECK_IMPL( (P), M, WARN, CHECK_MSG ) +#define BOOST_CHECK_MESSAGE( P, M ) BOOST_CHECK_IMPL( (P), M, CHECK, CHECK_MSG ) +#define BOOST_REQUIRE_MESSAGE( P, M ) BOOST_CHECK_IMPL( (P), M, REQUIRE, CHECK_MSG ) + +//____________________________________________________________________________// + +#define BOOST_ERROR( M ) BOOST_CHECK_MESSAGE( false, M ) +#define BOOST_FAIL( M ) BOOST_REQUIRE_MESSAGE( false, M ) + +//____________________________________________________________________________// + +#define BOOST_CHECK_THROW_IMPL( S, E, P, prefix, TL ) \ + try { \ + BOOST_TEST_PASSPOINT(); \ + S; \ + BOOST_CHECK_IMPL( false, "exception " BOOST_STRINGIZE( E ) " is expected", TL, CHECK_MSG ); } \ + catch( E const& ex ) { \ + ::boost::unit_test::ut_detail::ignore_unused_variable_warning( ex ); \ + BOOST_CHECK_IMPL( P, prefix BOOST_STRINGIZE( E ) " is caught", TL, CHECK_MSG ); \ + } \ +/**/ + +//____________________________________________________________________________// + +#define BOOST_WARN_THROW( S, E ) BOOST_CHECK_THROW_IMPL( S, E, true, "exception ", WARN ) +#define BOOST_CHECK_THROW( S, E ) BOOST_CHECK_THROW_IMPL( S, E, true, "exception ", CHECK ) +#define BOOST_REQUIRE_THROW( S, E ) BOOST_CHECK_THROW_IMPL( S, E, true, "exception ", REQUIRE ) + +//____________________________________________________________________________// + +#define BOOST_WARN_EXCEPTION( S, E, P ) BOOST_CHECK_THROW_IMPL( S, E, P( ex ), "incorrect exception ", WARN ) +#define BOOST_CHECK_EXCEPTION( S, E, P ) BOOST_CHECK_THROW_IMPL( S, E, P( ex ), "incorrect exception ", CHECK ) +#define BOOST_REQUIRE_EXCEPTION( S, E, P ) BOOST_CHECK_THROW_IMPL( S, E, P( ex ), "incorrect exception ", REQUIRE ) + +//____________________________________________________________________________// + +#define BOOST_CHECK_NO_THROW_IMPL( S, TL ) \ + try { \ + S; \ + BOOST_CHECK_IMPL( true, "no exceptions thrown by " BOOST_STRINGIZE( S ), TL, CHECK_MSG ); } \ + catch( ... ) { \ + BOOST_CHECK_IMPL( false, "exception thrown by " BOOST_STRINGIZE( S ), TL, CHECK_MSG ); \ + } \ +/**/ + +#define BOOST_WARN_NO_THROW( S ) BOOST_CHECK_NO_THROW_IMPL( S, WARN ) +#define BOOST_CHECK_NO_THROW( S ) BOOST_CHECK_NO_THROW_IMPL( S, CHECK ) +#define BOOST_REQUIRE_NO_THROW( S ) BOOST_CHECK_NO_THROW_IMPL( S, REQUIRE ) + +//____________________________________________________________________________// + +#define BOOST_WARN_EQUAL( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::equal_impl_frwd(), "", WARN, CHECK_EQUAL, (L)(R) ) +#define BOOST_CHECK_EQUAL( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::equal_impl_frwd(), "", CHECK, CHECK_EQUAL, (L)(R) ) +#define BOOST_REQUIRE_EQUAL( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::equal_impl_frwd(), "", REQUIRE, CHECK_EQUAL, (L)(R) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_NE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::ne_impl(), "", WARN, CHECK_NE, (L)(R) ) +#define BOOST_CHECK_NE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::ne_impl(), "", CHECK, CHECK_NE, (L)(R) ) +#define BOOST_REQUIRE_NE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::ne_impl(), "", REQUIRE, CHECK_NE, (L)(R) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_LT( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::lt_impl(), "", WARN, CHECK_LT, (L)(R) ) +#define BOOST_CHECK_LT( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::lt_impl(), "", CHECK, CHECK_LT, (L)(R) ) +#define BOOST_REQUIRE_LT( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::lt_impl(), "", REQUIRE, CHECK_LT, (L)(R) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_LE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::le_impl(), "", WARN, CHECK_LE, (L)(R) ) +#define BOOST_CHECK_LE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::le_impl(), "", CHECK, CHECK_LE, (L)(R) ) +#define BOOST_REQUIRE_LE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::le_impl(), "", REQUIRE, CHECK_LE, (L)(R) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_GT( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::gt_impl(), "", WARN, CHECK_GT, (L)(R) ) +#define BOOST_CHECK_GT( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::gt_impl(), "", CHECK, CHECK_GT, (L)(R) ) +#define BOOST_REQUIRE_GT( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::gt_impl(), "", REQUIRE, CHECK_GT, (L)(R) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_GE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::ge_impl(), "", WARN, CHECK_GE, (L)(R) ) +#define BOOST_CHECK_GE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::ge_impl(), "", CHECK, CHECK_GE, (L)(R) ) +#define BOOST_REQUIRE_GE( L, R ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::ge_impl(), "", REQUIRE, CHECK_GE, (L)(R) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_CLOSE( L, R, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_close, "", WARN, CHECK_CLOSE, \ + (L)(R)(::boost::test_tools::percent_tolerance(T)) ) +#define BOOST_CHECK_CLOSE( L, R, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_close, "", CHECK, CHECK_CLOSE, \ + (L)(R)(::boost::test_tools::percent_tolerance(T)) ) +#define BOOST_REQUIRE_CLOSE( L, R, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_close, "", REQUIRE, CHECK_CLOSE, \ + (L)(R)(::boost::test_tools::percent_tolerance(T)) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_CLOSE_FRACTION( L, R, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_close, "", WARN, CHECK_CLOSE_FRACTION, \ + (L)(R)(::boost::test_tools::fraction_tolerance(T)) ) +#define BOOST_CHECK_CLOSE_FRACTION( L, R, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_close, "", CHECK, CHECK_CLOSE_FRACTION, \ + (L)(R)(::boost::test_tools::fraction_tolerance(T)) ) +#define BOOST_REQUIRE_CLOSE_FRACTION( L, R, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_close, "", REQUIRE, CHECK_CLOSE_FRACTION, \ + (L)(R)(::boost::test_tools::fraction_tolerance(T)) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_SMALL( FPV, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_small, "", WARN, CHECK_SMALL, (FPV)(T) ) +#define BOOST_CHECK_SMALL( FPV, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_small, "", CHECK, CHECK_SMALL, (FPV)(T) ) +#define BOOST_REQUIRE_SMALL( FPV, T ) \ + BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::check_is_small, "", REQUIRE, CHECK_SMALL, (FPV)(T) ) + +//____________________________________________________________________________// + +#define BOOST_WARN_PREDICATE( P, ARGS ) \ + BOOST_CHECK_WITH_ARGS_IMPL( P, BOOST_TEST_STRINGIZE( P ), WARN, CHECK_PRED_WITH_ARGS, ARGS ) +#define BOOST_CHECK_PREDICATE( P, ARGS ) \ + BOOST_CHECK_WITH_ARGS_IMPL( P, BOOST_TEST_STRINGIZE( P ), CHECK, CHECK_PRED_WITH_ARGS, ARGS ) +#define BOOST_REQUIRE_PREDICATE( P, ARGS ) \ + BOOST_CHECK_WITH_ARGS_IMPL( P, BOOST_TEST_STRINGIZE( P ), REQUIRE, CHECK_PRED_WITH_ARGS, ARGS ) + +//____________________________________________________________________________// + +#define BOOST_EQUAL_COLLECTIONS_IMPL( L_begin, L_end, R_begin, R_end, TL ) \ + BOOST_TEST_TOOL_IMPL( check_impl, ::boost::test_tools::tt_detail::equal_coll_impl( \ + (L_begin), (L_end), (R_begin), (R_end) ), "", TL, CHECK_EQUAL_COLL ), \ + 4, \ + BOOST_STRINGIZE( L_begin ), BOOST_STRINGIZE( L_end ), \ + BOOST_STRINGIZE( R_begin ), BOOST_STRINGIZE( R_end ) ) \ +/**/ + +#define BOOST_WARN_EQUAL_COLLECTIONS( L_begin, L_end, R_begin, R_end ) \ + BOOST_EQUAL_COLLECTIONS_IMPL( L_begin, L_end, R_begin, R_end, WARN ) +#define BOOST_CHECK_EQUAL_COLLECTIONS( L_begin, L_end, R_begin, R_end ) \ + BOOST_EQUAL_COLLECTIONS_IMPL( L_begin, L_end, R_begin, R_end, CHECK ) +#define BOOST_REQUIRE_EQUAL_COLLECTIONS( L_begin, L_end, R_begin, R_end ) \ + BOOST_EQUAL_COLLECTIONS_IMPL( L_begin, L_end, R_begin, R_end, REQUIRE ) + +//____________________________________________________________________________// + +#define BOOST_BITWISE_EQUAL_IMPL( L, R, TL ) \ + BOOST_TEST_TOOL_IMPL( check_impl, \ + ::boost::test_tools::tt_detail::bitwise_equal_impl( (L), (R) ), \ + "", TL, CHECK_BITWISE_EQUAL ), \ + 2, BOOST_STRINGIZE( L ), BOOST_STRINGIZE( R ) ) \ +/**/ + +#define BOOST_WARN_BITWISE_EQUAL( L, R ) BOOST_BITWISE_EQUAL_IMPL( L, R, WARN ) +#define BOOST_CHECK_BITWISE_EQUAL( L, R ) BOOST_BITWISE_EQUAL_IMPL( L, R, CHECK ) +#define BOOST_REQUIRE_BITWISE_EQUAL( L, R ) BOOST_BITWISE_EQUAL_IMPL( L, R, REQUIRE ) + +//____________________________________________________________________________// + +#define BOOST_IS_DEFINED( symb ) ::boost::test_tools::tt_detail::is_defined_impl( #symb, BOOST_STRINGIZE(= symb) ) + +//____________________________________________________________________________// + +// ***************************** // +// deprecated interface + +#define BOOST_BITWISE_EQUAL( L, R ) BOOST_CHECK_BITWISE_EQUAL( L, R ) +#define BOOST_MESSAGE( M ) BOOST_TEST_MESSAGE( M ) +#define BOOST_CHECKPOINT( M ) BOOST_TEST_CHECKPOINT( M ) + +namespace boost { + +namespace test_tools { + +typedef unit_test::const_string const_string; + +namespace { bool dummy_cond = false; } + +// ************************************************************************** // +// ************** print_log_value ************** // +// ************************************************************************** // + +template +struct print_log_value { + void operator()( std::ostream& ostr, T const& t ) + { + // avoid warning: 'boost::test_tools::::dummy_cond' defined but not used + if (::boost::test_tools::dummy_cond) {} + + typedef typename mpl::or_,is_function,is_abstract >::type cant_use_nl; + + set_precision( ostr, cant_use_nl() ); + + ostr << t; // by default print the value + } + + void set_precision( std::ostream& ostr, mpl::false_ ) + { + if( std::numeric_limits::is_specialized && std::numeric_limits::radix == 2 ) + ostr.precision( 2 + std::numeric_limits::digits * 301/1000 ); + } + + void set_precision( std::ostream&, mpl::true_ ) {} +}; + +//____________________________________________________________________________// + +#define BOOST_TEST_DONT_PRINT_LOG_VALUE( the_type ) \ +namespace boost { namespace test_tools { \ +template<> \ +struct print_log_value { \ + void operator()( std::ostream&, the_type const& ) {} \ +}; \ +}} \ +/**/ + +//____________________________________________________________________________// + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +template +struct print_log_value< T[N] > { + void operator()( std::ostream& ostr, T const* t ) + { + ostr << t; + } +}; +#endif + +//____________________________________________________________________________// + +template<> +struct BOOST_TEST_DECL print_log_value { + void operator()( std::ostream& ostr, bool t ) + { + ostr << std::boolalpha << t; + } +}; + +//____________________________________________________________________________// + +template<> +struct BOOST_TEST_DECL print_log_value { + void operator()( std::ostream& ostr, char t ); +}; + +//____________________________________________________________________________// + +template<> +struct BOOST_TEST_DECL print_log_value { + void operator()( std::ostream& ostr, unsigned char t ); +}; + +//____________________________________________________________________________// + +template<> +struct BOOST_TEST_DECL print_log_value { + void operator()( std::ostream& ostr, char const* t ); +}; + +//____________________________________________________________________________// + +template<> +struct BOOST_TEST_DECL print_log_value { + void operator()( std::ostream& ostr, wchar_t const* t ); +}; + +//____________________________________________________________________________// + +namespace tt_detail { + +// ************************************************************************** // +// ************** tools classification ************** // +// ************************************************************************** // + +enum check_type { + CHECK_PRED, + CHECK_MSG, + CHECK_EQUAL, + CHECK_NE, + CHECK_LT, + CHECK_LE, + CHECK_GT, + CHECK_GE, + CHECK_CLOSE, + CHECK_CLOSE_FRACTION, + CHECK_SMALL, + CHECK_BITWISE_EQUAL, + CHECK_PRED_WITH_ARGS, + CHECK_EQUAL_COLL +}; + +enum tool_level { + WARN, CHECK, REQUIRE, PASS +}; + +// ************************************************************************** // +// ************** print_helper ************** // +// ************************************************************************** // +// Adds level of indirection to the output operation, allowing us to customize +// it for types that do not support operator << directly or for any other reason + +template +struct print_helper_t { + explicit print_helper_t( T const& t ) : m_t( t ) {} + + T const& m_t; +}; + +//____________________________________________________________________________// + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +// Borland suffers premature pointer decay passing arrays by reference +template +struct print_helper_t< T[N] > { + explicit print_helper_t( T const * t ) : m_t( t ) {} + + T const * m_t; +}; +#endif + +//____________________________________________________________________________// + +template +inline print_helper_t print_helper( T const& t ) +{ + return print_helper_t( t ); +} + +//____________________________________________________________________________// + +template +inline std::ostream& +operator<<( std::ostream& ostr, print_helper_t const& ph ) +{ + print_log_value()( ostr, ph.m_t ); + + return ostr; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** TOOL BOX Implementation ************** // +// ************************************************************************** // + +BOOST_TEST_DECL +bool check_impl( predicate_result const& pr, ::boost::unit_test::lazy_ostream const& check_descr, + const_string file_name, std::size_t line_num, + tool_level tl, check_type ct, + std::size_t num_args, ... ); + +//____________________________________________________________________________// + +#define TEMPL_PARAMS( z, m, dummy ) , typename BOOST_JOIN( Arg, m ) +#define FUNC_PARAMS( z, m, dummy ) \ + , BOOST_JOIN( Arg, m ) const& BOOST_JOIN( arg, m ) \ + , char const* BOOST_JOIN( BOOST_JOIN( arg, m ), _descr ) \ +/**/ + +#define PRED_PARAMS( z, m, dummy ) BOOST_PP_COMMA_IF( m ) BOOST_JOIN( arg, m ) + +#define ARG_INFO( z, m, dummy ) \ + , BOOST_JOIN( BOOST_JOIN( arg, m ), _descr ) \ + , &static_cast(unit_test::lazy_ostream::instance() \ + << ::boost::test_tools::tt_detail::print_helper( BOOST_JOIN( arg, m ) )) \ +/**/ + +#define IMPL_FRWD( z, n, dummy ) \ +template \ +inline bool \ +check_frwd( Pred P, unit_test::lazy_ostream const& check_descr, \ + const_string file_name, std::size_t line_num, \ + tool_level tl, check_type ct \ + BOOST_PP_REPEAT_ ## z( BOOST_PP_ADD( n, 1 ), FUNC_PARAMS, _ ) \ +) \ +{ \ + return \ + check_impl( P( BOOST_PP_REPEAT_ ## z( BOOST_PP_ADD( n, 1 ), PRED_PARAMS, _ ) ), \ + check_descr, file_name, line_num, tl, ct, \ + BOOST_PP_ADD( n, 1 ) \ + BOOST_PP_REPEAT_ ## z( BOOST_PP_ADD( n, 1 ), ARG_INFO, _ ) \ + ); \ +} \ +/**/ + +#ifndef BOOST_TEST_MAX_PREDICATE_ARITY +#define BOOST_TEST_MAX_PREDICATE_ARITY 5 +#endif + +BOOST_PP_REPEAT( BOOST_TEST_MAX_PREDICATE_ARITY, IMPL_FRWD, _ ) + +#undef TEMPL_PARAMS +#undef FUNC_PARAMS +#undef PRED_INFO +#undef ARG_INFO +#undef IMPL_FRWD + +//____________________________________________________________________________// + +template +predicate_result equal_impl( Left const& left, Right const& right ) +{ + return left == right; +} + +//____________________________________________________________________________// + +predicate_result BOOST_TEST_DECL equal_impl( char const* left, char const* right ); +inline predicate_result equal_impl( char* left, char const* right ) { return equal_impl( static_cast(left), static_cast(right) ); } +inline predicate_result equal_impl( char const* left, char* right ) { return equal_impl( static_cast(left), static_cast(right) ); } +inline predicate_result equal_impl( char* left, char* right ) { return equal_impl( static_cast(left), static_cast(right) ); } + +#if !defined( BOOST_NO_CWCHAR ) +predicate_result BOOST_TEST_DECL equal_impl( wchar_t const* left, wchar_t const* right ); +inline predicate_result equal_impl( wchar_t* left, wchar_t const* right ) { return equal_impl( static_cast(left), static_cast(right) ); } +inline predicate_result equal_impl( wchar_t const* left, wchar_t* right ) { return equal_impl( static_cast(left), static_cast(right) ); } +inline predicate_result equal_impl( wchar_t* left, wchar_t* right ) { return equal_impl( static_cast(left), static_cast(right) ); } +#endif + +//____________________________________________________________________________// + +struct equal_impl_frwd { + template + inline predicate_result + call_impl( Left const& left, Right const& right, mpl::false_ ) const + { + return equal_impl( left, right ); + } + + template + inline predicate_result + call_impl( Left const& left, Right const& right, mpl::true_ ) const + { + return (*this)( right, &left[0] ); + } + + template + inline predicate_result + operator()( Left const& left, Right const& right ) const + { + typedef typename is_array::type left_is_array; + return call_impl( left, right, left_is_array() ); + } +}; + +//____________________________________________________________________________// + +struct ne_impl { + template + predicate_result operator()( Left const& left, Right const& right ) + { + return !equal_impl_frwd()( left, right ); + } +}; + +//____________________________________________________________________________// + +struct lt_impl { + template + predicate_result operator()( Left const& left, Right const& right ) + { + return left < right; + } +}; + +//____________________________________________________________________________// + +struct le_impl { + template + predicate_result operator()( Left const& left, Right const& right ) + { + return left <= right; + } +}; + +//____________________________________________________________________________// + +struct gt_impl { + template + predicate_result operator()( Left const& left, Right const& right ) + { + return left > right; + } +}; + +//____________________________________________________________________________// + +struct ge_impl { + template + predicate_result operator()( Left const& left, Right const& right ) + { + return left >= right; + } +}; + +//____________________________________________________________________________// + +template +inline predicate_result +equal_coll_impl( Left left_begin, Left left_end, Right right_begin, Right right_end ) +{ + predicate_result res( true ); + std::size_t pos = 0; + + for( ; left_begin != left_end && right_begin != right_end; ++left_begin, ++right_begin, ++pos ) { + if( *left_begin != *right_begin ) { + res = false; + res.message() << "\nMismatch in a position " << pos << ": " << *left_begin << " != " << *right_begin; + } + } + + if( left_begin != left_end ) { + std::size_t r_size = pos; + while( left_begin != left_end ) { + ++pos; + ++left_begin; + } + + res = false; + res.message() << "\nCollections size mismatch: " << pos << " != " << r_size; + } + + if( right_begin != right_end ) { + std::size_t l_size = pos; + while( right_begin != right_end ) { + ++pos; + ++right_begin; + } + + res = false; + res.message() << "\nCollections size mismatch: " << l_size << " != " << pos; + } + + return res; +} + +//____________________________________________________________________________// + +template +inline predicate_result +bitwise_equal_impl( Left const& left, Right const& right ) +{ + predicate_result res( true ); + + std::size_t left_bit_size = sizeof(Left)*CHAR_BIT; + std::size_t right_bit_size = sizeof(Right)*CHAR_BIT; + + static Left const leftOne( 1 ); + static Right const rightOne( 1 ); + + std::size_t total_bits = left_bit_size < right_bit_size ? left_bit_size : right_bit_size; + + for( std::size_t counter = 0; counter < total_bits; ++counter ) { + if( ( left & ( leftOne << counter ) ) != ( right & ( rightOne << counter ) ) ) { + res = false; + res.message() << "\nMismatch in a position " << counter; + } + } + + if( left_bit_size != right_bit_size ) { + res = false; + res.message() << "\nOperands bit sizes mismatch: " << left_bit_size << " != " << right_bit_size; + } + + return res; +} + +//____________________________________________________________________________// + +bool BOOST_TEST_DECL is_defined_impl( const_string symbol_name, const_string symbol_value ); + +//____________________________________________________________________________// + +} // namespace tt_detail + +} // namespace test_tools + +namespace test_toolbox = test_tools; + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_TEST_TOOLS_HPP_012705GER diff --git a/cpp/BoostParts/boost/test/unit_test.hpp b/cpp/BoostParts/boost/test/unit_test.hpp new file mode 100644 index 00000000..69d10e09 --- /dev/null +++ b/cpp/BoostParts/boost/test/unit_test.hpp @@ -0,0 +1,66 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : Entry point for the end user into the Unit Test Framework. +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_HPP_071894GER +#define BOOST_TEST_UNIT_TEST_HPP_071894GER + +// Boost.Test +#include +#include + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** Auto Linking ************** // +// ************************************************************************** // + +#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_TEST_NO_LIB) && \ + !defined(BOOST_TEST_SOURCE) && !defined(BOOST_TEST_INCLUDED) +# define BOOST_LIB_NAME boost_unit_test_framework + +# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_TEST_DYN_LINK) +# define BOOST_DYN_LINK +# endif + +# include + +#endif // auto-linking disabled + +// ************************************************************************** // +// ************** unit_test_main ************** // +// ************************************************************************** // + +namespace boost { namespace unit_test { + +int BOOST_TEST_DECL unit_test_main( init_unit_test_func init_func, int argc, char* argv[] ); + +}} + +#if defined(BOOST_TEST_DYN_LINK) && defined(BOOST_TEST_MAIN) && !defined(BOOST_TEST_NO_MAIN) + +// ************************************************************************** // +// ************** main function for tests using dll ************** // +// ************************************************************************** // + +int BOOST_TEST_CALL_DECL +main( int argc, char* argv[] ) +{ + return ::boost::unit_test::unit_test_main( &init_unit_test, argc, argv ); +} + +//____________________________________________________________________________// + +#endif // BOOST_TEST_DYN_LINK && BOOST_TEST_MAIN && !BOOST_TEST_NO_MAIN + +#endif // BOOST_TEST_UNIT_TEST_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/unit_test_log.hpp b/cpp/BoostParts/boost/test/unit_test_log.hpp new file mode 100644 index 00000000..fe76eb67 --- /dev/null +++ b/cpp/BoostParts/boost/test/unit_test_log.hpp @@ -0,0 +1,177 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : defines singleton class unit_test_log and all manipulators. +// unit_test_log has output stream like interface. It's implementation is +// completely hidden with pimple idiom +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_LOG_HPP_071894GER +#define BOOST_TEST_UNIT_TEST_LOG_HPP_071894GER + +// Boost.Test +#include + +#include +#include +#include + +#include +#include +#include + +// Boost +#include + +// STL +#include // for std::ostream& + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** log manipulators ************** // +// ************************************************************************** // + +namespace log { + +struct BOOST_TEST_DECL begin { + begin( const_string fn, std::size_t ln ) + : m_file_name( fn ) + , m_line_num( ln ) + {} + + const_string m_file_name; + std::size_t m_line_num; +}; + +struct end {}; + +} // namespace log + +// ************************************************************************** // +// ************** entry_value_collector ************** // +// ************************************************************************** // + +namespace ut_detail { + +class BOOST_TEST_DECL entry_value_collector { +public: + // Constructors + entry_value_collector() : m_last( true ) {} + entry_value_collector( entry_value_collector const& rhs ) : m_last( true ) { rhs.m_last = false; } + ~entry_value_collector(); + + // collection interface + entry_value_collector const& operator<<( lazy_ostream const& ) const; + entry_value_collector const& operator<<( const_string ) const; + +private: + // Data members + mutable bool m_last; +}; + +} // namespace ut_detail + +// ************************************************************************** // +// ************** unit_test_log ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL unit_test_log_t : public test_observer, public singleton { +public: + // test_observer interface implementation + void test_start( counter_t test_cases_amount ); + void test_finish(); + void test_aborted(); + + void test_unit_start( test_unit const& ); + void test_unit_finish( test_unit const&, unsigned long elapsed ); + void test_unit_skipped( test_unit const& ); + void test_unit_aborted( test_unit const& ); + + void assertion_result( bool passed ); + void exception_caught( execution_exception const& ); + + virtual int priority() { return 1; } + + // log configuration methods + void set_stream( std::ostream& ); + void set_threshold_level( log_level ); + void set_format( output_format ); + void set_formatter( unit_test_log_formatter* ); + + // test progress logging + void set_checkpoint( const_string file, std::size_t line_num, const_string msg = const_string() ); + + // entry logging + unit_test_log_t& operator<<( log::begin const& ); // begin entry + unit_test_log_t& operator<<( log::end const& ); // end entry + unit_test_log_t& operator<<( log_level ); // set entry level + unit_test_log_t& operator<<( const_string ); // log entry value + unit_test_log_t& operator<<( lazy_ostream const& ); // log entry value + + ut_detail::entry_value_collector operator()( log_level ); // initiate entry collection + +private: + bool log_entry_start(); + + BOOST_TEST_SINGLETON_CONS( unit_test_log_t ); +}; // unit_test_log_t + +BOOST_TEST_SINGLETON_INST( unit_test_log ) + +// helper macros +#define BOOST_TEST_LOG_ENTRY( ll ) \ + (::boost::unit_test::unit_test_log \ + << ::boost::unit_test::log::begin( BOOST_TEST_L(__FILE__), __LINE__ ))(ll) \ +/**/ + +} // namespace unit_test + +} // namespace boost + +// ************************************************************************** // +// ************** Unit test log interface helpers ************** // +// ************************************************************************** // + +#define BOOST_TEST_MESSAGE( M ) \ + BOOST_TEST_LOG_ENTRY( ::boost::unit_test::log_messages ) \ + << (::boost::unit_test::lazy_ostream::instance() << M) \ +/**/ + +//____________________________________________________________________________// + +#define BOOST_TEST_PASSPOINT() \ + ::boost::unit_test::unit_test_log.set_checkpoint( \ + BOOST_TEST_L(__FILE__), \ + static_cast(__LINE__) ) \ +/**/ + +//____________________________________________________________________________// + +#define BOOST_TEST_CHECKPOINT( M ) \ + ::boost::unit_test::unit_test_log.set_checkpoint( \ + BOOST_TEST_L(__FILE__), \ + static_cast(__LINE__), \ + (::boost::wrap_stringstream().ref() << M).str() ) \ +/**/ + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_LOG_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/unit_test_log_formatter.hpp b/cpp/BoostParts/boost/test/unit_test_log_formatter.hpp new file mode 100644 index 00000000..ca4b1f29 --- /dev/null +++ b/cpp/BoostParts/boost/test/unit_test_log_formatter.hpp @@ -0,0 +1,123 @@ +// (C) Copyright Gennadiy Rozental 2003-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_LOG_FORMATTER_HPP_071894GER +#define BOOST_TEST_UNIT_TEST_LOG_FORMATTER_HPP_071894GER + +// Boost.Test +#include +#include +#include + +#include + +// STL +#include +#include // for std::string + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** log_entry_data ************** // +// ************************************************************************** // + +struct BOOST_TEST_DECL log_entry_data { + log_entry_data() + { + m_file_name.reserve( 200 ); + } + + std::string m_file_name; + std::size_t m_line_num; + log_level m_level; + + void clear() + { + m_file_name.erase(); + m_line_num = 0; + m_level = log_nothing; + } +}; + +// ************************************************************************** // +// ************** checkpoint_data ************** // +// ************************************************************************** // + +struct BOOST_TEST_DECL log_checkpoint_data +{ + const_string m_file_name; + std::size_t m_line_num; + std::string m_message; + + void clear() + { + m_file_name.clear(); + m_line_num = 0; + m_message = std::string(); + } +}; + +// ************************************************************************** // +// ************** unit_test_log_formatter ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL unit_test_log_formatter { +public: + enum log_entry_types { BOOST_UTL_ET_INFO, + BOOST_UTL_ET_MESSAGE, + BOOST_UTL_ET_WARNING, + BOOST_UTL_ET_ERROR, + BOOST_UTL_ET_FATAL_ERROR }; + + // Destructor + virtual ~unit_test_log_formatter() {} + + // Formatter interface + virtual void log_start( std::ostream&, counter_t test_cases_amount ) = 0; + virtual void log_finish( std::ostream& ) = 0; + virtual void log_build_info( std::ostream& ) = 0; + + virtual void test_unit_start( std::ostream&, test_unit const& tu ) = 0; + virtual void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ) = 0; + virtual void test_unit_skipped( std::ostream&, test_unit const& ) = 0; + + virtual void log_exception( std::ostream& os, log_checkpoint_data const& cd, execution_exception const& ex ) + { + // for backward compatibility + log_exception( os, cd, ex.what() ); + } + virtual void log_exception( std::ostream&, log_checkpoint_data const&, const_string /* explanation */ ) {} + + virtual void log_entry_start( std::ostream&, log_entry_data const&, log_entry_types let ) = 0; + virtual void log_entry_value( std::ostream&, const_string value ) = 0; + virtual void log_entry_value( std::ostream&, lazy_ostream const& value ); // there is a default impl + virtual void log_entry_finish( std::ostream& ) = 0; +}; + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_LOG_FORMATTER_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/unit_test_monitor.hpp b/cpp/BoostParts/boost/test/unit_test_monitor.hpp new file mode 100644 index 00000000..0bd14946 --- /dev/null +++ b/cpp/BoostParts/boost/test/unit_test_monitor.hpp @@ -0,0 +1,69 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines specific version of execution monitor used to managed +// run unit of test cases. Translates execution exception into error level +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_MONITOR_HPP_020905GER +#define BOOST_TEST_UNIT_TEST_MONITOR_HPP_020905GER + +// Boost.Test +#include +#include +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** unit_test_monitor ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL unit_test_monitor_t : public singleton, public execution_monitor { +public: + enum error_level { + test_fail = 1, + test_ok = 0, + constructor_error = -1, + unexpected_exception = -2, + os_exception = -3, + os_timeout = -4, + fatal_error = -5, // includes both system and user + destructor_error = -6 + }; + + static bool is_critical_error( error_level e ) { return e <= fatal_error; } + + // monitor method + error_level execute_and_translate( test_case const& ); + +private: + BOOST_TEST_SINGLETON_CONS( unit_test_monitor_t ); +}; + +BOOST_TEST_SINGLETON_INST( unit_test_monitor ) + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_UNIT_TEST_MONITOR_HPP_020905GER diff --git a/cpp/BoostParts/boost/test/unit_test_suite.hpp b/cpp/BoostParts/boost/test/unit_test_suite.hpp new file mode 100644 index 00000000..3147f28d --- /dev/null +++ b/cpp/BoostParts/boost/test/unit_test_suite.hpp @@ -0,0 +1,245 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : defines Unit Test Framework public API +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_SUITE_HPP_071894GER +#define BOOST_TEST_UNIT_TEST_SUITE_HPP_071894GER + +// Boost.Test +#include +#include + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** Non-auto (explicit) test case interface ************** // +// ************************************************************************** // + +#define BOOST_TEST_CASE( test_function ) \ +boost::unit_test::make_test_case( boost::unit_test::callback0<>(test_function), BOOST_TEST_STRINGIZE( test_function ) ) +#define BOOST_CLASS_TEST_CASE( test_function, tc_instance ) \ +boost::unit_test::make_test_case((test_function), BOOST_TEST_STRINGIZE( test_function ), tc_instance ) + +// ************************************************************************** // +// ************** BOOST_TEST_SUITE ************** // +// ************************************************************************** // + +#define BOOST_TEST_SUITE( testsuite_name ) \ +( new boost::unit_test::test_suite( testsuite_name ) ) + +// ************************************************************************** // +// ************** BOOST_AUTO_TEST_SUITE ************** // +// ************************************************************************** // + +#define BOOST_AUTO_TEST_SUITE( suite_name ) \ +namespace suite_name { \ +BOOST_AUTO_TU_REGISTRAR( suite_name )( BOOST_STRINGIZE( suite_name ) ); \ +/**/ + +// ************************************************************************** // +// ************** BOOST_FIXTURE_TEST_SUITE ************** // +// ************************************************************************** // + +#define BOOST_FIXTURE_TEST_SUITE( suite_name, F ) \ +BOOST_AUTO_TEST_SUITE( suite_name ) \ +typedef F BOOST_AUTO_TEST_CASE_FIXTURE; \ +/**/ + +// ************************************************************************** // +// ************** BOOST_AUTO_TEST_SUITE_END ************** // +// ************************************************************************** // + +#define BOOST_AUTO_TEST_SUITE_END() \ +BOOST_AUTO_TU_REGISTRAR( BOOST_JOIN( end_suite, __LINE__ ) )( 1 ); \ +} \ +/**/ + +// ************************************************************************** // +// ************** BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES ************** // +// ************************************************************************** // + +#define BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES( test_name, n ) \ +struct BOOST_AUTO_TC_UNIQUE_ID( test_name ); \ + \ +static struct BOOST_JOIN( test_name, _exp_fail_num_spec ) \ +: boost::unit_test::ut_detail:: \ + auto_tc_exp_fail \ +{ \ + BOOST_JOIN( test_name, _exp_fail_num_spec )() \ + : boost::unit_test::ut_detail:: \ + auto_tc_exp_fail( n ) \ + {} \ +} BOOST_JOIN( test_name, _exp_fail_num_spec_inst ); \ + \ +/**/ + +// ************************************************************************** // +// ************** BOOST_FIXTURE_TEST_CASE ************** // +// ************************************************************************** // + +#define BOOST_FIXTURE_TEST_CASE( test_name, F ) \ +struct test_name : public F { void test_method(); }; \ + \ +static void BOOST_AUTO_TC_INVOKER( test_name )() \ +{ \ + test_name t; \ + t.test_method(); \ +} \ + \ +struct BOOST_AUTO_TC_UNIQUE_ID( test_name ) {}; \ + \ +BOOST_AUTO_TU_REGISTRAR( test_name )( \ + boost::unit_test::make_test_case( \ + &BOOST_AUTO_TC_INVOKER( test_name ), #test_name ), \ + boost::unit_test::ut_detail::auto_tc_exp_fail< \ + BOOST_AUTO_TC_UNIQUE_ID( test_name )>::instance()->value() ); \ + \ +void test_name::test_method() \ +/**/ + +// ************************************************************************** // +// ************** BOOST_AUTO_TEST_CASE ************** // +// ************************************************************************** // + +#define BOOST_AUTO_TEST_CASE( test_name ) \ +BOOST_FIXTURE_TEST_CASE( test_name, BOOST_AUTO_TEST_CASE_FIXTURE ) +/**/ + +// ************************************************************************** // +// ************** BOOST_FIXTURE_TEST_CASE_TEMPLATE ************** // +// ************************************************************************** // + +#define BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_name, type_name, TL, F ) \ +template \ +struct test_name : public F \ +{ void test_method(); }; \ + \ +struct BOOST_AUTO_TC_INVOKER( test_name ) { \ + template \ + static void run( boost::type* = 0 ) \ + { \ + test_name t; \ + t.test_method(); \ + } \ +}; \ + \ +BOOST_AUTO_TU_REGISTRAR( test_name )( \ + boost::unit_test::ut_detail::template_test_case_gen< \ + BOOST_AUTO_TC_INVOKER( test_name ),TL >( \ + BOOST_STRINGIZE( test_name ) ) ); \ + \ +template \ +void test_name::test_method() \ +/**/ + +// ************************************************************************** // +// ************** BOOST_AUTO_TEST_CASE_TEMPLATE ************** // +// ************************************************************************** // + +#define BOOST_AUTO_TEST_CASE_TEMPLATE( test_name, type_name, TL ) \ +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_name, type_name, TL, BOOST_AUTO_TEST_CASE_FIXTURE ) + +// ************************************************************************** // +// ************** BOOST_TEST_CASE_TEMPLATE ************** // +// ************************************************************************** // + +#define BOOST_TEST_CASE_TEMPLATE( name, typelist ) \ + boost::unit_test::ut_detail::template_test_case_gen( \ + BOOST_TEST_STRINGIZE( name ) ) \ +/**/ + +// ************************************************************************** // +// ************** BOOST_TEST_CASE_TEMPLATE_FUNCTION ************** // +// ************************************************************************** // + +#define BOOST_TEST_CASE_TEMPLATE_FUNCTION( name, type_name ) \ +template \ +void BOOST_JOIN( name, _impl )( boost::type* ); \ + \ +struct name { \ + template \ + static void run( boost::type* frwrd = 0 ) \ + { \ + BOOST_JOIN( name, _impl )( frwrd ); \ + } \ +}; \ + \ +template \ +void BOOST_JOIN( name, _impl )( boost::type* ) \ +/**/ + +// ************************************************************************** // +// ************** BOOST_GLOBAL_FIXURE ************** // +// ************************************************************************** // + +#define BOOST_GLOBAL_FIXTURE( F ) \ +static boost::unit_test::ut_detail::global_fixture_impl BOOST_JOIN( gf_, F ) ; \ +/**/ + +// ************************************************************************** // +// ************** BOOST_AUTO_TEST_CASE_FIXTURE ************** // +// ************************************************************************** // + +namespace boost { namespace unit_test { namespace ut_detail { + +struct nil_t {}; + +} // namespace ut_detail +} // unit_test +} // namespace boost + +// Intentionally is in global namespace, so that FIXURE_TEST_SUITE can reset it in user code. +typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE; + +// ************************************************************************** // +// ************** Auto registration facility helper macros ************** // +// ************************************************************************** // + +#define BOOST_AUTO_TU_REGISTRAR( test_name ) \ +static boost::unit_test::ut_detail::auto_test_unit_registrar BOOST_JOIN( BOOST_JOIN( test_name, _registrar ), __LINE__ ) +#define BOOST_AUTO_TC_INVOKER( test_name ) BOOST_JOIN( test_name, _invoker ) +#define BOOST_AUTO_TC_UNIQUE_ID( test_name ) BOOST_JOIN( test_name, _id ) + +// ************************************************************************** // +// ************** BOOST_TEST_MAIN ************** // +// ************************************************************************** // + +#if defined(BOOST_TEST_MAIN) + +#ifdef BOOST_TEST_ALTERNATIVE_INIT_API +bool init_unit_test() { +#else +::boost::unit_test::test_suite* +init_unit_test_suite( int, char* [] ) { +#endif + +#ifdef BOOST_TEST_MODULE + using namespace ::boost::unit_test; + assign_op( framework::master_test_suite().p_name.value, BOOST_TEST_STRINGIZE( BOOST_TEST_MODULE ).trim( "\"" ), 0 ); + +#endif + +#ifdef BOOST_TEST_ALTERNATIVE_INIT_API + return true; +} +#else + return 0; +} +#endif + +#endif + +//____________________________________________________________________________// + +#endif // BOOST_TEST_UNIT_TEST_SUITE_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/unit_test_suite_impl.hpp b/cpp/BoostParts/boost/test/unit_test_suite_impl.hpp new file mode 100644 index 00000000..993e0560 --- /dev/null +++ b/cpp/BoostParts/boost/test/unit_test_suite_impl.hpp @@ -0,0 +1,434 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : defines test_unit, test_case, test_case_results, test_suite and test_tree_visitor +// *************************************************************************** + +#ifndef BOOST_TEST_UNIT_TEST_SUITE_IMPL_HPP_071894GER +#define BOOST_TEST_UNIT_TEST_SUITE_IMPL_HPP_071894GER + +// Boost.Test +#include +#include +#include +#include +#include +#include +#include + +// Boost +#include +#include +#include +#include +#include + +// STL +#include // for typeid +#include // for std::string +#include // for std::list +#include // for std::vector + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** test_unit ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL test_unit { +public: + enum { type = tut_any }; + + // Constructor + test_unit( const_string tu_name, test_unit_type t ); + + // dependencies management + void depends_on( test_unit* tu ); + bool check_dependencies() const; + + // Public r/o properties + typedef BOOST_READONLY_PROPERTY(test_unit_id,(framework_impl)) id_t; + typedef BOOST_READONLY_PROPERTY(test_unit_id,(test_suite)) parent_id_t; + readonly_property p_type; // type for this test unit + readonly_property p_type_name; // "case"/"suite" + id_t p_id; // unique id for this test unit + parent_id_t p_parent_id; // parent test suite id + + // Public r/w properties + readwrite_property p_name; // name for this test unit + readwrite_property p_timeout; // timeout for the test unit execution + readwrite_property p_expected_failures; // number of expected failures in this test unit + mutable readwrite_property p_enabled; // enabled status for this unit + + void increase_exp_fail( unsigned num ); + +protected: + ~test_unit(); + +private: + // Data members + std::list m_dependencies; +}; + +// ************************************************************************** // +// ************** test_case_generator ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL test_unit_generator { +public: + virtual test_unit* next() const = 0; + +protected: + BOOST_TEST_PROTECTED_VIRTUAL ~test_unit_generator() {} +}; + +// ************************************************************************** // +// ************** test_case ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL test_case : public test_unit { +public: + enum { type = tut_case }; + + // Constructor + test_case( const_string tc_name, callback0<> const& test_func ); + + // Access methods + callback0<> const& test_func() const { return m_test_func; } + +private: + friend class framework_impl; + ~test_case() {} + + // BOOST_MSVC <= 1200 have problems with callback as property + // Data members + callback0<> m_test_func; +}; + +// ************************************************************************** // +// ************** test_suite ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL test_suite : public test_unit { +public: + enum { type = tut_suite }; + + // Constructor + explicit test_suite( const_string ts_name ); + + // test unit list management + void add( test_unit* tu, counter_t expected_failures = 0, unsigned timeout = 0 ); + void add( test_unit_generator const& gen, unsigned timeout = 0 ); + void remove( test_unit_id id ); + + // access methods + test_unit_id get( const_string tu_name ) const; + std::size_t size() const { return m_members.size(); } + +protected: + friend BOOST_TEST_DECL + void traverse_test_tree( test_suite const&, test_tree_visitor& ); + friend class framework_impl; + virtual ~test_suite() {} + + // Data members + std::vector m_members; +}; + +// ************************************************************************** // +// ************** master_test_suite ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL master_test_suite_t : public test_suite { +public: + master_test_suite_t() : test_suite( "Master Test Suite" ) + , argc( 0 ) + , argv( 0 ) + {} + + // Data members + int argc; + char** argv; +}; + + +// ************************************************************************** // +// ************** test_tree_visitor ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL test_tree_visitor { +public: + // test tree visitor interface + virtual void visit( test_case const& ) {} + virtual bool test_suite_start( test_suite const& ) { return true; } + virtual void test_suite_finish( test_suite const& ) {} + +protected: + BOOST_TEST_PROTECTED_VIRTUAL ~test_tree_visitor() {} +}; + +// ************************************************************************** // +// ************** traverse_test_tree ************** // +// ************************************************************************** // + +BOOST_TEST_DECL void traverse_test_tree( test_case const&, test_tree_visitor& ); +BOOST_TEST_DECL void traverse_test_tree( test_suite const&, test_tree_visitor& ); +BOOST_TEST_DECL void traverse_test_tree( test_unit_id , test_tree_visitor& ); + +//____________________________________________________________________________// + +inline void +traverse_test_tree( test_unit const& tu, test_tree_visitor& V ) +{ + if( tu.p_type == tut_case ) + traverse_test_tree( static_cast( tu ), V ); + else + traverse_test_tree( static_cast( tu ), V ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** test_case_counter ************** // +// ************************************************************************** // + +class test_case_counter : public test_tree_visitor { +public: + // Constructor + test_case_counter() : p_count( 0 ) {} + + BOOST_READONLY_PROPERTY( counter_t, (test_case_counter)) p_count; +private: + // test tree visitor interface + virtual void visit( test_case const& ); + virtual bool test_suite_start( test_suite const& ts ) { return ts.p_enabled; } +}; + +// ************************************************************************** // +// ************** test_being_aborted ************** // +// ************************************************************************** // + +struct BOOST_TEST_DECL test_being_aborted {}; + +// ************************************************************************** // +// ************** object generators ************** // +// ************************************************************************** // + +namespace ut_detail { + +BOOST_TEST_DECL std::string normalize_test_case_name( const_string tu_name ); + +template +struct user_tc_method_invoker { + typedef void (UserTestCase::*TestMethod )(); + + user_tc_method_invoker( shared_ptr inst, TestMethod test_method ) + : m_inst( inst ), m_test_method( test_method ) {} + + void operator()() { ((*m_inst).*m_test_method)(); } + + shared_ptr m_inst; + TestMethod m_test_method; +}; + +} // namespace ut_detail + +//____________________________________________________________________________// + +inline test_case* +make_test_case( callback0<> const& test_func, const_string tc_name ) +{ + return new test_case( ut_detail::normalize_test_case_name( tc_name ), test_func ); +} + +//____________________________________________________________________________// + +template +inline test_case* +make_test_case( void (UserTestCase::* test_method )(), + const_string tc_name, + boost::shared_ptr user_test_case ) +{ + return new test_case( ut_detail::normalize_test_case_name( tc_name ), + ut_detail::user_tc_method_invoker( user_test_case, test_method ) ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** auto_test_unit_registrar ************** // +// ************************************************************************** // + +namespace ut_detail { + +struct BOOST_TEST_DECL auto_test_unit_registrar +{ + // Constructors + auto_test_unit_registrar( test_case* tc, counter_t exp_fail ); + explicit auto_test_unit_registrar( const_string ts_name ); + explicit auto_test_unit_registrar( test_unit_generator const& tc_gen ); + explicit auto_test_unit_registrar( int ); + +private: + static std::list& curr_ts_store(); +}; + +//____________________________________________________________________________// + +template +struct auto_tc_exp_fail { + auto_tc_exp_fail() : m_value( 0 ) {} + + explicit auto_tc_exp_fail( unsigned v ) + : m_value( v ) + { + instance() = this; + } + + static auto_tc_exp_fail*& instance() + { + static auto_tc_exp_fail inst; + static auto_tc_exp_fail* inst_ptr = &inst; + + return inst_ptr; + } + + unsigned value() const { return m_value; } + +private: + // Data members + unsigned m_value; +}; + +//____________________________________________________________________________// + +} // namespace ut_detail + +// ************************************************************************** // +// ************** global_fixture ************** // +// ************************************************************************** // + +class BOOST_TEST_DECL global_fixture : public test_observer { +public: + // Constructor + global_fixture(); +}; + +//____________________________________________________________________________// + +namespace ut_detail { + +template +struct global_fixture_impl : public global_fixture { + // Constructor + global_fixture_impl(): m_fixure( 0 ) {} + + // test observer interface + virtual void test_start( counter_t ) { m_fixure = new F; } + virtual void test_finish() { delete m_fixure; m_fixure = 0; } + virtual void test_aborted() { delete m_fixure; m_fixure = 0; } + +private: + // Data members + F* m_fixure; +}; + +// ************************************************************************** // +// ************** test_case_template_invoker ************** // +// ************************************************************************** // + +template +class test_case_template_invoker { +public: + void operator()() { TestCaseTemplate::run( (boost::type*)0 ); } +}; + +// ************************************************************************** // +// ************** generate_test_case_4_type ************** // +// ************************************************************************** // + +template +struct generate_test_case_4_type { + explicit generate_test_case_4_type( const_string tc_name, Generator& G ) + : m_test_case_name( tc_name ) + , m_holder( G ) + {} + + template + void operator()( mpl::identity ) + { + std::string full_name; + assign_op( full_name, m_test_case_name, 0 ); + full_name += '<'; + full_name += typeid(TestType).name(); + if( boost::is_const::value ) + full_name += " const"; + full_name += '>'; + + m_holder.m_test_cases.push_back( + new test_case( full_name, test_case_template_invoker() ) ); + } + +private: + // Data members + const_string m_test_case_name; + Generator& m_holder; +}; + +// ************************************************************************** // +// ************** test_case_template ************** // +// ************************************************************************** // + +template +class template_test_case_gen : public test_unit_generator { +public: + // Constructor + template_test_case_gen( const_string tc_name ) + { + typedef generate_test_case_4_type, + TestCaseTemplate + > single_test_gen; + mpl::for_each >( single_test_gen( tc_name, *this ) ); + } + + virtual test_unit* next() const + { + if( m_test_cases.empty() ) + return 0; + + test_unit* res = m_test_cases.front(); + m_test_cases.pop_front(); + + return res; + } + + // Data members + mutable std::list m_test_cases; +}; + +//____________________________________________________________________________// + +} // namespace ut_detail + +} // unit_test + +} // namespace boost + +#include + +#endif // BOOST_TEST_UNIT_TEST_SUITE_IMPL_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/utils/algorithm.hpp b/cpp/BoostParts/boost/test/utils/algorithm.hpp new file mode 100644 index 00000000..d5c6d12c --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/algorithm.hpp @@ -0,0 +1,228 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : addition to STL algorithms +// *************************************************************************** + +#ifndef BOOST_ALGORITHM_HPP_062304GER +#define BOOST_ALGORITHM_HPP_062304GER + +#include +#include // std::find +#include // std::bind1st + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +/// @brief this algorithm search through two collections for first mismatch position that get returned as a pair +/// of iterators, first pointing to the mismatch position in first collection, second iterator in second one + +/// @param first1 - first collection begin iterator +/// @param last1 - first collection end iterator +/// @param first2 - second collection begin iterator +/// @param last2 - second collection end iterator +template +inline std::pair +mismatch( InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2 ) +{ + while( first1 != last1 && first2 != last2 && *first1 == *first2 ) { + ++first1; + ++first2; + } + + return std::pair(first1, first2); +} + +//____________________________________________________________________________// + +/// @brief this algorithm search through two collections for first mismatch position that get returned as a pair +/// of iterators, first pointing to the mismatch position in first collection, second iterator in second one. This algorithms +/// uses supplied predicate for collection elements comparison + +/// @param first1 - first collection begin iterator +/// @param last1 - first collection end iterator +/// @param first2 - second collection begin iterator +/// @param last2 - second collection end iterator +/// @param pred - predicate to be used for search +template +inline std::pair +mismatch( InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + Predicate pred ) +{ + while( first1 != last1 && first2 != last2 && pred( *first1, *first2 ) ) { + ++first1; + ++first2; + } + + return std::pair(first1, first2); +} + +//____________________________________________________________________________// + +/// @brief this algorithm search through first collection for first element that does not belong a second one + +/// @param first1 - first collection begin iterator +/// @param last1 - first collection end iterator +/// @param first2 - second collection begin iterator +/// @param last2 - second collection end iterator +template +inline ForwardIterator1 +find_first_not_of( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2 ) +{ + while( first1 != last1 ) { + if( std::find( first2, last2, *first1 ) == last2 ) + break; + ++first1; + } + + return first1; +} + +//____________________________________________________________________________// + +/// @brief this algorithm search through first collection for first element that does not satisfy binary +/// predicate in conjunction will any element in second collection + +/// @param first1 - first collection begin iterator +/// @param last1 - first collection end iterator +/// @param first2 - second collection begin iterator +/// @param last2 - second collection end iterator +/// @param pred - predicate to be used for search +template +inline ForwardIterator1 +find_first_not_of( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + Predicate pred ) +{ + while( first1 != last1 ) { + if( std::find_if( first2, last2, std::bind1st( pred, *first1 ) ) == last2 ) + break; + ++first1; + } + + return first1; +} + +//____________________________________________________________________________// + +/// @brief this algorithm search through first collection for last element that belongs to a second one + +/// @param first1 - first collection begin iterator +/// @param last1 - first collection end iterator +/// @param first2 - second collection begin iterator +/// @param last2 - second collection end iterator +template +inline BidirectionalIterator1 +find_last_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2 ) +{ + if( first1 == last1 || first2 == last2 ) + return last1; + + BidirectionalIterator1 it1 = last1; + while( --it1 != first1 && std::find( first2, last2, *it1 ) == last2 ) {} + + return it1 == first1 && std::find( first2, last2, *it1 ) == last2 ? last1 : it1; +} + +//____________________________________________________________________________// + +/// @brief this algorithm search through first collection for last element that satisfy binary +/// predicate in conjunction will at least one element in second collection + +/// @param first1 - first collection begin iterator +/// @param last1 - first collection end iterator +/// @param first2 - second collection begin iterator +/// @param last2 - second collection end iterator +/// @param pred - predicate to be used for search +template +inline BidirectionalIterator1 +find_last_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + Predicate pred ) +{ + if( first1 == last1 || first2 == last2 ) + return last1; + + BidirectionalIterator1 it1 = last1; + while( --it1 != first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ) {} + + return it1 == first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ? last1 : it1; +} + +//____________________________________________________________________________// + +/// @brief this algorithm search through first collection for last element that does not belong to a second one + +/// @param first1 - first collection begin iterator +/// @param last1 - first collection end iterator +/// @param first2 - second collection begin iterator +/// @param last2 - second collection end iterator +template +inline BidirectionalIterator1 +find_last_not_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2 ) +{ + if( first1 == last1 || first2 == last2 ) + return last1; + + BidirectionalIterator1 it1 = last1; + while( --it1 != first1 && std::find( first2, last2, *it1 ) != last2 ) {} + + return it1 == first1 && std::find( first2, last2, *it1 ) != last2 ? last1 : it1; +} + +//____________________________________________________________________________// + +/// @brief this algorithm search through first collection for last element that does not satisfy binary +/// predicate in conjunction will any element in second collection + +/// @param first1 - first collection begin iterator +/// @param last1 - first collection end iterator +/// @param first2 - second collection begin iterator +/// @param last2 - second collection end iterator +/// @param pred - predicate to be used for search +template +inline BidirectionalIterator1 +find_last_not_of( BidirectionalIterator1 first1, BidirectionalIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + Predicate pred ) +{ + if( first1 == last1 || first2 == last2 ) + return last1; + + BidirectionalIterator1 it1 = last1; + while( --it1 != first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) != last2 ) {} + + return it1 == first1 && std::find_if( first2, last2, std::bind1st( pred, *it1 ) ) == last2 ? last1 : it1; +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_ALGORITHM_HPP_062304GER + + diff --git a/cpp/BoostParts/boost/test/utils/assign_op.hpp b/cpp/BoostParts/boost/test/utils/assign_op.hpp new file mode 100644 index 00000000..1ddcf7d1 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/assign_op.hpp @@ -0,0 +1,41 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : overloadable assignment +// *************************************************************************** + +#ifndef BOOST_TEST_ASSIGN_OP_033005GER +#define BOOST_TEST_ASSIGN_OP_033005GER + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** generic assign operator ************** // +// ************************************************************************** // + +// generic +template +inline void +assign_op( T& t, S const& s, long ) +{ + t = s; +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +#endif // BOOST_TEST_ASSIGN_OP_033005GER + diff --git a/cpp/BoostParts/boost/test/utils/basic_cstring/basic_cstring.hpp b/cpp/BoostParts/boost/test/utils/basic_cstring/basic_cstring.hpp new file mode 100644 index 00000000..5589e616 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/basic_cstring/basic_cstring.hpp @@ -0,0 +1,731 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : class basic_cstring wraps C string and provide std_string like +// interface +// *************************************************************************** + +#ifndef BOOST_TEST_BASIC_CSTRING_HPP_071894GER +#define BOOST_TEST_BASIC_CSTRING_HPP_071894GER + +// Boost.Test +#include +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** basic_cstring ************** // +// ************************************************************************** // + +template +class basic_cstring { + typedef basic_cstring self_type; +public: + // Subtypes + typedef ut_detail::bcs_char_traits traits_type; + typedef typename ut_detail::bcs_char_traits::std_string std_string; + + typedef CharT value_type; + typedef value_type* pointer; + typedef value_type const* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef value_type const* const_iterator; + typedef value_type* iterator; + + // !! should also present reverse_iterator, const_reverse_iterator + +#if !BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) + enum npos_type { npos = static_cast(-1) }; +#else + // IBM/VisualAge version 6 is not able to handle enums larger than 4 bytes. + // But size_type is 8 bytes in 64bit mode. + static const size_type npos = -1 ; +#endif + + static pointer null_str(); + + // Constructors; default copy constructor is generated by compiler + basic_cstring(); + basic_cstring( std_string const& s ); + basic_cstring( pointer s ); + basic_cstring( pointer s, size_type arg_size ); + basic_cstring( pointer first, pointer last ); + + // data access methods + value_type operator[]( size_type index ) const; + value_type at( size_type index ) const; + + // size operators + size_type size() const; + bool is_empty() const; + void clear(); + void resize( size_type new_len ); + + // !! only for STL container conformance use is_empty instead + bool empty() const; + + // Trimming + self_type& trim_right( size_type trim_size ); + self_type& trim_left( size_type trim_size ); + self_type& trim_right( iterator it ); + self_type& trim_left( iterator it ); +#ifndef __IBMCPP__ + self_type& trim_left( self_type exclusions = self_type() ) ; + self_type& trim_right( self_type exclusions = self_type() ) ; + self_type& trim( self_type exclusions = self_type() ) ; +#else + // VisualAge version 6 has in this case a problem with the default arguments. + self_type& trim_left( self_type exclusions ) ; + self_type& trim_right( self_type exclusions ) ; + self_type& trim( self_type exclusions ) ; + self_type& trim_left() { trim_left( self_type() ) ; } + self_type& trim_right() { trim_right( self_type() ) ; } + self_type& trim() { trim( self_type() ) ; } +#endif + + // Assignment operators + basic_cstring& operator=( self_type const& s ); + basic_cstring& operator=( std_string const& s ); + basic_cstring& operator=( pointer s ); + + template + basic_cstring& assign( basic_cstring const& s ) { *this = basic_cstring( s.begin(), s.end() ); return *this; } + basic_cstring& assign( self_type const& s, size_type pos, size_type len ); + basic_cstring& assign( std_string const& s ); + basic_cstring& assign( std_string const& s, size_type pos, size_type len ); + basic_cstring& assign( pointer s ); + basic_cstring& assign( pointer s, size_type len ); + basic_cstring& assign( pointer f, pointer l ); + + // swapping + void swap( self_type& s ); + + // Iterators + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + // !! should have rbegin, rend + + // substring search operation + size_type find( basic_cstring ) const; + size_type rfind( basic_cstring ) const; + self_type substr( size_type beg_index, size_type end_index = npos ) const; + +private: + static self_type default_trim_ex(); + + // Data members + iterator m_begin; + iterator m_end; +}; + +//____________________________________________________________________________// + +template +inline typename basic_cstring::pointer +basic_cstring::null_str() +{ + static CharT null = 0; + return &null; +} + +//____________________________________________________________________________// + +template +inline +basic_cstring::basic_cstring() +: m_begin( null_str() ) +, m_end( m_begin ) +{ +} + +//____________________________________________________________________________// + +template +inline +basic_cstring::basic_cstring( std_string const& s ) +: m_begin( s.c_str() ) +, m_end( m_begin + s.size() ) +{ +} + +//____________________________________________________________________________// + +template +inline +basic_cstring::basic_cstring( pointer s ) +: m_begin( s ? s : null_str() ) +, m_end ( m_begin + (s ? traits_type::length( s ) : 0 ) ) +{ +} + +//____________________________________________________________________________// + +template +inline +basic_cstring::basic_cstring( pointer s, size_type arg_size ) +: m_begin( s ), m_end( m_begin + arg_size ) +{ +} + +//____________________________________________________________________________// + +template +inline +basic_cstring::basic_cstring( pointer first, pointer last ) +: m_begin( first ) +, m_end( last ) +{ +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::value_type +basic_cstring::operator[]( size_type index ) const +{ + return m_begin[index]; +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::value_type +basic_cstring::at( size_type index ) const +{ + if( m_begin + index >= m_end ) + return static_cast(0); + + return m_begin[index]; +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::size_type +basic_cstring::size() const +{ + return m_end - m_begin; +} + +//____________________________________________________________________________// + +template +inline bool +basic_cstring::is_empty() const +{ + return m_end == m_begin; +} + +//____________________________________________________________________________// + +template +inline bool +basic_cstring::empty() const +{ + return is_empty(); +} + +//____________________________________________________________________________// + +template +inline void +basic_cstring::clear() +{ + m_begin = m_end; +} + +//____________________________________________________________________________// + +template +inline void +basic_cstring::resize( size_type new_len ) +{ + if( m_begin + new_len < m_end ) + m_end = m_begin + new_len; +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::trim_left( size_type trim_size ) +{ + m_begin += trim_size; + if( m_end <= m_begin ) + clear(); + + return *this; +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::trim_left( iterator it ) +{ + m_begin = it; + if( m_end <= m_begin ) + clear(); + + return *this; +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::trim_left( basic_cstring exclusions ) +{ + if( exclusions.is_empty() ) + exclusions = default_trim_ex(); + + iterator it; + for( it = begin(); it != end(); ++it ) { + if( traits_type::find( exclusions.begin(), exclusions.size(), *it ) == reinterpret_cast(0) ) + break; + } + + return trim_left( it ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::trim_right( size_type trim_size ) +{ + m_end -= trim_size; + if( m_end <= m_begin ) + clear(); + + return *this; +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::trim_right( iterator it ) +{ + m_end = it; + if( m_end <= m_begin ) + clear(); + + return *this; +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::trim_right( basic_cstring exclusions ) +{ + if( exclusions.is_empty() ) + exclusions = default_trim_ex(); + + iterator it; + + for( it = end()-1; it != begin()-1; --it ) { + if( self_type::traits_type::find( exclusions.begin(), exclusions.size(), *it ) == reinterpret_cast(0) ) + break; + } + + return trim_right( it+1 ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::trim( basic_cstring exclusions ) +{ + trim_left( exclusions ); + trim_right( exclusions ); + + return *this; +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::operator=( basic_cstring const& s ) +{ + m_begin = s.m_begin; + m_end = s.m_end; + + return *this; +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::operator=( std_string const& s ) +{ + return *this = self_type( s ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::operator=( pointer s ) +{ + return *this = self_type( s ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::assign( basic_cstring const& s, size_type pos, size_type len ) +{ + return *this = self_type( s.m_begin + pos, len ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::assign( std_string const& s ) +{ + return *this = self_type( s ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::assign( std_string const& s, size_type pos, size_type len ) +{ + return *this = self_type( s.c_str() + pos, len ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::assign( pointer s ) +{ + return *this = self_type( s ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::assign( pointer s, size_type len ) +{ + return *this = self_type( s, len ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring& +basic_cstring::assign( pointer f, pointer l ) +{ + return *this = self_type( f, l ); +} + +//____________________________________________________________________________// + +template +inline void +basic_cstring::swap( basic_cstring& s ) +{ + // do not want to include alogrithm + pointer tmp1 = m_begin; + pointer tmp2 = m_end; + + m_begin = s.m_begin; + m_end = s.m_end; + + s.m_begin = tmp1; + s.m_end = tmp2; +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::iterator +basic_cstring::begin() +{ + return m_begin; +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::const_iterator +basic_cstring::begin() const +{ + return m_begin; +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::iterator +basic_cstring::end() +{ + return m_end; +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::const_iterator +basic_cstring::end() const +{ + return m_end; +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::size_type +basic_cstring::find( basic_cstring str ) const +{ + if( str.is_empty() || str.size() > size() ) + return static_cast(npos); + + const_iterator it = begin(); + const_iterator last = end() - str.size() + 1; + + while( it != last ) { + if( traits_type::compare( it, str.begin(), str.size() ) == 0 ) + break; + + ++it; + } + + return it == last ? static_cast(npos) : it - begin(); +} + +//____________________________________________________________________________// + +template +inline typename basic_cstring::size_type +basic_cstring::rfind( basic_cstring str ) const +{ + if( str.is_empty() || str.size() > size() ) + return static_cast(npos); + + const_iterator it = end() - str.size(); + const_iterator last = begin()-1; + + while( it != last ) { + if( traits_type::compare( it, str.begin(), str.size() ) == 0 ) + break; + + --it; + } + + return it == last ? static_cast(npos) : static_cast(it - begin()); +} + +//____________________________________________________________________________// + +template +inline basic_cstring +basic_cstring::substr( size_type beg_index, size_type end_index ) const +{ + return beg_index > size() + ? self_type() + : end_index > size() + ? self_type( m_begin + beg_index, m_end ) + : self_type( m_begin + beg_index, m_begin + end_index ); +} + +//____________________________________________________________________________// + +template +inline basic_cstring +basic_cstring::default_trim_ex() +{ + static CharT ws[3] = { CharT(' '), CharT('\t'), CharT('\n') }; // !! wide case + + return self_type( ws, 3 ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** comparison operators ************** // +// ************************************************************************** // + +template +inline bool +operator==( basic_cstring const& s1, basic_cstring const& s2 ) +{ + typedef typename basic_cstring::traits_type traits_type; + return s1.size() == s2.size() && + traits_type::compare( s1.begin(), s2.begin(), s1.size() ) == 0; +} + +//____________________________________________________________________________// + +template +inline bool +operator==( basic_cstring const& s1, CharT2* s2 ) +{ +#if !defined(__DMC__) + return s1 == basic_cstring( s2 ); +#else + return s1 == basic_cstring( s2 ); +#endif +} + +//____________________________________________________________________________// + +template +inline bool +operator==( basic_cstring const& s1, typename basic_cstring::std_string const& s2 ) +{ + return s1 == basic_cstring( s2 ); +} + +//____________________________________________________________________________// + +template +inline bool +operator==( CharT1* s2, basic_cstring const& s1 ) +{ + return s1 == s2; +} + +//____________________________________________________________________________// + +template +inline bool +operator==( typename basic_cstring::std_string const& s2, basic_cstring const& s1 ) +{ + return s1 == s2; +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( basic_cstring const& s1, CharT* s2 ) +{ + return !(s1 == s2); +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( CharT* s2, basic_cstring const& s1 ) +{ + return !(s1 == s2); +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( basic_cstring const& s1, basic_cstring const& s2 ) +{ + return !(s1 == s2); +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( basic_cstring const& s1, typename basic_cstring::std_string const& s2 ) +{ + return !(s1 == s2); +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( typename basic_cstring::std_string const& s2, basic_cstring const& s1 ) +{ + return !(s1 == s2); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** first_char ************** // +// ************************************************************************** // + +template +inline typename basic_cstring::value_type +first_char( basic_cstring source ) +{ + typedef typename basic_cstring::value_type string_value_type; + + return source.is_empty() ? static_cast(0) : *source.begin(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** last_char ************** // +// ************************************************************************** // + +template +inline typename basic_cstring::value_type +last_char( basic_cstring source ) +{ + typedef typename basic_cstring::value_type string_value_type; + + return source.is_empty() ? static_cast(0) : *(source.end()-1); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** assign_op ************** // +// ************************************************************************** // + +template +inline void +assign_op( std::basic_string& target, basic_cstring src, int ) +{ + target.assign( src.begin(), src.size() ); +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_BASIC_CSTRING_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/utils/basic_cstring/basic_cstring_fwd.hpp b/cpp/BoostParts/boost/test/utils/basic_cstring/basic_cstring_fwd.hpp new file mode 100644 index 00000000..e89456c2 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/basic_cstring/basic_cstring_fwd.hpp @@ -0,0 +1,40 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : basic_cstring class wrap C string and provide std_string like +// interface +// *************************************************************************** + +#ifndef BOOST_TEST_BASIC_CSTRING_FWD_HPP_071894GER +#define BOOST_TEST_BASIC_CSTRING_FWD_HPP_071894GER + +#include + +namespace boost { + +namespace unit_test { + +template class basic_cstring; +typedef basic_cstring const_string; +#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590041)) +typedef const_string literal_string; +#else +typedef const_string const literal_string; +#endif + +typedef char const* const c_literal_string; + +} // namespace unit_test + +} // namespace boost + +#endif // BOOST_TEST_BASIC_CSTRING_FWD_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/utils/basic_cstring/bcs_char_traits.hpp b/cpp/BoostParts/boost/test/utils/basic_cstring/bcs_char_traits.hpp new file mode 100644 index 00000000..f932d473 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/basic_cstring/bcs_char_traits.hpp @@ -0,0 +1,150 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : generic char traits class; wraps std::char_traits +// *************************************************************************** + +#ifndef BOOST_TEST_BCS_CHAR_TRAITS_HPP_071894GER +#define BOOST_TEST_BCS_CHAR_TRAITS_HPP_071894GER + +// Boost +#include +#include +#include +#include + +// STL +#include // std::char_traits +#include // std::size_t + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace ut_detail { + +template struct bcs_base_char { typedef CharT type; }; + +template<> struct bcs_base_char { typedef char type; }; +template<> struct bcs_base_char { typedef char type; }; +#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) +template<> struct bcs_base_char { typedef char type; }; +#endif + +template<> struct bcs_base_char { typedef wchar_t type; }; + +// ************************************************************************** // +// ************** bcs_char_traits ************** // +// ************************************************************************** // + +template +struct bcs_char_traits_impl +{ +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + typedef CharT const const_char; +#else + typedef typename boost::add_const::type const_char; +#endif + static bool eq( CharT c1, CharT c2 ) + { + return c1 == c2; + } + static bool lt( CharT c1, CharT c2 ) + { + return c1 < c2; + } + + static int compare( const_char* cstr1, const_char* cstr2, std::size_t n ) + { + while( n > 0 ) { + if( !eq( *cstr1, *cstr2 ) ) + return lt( *cstr1, *cstr2 ) ? -1 : 1; + ++cstr1; + ++cstr2; + --n; + } + + return 0; + } + + static std::size_t length( const_char* cstr ) + { + const_char null_char = CharT(); + + const_char* ptr = cstr; + while( !eq( *ptr, null_char ) ) + ++ptr; + + return ptr - cstr; + } + + static const_char* find( const_char* s, std::size_t n, CharT c ) + { + while( n > 0 ) { + if( eq( *s, c ) ) + return s; + + ++s; + --n; + } + return 0; + } +}; + +#ifdef BOOST_CLASSIC_IOSTREAMS +template +struct char_traits_with_find : std::string_char_traits { + static CharT const* find( CharT const* s, std::size_t n, CharT c ) + { + while( n > 0 ) { + if( eq( *s, c ) ) + return s; + + ++s; + --n; + } + return 0; + } +}; + +template<> struct bcs_char_traits_impl : char_traits_with_find {}; +template<> struct bcs_char_traits_impl : char_traits_with_find {}; +#else +template<> struct bcs_char_traits_impl : std::char_traits {}; +template<> struct bcs_char_traits_impl : std::char_traits {}; +#endif + +template +class bcs_char_traits : public bcs_char_traits_impl { + typedef typename ut_detail::bcs_base_char::type the_base_char; +public: +#ifdef BOOST_CLASSIC_IOSTREAMS + typedef std::basic_string > std_string; +#else + typedef std::basic_string > std_string; +#endif +}; + +} // namespace ut_detail + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_BCS_CHAR_TRAITS_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/utils/basic_cstring/compare.hpp b/cpp/BoostParts/boost/test/utils/basic_cstring/compare.hpp new file mode 100644 index 00000000..8866c44c --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/basic_cstring/compare.hpp @@ -0,0 +1,115 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : class basic_cstring comparisons implementation +// *************************************************************************** + +#ifndef BOOST_TEST_BASIC_CSTRING_COMPARE_HPP_071894GER +#define BOOST_TEST_BASIC_CSTRING_COMPARE_HPP_071894GER + +// Boost.Test +#include + +// STL +#include +#include + +#include + +//____________________________________________________________________________// + +# if defined(BOOST_NO_STDC_NAMESPACE) && !BOOST_WORKAROUND(__BORLANDC__, <= 0x570) +namespace std { using ::toupper; } +# endif + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** case_ins_compare ************** // +// ************************************************************************** // + +namespace ut_detail { + +template +struct case_ins +{ + static bool eq( CharT c1, CharT c2 ) { return (std::toupper)( c1 ) == (std::toupper)( c2 ); } + static bool lt( CharT c1, CharT c2 ) { return (std::toupper)( c1 ) < (std::toupper)( c2 ); } + + static int compare( CharT const* s1, CharT const* s2, std::size_t n ) + { + for( std::size_t i = 0; i < n; ++i ) { + if( !eq( s1[i], s2[i] ) ) + return lt( s1[i], s2[i] ) ? -1 : 1; + } + return 0; + } +}; + +} // namespace ut_detail + +// ************************************************************************** // +// ************** case_ins_eq ************** // +// ************************************************************************** // + +template +inline bool +case_ins_eq( basic_cstring x, basic_cstring y ) +{ + return x.size() == y.size() && ut_detail::case_ins::compare( x.begin(), y.begin(), x.size() ) == 0; +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** case_ins_less ************** // +// ************************************************************************** // + +template +class case_ins_less : public std::binary_function,basic_cstring,bool> +{ +public: + bool operator()( basic_cstring x, basic_cstring y ) const + { + return x.size() != y.size() + ? x.size() < y.size() + : ut_detail::case_ins::compare( x.begin(), y.begin(), x.size() ) < 0; + } +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** operator < ************** // +// ************************************************************************** // + +template +inline bool +operator <( boost::unit_test::basic_cstring const& x, + boost::unit_test::basic_cstring const& y ) +{ + typedef typename boost::unit_test::basic_cstring::traits_type traits_type; + return x.size() != y.size() + ? x.size() < y.size() + : traits_type::compare( x.begin(), y.begin(), x.size() ) < 0; +} + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_BASIC_CSTRING_COMPARE_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/utils/basic_cstring/io.hpp b/cpp/BoostParts/boost/test/utils/basic_cstring/io.hpp new file mode 100644 index 00000000..04e4b4c2 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/basic_cstring/io.hpp @@ -0,0 +1,73 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : basic_cstring i/o implementation +// *************************************************************************** + +#ifndef BOOST_TEST_BASIC_CSTRING_IO_HPP_071894GER +#define BOOST_TEST_BASIC_CSTRING_IO_HPP_071894GER + +// Boost.Test +#include + +// STL +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +#ifdef BOOST_CLASSIC_IOSTREAMS + +template +inline std::ostream& +operator<<( std::ostream& os, basic_cstring const& str ) +{ + typedef typename ut_detail::bcs_base_char::type char_type; + char_type const* const beg = reinterpret_cast( str.begin() ); + char_type const* const end = reinterpret_cast( str.end() ); + os << std::basic_string( beg, end - beg ); + + return os; +} + +#else + +template +inline std::basic_ostream& +operator<<( std::basic_ostream& os, basic_cstring const& str ) +{ + CharT1 const* const beg = reinterpret_cast( str.begin() ); // !! + CharT1 const* const end = reinterpret_cast( str.end() ); + os << std::basic_string( beg, end - beg ); + + return os; +} + +#endif + +//____________________________________________________________________________// + + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_BASIC_CSTRING_IO_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/utils/callback.hpp b/cpp/BoostParts/boost/test/utils/callback.hpp new file mode 100644 index 00000000..bd7d3e12 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/callback.hpp @@ -0,0 +1,310 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : +// *************************************************************************** + +#ifndef BOOST_TEST_CALLBACK_020505GER +#define BOOST_TEST_CALLBACK_020505GER + +// Boost +#include +#include +#include + +#include + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) || BOOST_WORKAROUND(BOOST_INTEL, <= 700) +# define BOOST_CALLBACK_EXPLICIT_COPY_CONSTRUCTOR +#endif + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace ut_detail { + +struct unused {}; + +template +struct invoker { + template + R invoke( Functor& f ) { return f(); } + template + R invoke( Functor& f, T1 t1 ) { return f( t1 ); } + template + R invoke( Functor& f, T1 t1, T2 t2 ) { return f( t1, t2 ); } + template + R invoke( Functor& f, T1 t1, T2 t2, T3 t3 ) { return f( t1, t2, t3 ); } +}; + +//____________________________________________________________________________// + +template<> +struct invoker { + template + unused invoke( Functor& f ) { f(); return unused(); } + template + unused invoke( Functor& f, T1 t1 ) { f( t1 ); return unused(); } + template + unused invoke( Functor& f, T1 t1, T2 t2 ) { f( t1, t2 ); return unused(); } + template + unused invoke( Functor& f, T1 t1, T2 t2, T3 t3 ) { f( t1, t2, t3 ); return unused(); } +}; + +//____________________________________________________________________________// + +} // namespace ut_detail + +// ************************************************************************** // +// ************** unit_test::callback0 ************** // +// ************************************************************************** // + +namespace ut_detail { + +template +struct callback0_impl { + virtual ~callback0_impl() {} + + virtual R invoke() = 0; +}; + +//____________________________________________________________________________// + +template +struct callback0_impl_t : callback0_impl { + // Constructor + explicit callback0_impl_t( Functor f ) : m_f( f ) {} + + virtual R invoke() { return invoker().invoke( m_f ); } + +private: + // Data members + Functor m_f; +}; + +//____________________________________________________________________________// + +} // namespace ut_detail + +template +class callback0 { +public: + // Constructors + callback0() {} +#ifdef BOOST_CALLBACK_EXPLICIT_COPY_CONSTRUCTOR + callback0( callback0 const& rhs ) : m_impl( rhs.m_impl ) {} +#endif + + template + callback0( Functor f ) + : m_impl( new ut_detail::callback0_impl_t( f ) ) {} + + void operator=( callback0 const& rhs ) { m_impl = rhs.m_impl; } + + template + void operator=( Functor f ) { m_impl.reset( new ut_detail::callback0_impl_t( f ) ); } + + R operator()() const { return m_impl->invoke(); } + + bool operator!() const { return !m_impl; } + +private: + // Data members + boost::shared_ptr > m_impl; +}; + +// ************************************************************************** // +// ************** unit_test::callback1 ************** // +// ************************************************************************** // + +namespace ut_detail { + +template +struct callback1_impl { + virtual ~callback1_impl() {} + + virtual R invoke( T1 t1 ) = 0; +}; + +//____________________________________________________________________________// + +template +struct callback1_impl_t : callback1_impl { + // Constructor + explicit callback1_impl_t( Functor f ) : m_f( f ) {} + + virtual R invoke( T1 t1 ) { return invoker().invoke( m_f, t1 ); } + +private: + // Data members + Functor m_f; +}; + +//____________________________________________________________________________// + +} // namespace ut_detail + +template +class callback1 { +public: + // Constructors + callback1() {} +#ifdef BOOST_CALLBACK_EXPLICIT_COPY_CONSTRUCTOR + callback1( callback1 const& rhs ) : m_impl( rhs.m_impl ) {} +#endif + + template + callback1( Functor f ) + : m_impl( new ut_detail::callback1_impl_t( f ) ) {} + + void operator=( callback1 const& rhs ) { m_impl = rhs.m_impl; } + + template + void operator=( Functor f ) { m_impl.reset( new ut_detail::callback1_impl_t( f ) ); } + + R operator()( T1 t1 ) const { return m_impl->invoke( t1 ); } + + bool operator!() const { return !m_impl; } + +private: + // Data members + boost::shared_ptr > m_impl; +}; + +// ************************************************************************** // +// ************** unit_test::callback2 ************** // +// ************************************************************************** // + +namespace ut_detail { + +template +struct callback2_impl { + virtual ~callback2_impl() {} + + virtual R invoke( T1 t1, T2 t2 ) = 0; +}; + +//____________________________________________________________________________// + +template +struct callback2_impl_t : callback2_impl { + // Constructor + explicit callback2_impl_t( Functor f ) : m_f( f ) {} + + virtual R invoke( T1 t1, T2 t2 ) { return invoker().template invoke( m_f, t1, t2 ); } + +private: + // Data members + Functor m_f; +}; + +//____________________________________________________________________________// + +} // namespace ut_detail + +template +class callback2 { +public: + // Constructors + callback2() {} +#ifdef BOOST_CALLBACK_EXPLICIT_COPY_CONSTRUCTOR + callback2( callback2 const& rhs ) : m_impl( rhs.m_impl ) {} +#endif + + template + callback2( Functor f ) : m_impl( new ut_detail::callback2_impl_t( f ) ) {} + + void operator=( callback2 const& rhs ) { m_impl = rhs.m_impl; } + + template + void operator=( Functor f ) { m_impl.reset( new ut_detail::callback2_impl_t( f ) ); } + + R operator()( T1 t1, T2 t2 ) const { return m_impl->invoke( t1, t2 ); } + + bool operator!() const { return !m_impl; } + +private: + // Data members + boost::shared_ptr > m_impl; +}; + +// ************************************************************************** // +// ************** unit_test::callback3 ************** // +// ************************************************************************** // + +namespace ut_detail { + +template +struct callback3_impl { + virtual ~callback3_impl() {} + + virtual R invoke( T1 t1, T2 t2, T3 t3 ) = 0; +}; + +//____________________________________________________________________________// + +template +struct callback3_impl_t : callback3_impl { + // Constructor + explicit callback3_impl_t( Functor f ) : m_f( f ) {} + + virtual R invoke( T1 t1, T2 t2, T3 t3 ) { return invoker().invoke( m_f, t1, t2, t3 ); } + +private: + // Data members + Functor m_f; +}; + +//____________________________________________________________________________// + +} // namespace ut_detail + +template +class callback3 { +public: + // Constructors + callback3() {} +#ifdef BOOST_CALLBACK_EXPLICIT_COPY_CONSTRUCTOR + callback3( callback3 const& rhs ) : m_impl( rhs.m_impl ) {} +#endif + + template + callback3( Functor f ) + : m_impl( new ut_detail::callback3_impl_t( f ) ) {} + + void operator=( callback3 const& rhs ) { m_impl = rhs.m_impl; } + + template + void operator=( Functor f ) { m_impl.reset( new ut_detail::callback3_impl_t( f ) ); } + + R operator()( T1 t1, T2 t2, T3 t3 ) const { return m_impl->invoke( t1, t2, t3 ); } + + bool operator!() const { return !m_impl; } + +private: + // Data members + boost::shared_ptr > m_impl; +}; + +} // namespace unit_test + +} // namespace boost + +#undef BOOST_CALLBACK_EXPLICIT_COPY_CONSTRUCTOR + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_CALLBACK_020505GER diff --git a/cpp/BoostParts/boost/test/utils/class_properties.hpp b/cpp/BoostParts/boost/test/utils/class_properties.hpp new file mode 100644 index 00000000..a7842b5b --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/class_properties.hpp @@ -0,0 +1,221 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : simple facility that mimmic notion of read-only read-write +// properties in C++ classes. Original idea by Henrik Ravn. +// *************************************************************************** + +#ifndef BOOST_TEST_CLASS_PROPERTIES_HPP_071894GER +#define BOOST_TEST_CLASS_PROPERTIES_HPP_071894GER + +// Boost.Test +#include + +// Boost +#if !BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) +#include +#endif +#include +#include +#include +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** class_property ************** // +// ************************************************************************** // + +template +class class_property { +protected: + typedef typename call_traits::const_reference read_access_t; + typedef typename call_traits::param_type write_param_t; + typedef typename add_pointer::type>::type address_res_t; +public: + // Constructor + class_property() : value( PropertyType() ) {} + explicit class_property( write_param_t init_value ) + : value( init_value ) {} + + // Access methods + operator read_access_t() const { return value; } + read_access_t get() const { return value; } + bool operator!() const { return !value; } + address_res_t operator&() const { return &value; } + + // Data members +#ifndef BOOST_TEST_NO_PROTECTED_USING +protected: +#endif + PropertyType value; +}; + +//____________________________________________________________________________// + +#ifdef BOOST_CLASSIC_IOSTREAMS + +template +inline std::ostream& +operator<<( std::ostream& os, class_property const& p ) + +#else + +template +inline std::basic_ostream& +operator<<( std::basic_ostream& os, class_property const& p ) + +#endif +{ + return os << p.get(); +} + +//____________________________________________________________________________// + +#define DEFINE_PROPERTY_FREE_BINARY_OPERATOR( op ) \ +template \ +inline bool \ +operator op( PropertyType const& lhs, class_property const& rhs ) \ +{ \ + return lhs op rhs.get(); \ +} \ +template \ +inline bool \ +operator op( class_property const& lhs, PropertyType const& rhs ) \ +{ \ + return lhs.get() op rhs; \ +} \ +template \ +inline bool \ +operator op( class_property const& lhs, \ + class_property const& rhs ) \ +{ \ + return lhs.get() op rhs.get(); \ +} \ +/**/ + +DEFINE_PROPERTY_FREE_BINARY_OPERATOR( == ) +DEFINE_PROPERTY_FREE_BINARY_OPERATOR( != ) + +#undef DEFINE_PROPERTY_FREE_BINARY_OPERATOR + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) + +#define DEFINE_PROPERTY_LOGICAL_OPERATOR( op ) \ +template \ +inline bool \ +operator op( bool b, class_property const& p ) \ +{ \ + return b op p.get(); \ +} \ +template \ +inline bool \ +operator op( class_property const& p, bool b ) \ +{ \ + return b op p.get(); \ +} \ +/**/ + +DEFINE_PROPERTY_LOGICAL_OPERATOR( && ) +DEFINE_PROPERTY_LOGICAL_OPERATOR( || ) + +#endif + +// ************************************************************************** // +// ************** readonly_property ************** // +// ************************************************************************** // + +template +class readonly_property : public class_property { + typedef class_property base_prop; + typedef typename base_prop::address_res_t arrow_res_t; +protected: + typedef typename base_prop::write_param_t write_param_t; +public: + // Constructor + readonly_property() {} + explicit readonly_property( write_param_t init_value ) : base_prop( init_value ) {} + + // access methods + arrow_res_t operator->() const { return boost::addressof( base_prop::value ); } +}; + +//____________________________________________________________________________// + +#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) + +#define BOOST_READONLY_PROPERTY( property_type, friends ) boost::unit_test::readwrite_property + +#else + +#define BOOST_READONLY_PROPERTY_DECLARE_FRIEND(r, data, elem) friend class elem; + +#define BOOST_READONLY_PROPERTY( property_type, friends ) \ +class BOOST_JOIN( readonly_property, __LINE__ ) \ +: public boost::unit_test::readonly_property { \ + typedef boost::unit_test::readonly_property base_prop; \ + BOOST_PP_SEQ_FOR_EACH( BOOST_READONLY_PROPERTY_DECLARE_FRIEND, ' ', friends ) \ + typedef base_prop::write_param_t write_param_t; \ +public: \ + BOOST_JOIN( readonly_property, __LINE__ )() {} \ + explicit BOOST_JOIN( readonly_property, __LINE__ )( write_param_t init_v ) \ + : base_prop( init_v ) {} \ +} \ +/**/ + +#endif + +// ************************************************************************** // +// ************** readwrite_property ************** // +// ************************************************************************** // + +template +class readwrite_property : public class_property { + typedef class_property base_prop; + typedef typename add_pointer::type arrow_res_t; + typedef typename base_prop::address_res_t const_arrow_res_t; + typedef typename base_prop::write_param_t write_param_t; +public: + readwrite_property() : base_prop() {} + explicit readwrite_property( write_param_t init_value ) : base_prop( init_value ) {} + + // access methods + void set( write_param_t v ) { base_prop::value = v; } + arrow_res_t operator->() { return boost::addressof( base_prop::value ); } + const_arrow_res_t operator->() const { return boost::addressof( base_prop::value ); } + +#ifndef BOOST_TEST_NO_PROTECTED_USING + using base_prop::value; +#endif +}; + +//____________________________________________________________________________// + +} // unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#undef BOOST_TEST_NO_PROTECTED_USING + +#endif // BOOST_TEST_CLASS_PROPERTIES_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/utils/custom_manip.hpp b/cpp/BoostParts/boost/test/utils/custom_manip.hpp new file mode 100644 index 00000000..8788ccbf --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/custom_manip.hpp @@ -0,0 +1,63 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : simple helpers for creating cusom output manipulators +// *************************************************************************** + +#ifndef BOOST_TEST_CUSTOM_MANIP_HPP_071894GER +#define BOOST_TEST_CUSTOM_MANIP_HPP_071894GER + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** custom manipulators helpers ************** // +// ************************************************************************** // + +template +struct custom_printer { + explicit custom_printer( std::ostream& ostr ) : m_ostr( &ostr ) {} + + std::ostream& operator*() const { return *m_ostr; } + +private: + std::ostream* const m_ostr; +}; + +//____________________________________________________________________________// + +template struct custom_manip {}; + +//____________________________________________________________________________// + +template +inline custom_printer > +operator<<( std::ostream& ostr, custom_manip const& ) { return custom_printer >( ostr ); } + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_CUSTOM_MANIP_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/utils/fixed_mapping.hpp b/cpp/BoostParts/boost/test/utils/fixed_mapping.hpp new file mode 100644 index 00000000..b0ab3b87 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/fixed_mapping.hpp @@ -0,0 +1,124 @@ +// (C) Copyright Gennadiy Rozental 2001-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : fixed sized mapping with specified invalid value +// *************************************************************************** + +#ifndef BOOST_TEST_FIXED_MAPPING_HPP_071894GER +#define BOOST_TEST_FIXED_MAPPING_HPP_071894GER + +// Boost +#include +#include +#include +#include + +// STL +#include +#include +#include +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// configurable maximum fixed sized mapping size supported by this header. +// You can redefine it before inclusion of this file. +#ifndef MAX_MAP_SIZE +#define MAX_MAP_SIZE 20 +#endif + +#define CONSTR_DECL_MID( z, i, dummy1 ) key_param_type key##i, value_param_type v##i, +#define CONSTR_BODY_MID( z, i, dummy1 ) add_pair( key##i, v##i ); + +#define CONSTR_DECL( z, n, dummy1 ) \ + fixed_mapping( BOOST_PP_REPEAT_ ## z( n, CONSTR_DECL_MID, "" ) \ + value_param_type invalid_value ) \ + : m_invalid_value( invalid_value ) \ + { \ + BOOST_PP_REPEAT_ ## z( n, CONSTR_BODY_MID, "" ) \ + init(); \ + } \ +/**/ + +#define CONTRUCTORS( n ) BOOST_PP_REPEAT( n, CONSTR_DECL, "" ) + +template > +class fixed_mapping +{ + typedef std::pair elem_type; + typedef std::vector map_type; + typedef typename std::vector::const_iterator iterator; + + typedef typename call_traits::param_type key_param_type; + typedef typename call_traits::param_type value_param_type; + typedef typename call_traits::const_reference value_ref_type; + +#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) + struct p1; friend struct p1; + struct p2; friend struct p2; +#endif + + // bind( Compare(), bind(select1st(), _1), bind(identity(), _2) ) + struct p1 : public std::binary_function + { + bool operator()( elem_type const& x, Key const& y ) const { return Compare()( x.first, y ); } + }; + + // bind( Compare(), bind(select1st(), _1), bind(select1st(), _2) ) + struct p2 : public std::binary_function + { + bool operator()( elem_type const& x, elem_type const& y ) const { return Compare()( x.first, y.first ); } + }; + +public: + // Constructors + CONTRUCTORS( BOOST_PP_ADD( MAX_MAP_SIZE, 1 ) ) + + // key -> value access + value_ref_type operator[]( key_param_type key ) const + { + iterator it = boost::detail::lower_bound( m_map.begin(), m_map.end(), key, p1() ); + + return (it == m_map.end() || Compare()( key, it->first ) ) ? m_invalid_value : it->second; + } + +private: + // Implementation + void init() { std::sort( m_map.begin(), m_map.end(), p2() ); } + void add_pair( key_param_type key, value_param_type value ) { m_map.push_back( elem_type( key, value ) ); } + + // Data members + Value m_invalid_value; + map_type m_map; +}; + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#undef MAX_MAP_SIZE +#undef CONSTR_DECL_MID +#undef CONSTR_BODY_MID +#undef CONSTR_DECL +#undef CONTRUCTORS + +#endif // BOOST_TEST_FIXED_MAPPING_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/utils/foreach.hpp b/cpp/BoostParts/boost/test/utils/foreach.hpp new file mode 100644 index 00000000..d12fa430 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/foreach.hpp @@ -0,0 +1,281 @@ +// (C) Copyright Eric Niebler 2004-2005 +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : this is an abridged version of an excelent BOOST_FOREACH facility +// presented by Eric Niebler. I am so fond of it so I can't wait till it +// going to be accepted into Boost. Also I need version with less number of dependencies +// and more portable. This version doesn't support rvalues and will reeveluate it's +// parameters, but should be good enough for my purposes. +// *************************************************************************** + +#ifndef BOOST_TEST_FOREACH_HPP_021005GER +#define BOOST_TEST_FOREACH_HPP_021005GER + +// Boost.Test +#include + +// Boost +#include +#include +#include + +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +namespace for_each { + +// ************************************************************************** // +// ************** static_any ************** // +// ************************************************************************** // + +struct static_any_base +{ + operator bool() const { return false; } +}; + +//____________________________________________________________________________// + +template +struct static_any : static_any_base +{ + static_any( Iter const& t ) : m_it( t ) {} + + mutable Iter m_it; +}; + +//____________________________________________________________________________// + +typedef static_any_base const& static_any_t; + +//____________________________________________________________________________// + +template +inline Iter& +static_any_cast( static_any_t a, Iter* = 0 ) +{ + return static_cast( static_cast const&>( a ).m_it ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** is_const ************** // +// ************************************************************************** // + +template +inline is_const +is_const_coll( C& ) +{ + return is_const(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** begin ************** // +// ************************************************************************** // + +template +inline static_any +begin( C& t, mpl::false_ ) +{ + return static_any( t.begin() ); +} + +//____________________________________________________________________________// + +template +inline static_any +begin( C const& t, mpl::true_ ) +{ + return static_any( t.begin() ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** end ************** // +// ************************************************************************** // + +template +inline static_any +end( C& t, mpl::false_ ) +{ + return static_any( t.end() ); +} + +//____________________________________________________________________________// + +template +inline static_any +end( C const& t, mpl::true_ ) +{ + return static_any( t.end() ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** done ************** // +// ************************************************************************** // + +template +inline bool +done( static_any_t cur, static_any_t end, C&, mpl::false_ ) +{ + return static_any_cast( cur ) == + static_any_cast( end ); +} + +//____________________________________________________________________________// + +template +inline bool +done( static_any_t cur, static_any_t end, C const&, mpl::true_ ) +{ + return static_any_cast( cur ) == + static_any_cast( end ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** next ************** // +// ************************************************************************** // + +template +inline void +next( static_any_t cur, C&, mpl::false_ ) +{ + ++static_any_cast( cur ); +} + +//____________________________________________________________________________// + +template +inline void +next( static_any_t cur, C const&, mpl::true_ ) +{ + ++static_any_cast( cur ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** deref ************** // +// ************************************************************************** // + +template +inline RefType +deref( static_any_t cur, C&, ::boost::type, mpl::false_ ) +{ + return *static_any_cast( cur ); +} + +//____________________________________________________________________________// + +template +inline RefType +deref( static_any_t cur, C const&, ::boost::type, mpl::true_ ) +{ + return *static_any_cast( cur ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** BOOST_TEST_FOREACH ************** // +// ************************************************************************** // + +#define BOOST_TEST_FE_ANY ::boost::unit_test::for_each::static_any_t +#define BOOST_TEST_FE_IS_CONST( COL ) ::boost::unit_test::for_each::is_const_coll( COL ) + +#define BOOST_TEST_FE_BEG( COL ) \ + ::boost::unit_test::for_each::begin( \ + COL, \ + BOOST_TEST_FE_IS_CONST( COL ) ) \ +/**/ + +#define BOOST_TEST_FE_END( COL ) \ + ::boost::unit_test::for_each::end( \ + COL, \ + BOOST_TEST_FE_IS_CONST( COL ) ) \ +/**/ + +#define BOOST_TEST_FE_DONE( COL ) \ + ::boost::unit_test::for_each::done( \ + BOOST_TEST_FE_CUR_VAR, \ + BOOST_TEST_FE_END_VAR, \ + COL, \ + BOOST_TEST_FE_IS_CONST( COL ) ) \ +/**/ + +#define BOOST_TEST_FE_NEXT( COL ) \ + ::boost::unit_test::for_each::next( \ + BOOST_TEST_FE_CUR_VAR, \ + COL, \ + BOOST_TEST_FE_IS_CONST( COL ) ) \ +/**/ + +#define BOOST_FOREACH_NOOP(COL) \ + ((void)&(COL)) + +#define BOOST_TEST_FE_DEREF( COL, RefType ) \ + ::boost::unit_test::for_each::deref( \ + BOOST_TEST_FE_CUR_VAR, \ + COL, \ + ::boost::type(), \ + BOOST_TEST_FE_IS_CONST( COL ) ) \ +/**/ + +#if BOOST_WORKAROUND( BOOST_MSVC, == 1310 ) +#define BOOST_TEST_LINE_NUM +#else +#define BOOST_TEST_LINE_NUM __LINE__ +#endif + +#define BOOST_TEST_FE_CUR_VAR BOOST_JOIN( _fe_cur_, BOOST_TEST_LINE_NUM ) +#define BOOST_TEST_FE_END_VAR BOOST_JOIN( _fe_end_, BOOST_TEST_LINE_NUM ) +#define BOOST_TEST_FE_CON_VAR BOOST_JOIN( _fe_con_, BOOST_TEST_LINE_NUM ) + +#define BOOST_TEST_FOREACH( RefType, var, COL ) \ +if( BOOST_TEST_FE_ANY BOOST_TEST_FE_CUR_VAR = BOOST_TEST_FE_BEG( COL ) ) {} else \ +if( BOOST_TEST_FE_ANY BOOST_TEST_FE_END_VAR = BOOST_TEST_FE_END( COL ) ) {} else \ +for( bool BOOST_TEST_FE_CON_VAR = true; \ + BOOST_TEST_FE_CON_VAR && !BOOST_TEST_FE_DONE( COL ); \ + BOOST_TEST_FE_CON_VAR ? BOOST_TEST_FE_NEXT( COL ) : BOOST_FOREACH_NOOP( COL )) \ + \ + if( (BOOST_TEST_FE_CON_VAR = false, false) ) {} else \ + for( RefType var = BOOST_TEST_FE_DEREF( COL, RefType ); \ + !BOOST_TEST_FE_CON_VAR; BOOST_TEST_FE_CON_VAR = true ) \ +/**/ + +//____________________________________________________________________________// + +} // namespace for_each + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_FOREACH_HPP_021005GER diff --git a/cpp/BoostParts/boost/test/utils/iterator/input_iterator_facade.hpp b/cpp/BoostParts/boost/test/utils/iterator/input_iterator_facade.hpp new file mode 100644 index 00000000..ec29e21a --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/iterator/input_iterator_facade.hpp @@ -0,0 +1,109 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : Input iterator facade +// *************************************************************************** + +#ifndef BOOST_INPUT_ITERATOR_FACADE_HPP_071894GER +#define BOOST_INPUT_ITERATOR_FACADE_HPP_071894GER + +// Boost +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** input_iterator_core_access ************** // +// ************************************************************************** // + +class input_iterator_core_access +{ +#if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) +public: +#else + template friend class input_iterator_facade; +#endif + + template + static bool get( Facade& f ) + { + return f.get(); + } + +private: + // objects of this class are useless + input_iterator_core_access(); //undefined +}; + +// ************************************************************************** // +// ************** input_iterator_facade ************** // +// ************************************************************************** // + +template +class input_iterator_facade : public iterator_facade +{ +public: + // Constructor + input_iterator_facade() : m_valid( false ), m_value() {} + +protected: // provide access to the Derived + void init() + { + m_valid = true; + increment(); + } + + // Data members + mutable bool m_valid; + ValueType m_value; + +private: + friend class boost::iterator_core_access; + + // iterator facade interface implementation + void increment() + { + // we make post-end incrementation indefinetly safe + if( m_valid ) + m_valid = input_iterator_core_access::get( *static_cast(this) ); + } + Reference dereference() const + { + return m_value; + } + + // iterator facade interface implementation + bool equal( input_iterator_facade const& rhs ) const + { + // two invalid iterator equals, inequal otherwise + return !m_valid && !rhs.m_valid; + } +}; + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_INPUT_ITERATOR_FACADE_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/utils/iterator/token_iterator.hpp b/cpp/BoostParts/boost/test/utils/iterator/token_iterator.hpp new file mode 100644 index 00000000..c303ab7e --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/iterator/token_iterator.hpp @@ -0,0 +1,418 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : token iterator for string and range tokenization +// *************************************************************************** + +#ifndef BOOST_TOKEN_ITERATOR_HPP_071894GER +#define BOOST_TOKEN_ITERATOR_HPP_071894GER + +// Boost +#include +#include + +#include +#include + +#include +#include +#include +#include + +// STL +#include +#include + +#include + +//____________________________________________________________________________// + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std{ using ::ispunct; using ::isspace; } +#endif + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** ti_delimeter_type ************** // +// ************************************************************************** // + +enum ti_delimeter_type { + dt_char, // character is delimeter if it among explicit list of some characters + dt_ispunct, // character is delimeter if it satisfies ispunct functor + dt_isspace, // character is delimeter if it satisfies isspace functor + dt_none // no character is delimeter +}; + +namespace ut_detail { + +// ************************************************************************** // +// ************** default_char_compare ************** // +// ************************************************************************** // + +template +class default_char_compare { +public: + bool operator()( CharT c1, CharT c2 ) + { +#ifdef BOOST_CLASSIC_IOSTREAMS + return std::string_char_traits::eq( c1, c2 ); +#else + return std::char_traits::eq( c1, c2 ); +#endif + } +}; + +// ************************************************************************** // +// ************** delim_policy ************** // +// ************************************************************************** // + +template +class delim_policy { + typedef basic_cstring cstring; +public: + // Constructor + explicit delim_policy( ti_delimeter_type t = dt_char, cstring d = cstring() ) + : m_type( t ) + { + set_delimeters( d ); + } + + void set_delimeters( ti_delimeter_type t ) { m_type = t; } + template + void set_delimeters( Src d ) + { + nfp::optionally_assign( m_delimeters, d ); + + if( !m_delimeters.is_empty() ) + m_type = dt_char; + } + + bool operator()( CharT c ) + { + switch( m_type ) { + case dt_char: { + BOOST_TEST_FOREACH( CharT, delim, m_delimeters ) + if( CharCompare()( delim, c ) ) + return true; + + return false; + } + case dt_ispunct: + return (std::ispunct)( c ) != 0; + case dt_isspace: + return (std::isspace)( c ) != 0; + case dt_none: + return false; + } + + return false; + } + +private: + // Data members + cstring m_delimeters; + ti_delimeter_type m_type; +}; + +// ************************************************************************** // +// ************** token_assigner ************** // +// ************************************************************************** // + +template +struct token_assigner { +#if BOOST_WORKAROUND( BOOST_DINKUMWARE_STDLIB, < 306 ) + template + static void assign( Iterator b, Iterator e, std::basic_string& t ) + { for( ; b != e; ++b ) t += *b; } + + template + static void assign( Iterator b, Iterator e, basic_cstring& t ) { t.assign( b, e ); } +#else + template + static void assign( Iterator b, Iterator e, Token& t ) { t.assign( b, e ); } +#endif + template + static void append_move( Iterator& b, Token& ) { ++b; } +}; + +//____________________________________________________________________________// + +template<> +struct token_assigner { + template + static void assign( Iterator b, Iterator e, Token& t ) {} + + template + static void append_move( Iterator& b, Token& t ) { t += *b; ++b; } +}; + +} // namespace ut_detail + +// ************************************************************************** // +// ************** modifiers ************** // +// ************************************************************************** // + +namespace { +nfp::keyword dropped_delimeters; +nfp::keyword kept_delimeters; +nfp::typed_keyword keep_empty_tokens; +nfp::typed_keyword max_tokens; +} + +// ************************************************************************** // +// ************** token_iterator_base ************** // +// ************************************************************************** // + +template, + typename ValueType = basic_cstring, + typename Reference = basic_cstring, + typename Traversal = forward_traversal_tag> +class token_iterator_base +: public input_iterator_facade { + typedef basic_cstring cstring; + typedef ut_detail::delim_policy delim_policy; + typedef input_iterator_facade base; + +protected: + // Constructor + explicit token_iterator_base() + : m_is_dropped( dt_isspace ) + , m_is_kept( dt_ispunct ) + , m_keep_empty_tokens( false ) + , m_tokens_left( static_cast(-1) ) + , m_token_produced( false ) + { + } + + template + void + apply_modifier( Modifier const& m ) + { + if( m.has( dropped_delimeters ) ) + m_is_dropped.set_delimeters( m[dropped_delimeters] ); + + if( m.has( kept_delimeters ) ) + m_is_kept.set_delimeters( m[kept_delimeters] ); + + if( m.has( keep_empty_tokens ) ) + m_keep_empty_tokens = true; + + nfp::optionally_assign( m_tokens_left, m, max_tokens ); + } + + template + bool get( Iter& begin, Iter end ) + { + typedef ut_detail::token_assigner::type> Assigner; + Iter check_point; + + this->m_value.clear(); + + if( !m_keep_empty_tokens ) { + while( begin != end && m_is_dropped( *begin ) ) + ++begin; + + if( begin == end ) + return false; + + check_point = begin; + + if( m_tokens_left == 1 ) + while( begin != end ) + Assigner::append_move( begin, this->m_value ); + else if( m_is_kept( *begin ) ) + Assigner::append_move( begin, this->m_value ); + else + while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) ) + Assigner::append_move( begin, this->m_value ); + + --m_tokens_left; + } + else { // m_keep_empty_tokens is true + check_point = begin; + + if( begin == end ) { + if( m_token_produced ) + return false; + + m_token_produced = true; + } + if( m_is_kept( *begin ) ) { + if( m_token_produced ) + Assigner::append_move( begin, this->m_value ); + + m_token_produced = !m_token_produced; + } + else if( !m_token_produced && m_is_dropped( *begin ) ) + m_token_produced = true; + else { + if( m_is_dropped( *begin ) ) + check_point = ++begin; + + while( begin != end && !m_is_dropped( *begin ) && !m_is_kept( *begin ) ) + Assigner::append_move( begin, this->m_value ); + + m_token_produced = true; + } + } + + Assigner::assign( check_point, begin, this->m_value ); + + return true; + } + +private: + // Data members + delim_policy m_is_dropped; + delim_policy m_is_kept; + bool m_keep_empty_tokens; + std::size_t m_tokens_left; + bool m_token_produced; +}; + +// ************************************************************************** // +// ************** basic_string_token_iterator ************** // +// ************************************************************************** // + +template > +class basic_string_token_iterator +: public token_iterator_base,CharT,CharCompare> { + typedef basic_cstring cstring; + typedef token_iterator_base,CharT,CharCompare> base; +public: + explicit basic_string_token_iterator() {} + explicit basic_string_token_iterator( cstring src ) + : m_src( src ) + { + this->init(); + } + + template + basic_string_token_iterator( Src src, Modifier const& m ) + : m_src( src ) + { + this->apply_modifier( m ); + + this->init(); + } + +private: + friend class input_iterator_core_access; + + // input iterator implementation + bool get() + { + typename cstring::iterator begin = m_src.begin(); + bool res = base::get( begin, m_src.end() ); + + m_src.assign( begin, m_src.end() ); + + return res; + } + + // Data members + cstring m_src; +}; + +typedef basic_string_token_iterator string_token_iterator; +typedef basic_string_token_iterator wstring_token_iterator; + +// ************************************************************************** // +// ************** range_token_iterator ************** // +// ************************************************************************** // + +template::type>, + typename ValueType = std::basic_string::type>, + typename Reference = ValueType const&> +class range_token_iterator +: public token_iterator_base, + typename iterator_value::type,CharCompare,ValueType,Reference> { + typedef basic_cstring cstring; + typedef token_iterator_base, + typename iterator_value::type,CharCompare,ValueType,Reference> base; +public: + explicit range_token_iterator() {} + explicit range_token_iterator( Iter begin, Iter end = Iter() ) + : m_begin( begin ), m_end( end ) + { + this->init(); + } + range_token_iterator( range_token_iterator const& rhs ) + : base( rhs ) + { + if( this->m_valid ) { + m_begin = rhs.m_begin; + m_end = rhs.m_end; + } + } + + template + range_token_iterator( Iter begin, Iter end, Modifier const& m ) + : m_begin( begin ), m_end( end ) + { + this->apply_modifier( m ); + + this->init(); + } + +private: + friend class input_iterator_core_access; + + // input iterator implementation + bool get() + { + return base::get( m_begin, m_end ); + } + + // Data members + Iter m_begin; + Iter m_end; +}; + +// ************************************************************************** // +// ************** make_range_token_iterator ************** // +// ************************************************************************** // + +template +inline range_token_iterator +make_range_token_iterator( Iter begin, Iter end = Iter() ) +{ + return range_token_iterator( begin, end ); +} + +//____________________________________________________________________________// + +template +inline range_token_iterator +make_range_token_iterator( Iter begin, Iter end, Modifier const& m ) +{ + return range_token_iterator( begin, end, m ); +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TOKEN_ITERATOR_HPP_071894GER + diff --git a/cpp/BoostParts/boost/test/utils/lazy_ostream.hpp b/cpp/BoostParts/boost/test/utils/lazy_ostream.hpp new file mode 100644 index 00000000..d7d7d6cb --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/lazy_ostream.hpp @@ -0,0 +1,114 @@ +// (C) Copyright Gennadiy Rozental 2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : contains definition for all test tools in test toolbox +// *************************************************************************** + +#ifndef BOOST_TEST_LAZY_OSTREAM_HPP_070708GER +#define BOOST_TEST_LAZY_OSTREAM_HPP_070708GER + +// Boost.Test +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** lazy_ostream ************** // +// ************************************************************************** // + +namespace boost { + +namespace unit_test { + +class lazy_ostream { +public: + static lazy_ostream& instance() { static lazy_ostream inst; return inst; } + + friend std::ostream& operator<<( std::ostream& ostr, lazy_ostream const& o ) { return o( ostr ); } + + // access method + bool empty() const { return m_empty; } + + // actual printing interface; to be accessed only by this class and children + virtual std::ostream& operator()( std::ostream& ostr ) const { return ostr; } +protected: + explicit lazy_ostream( bool empty = true ) : m_empty( empty ) {} + + // protected destructor to make sure right one is called +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) +public: +#endif + BOOST_TEST_PROTECTED_VIRTUAL ~lazy_ostream() {} + +private: + // Data members + bool m_empty; +}; + +//____________________________________________________________________________// + +template +class lazy_ostream_impl : public lazy_ostream { +public: + lazy_ostream_impl( lazy_ostream const& prev, T value ) + : lazy_ostream( false ) + , m_prev( prev ) + , m_value( value ) + {} +private: + virtual std::ostream& operator()( std::ostream& ostr ) const + { + return m_prev(ostr) << m_value; + } + + // Data members + lazy_ostream const& m_prev; + T m_value; +}; + +//____________________________________________________________________________// + +template +inline lazy_ostream_impl +operator<<( lazy_ostream const& prev, T const& v ) +{ + return lazy_ostream_impl( prev, v ); +} + +//____________________________________________________________________________// + +#if BOOST_TEST_USE_STD_LOCALE + +template +inline lazy_ostream_impl +operator<<( lazy_ostream const& prev, R& (BOOST_TEST_CALL_DECL *man)(S&) ) +{ + return lazy_ostream_impl( prev, man ); +} + +//____________________________________________________________________________// + +#endif + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_LAZY_OSTREAM_HPP_070708GER diff --git a/cpp/BoostParts/boost/test/utils/named_params.hpp b/cpp/BoostParts/boost/test/utils/named_params.hpp new file mode 100644 index 00000000..f7f8e68d --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/named_params.hpp @@ -0,0 +1,329 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : facilities for named function parameters support +// *************************************************************************** + +#ifndef BOOST_TEST_NAMED_PARAM_022505GER +#define BOOST_TEST_NAMED_PARAM_022505GER + +// Boost +#include +#include + +// Boost.Test +#include +#include + +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace nfp { // named function parameters + +// ************************************************************************** // +// ************** forward declarations ************** // +// ************************************************************************** // + +template struct named_parameter; +template struct keyword; + +namespace nfp_detail { + +template struct named_parameter_combine; + +// ************************************************************************** // +// ************** access_to_invalid_parameter ************** // +// ************************************************************************** // + +struct access_to_invalid_parameter {}; + +//____________________________________________________________________________// + +inline void +report_access_to_invalid_parameter() +{ + throw access_to_invalid_parameter(); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** nil ************** // +// ************************************************************************** // + +struct nil { + template +#if defined(__GNUC__) || defined(__HP_aCC) || defined(__EDG__) || defined(__SUNPRO_CC) + operator T() const +#else + operator T const&() const +#endif + { report_access_to_invalid_parameter(); static T* v = 0; return *v; } + + template + T any_cast() const + { report_access_to_invalid_parameter(); static typename remove_reference::type* v = 0; return *v; } + + template + nil operator()( Arg1 const& ) + { report_access_to_invalid_parameter(); return nil(); } + + template + nil operator()( Arg1 const&, Arg2 const& ) + { report_access_to_invalid_parameter(); return nil(); } + + template + nil operator()( Arg1 const&, Arg2 const&, Arg3 const& ) + { report_access_to_invalid_parameter(); return nil(); } + + // Visitation support + template + void apply_to( Visitor& V ) const {} + + static nil& inst() { static nil s_inst; return s_inst; } +private: + nil() {} +}; + +// ************************************************************************** // +// ************** named_parameter_base ************** // +// ************************************************************************** // + +template +struct named_parameter_base { + template + named_parameter_combine + operator,( NP const& np ) const { return named_parameter_combine( np, *static_cast(this) ); } +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** named_parameter_combine ************** // +// ************************************************************************** // + +template +struct named_parameter_combine +: Rest +, named_parameter_base > { + typedef typename NP::ref_type res_type; + typedef named_parameter_combine self_type; + + // Constructor + named_parameter_combine( NP const& np, Rest const& r ) + : Rest( r ) + , m_param( np ) + {} + + // Access methods + res_type operator[]( keyword kw ) const { return m_param[kw]; } + res_type operator[]( keyword kw ) const { return m_param[kw]; } + using Rest::operator[]; + + bool has( keyword kw ) const { return m_param.has( kw ); } + using Rest::has; + + void erase( keyword kw ) const { m_param.erase( kw ); } + using Rest::erase; + +#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) || \ + BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0610)) + template + named_parameter_combine operator,( NP const& np ) const + { return named_parameter_combine( np, *this ); } +#else + using named_parameter_base >::operator,; +#endif + + // Visitation support + template + void apply_to( Visitor& V ) const + { + m_param.apply_to( V ); + + Rest::apply_to( V ); + } +private: + // Data members + NP m_param; +}; + +} // namespace nfp_detail + +// ************************************************************************** // +// ************** named_parameter ************** // +// ************************************************************************** // + +template +struct named_parameter +: nfp_detail::named_parameter_base > +{ + typedef nfp_detail::nil nil_t; + typedef T data_type; + typedef ReferenceType ref_type; + typedef unique_id id; + + // Constructor + explicit named_parameter( ref_type v ) + : m_value( v ) + , m_erased( false ) + {} + named_parameter( named_parameter const& np ) + : m_value( np.m_value ) + , m_erased( np.m_erased ) + {} + + // Access methods + ref_type operator[]( keyword ) const { return m_erased ? nil_t::inst().template any_cast() : m_value; } + ref_type operator[]( keyword ) const { return m_erased ? nil_t::inst().template any_cast() : m_value; } + template + nil_t operator[]( keyword ) const { return nil_t::inst(); } + + bool has( keyword ) const { return !m_erased; } + template + bool has( keyword ) const { return false; } + + void erase( keyword ) const { m_erased = true; } + template + void erase( keyword ) const {} + + // Visitation support + template + void apply_to( Visitor& V ) const + { + V.set_parameter( rtti::type_id(), m_value ); + } + +private: + // Data members + ref_type m_value; + mutable bool m_erased; +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** no_params ************** // +// ************************************************************************** // + +namespace nfp_detail { +typedef named_parameter no_params_type; +} // namespace nfp_detail + +namespace { +nfp_detail::no_params_type no_params( '\0' ); +} // local namespace + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** keyword ************** // +// ************************************************************************** // + +template +struct keyword { + typedef unique_id id; + + template + named_parameter + operator=( T const& t ) const { return named_parameter( t ); } + + template + named_parameter + operator=( T& t ) const { return named_parameter( t ); } + + named_parameter + operator=( char const* t ) const { return named_parameter( t ); } +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** typed_keyword ************** // +// ************************************************************************** // + +template +struct typed_keyword : keyword { + named_parameter + operator=( T const& t ) const { return named_parameter( t ); } + + named_parameter + operator=( T& t ) const { return named_parameter( t ); } +}; + +//____________________________________________________________________________// + +template +struct typed_keyword +: keyword +, named_parameter { + typedef unique_id id; + + typed_keyword() : named_parameter( true ) {} + + named_parameter + operator!() const { return named_parameter( false ); } +}; + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** optionally_assign ************** // +// ************************************************************************** // + +template +inline void +optionally_assign( T&, nfp_detail::nil ) +{ + nfp_detail::report_access_to_invalid_parameter(); +} + +//____________________________________________________________________________// + +template +inline void +#if BOOST_WORKAROUND( __MWERKS__, BOOST_TESTED_AT( 0x3003 ) ) \ + || BOOST_WORKAROUND( __DECCXX_VER, BOOST_TESTED_AT(60590042) ) +optionally_assign( T& target, Source src ) +#else +optionally_assign( T& target, Source const& src ) +#endif +{ + using namespace unit_test; + + assign_op( target, src, static_cast(0) ); +} + +//____________________________________________________________________________// + +template +inline void +optionally_assign( T& target, Params const& p, Keyword k ) +{ + if( p.has(k) ) + optionally_assign( target, p[k] ); +} + +//____________________________________________________________________________// + +} // namespace nfp + +} // namespace boost + +#include + +#endif // BOOST_TEST_NAMED_PARAM_022505GER + diff --git a/cpp/BoostParts/boost/test/utils/rtti.hpp b/cpp/BoostParts/boost/test/utils/rtti.hpp new file mode 100644 index 00000000..655222de --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/rtti.hpp @@ -0,0 +1,64 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : simple facilities for accessing type information at runtime +// *************************************************************************** + +#ifndef BOOST_TEST_RTTI_HPP_062604GER +#define BOOST_TEST_RTTI_HPP_062604GER + +#include + +namespace boost { + +namespace rtti { + +// ************************************************************************** // +// ************** rtti::type_id ************** // +// ************************************************************************** // + +typedef std::ptrdiff_t id_t; + +namespace rtti_detail { + +template +struct rttid_holder { + static id_t id() { return reinterpret_cast( &inst() ); } + +private: + struct rttid {}; + + static rttid const& inst() { static rttid s_inst; return s_inst; } +}; + +} // namespace rtti_detail + +//____________________________________________________________________________// + +template +inline id_t +type_id() +{ + return rtti_detail::rttid_holder::id(); +} + +//____________________________________________________________________________// + +#define BOOST_RTTI_SWITCH( type_id_ ) if( ::boost::rtti::id_t switch_by_id = type_id_ ) +#define BOOST_RTTI_CASE( type ) if( switch_by_id == ::boost::rtti::type_id() ) + +//____________________________________________________________________________// + +} // namespace rtti + +} // namespace boost + +#endif // BOOST_RT_RTTI_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/argument.hpp b/cpp/BoostParts/boost/test/utils/runtime/argument.hpp new file mode 100644 index 00000000..d22745cb --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/argument.hpp @@ -0,0 +1,112 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : model of actual argument (both typed and abstract interface) +// *************************************************************************** + +#ifndef BOOST_RT_ARGUMENT_HPP_062604GER +#define BOOST_RT_ARGUMENT_HPP_062604GER + +// Boost.Runtime.Parameter +#include +#include +#include + +// Boost.Test +#include +#include + +// STL +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::argument ************** // +// ************************************************************************** // + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4244) +#endif + +class argument { +public: + // Constructor + argument( parameter const& p, rtti::id_t value_type ) + : p_formal_parameter( p ) + , p_value_type( value_type ) + {} + + // Destructor + virtual ~argument() {} + + // Public properties + unit_test::readonly_property p_formal_parameter; + unit_test::readonly_property p_value_type; +}; + +// ************************************************************************** // +// ************** runtime::typed_argument ************** // +// ************************************************************************** // + +template +class typed_argument : public argument { +public: + // Constructor + explicit typed_argument( parameter const& p ) + : argument( p, rtti::type_id() ) + {} + typed_argument( parameter const& p, T const& t ) + : argument( p, rtti::type_id() ) + , p_value( t ) + {} + + unit_test::readwrite_property p_value; +}; + +// ************************************************************************** // +// ************** runtime::arg_value ************** // +// ************************************************************************** // + +template +inline T const& +arg_value( argument const& arg_ ) +{ + assert( arg_.p_value_type == rtti::type_id() ); // detect logic error + + return static_cast const&>( arg_ ).p_value.value; +} + +//____________________________________________________________________________// + +template +inline T& +arg_value( argument& arg_ ) +{ + assert( arg_.p_value_type == rtti::type_id() ); // detect logic error + + return static_cast&>( arg_ ).p_value.value; +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +//____________________________________________________________________________// + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_ARGUMENT_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/argument_factory.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/argument_factory.hpp new file mode 100644 index 00000000..11170669 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/argument_factory.hpp @@ -0,0 +1,218 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : generic typed_argument_factory implementation +// *************************************************************************** + +#ifndef BOOST_RT_CLA_ARGUMENT_FACTORY_HPP_062604GER +#define BOOST_RT_CLA_ARGUMENT_FACTORY_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +// Boost.Test +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** default_value_interpreter ************** // +// ************************************************************************** // + +namespace rt_cla_detail { + +struct default_value_interpreter { + template + void operator()( argv_traverser& tr, boost::optional& value ) + { + if( interpret_argument_value( tr.token(), value, 0 ) ) + tr.next_token(); + } +}; + +} // namespace rt_cla_detail + +// ************************************************************************** // +// ************** typed_argument_factory ************** // +// ************************************************************************** // + +template +struct typed_argument_factory : public argument_factory { + // Constructor + typed_argument_factory() + : m_value_interpreter( rt_cla_detail::default_value_interpreter() ) + {} + BOOST_RT_PARAM_UNNEEDED_VIRTUAL ~typed_argument_factory() {} + + // properties modification + template + void accept_modifier( Modifier const& m ) + { + optionally_assign( m_value_handler, m, handler ); + optionally_assign( m_value_interpreter, m, interpreter ); + + if( m.has( default_value ) ) { + BOOST_RT_PARAM_VALIDATE_LOGIC( !m_value_generator, + BOOST_RT_PARAM_LITERAL( "multiple value generators for parameter" ) ); + + T const& dv_ref = m[default_value]; + m_value_generator = rt_cla_detail::const_generator( dv_ref ); + } + + if( m.has( default_refer_to ) ) { + BOOST_RT_PARAM_VALIDATE_LOGIC( !m_value_generator, + BOOST_RT_PARAM_LITERAL( "multiple value generators for parameter" ) ); + + cstring ref_id = m[default_refer_to]; + m_value_generator = rt_cla_detail::ref_generator( ref_id ); + } + + if( m.has( assign_to ) ) { + BOOST_RT_PARAM_VALIDATE_LOGIC( !m_value_handler, + BOOST_RT_PARAM_LITERAL( "multiple value handlers for parameter" ) ); + + m_value_handler = rt_cla_detail::assigner( m[assign_to] ); + } + } + + // Argument factory implementation + virtual argument_ptr produce_using( parameter& p, argv_traverser& tr ); + virtual argument_ptr produce_using( parameter& p, parser const& ); + virtual void argument_usage_info( format_stream& fs ); + +// !! private? + // Data members + unit_test::callback2 m_value_handler; + unit_test::callback2&> m_value_generator; + unit_test::callback2&> m_value_interpreter; +}; + +//____________________________________________________________________________// + +template +inline argument_ptr +typed_argument_factory::produce_using( parameter& p, argv_traverser& tr ) +{ + boost::optional value; + + try { + m_value_interpreter( tr, value ); + } + catch( ... ) { // !! should we do that? + BOOST_RT_PARAM_TRACE( "Fail to parse argument value" ); + + if( !p.p_optional_value ) + throw; + } + + argument_ptr actual_arg = p.actual_argument(); + + BOOST_RT_CLA_VALIDATE_INPUT( !!value || p.p_optional_value, tr, + BOOST_RT_PARAM_LITERAL( "Argument value missing for parameter " ) << p.id_2_report() ); + + BOOST_RT_CLA_VALIDATE_INPUT( !actual_arg || p.p_multiplicable, tr, + BOOST_RT_PARAM_LITERAL( "Unexpected repetition of the parameter " ) << p.id_2_report() ); + + if( !!value && !!m_value_handler ) + m_value_handler( p, *value ); + + if( !p.p_multiplicable ) + actual_arg.reset( p.p_optional_value && (rtti::type_id() != rtti::type_id()) + ? static_cast(new typed_argument >( p, value )) + : static_cast(new typed_argument( p, *value )) ); + else { + typedef std::list > optional_list; + + if( !actual_arg ) + actual_arg.reset( p.p_optional_value + ? static_cast(new typed_argument( p )) + : static_cast(new typed_argument >( p )) ); + + if( p.p_optional_value ) { + optional_list& values = arg_value( *actual_arg ); + + values.push_back( value ); + } + else { + std::list& values = arg_value >( *actual_arg ); + + values.push_back( *value ); + } + } + + return actual_arg; +} + +//____________________________________________________________________________// + +template +inline argument_ptr +typed_argument_factory::produce_using( parameter& p, parser const& pa ) +{ + argument_ptr actual_arg; + + if( !m_value_generator ) + return actual_arg; + + boost::optional value; + m_value_generator( pa, value ); + + if( !value ) + return actual_arg; + + if( !!m_value_handler ) + m_value_handler( p, *value ); + + actual_arg.reset( new typed_argument( p, *value ) ); + + return actual_arg; +} + +//____________________________________________________________________________// + +template +inline void +typed_argument_factory::argument_usage_info( format_stream& fs ) +{ + rt_cla_detail::argument_value_usage( fs, 0, reinterpret_cast(0) ); +} + +//____________________________________________________________________________// + +} // namespace boost + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace cla + +#endif // BOOST_RT_CLA_ARGUMENT_FACTORY_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/argv_traverser.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/argv_traverser.hpp new file mode 100644 index 00000000..c1fb95ef --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/argv_traverser.hpp @@ -0,0 +1,98 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : defines facility to hide input traversing details +// *************************************************************************** + +#ifndef BOOST_RT_CLA_ARGV_TRAVERSER_HPP_062604GER +#define BOOST_RT_CLA_ARGV_TRAVERSER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +// Boost.Test +#include + +// Boost +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::argv_traverser ************** // +// ************************************************************************** // + +class argv_traverser : noncopyable { + class parser; +public: + // Constructor + argv_traverser(); + + // public_properties + unit_test::readwrite_property p_ignore_mismatch; + unit_test::readwrite_property p_separator; + + // argc+argv <-> internal buffer exchange + void init( int argc, char_type** argv ); + void remainder( int& argc, char_type** argv ); + + // token based parsing + cstring token() const; + void next_token(); + + // whole input parsing + cstring input() const; + void trim( std::size_t size ); + bool match_front( cstring ); + bool match_front( char_type c ); + bool eoi() const; + + // transaction logic support + void commit(); + void rollback(); + + // current position access; used to save some reference points in input + std::size_t input_pos() const; + + // returns true if mismatch detected during input parsing handled successfully + bool handle_mismatch(); + +private: + // Data members + dstring m_buffer; + cstring m_work_buffer; + + cstring m_token; + cstring::iterator m_commited_end; + + shared_array m_remainder; + std::size_t m_remainder_size; +}; + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_RT_PARAM_OFFLINE + +# define BOOST_RT_PARAM_INLINE inline +# include + +#endif + +#endif // BOOST_RT_CLA_ARGV_TRAVERSER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/argv_traverser.ipp b/cpp/BoostParts/boost/test/utils/runtime/cla/argv_traverser.ipp new file mode 100644 index 00000000..d7bd6c0e --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/argv_traverser.ipp @@ -0,0 +1,209 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : implements facility to hide input traversing details +// *************************************************************************** + +#ifndef BOOST_RT_CLA_ARGV_TRAVERSER_IPP_070604GER +#define BOOST_RT_CLA_ARGV_TRAVERSER_IPP_070604GER + +// Boost.Runtime.Parameter +#include + +#include + +// STL +#include +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::memcpy; } +#endif + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::argv_traverser ************** // +// ************************************************************************** // + +BOOST_RT_PARAM_INLINE +argv_traverser::argv_traverser() +: p_ignore_mismatch( false ), p_separator( BOOST_RT_PARAM_LITERAL( ' ' ) ) +{ +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +argv_traverser::init( int argc, char_type** argv ) +{ + for( int index = 1; index < argc; ++index ) { + m_buffer += argv[index]; + if( index != argc-1 ) + m_buffer += BOOST_RT_PARAM_LITERAL( ' ' ); + } + + m_remainder.reset( new char_type[m_buffer.size()+1] ); + m_remainder_size = 0; + m_work_buffer = m_buffer; + m_commited_end = m_work_buffer.begin(); + + BOOST_RT_PARAM_TRACE( "Input buffer: " << m_buffer ); + + next_token(); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +argv_traverser::remainder( int& argc, char_type** argv ) +{ + argc = 1; + std::size_t pos = 0; + while(pos < m_remainder_size ) { + argv[argc++] = m_remainder.get() + pos; + + pos = std::find( m_remainder.get() + pos, m_remainder.get() + m_remainder_size, + BOOST_RT_PARAM_LITERAL( ' ' ) ) - m_remainder.get(); + m_remainder[pos++] = BOOST_RT_PARAM_LITERAL( '\0' ); + } +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE cstring +argv_traverser::token() const +{ + return m_token; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +argv_traverser::next_token() +{ + if( m_work_buffer.is_empty() ) + return; + + m_work_buffer.trim_left( m_token.size() ); // skip remainder of current token + + if( m_work_buffer.size() != m_buffer.size() ) // !! is there a better way to identify first token + m_work_buffer.trim_left( 1 ); // skip separator if not first token; + + m_token.assign( m_work_buffer.begin(), + std::find( m_work_buffer.begin(), m_work_buffer.end(), p_separator ) ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE cstring +argv_traverser::input() const +{ + return m_work_buffer; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +argv_traverser::trim( std::size_t size ) +{ + m_work_buffer.trim_left( size ); + + if( size <= m_token.size() ) + m_token.trim_left( size ); + else { + m_token.assign( m_work_buffer.begin(), + std::find( m_work_buffer.begin(), m_work_buffer.end(), p_separator ) ); + } +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +argv_traverser::match_front( cstring str ) +{ + return m_work_buffer.size() < str.size() ? false : m_work_buffer.substr( 0, str.size() ) == str; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +argv_traverser::match_front( char_type c ) +{ + return first_char( m_work_buffer ) == c; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +argv_traverser::eoi() const +{ + return m_work_buffer.is_empty(); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +argv_traverser::commit() +{ + m_commited_end = m_work_buffer.begin(); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +argv_traverser::rollback() +{ + m_work_buffer.assign( m_commited_end, m_work_buffer.end() ); + m_token.assign( m_work_buffer.begin(), + std::find( m_work_buffer.begin(), m_work_buffer.end(), p_separator ) ); + +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE std::size_t +argv_traverser::input_pos() const +{ + return m_work_buffer.begin() - m_commited_end; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +argv_traverser::handle_mismatch() +{ + if( !p_ignore_mismatch ) + return false; + + std::memcpy( m_remainder.get() + m_remainder_size, token().begin(), token().size() ); + m_remainder_size += token().size(); + m_remainder[m_remainder_size++] = p_separator; + + next_token(); + commit(); + + return true; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_ARGV_TRAVERSER_IPP_070604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/basic_parameter.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/basic_parameter.hpp new file mode 100644 index 00000000..e7e084cd --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/basic_parameter.hpp @@ -0,0 +1,85 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : generic custom parameter generator +// *************************************************************************** + +#ifndef BOOST_RT_CLA_BASIC_PARAMETER_HPP_062604GER +#define BOOST_RT_CLA_BASIC_PARAMETER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include + +// Boost.Test +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::basic_parameter ************** // +// ************************************************************************** // + +template +class basic_parameter : private base_from_member, public typed_parameter { +public: + // Constructors + explicit basic_parameter( cstring n ) + : base_from_member() + , typed_parameter( base_from_member::member ) + { + this->accept_modifier( name = n ); + } + + // parameter properties modification + template + void accept_modifier( Modifier const& m ) + { + typed_parameter::accept_modifier( m ); + + base_from_member::member.accept_modifier( m ); + } +}; + +//____________________________________________________________________________// + +#define BOOST_RT_CLA_NAMED_PARAM_GENERATORS( param_type ) \ +template \ +inline shared_ptr > \ +param_type( cstring name = cstring() ) \ +{ \ + return shared_ptr >( new param_type ## _t( name ) ); \ +} \ + \ +inline shared_ptr > \ +param_type( cstring name = cstring() ) \ +{ \ + return shared_ptr >( new param_type ## _t( name ) ); \ +} \ +/**/ + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_BASIC_PARAMETER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/char_parameter.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/char_parameter.hpp new file mode 100644 index 00000000..3e9b2d84 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/char_parameter.hpp @@ -0,0 +1,98 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : defines model of parameter with single char name +// *************************************************************************** + +#ifndef BOOST_RT_CLA_CHAR_PARAMETER_HPP_062604GER +#define BOOST_RT_CLA_CHAR_PARAMETER_HPP_062604GER + +// Boost.Runtime.Parameter +#include +#include + +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** char_name_policy ************** // +// ************************************************************************** // + +class char_name_policy : public basic_naming_policy { +public: + // Constructor + char_name_policy(); + BOOST_RT_PARAM_UNNEEDED_VIRTUAL ~char_name_policy() {} + + // policy interface + virtual bool conflict_with( identification_policy const& ) const; + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + basic_naming_policy::accept_modifier( m ); + + BOOST_RT_PARAM_VALIDATE_LOGIC( p_name->size() <= 1, "Invalid parameter name " << p_name ); + } +}; + +// ************************************************************************** // +// ************** runtime::cla::char_parameter ************** // +// ************************************************************************** // + +template +class char_parameter_t : public basic_parameter { + typedef basic_parameter base; +public: + // Constructors + explicit char_parameter_t( char_type name ) : base( cstring( &name, 1 ) ) {} +}; + +//____________________________________________________________________________// + +template +inline shared_ptr > +char_parameter( char_type name ) +{ + return shared_ptr >( new char_parameter_t( name ) ); +} + +//____________________________________________________________________________// + +inline shared_ptr > +char_parameter( char_type name ) +{ + return shared_ptr >( new char_parameter_t( name ) ); +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_RT_PARAM_OFFLINE + +# define BOOST_RT_PARAM_INLINE inline +# include + +#endif + +#endif // BOOST_RT_CLA_CHAR_PARAMETER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/char_parameter.ipp b/cpp/BoostParts/boost/test/utils/runtime/cla/char_parameter.ipp new file mode 100644 index 00000000..cc9e923a --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/char_parameter.ipp @@ -0,0 +1,57 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : implements model of parameter with single char name +// *************************************************************************** + +#ifndef BOOST_RT_CLA_CHAR_PARAMETER_IPP_062904GER +#define BOOST_RT_CLA_CHAR_PARAMETER_IPP_062904GER + +// Boost.Runtime.Parameter +#include + +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** char_name_policy ************** // +// ************************************************************************** // + +BOOST_RT_PARAM_INLINE +char_name_policy::char_name_policy() +: basic_naming_policy( rtti::type_id() ) +{ + assign_op( p_prefix.value, BOOST_RT_PARAM_CSTRING_LITERAL( "-" ), 0 ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +char_name_policy::conflict_with( identification_policy const& id ) const +{ + return id.p_type_id == p_type_id && + p_name == static_cast( id ).p_name; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_CHAR_PARAMETER_IPP_062904GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/detail/argument_value_usage.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/detail/argument_value_usage.hpp new file mode 100644 index 00000000..1986b6d2 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/detail/argument_value_usage.hpp @@ -0,0 +1,82 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied warranty, +// and with no claim as to its suitability for any purpose. + +// See http://www.boost.org for updates, documentation, and revision history. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : argument usage printing helpers +// *************************************************************************** + +#ifndef BOOST_RT_CLA_ARGUMENT_VALUE_USAGE_HPP_062604GER +#define BOOST_RT_CLA_ARGUMENT_VALUE_USAGE_HPP_062604GER + +// Boost.Runtime.Parameter +#include +#include + +// Boost.Test +#include +#include + +#include + +// STL +// !! can we eliminate these includes? +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +namespace rt_cla_detail { + +// ************************************************************************** // +// ************** argument_value_usage ************** // +// ************************************************************************** // + +// generic case +template +inline void +argument_value_usage( format_stream& fs, long, T* = 0 ) +{ + fs << BOOST_RT_PARAM_CSTRING_LITERAL( "" ); +} + +//____________________________________________________________________________// + +// specialization for list of values +template +inline void +argument_value_usage( format_stream& fs, int, std::list* = 0 ) +{ + fs << BOOST_RT_PARAM_CSTRING_LITERAL( "(, ..., )" ); +} + +//____________________________________________________________________________// + +// specialization for type bool +inline void +argument_value_usage( format_stream& fs, int, bool* = 0 ) +{ + fs << BOOST_RT_PARAM_CSTRING_LITERAL( "yes|y|no|n" ); +} + +//____________________________________________________________________________// + +} // namespace rt_cla_detail + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_ARGUMENT_VALUE_USAGE_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/dual_name_parameter.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/dual_name_parameter.hpp new file mode 100644 index 00000000..233f6322 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/dual_name_parameter.hpp @@ -0,0 +1,96 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : defines model of generic parameter with dual naming +// *************************************************************************** + +#ifndef BOOST_RT_CLA_DUAL_NAME_PARAMETER_HPP_062604GER +#define BOOST_RT_CLA_DUAL_NAME_PARAMETER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** dual_name_policy ************** // +// ************************************************************************** // + +class dual_name_policy : public dual_id_policy { +public: + dual_name_policy(); + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + if( m.has( prefix ) ) { + set_prefix( m[prefix] ); + m.erase( prefix ); + } + + if( m.has( name ) ) { + set_name( m[name] ); + m.erase( name ); + } + + if( m.has( separator ) ) { + set_separator( m[separator] ); + m.erase( separator ); + } + + dual_id_policy::accept_modifier( m ); + } +private: + void set_prefix( cstring ); + void set_name( cstring ); + void set_separator( cstring ); +}; + +// ************************************************************************** // +// ************** runtime::cla::dual_name_parameter ************** // +// ************************************************************************** // + +template +class dual_name_parameter_t : public basic_parameter { + typedef basic_parameter base; +public: + // Constructors + explicit dual_name_parameter_t( cstring name ) : base( name ) {} +}; + +//____________________________________________________________________________// + +BOOST_RT_CLA_NAMED_PARAM_GENERATORS( dual_name_parameter ) + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_RT_PARAM_OFFLINE + +# define BOOST_RT_PARAM_INLINE inline +# include + +#endif + +#endif // BOOST_RT_CLA_DUAL_NAME_PARAMETER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/dual_name_parameter.ipp b/cpp/BoostParts/boost/test/utils/runtime/cla/dual_name_parameter.ipp new file mode 100644 index 00000000..f9356bdf --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/dual_name_parameter.ipp @@ -0,0 +1,90 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : implements model of generic parameter with dual naming +// *************************************************************************** + +#ifndef BOOST_RT_CLA_DUAL_NAME_PARAMETER_IPP_062904GER +#define BOOST_RT_CLA_DUAL_NAME_PARAMETER_IPP_062904GER + +// Boost.Runtime.Parameter +#include +#include + +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** dual_name_policy ************** // +// ************************************************************************** // + +BOOST_RT_PARAM_INLINE +dual_name_policy::dual_name_policy() +{ + m_primary.accept_modifier( prefix = BOOST_RT_PARAM_CSTRING_LITERAL( "--" ) ); + m_secondary.accept_modifier( prefix = BOOST_RT_PARAM_CSTRING_LITERAL( "-" ) ); +} + +//____________________________________________________________________________// + +namespace { + +template +inline void +split( string_name_policy& snp, char_name_policy& cnp, cstring src, K const& k ) +{ + cstring::iterator sep = std::find( src.begin(), src.end(), BOOST_RT_PARAM_LITERAL( '|' ) ); + + if( sep != src.begin() ) + snp.accept_modifier( k = cstring( src.begin(), sep ) ); + + if( sep != src.end() ) + cnp.accept_modifier( k = cstring( sep+1, src.end() ) ); +} + +} // local namespace + +BOOST_RT_PARAM_INLINE void +dual_name_policy::set_prefix( cstring src ) +{ + split( m_primary, m_secondary, src, prefix ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +dual_name_policy::set_name( cstring src ) +{ + split( m_primary, m_secondary, src, name ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +dual_name_policy::set_separator( cstring src ) +{ + split( m_primary, m_secondary, src, separator ); +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_DUAL_NAME_PARAMETER_IPP_062904GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/fwd.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/fwd.hpp new file mode 100644 index 00000000..66d6efc1 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/fwd.hpp @@ -0,0 +1,55 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : cla subsystem forward declarations +// *************************************************************************** + +#ifndef BOOST_RT_CLA_FWD_HPP_062604GER +#define BOOST_RT_CLA_FWD_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +class parser; +class parameter; +typedef shared_ptr parameter_ptr; +class naming_policy; +typedef shared_ptr naming_policy_ptr; +class argv_traverser; + +namespace rt_cla_detail { + +template class const_generator; +template class ref_generator; + +template class assigner; + +class named_parameter_base; +class positional_parameter_base; + +} // namespace rt_cla_detail + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_FWD_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/id_policy.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/id_policy.hpp new file mode 100644 index 00000000..07849799 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/id_policy.hpp @@ -0,0 +1,145 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : some generic identification policies definition +// *************************************************************************** + +#ifndef BOOST_RT_CLA_ID_POLICY_HPP_062604GER +#define BOOST_RT_CLA_ID_POLICY_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include +#include +#include + +#include + +// Boost.Test +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** naming_policy_base ************** // +// ************************************************************************** // +// model: + +class basic_naming_policy : public identification_policy { +public: + // Public properties + unit_test::readwrite_property p_prefix; + unit_test::readwrite_property p_name; + unit_test::readwrite_property p_separator; + + // Policy interface + virtual bool responds_to( cstring name ) const { return p_name == name; } + virtual cstring id_2_report() const { return p_name.get(); } + virtual void usage_info( format_stream& fs ) const; + virtual bool matching( parameter const& p, argv_traverser& tr, bool primary ) const; + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + nfp::optionally_assign( p_prefix.value, m, prefix ); + nfp::optionally_assign( p_name.value, m, name ); + nfp::optionally_assign( p_separator.value, m, separator ); + } + +protected: + explicit basic_naming_policy( rtti::id_t dyn_type ) + : identification_policy( dyn_type ) + {} + BOOST_RT_PARAM_UNNEEDED_VIRTUAL ~basic_naming_policy() {} + + // Naming policy interface + virtual bool match_prefix( argv_traverser& tr ) const; + virtual bool match_name( argv_traverser& tr ) const; + virtual bool match_separator( argv_traverser& tr, bool optional_value ) const; +}; + +// ************************************************************************** // +// ************** dual_id_policy ************** // +// ************************************************************************** // + +template +class dual_id_policy : public identification_policy { +public: + // Constructor + dual_id_policy() + : identification_policy( rtti::type_id() ) + , m_primary() + , m_secondary() + {} + + // Policy interface + virtual bool responds_to( cstring name ) const + { + return m_primary.responds_to( name ) || m_secondary.responds_to( name ); + } + virtual bool conflict_with( identification_policy const& id_p ) const + { + return id_p.conflict_with( m_primary ) || id_p.conflict_with( m_secondary ); + } + virtual cstring id_2_report() const + { + return m_primary.id_2_report(); + } + virtual void usage_info( format_stream& fs ) const + { + fs << BOOST_RT_PARAM_LITERAL( '{' ); + m_primary.usage_info( fs ); + fs << BOOST_RT_PARAM_LITERAL( '|' ); + m_secondary.usage_info( fs ); + fs << BOOST_RT_PARAM_LITERAL( '}' ); + } + virtual bool matching( parameter const& p, argv_traverser& tr, bool primary ) const + { + return m_primary.matching( p, tr, primary ) || m_secondary.matching( p, tr, primary ); + } + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + m_primary.accept_modifier( m ); + m_secondary.accept_modifier( m ); + } + +protected: + BOOST_RT_PARAM_UNNEEDED_VIRTUAL ~dual_id_policy() {} + + // Data members + PrimaryId m_primary; + SecondId m_secondary; +}; + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_RT_PARAM_OFFLINE + +# define BOOST_RT_PARAM_INLINE inline +# include + +#endif + +#endif // BOOST_RT_CLA_ID_POLICY_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/id_policy.ipp b/cpp/BoostParts/boost/test/utils/runtime/cla/id_policy.ipp new file mode 100644 index 00000000..0de8d85d --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/id_policy.ipp @@ -0,0 +1,118 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : some generic identification policies implementation +// *************************************************************************** + +#ifndef BOOST_RT_CLA_ID_POLICY_IPP_062904GER +#define BOOST_RT_CLA_ID_POLICY_IPP_062904GER + +// Boost.Runtime.Parameter +#include + +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** basic_naming_policy ************** // +// ************************************************************************** // + +BOOST_RT_PARAM_INLINE void +basic_naming_policy::usage_info( format_stream& fs ) const +{ + fs << p_prefix << p_name << p_separator; + + if( p_separator->empty() ) + fs << BOOST_RT_PARAM_LITERAL( ' ' ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +basic_naming_policy::match_prefix( argv_traverser& tr ) const +{ + if( !tr.match_front( p_prefix.get() ) ) + return false; + + tr.trim( p_prefix->size() ); + return true; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +basic_naming_policy::match_name( argv_traverser& tr ) const +{ + if( !tr.match_front( p_name.get() ) ) + return false; + + tr.trim( p_name->size() ); + return true; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +basic_naming_policy::match_separator( argv_traverser& tr, bool optional_value ) const +{ + if( p_separator->empty() ) { + if( !tr.token().is_empty() ) + return false; + + tr.trim( 1 ); + } + else { + if( !tr.match_front( p_separator.get() ) ) { + // if parameter has optional value separator is optional as well + if( optional_value && ( tr.eoi() || tr.match_front( ' ' ) ) ) { + return true; + } + return false; + } + + tr.trim( p_separator->size() ); + } + + return true; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +basic_naming_policy::matching( parameter const& p, argv_traverser& tr, bool ) const +{ + if( !match_prefix( tr ) ) + return false; + + if( !match_name( tr ) ) + return false; + + if( !match_separator( tr, p.p_optional_value ) ) + return false; + + return true; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_ID_POLICY_IPP_062904GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/iface/argument_factory.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/iface/argument_factory.hpp new file mode 100644 index 00000000..6f549653 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/iface/argument_factory.hpp @@ -0,0 +1,51 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : defines interface for argument_factory +// *************************************************************************** + +#ifndef BOOST_RT_CLA_IFACE_ARGUMENT_FACTORY_HPP_062604GER +#define BOOST_RT_CLA_IFACE_ARGUMENT_FACTORY_HPP_062604GER + +// Boost.Runtime.Parameter +#include +#include + +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** argument_factory ************** // +// ************************************************************************** // +// another name can be argument production policy + +class argument_factory { +public: + // Argument factory interface + virtual argument_ptr produce_using( parameter& p, argv_traverser& tr ) = 0; /// produce argument based on input + virtual argument_ptr produce_using( parameter& p, parser const& ) = 0; /// produce argument based on internal generator and/or values of other parameters + virtual void argument_usage_info( format_stream& fs ) = 0; /// argument value format information +protected: + BOOST_TEST_PROTECTED_VIRTUAL ~argument_factory() {} +}; + +} // namespace boost + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace cla + +#endif // BOOST_RT_CLA_IFACE_ARGUMENT_FACTORY_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/iface/id_policy.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/iface/id_policy.hpp new file mode 100644 index 00000000..c69a0945 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/iface/id_policy.hpp @@ -0,0 +1,73 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : defines interface for identification_policy +// *************************************************************************** + +#ifndef BOOST_RT_CLA_IFACE_ID_POLICY_HPP_062604GER +#define BOOST_RT_CLA_IFACE_ID_POLICY_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include + +// Boost.Test +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** identification_policy ************** // +// ************************************************************************** // + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4244) +#endif + +class identification_policy { +public: + // Public properties + unit_test::readwrite_property p_type_id; + + // Policy interface + virtual bool responds_to( cstring name ) const = 0; + virtual cstring id_2_report() const = 0; + virtual void usage_info( format_stream& fs ) const = 0; + virtual bool matching( parameter const& p, argv_traverser& tr, bool primary ) const = 0; + + virtual bool conflict_with( identification_policy const& ) const = 0; + +protected: + // Constructor + explicit identification_policy( rtti::id_t dyn_type ) + : p_type_id( dyn_type ) + {} + BOOST_TEST_PROTECTED_VIRTUAL ~identification_policy() {} +}; + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_IFACE_ID_POLICY_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/modifier.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/modifier.hpp new file mode 100644 index 00000000..bc6a7eb9 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/modifier.hpp @@ -0,0 +1,69 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : parameter modifiers +// *************************************************************************** + +#ifndef BOOST_RT_CLA_MODIFIER_HPP_062604GER +#define BOOST_RT_CLA_MODIFIER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** environment variable modifiers ************** // +// ************************************************************************** // + +namespace { + +nfp::typed_keyword optional_m; +nfp::named_parameter optional( true ); +nfp::typed_keyword required_m; +nfp::named_parameter required( true ); +nfp::typed_keyword multiplicable_m; +nfp::named_parameter multiplicable( true ); +nfp::typed_keyword guess_name_m; +nfp::named_parameter guess_name( true ); +nfp::typed_keyword ignore_mismatch_m; +nfp::named_parameter ignore_mismatch( true ); +nfp::typed_keyword optional_value_m; +nfp::named_parameter optional_value( true ); + +nfp::typed_keyword input_separator; +nfp::typed_keyword prefix; +nfp::typed_keyword name; +nfp::typed_keyword separator; +nfp::typed_keyword description; +nfp::typed_keyword default_refer_to; + +nfp::keyword default_value; +nfp::keyword handler; +nfp::keyword interpreter; +nfp::keyword assign_to; + +} // local namespace + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_MODIFIER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/named_parameter.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/named_parameter.hpp new file mode 100644 index 00000000..51ef1da1 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/named_parameter.hpp @@ -0,0 +1,93 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines model of named parameter +// *************************************************************************** + +#ifndef BOOST_RT_CLA_NAMED_PARAMETER_HPP_062604GER +#define BOOST_RT_CLA_NAMED_PARAMETER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** string_name_policy ************** // +// ************************************************************************** // + +class string_name_policy : public basic_naming_policy { +public: + // Constructor + string_name_policy(); + BOOST_RT_PARAM_UNNEEDED_VIRTUAL ~string_name_policy() {} + + // policy interface + virtual bool responds_to( cstring name ) const; + virtual bool conflict_with( identification_policy const& ) const; + + // Accept modifier + template + void accept_modifier( Modifier const& m ) + { + basic_naming_policy::accept_modifier( m ); + + if( m.has( guess_name_m ) ) + m_guess_name = true; + } + +private: + // Naming policy interface + virtual bool match_name( argv_traverser& tr ) const; + + // Data members + bool m_guess_name; +}; + +// ************************************************************************** // +// ************** runtime::cla::named_parameter ************** // +// ************************************************************************** // + +template +class named_parameter_t : public basic_parameter { + typedef basic_parameter base; +public: + // Constructors + explicit named_parameter_t( cstring name ) : base( name ) {} +}; + +//____________________________________________________________________________// + +BOOST_RT_CLA_NAMED_PARAM_GENERATORS( named_parameter ) + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_RT_PARAM_OFFLINE + +# define BOOST_RT_PARAM_INLINE inline +# include + +#endif + +#endif // BOOST_RT_CLA_NAMED_PARAMETER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/named_parameter.ipp b/cpp/BoostParts/boost/test/utils/runtime/cla/named_parameter.ipp new file mode 100644 index 00000000..77f69aae --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/named_parameter.ipp @@ -0,0 +1,129 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : implements model of named parameter +// *************************************************************************** + +#ifndef BOOST_RT_CLA_NAMED_PARAMETER_IPP_062904GER +#define BOOST_RT_CLA_NAMED_PARAMETER_IPP_062904GER + +// Boost.Runtime.Parameter +#include + +#include +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** string_name_policy ************** // +// ************************************************************************** // + +BOOST_RT_PARAM_INLINE +string_name_policy::string_name_policy() +: basic_naming_policy( rtti::type_id() ) +, m_guess_name( false ) +{ + assign_op( p_prefix.value, BOOST_RT_PARAM_CSTRING_LITERAL( "-" ), 0 ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +string_name_policy::responds_to( cstring name ) const +{ + std::pair mm_pos; + + mm_pos = unit_test::mismatch( name.begin(), name.end(), p_name->begin(), p_name->end() ); + + return mm_pos.first == name.end() && (m_guess_name || (mm_pos.second == p_name->end()) ); +} + +//____________________________________________________________________________// + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4244) +#endif + +BOOST_RT_PARAM_INLINE bool +string_name_policy::conflict_with( identification_policy const& id ) const +{ + if( id.p_type_id == p_type_id ) { + string_name_policy const& snp = static_cast( id ); + + if( p_name->empty() || snp.p_name->empty() ) + return false; + + if( p_prefix != snp.p_prefix ) + return false; + + std::pair mm_pos = + unit_test::mismatch( p_name->begin(), p_name->end(), snp.p_name->begin(), snp.p_name->end() ); + + return mm_pos.first != p_name->begin() && // there is common substring + ((m_guess_name && (mm_pos.second == snp.p_name->end()) ) || // that match other guy and I am guessing + (snp.m_guess_name && (mm_pos.first == p_name->end()) )); // or me and the other guy is + } + + if( id.p_type_id == rtti::type_id() ) { + char_name_policy const& cnp = static_cast( id ); + + return m_guess_name && + (p_prefix == cnp.p_prefix) && + unit_test::first_char( cstring( p_name ) ) == unit_test::first_char( cstring( cnp.p_name ) ); + } + + return false; +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE bool +string_name_policy::match_name( argv_traverser& tr ) const +{ + if( !m_guess_name ) + return basic_naming_policy::match_name( tr ); + + cstring in = tr.input(); + + std::pair mm_pos; + + mm_pos = unit_test::mismatch( in.begin(), in.end(), p_name->begin(), p_name->end() ); + + if( mm_pos.first == in.begin() ) + return false; + + tr.trim( mm_pos.first - in.begin() ); + + return true; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_NAMED_PARAMETER_IPP_062904GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/parameter.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/parameter.hpp new file mode 100644 index 00000000..753268a9 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/parameter.hpp @@ -0,0 +1,150 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 81913 $ +// +// Description : defines model of formal parameter +// *************************************************************************** + +#ifndef BOOST_RT_CLA_PARAMETER_HPP_062604GER +#define BOOST_RT_CLA_PARAMETER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include +#include +#include + +#include +#include +#include +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::parameter ************** // +// ************************************************************************** // + +class parameter : public BOOST_RT_PARAM_NAMESPACE::parameter { +public: + parameter( identification_policy& ID, argument_factory& F, bool optional_value = false ) + : p_optional( false ) + , p_multiplicable( false ) + , p_optional_value( optional_value ) + , m_id_policy( ID ) + , m_arg_factory( F ) + {} + + // Destructor + virtual ~parameter() {} + + unit_test::readwrite_property p_optional; + unit_test::readwrite_property p_multiplicable; + unit_test::readwrite_property p_optional_value; + unit_test::readwrite_property p_description; + + // parameter properties modification + template + void accept_modifier( Modifier const& m ) + { + if( m.has( optional_m ) ) + p_optional.value = true; + + if( m.has( required_m ) ) + p_optional.value = false; + + if( m.has( multiplicable_m ) ) + p_multiplicable.value = true; + + if( m.has( optional_value_m ) ) + p_optional_value.value = true; + + nfp::optionally_assign( p_description.value, m, description ); + } + + // access methods + bool has_argument() const { return m_actual_argument!=0; } + argument const& actual_argument() const { return *m_actual_argument; } + argument_ptr actual_argument() { return m_actual_argument; } + + + // identification interface + bool responds_to( cstring name ) const { return m_id_policy.responds_to( name ); } + bool conflict_with( parameter const& p ) const + { + return (id_2_report() == p.id_2_report() && !id_2_report().is_empty()) || + m_id_policy.conflict_with( p.m_id_policy ) || + ((m_id_policy.p_type_id != p.m_id_policy.p_type_id) && p.m_id_policy.conflict_with( m_id_policy )); + } + cstring id_2_report() const { return m_id_policy.id_2_report(); } + void usage_info( format_stream& fs ) const + { + m_id_policy.usage_info( fs ); + if( p_optional_value ) + fs << BOOST_RT_PARAM_LITERAL( '[' ); + + m_arg_factory.argument_usage_info( fs ); + + if( p_optional_value ) + fs << BOOST_RT_PARAM_LITERAL( ']' ); + } + + // argument match/produce based on input + bool matching( argv_traverser& tr, bool primary ) const + { + return m_id_policy.matching( *this, tr, primary ); + } + + // argument production based on different source + void produce_argument( argv_traverser& tr ) + { + m_id_policy.matching( *this, tr, true ); // !! can we save this position somehow + m_actual_argument = m_arg_factory.produce_using( *this, tr ); + } + void produce_argument( parser const& p ) + { + m_actual_argument = m_arg_factory.produce_using( *this, p ); + } + +private: + //Data members + identification_policy& m_id_policy; + argument_factory& m_arg_factory; + argument_ptr m_actual_argument; +}; + +//____________________________________________________________________________// + +template +inline shared_ptr +operator-( shared_ptr p, Modifier const& m ) +{ + p->accept_modifier( m ); + + return p; +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_PARAMETER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/parser.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/parser.hpp new file mode 100644 index 00000000..5c3c341d --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/parser.hpp @@ -0,0 +1,153 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : defines parser - public interface for CLA parsing and accessing +// *************************************************************************** + +#ifndef BOOST_RT_CLA_PARSER_HPP_062604GER +#define BOOST_RT_CLA_PARSER_HPP_062604GER + +// Boost.Runtime.Parameter +#include +#include +#include + +#include +#include +#include + +// Boost +#include + +// STL +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::parser ************** // +// ************************************************************************** // + +namespace cla_detail { + +template +class global_mod_parser { +public: + global_mod_parser( parser& p, Modifier const& m ) + : m_parser( p ) + , m_modifiers( m ) + {} + + template + global_mod_parser const& + operator<<( shared_ptr param ) const + { + param->accept_modifier( m_modifiers ); + + m_parser << param; + + return *this; + } + +private: + // Data members; + parser& m_parser; + Modifier const& m_modifiers; +}; + +} + +// ************************************************************************** // +// ************** runtime::cla::parser ************** // +// ************************************************************************** // + +class parser { +public: + typedef std::list::const_iterator param_iterator; + + // Constructor + explicit parser( cstring program_name = cstring() ); + + // parameter list construction interface + parser& operator<<( parameter_ptr param ); + + // parser and global parameters modifiers + template + cla_detail::global_mod_parser + operator-( Modifier const& m ) + { + nfp::optionally_assign( m_traverser.p_separator.value, m, input_separator ); + nfp::optionally_assign( m_traverser.p_ignore_mismatch.value, m, ignore_mismatch_m ); + + return cla_detail::global_mod_parser( *this, m ); + } + + // input processing method + void parse( int& argc, char_type** argv ); + + // parameters access + param_iterator first_param() const; + param_iterator last_param() const; + + // arguments access + const_argument_ptr operator[]( cstring string_id ) const; + cstring get( cstring string_id ) const; + + template + T const& get( cstring string_id ) const + { + return arg_value( valid_argument( string_id ) ); + } + + template + void get( cstring string_id, boost::optional& res ) const + { + const_argument_ptr actual_arg = (*this)[string_id]; + + if( actual_arg ) + res = arg_value( *actual_arg ); + else + res.reset(); + } + + // help/usage + void usage( out_stream& ostr ); + void help( out_stream& ostr ); + +private: + argument const& valid_argument( cstring string_id ) const; + + // Data members + argv_traverser m_traverser; + std::list m_parameters; + dstring m_program_name; +}; + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_RT_PARAM_OFFLINE + +# define BOOST_RT_PARAM_INLINE inline +# include + +#endif + +#endif // BOOST_RT_CLA_PARSER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/parser.ipp b/cpp/BoostParts/boost/test/utils/runtime/cla/parser.ipp new file mode 100644 index 00000000..995411a7 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/parser.ipp @@ -0,0 +1,258 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : implements parser - public interface for CLA parsing and accessing +// *************************************************************************** + +#ifndef BOOST_RT_CLA_PARSER_IPP_062904GER +#define BOOST_RT_CLA_PARSER_IPP_062904GER + +// Boost.Runtime.Parameter +#include +#include +#include + +#include +#include +#include +#include +#include + +// Boost.Test +#include +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::parser ************** // +// ************************************************************************** // + +BOOST_RT_PARAM_INLINE +parser::parser( cstring program_name ) +{ + assign_op( m_program_name, program_name, 0 ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE parser::param_iterator +parser::first_param() const +{ + return m_parameters.begin(); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE parser::param_iterator +parser::last_param() const +{ + return m_parameters.end(); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE argument const& +parser::valid_argument( cstring string_id ) const +{ + const_argument_ptr arg = (*this)[string_id]; + + BOOST_RT_PARAM_VALIDATE_LOGIC( !!arg, "Actual argument for parameter " << string_id << " is not present" ); + + return *arg; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE parser& +parser::operator<<( parameter_ptr new_param ) +{ + BOOST_TEST_FOREACH( parameter_ptr, old_param, m_parameters ) { + BOOST_RT_PARAM_VALIDATE_LOGIC( !old_param->conflict_with( *new_param ), + BOOST_RT_PARAM_LITERAL( "Definition of parameter " ) << new_param->id_2_report() << + BOOST_RT_PARAM_LITERAL( " conflicts with defintion of parameter " ) << old_param->id_2_report() ); + } + + m_parameters.push_back( new_param ); + + return *this; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +parser::parse( int& argc, char_type** argv ) +{ + if( m_program_name.empty() ) { + m_program_name.assign( argv[0] ); + dstring::size_type pos = m_program_name.find_last_of( BOOST_RT_PARAM_LITERAL( "/\\" ) ); + + if( pos != static_cast(cstring::npos) ) + m_program_name.erase( 0, pos+1 ); + } + + m_traverser.init( argc, argv ); + + try { + while( !m_traverser.eoi() ) { + parameter_ptr found_param; + + BOOST_RT_PARAM_TRACE( "Total " << m_parameters.size() << " parameters registered" ); + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + BOOST_RT_PARAM_TRACE( "Try parameter " << curr_param->id_2_report() ); + + if( curr_param->matching( m_traverser, !found_param ) ) { + BOOST_RT_PARAM_TRACE( "Match found" ); + BOOST_RT_CLA_VALIDATE_INPUT( !found_param, (m_traverser.rollback(),m_traverser), "Ambiguous input" ); + + found_param = curr_param; + } + + m_traverser.rollback(); + } + + if( !found_param ) { + BOOST_RT_PARAM_TRACE( "No match found" ); + BOOST_RT_CLA_VALIDATE_INPUT( m_traverser.handle_mismatch(), m_traverser, + BOOST_RT_PARAM_LITERAL( "Unexpected input" ) ); + + continue; + } + + BOOST_RT_PARAM_TRACE( "Parse argument value" ); + found_param->produce_argument( m_traverser ); + + m_traverser.commit(); + } + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + if( !curr_param->p_optional && !curr_param->actual_argument() ) { + curr_param->produce_argument( *this ); + + BOOST_RT_PARAM_VALIDATE_LOGIC( curr_param->actual_argument(), + BOOST_RT_PARAM_LITERAL( "Required argument for parameter " ) << curr_param->id_2_report() + << BOOST_RT_PARAM_LITERAL( " is missing" ) ); + } + } + } + catch( bad_lexical_cast const& ) { + BOOST_RT_PARAM_REPORT_LOGIC_ERROR( + BOOST_RT_PARAM_LITERAL( "String to value convertion error during input parsing" ) ); + } + + m_traverser.remainder( argc, argv ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE const_argument_ptr +parser::operator[]( cstring string_id ) const +{ + parameter_ptr found_param; + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + if( curr_param->responds_to( string_id ) ) { + BOOST_RT_PARAM_VALIDATE_LOGIC( !found_param, + BOOST_RT_PARAM_LITERAL( "Ambiguous parameter string id: " ) << string_id ); + + found_param = curr_param; + } + } + + return found_param ? found_param->actual_argument() : argument_ptr(); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE cstring +parser::get( cstring string_id ) const +{ + return get( string_id ); +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +parser::usage( out_stream& ostr ) +{ + if( m_program_name.empty() ) + assign_op( m_program_name, BOOST_RT_PARAM_CSTRING_LITERAL( "" ), 0 ); + + format_stream fs; + + fs << m_program_name; + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + fs << BOOST_RT_PARAM_LITERAL( ' ' ); + + if( curr_param->p_optional ) + fs << BOOST_RT_PARAM_LITERAL( '[' ); + + curr_param->usage_info( fs ); + + if( curr_param->p_optional ) + fs << BOOST_RT_PARAM_LITERAL( ']' ); + + if( curr_param->p_multiplicable ) { + fs << BOOST_RT_PARAM_CSTRING_LITERAL( " ... " ); + + if( curr_param->p_optional ) + fs << BOOST_RT_PARAM_LITERAL( '[' ); + + curr_param->usage_info( fs ); + + if( curr_param->p_optional ) + fs << BOOST_RT_PARAM_LITERAL( ']' ); + } + } + + ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "Usage:\n" ) << fs.str() << std::endl; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +parser::help( out_stream& ostr ) +{ + usage( ostr ); + + bool need_where = true; + + BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { + if( curr_param->p_description->empty() ) + continue; + + if( need_where ) { + ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "where:\n" ); + need_where = false; + } + + ostr << curr_param->id_2_report() << BOOST_RT_PARAM_CSTRING_LITERAL( " - " ) << curr_param->p_description << std::endl; + } +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_PARSER_IPP_062904GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/typed_parameter.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/typed_parameter.hpp new file mode 100644 index 00000000..2d2e02ec --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/typed_parameter.hpp @@ -0,0 +1,70 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : generic typed parameter model +// *************************************************************************** + +#ifndef BOOST_RT_CLA_TYPED_PARAMETER_HPP_062604GER +#define BOOST_RT_CLA_TYPED_PARAMETER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include +#include + +#include +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::typed_parameter ************** // +// ************************************************************************** // + +template +class typed_parameter : public cla::parameter { +public: + explicit typed_parameter( identification_policy& ID ) + : cla::parameter( ID, m_arg_factory, rtti::type_id() == rtti::type_id() ) + {} + + // parameter properties modification + template + void accept_modifier( Modifier const& m ) + { + cla::parameter::accept_modifier( m ); + + m_arg_factory.accept_modifier( m ); + + BOOST_RT_PARAM_VALIDATE_LOGIC( !p_optional || !m_arg_factory.m_value_generator, + BOOST_RT_PARAM_LITERAL( "can't define a value generator for optional parameter " ) << id_2_report() ); + } + +private: + // Data members + typed_argument_factory m_arg_factory; +}; + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_TYPED_PARAMETER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/validation.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/validation.hpp new file mode 100644 index 00000000..6b2fea97 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/validation.hpp @@ -0,0 +1,55 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : input validation helpers definition +// *************************************************************************** + +#ifndef BOOST_RT_CLA_VALIDATION_HPP_062604GER +#define BOOST_RT_CLA_VALIDATION_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::report_input_error ************** // +// ************************************************************************** // + +void report_input_error( argv_traverser const& tr, format_stream& msg ); + +//____________________________________________________________________________// + +#define BOOST_RT_CLA_VALIDATE_INPUT( b, tr, msg ) \ + if( b ) ; else ::boost::BOOST_RT_PARAM_NAMESPACE::cla::report_input_error( tr, format_stream().ref() << msg ) + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_RT_PARAM_OFFLINE + +# define BOOST_RT_PARAM_INLINE inline +# include + +#endif + +#endif // BOOST_RT_CLA_VALIDATION_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/validation.ipp b/cpp/BoostParts/boost/test/utils/runtime/cla/validation.ipp new file mode 100644 index 00000000..8cde449c --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/validation.ipp @@ -0,0 +1,65 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : input validation helpers implementation +// *************************************************************************** + +#ifndef BOOST_RT_CLA_VALIDATION_IPP_070604GER +#define BOOST_RT_CLA_VALIDATION_IPP_070604GER + +// Boost.Runtime.Parameter +#include + +#include +#include +#include // BOOST_RT_PARAM_NAMESPACE::logic_error + +// Boost +#include + +// STL + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +// ************************************************************************** // +// ************** runtime::cla::validation ************** // +// ************************************************************************** // + +BOOST_RT_PARAM_INLINE void +report_input_error( argv_traverser const& tr, format_stream& msg ) +{ + if( tr.eoi() ) + msg << BOOST_RT_PARAM_LITERAL( " at the end of input" ); + else { + msg << BOOST_RT_PARAM_LITERAL( " in the following position: " ); + + if( tr.input().size() > 5 ) + msg << tr.input().substr( 0, 5 ) << BOOST_RT_PARAM_LITERAL( "..." ); + else + msg << tr.input(); + } + + throw BOOST_RT_PARAM_NAMESPACE::logic_error( msg.str() ); +} + +//____________________________________________________________________________// + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_VALIDATION_IPP_070604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/value_generator.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/value_generator.hpp new file mode 100644 index 00000000..1851592b --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/value_generator.hpp @@ -0,0 +1,81 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : specific value generators +// *************************************************************************** + +#ifndef BOOST_RT_CLA_VALUE_GENERATOR_HPP_062604GER +#define BOOST_RT_CLA_VALUE_GENERATOR_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +namespace rt_cla_detail { + +// ************************************************************************** // +// ************** runtime::cla::const_generator ************** // +// ************************************************************************** // + +template +class const_generator { +public: + // Constructor + explicit const_generator( T const& t ) : m_const_value( t ) {} + + // generator interface + void operator()( parser const&, boost::optional& t ) const { t = m_const_value; } + +private: + // Data members + T m_const_value; +}; + +// ************************************************************************** // +// ************** runtime::cla::ref_generator ************** // +// ************************************************************************** // + +template +class ref_generator { +public: + // Constructor + explicit ref_generator( cstring ref_id ) : m_ref_id( ref_id ) {} + + // generator interface + void operator()( parser const& p, boost::optional& t ) const + { + p.get( m_ref_id, t ); + } + +private: + // Data members + cstring m_ref_id; +}; + +//____________________________________________________________________________// + +} // namespace rt_cla_detail + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_VALUE_GENERATOR_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/cla/value_handler.hpp b/cpp/BoostParts/boost/test/utils/runtime/cla/value_handler.hpp new file mode 100644 index 00000000..2bc74b23 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/cla/value_handler.hpp @@ -0,0 +1,57 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : specific value handlers +// *************************************************************************** + +#ifndef BOOST_RT_CLA_VALUE_HANDLER_HPP_062604GER +#define BOOST_RT_CLA_VALUE_HANDLER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace cla { + +namespace rt_cla_detail { + +// ************************************************************************** // +// ************** runtime::cla::assigner ************** // +// ************************************************************************** // + +template +class assigner { +public: + // Constructor + explicit assigner( T& loc ) : m_target( loc ) {} + + // value handler implementation + void operator()( parameter const&, T& t ) { m_target = t; } + +private: + // Data members + T& m_target; +}; + +} // namespace rt_cla_detail + +} // namespace cla + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CLA_VALUE_HANDLER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/config.hpp b/cpp/BoostParts/boost/test/utils/runtime/config.hpp new file mode 100644 index 00000000..3f3ede8f --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/config.hpp @@ -0,0 +1,156 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : Runtime.Param library configuration +// *************************************************************************** + +#ifndef BOOST_RT_CONFIG_HPP_062604GER +#define BOOST_RT_CONFIG_HPP_062604GER + +// Boost +#include +#ifdef BOOST_MSVC +# pragma warning(disable: 4511) // copy constructor could not be generated +# pragma warning(disable: 4512) // assignment operator could not be generated +# pragma warning(disable: 4181) // qualifier applied to reference type; ignored +# pragma warning(disable: 4675) // resolved overload was found by argument-dependent lookup +#endif + +// Boost.Test +#include +#include +#include +#include // operator<<(boost::runtime::cstring) + +// STL +#include +#include + +//____________________________________________________________________________// + +#ifndef BOOST_RT_PARAM_CUSTOM_STRING +# ifndef BOOST_RT_PARAM_WIDE_STRING +# define BOOST_RT_PARAM_NAMESPACE runtime +# else +# define BOOST_RT_PARAM_NAMESPACE wide_runtime +# endif +#endif + +#ifdef __SUNPRO_CC +extern int putenv(char*); +#endif + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +#ifndef BOOST_RT_PARAM_CUSTOM_STRING +# ifndef BOOST_RT_PARAM_WIDE_STRING + +typedef char char_type; +typedef std::string dstring; +typedef unit_test::const_string cstring; +typedef unit_test::literal_string literal_cstring; +typedef wrap_stringstream format_stream; + +#ifdef BOOST_CLASSIC_IOSTREAMS +typedef std::ostream out_stream; +#else +typedef std::basic_ostream out_stream; +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4996) // putenv +#endif + +#ifndef UNDER_CE +#if defined(__COMO__) && 0 +inline void +putenv_impl( cstring name, cstring value ) +{ + using namespace std; + // !! this may actually fail. What should we do? + setenv( name.begin(), value.begin(), 1 ); +} +#else +inline void +putenv_impl( cstring name, cstring value ) +{ + format_stream fs; + + fs << name << '=' << value; + + // !! this may actually fail. What should we do? + // const_cast is used to satisfy putenv interface + using namespace std; + putenv( const_cast( fs.str().c_str() ) ); +} +#endif +#endif + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#define BOOST_RT_PARAM_LITERAL( l ) l +#define BOOST_RT_PARAM_CSTRING_LITERAL( l ) cstring( l, sizeof( l ) - 1 ) +#define BOOST_RT_PARAM_GETENV getenv +#define BOOST_RT_PARAM_PUTENV ::boost::BOOST_RT_PARAM_NAMESPACE::putenv_impl +#define BOOST_RT_PARAM_EXCEPTION_INHERIT_STD + +//____________________________________________________________________________// + +# else + +typedef wchar_t char_type; +typedef std::basic_string dstring; +typedef unit_test::basic_cstring cstring; +typedef const unit_test::basic_cstring literal_cstring; +typedef wrap_wstringstream format_stream; +typedef std::wostream out_stream; + +#ifndef UNDER_CE +inline void +putenv_impl( cstring name, cstring value ) +{ + format_stream fs; + + fs << name << '=' << value; + + // !! this may actually fail. What should we do? + // const_cast is used to satisfy putenv interface + using namespace std; + wputenv( const_cast( fs.str().c_str() ) ); +} +#endif + +#define BOOST_RT_PARAM_LITERAL( l ) L ## l +#define BOOST_RT_PARAM_CSTRING_LITERAL( l ) cstring( L ## l, sizeof( L ## l )/sizeof(wchar_t) - 1 ) +#define BOOST_RT_PARAM_GETENV wgetenv +#define BOOST_RT_PARAM_PUTENV putenv_impl + +# endif +#endif + +#ifdef __GNUC__ +#define BOOST_RT_PARAM_UNNEEDED_VIRTUAL virtual +#else +#define BOOST_RT_PARAM_UNNEEDED_VIRTUAL +#endif + +//____________________________________________________________________________// + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_CONFIG_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/env/environment.hpp b/cpp/BoostParts/boost/test/utils/runtime/env/environment.hpp new file mode 100644 index 00000000..f5e88a26 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/env/environment.hpp @@ -0,0 +1,172 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : defines and implements inline model of program environment +// *************************************************************************** + +#ifndef BOOST_RT_ENV_ENVIRONMENT_HPP_062604GER +#define BOOST_RT_ENV_ENVIRONMENT_HPP_062604GER + +#ifdef UNDER_CE +#error Windows CE does not support environment variables. +#endif + +// Boost.Runtime.Parameter +#include +#include +#include +#include + +#include +#include +#include + +// Boost.Test +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::environment implementation ************** // +// ************************************************************************** // + +namespace environment { + +namespace rt_env_detail { + +template +variable_data& +init_new_var( cstring var_name, Modifiers m = nfp::no_params ) +{ + rt_env_detail::variable_data& new_vd = new_var_record( var_name ); + + cstring str_value = sys_read_var( new_vd.m_var_name ); + + if( !str_value.is_empty() ) { + try { + boost::optional value; + + if( m.has( interpreter ) ) + m[interpreter]( str_value, value ); + else + interpret_argument_value( str_value, value, 0 ); + + if( !!value ) { + new_vd.m_value.reset( new typed_argument( new_vd ) ); + + arg_value( *new_vd.m_value ) = *value; + } + } + catch( ... ) { // !! could we do that + // !! should we report an error? + } + } + + if( !new_vd.m_value && m.has( default_value ) ) { + new_vd.m_value.reset( new typed_argument( new_vd ) ); + + nfp::optionally_assign( arg_value( *new_vd.m_value ), m[default_value] ); + } + + nfp::optionally_assign( new_vd.m_global_id, m, global_id ); + + return new_vd; +} + +//____________________________________________________________________________// + +} // namespace rt_env_detail + +} // namespace environment + +// ************************************************************************** // +// ************** runtime::environment ************** // +// ************************************************************************** // + +namespace environment { + + // variable access + variable_base + var( cstring var_name ); + + //________________________________________________________________________// + + template + inline variable + var( cstring var_name ) + { + rt_env_detail::variable_data* vd = rt_env_detail::find_var_record( var_name ); + + return environment::variable( !vd ? rt_env_detail::init_new_var( var_name, nfp::no_params ) : *vd ); + } + + //________________________________________________________________________// + + template + inline variable + var( cstring var_name, Modifiers const& m ) + { + rt_env_detail::variable_data* vd = rt_env_detail::find_var_record( var_name ); + + return environment::variable( !vd ? rt_env_detail::init_new_var( var_name, m ) : *vd ); + } + + //________________________________________________________________________// + + // direct variable value access + inline cstring + get( cstring var_name ) + { + return environment::var( var_name ).value(); + } + + //________________________________________________________________________// + + template + inline T const& + get( cstring var_name ) + { + return environment::var( var_name ).value(); + } + + //________________________________________________________________________// + + template + inline void + get( cstring var_name, boost::optional& res ) + { + variable const& v = environment::var( var_name ); + v.value( res ); + } + + //________________________________________________________________________// + +} // namespace environment + +namespace env = environment; + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#ifndef BOOST_RT_PARAM_OFFLINE + +#define BOOST_RT_PARAM_INLINE inline +#include + +#endif + +#endif // BOOST_RT_ENV_ENVIRONMENT_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/env/environment.ipp b/cpp/BoostParts/boost/test/utils/runtime/env/environment.ipp new file mode 100644 index 00000000..0a4afe87 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/env/environment.ipp @@ -0,0 +1,125 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : implements model of program environment +// *************************************************************************** + +#ifndef BOOST_RT_ENV_ENVIRONMENT_IPP_062904GER +#define BOOST_RT_ENV_ENVIRONMENT_IPP_062904GER + +// Boost.Runtime.Parameter +#include +#include + +#include + +// Boost.Test +#include +#include + +// STL +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace environment { + +// ************************************************************************** // +// ************** runtime::environment ************** // +// ************************************************************************** // + +namespace rt_env_detail { + +typedef std::map registry; +typedef std::list keys; + +BOOST_RT_PARAM_INLINE registry& s_registry() { static registry instance; return instance; } +BOOST_RT_PARAM_INLINE keys& s_keys() { static keys instance; return instance; } + +BOOST_RT_PARAM_INLINE variable_data& +new_var_record( cstring var_name ) +{ + // save the name in list of keys + s_keys().push_back( dstring() ); + dstring& key = s_keys().back(); + assign_op( key, var_name, 0 ); + + // create and return new record + variable_data& new_var_data = s_registry()[key]; + + new_var_data.m_var_name = key; + + return new_var_data; +} + +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE variable_data* +find_var_record( cstring var_name ) +{ + registry::iterator it = s_registry().find( var_name ); + + return it == s_registry().end() ? 0 : &(it->second); +} + +//____________________________________________________________________________// + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4996) // getenv +#endif + +BOOST_RT_PARAM_INLINE cstring +sys_read_var( cstring var_name ) +{ + using namespace std; + return BOOST_RT_PARAM_GETENV( var_name.begin() ); +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +//____________________________________________________________________________// + +BOOST_RT_PARAM_INLINE void +sys_write_var( cstring var_name, format_stream& var_value ) +{ + BOOST_RT_PARAM_PUTENV( var_name, cstring( var_value.str() ) ); +} + +//____________________________________________________________________________// + +} // namespace rt_env_detail + +BOOST_RT_PARAM_INLINE variable_base +var( cstring var_name ) +{ + rt_env_detail::variable_data* vd = rt_env_detail::find_var_record( var_name ); + + BOOST_RT_PARAM_VALIDATE_LOGIC( !!vd, + BOOST_RT_PARAM_LITERAL( "First access to the environment variable " ) + << var_name << BOOST_RT_PARAM_LITERAL( " should be typed" ) ); + + return variable_base( *vd ); +} + +//____________________________________________________________________________// + +} // namespace environment + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_ENV_ENVIRONMENT_IPP_062904GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/env/fwd.hpp b/cpp/BoostParts/boost/test/utils/runtime/env/fwd.hpp new file mode 100644 index 00000000..0808d0ea --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/env/fwd.hpp @@ -0,0 +1,54 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 54633 $ +// +// Description : environment subsystem forward declarations +// *************************************************************************** + +#ifndef BOOST_RT_ENV_FWD_HPP_062604GER +#define BOOST_RT_ENV_FWD_HPP_062604GER + +#ifdef UNDER_CE +#error Windows CE does not support environment variables. +#endif + +// Boost.Runtime.Parameter +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace environment { + +class variable_base; +variable_base var( cstring var_name ); + +namespace rt_env_detail { + +struct variable_data; + +variable_data& new_var_record( cstring var_name ); +variable_data* find_var_record( cstring var_name ); + +cstring sys_read_var( cstring var_name ); +void sys_write_var( cstring var_name, format_stream& var_value ); + +} + +template class variable; + +} // namespace environment + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_ENV_FWD_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/env/modifier.hpp b/cpp/BoostParts/boost/test/utils/runtime/env/modifier.hpp new file mode 100644 index 00000000..4204d0be --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/env/modifier.hpp @@ -0,0 +1,47 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines variable modifiers +// *************************************************************************** + +#ifndef BOOST_RT_ENV_MODIFIER_HPP_062604GER +#define BOOST_RT_ENV_MODIFIER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +// Boost.Test +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace environment { + +// ************************************************************************** // +// ************** environment variable modifiers ************** // +// ************************************************************************** // + +namespace { + +nfp::typed_keyword global_id; +nfp::keyword default_value; +nfp::keyword interpreter; + +} // local namespace +} // namespace environment + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_ENV_MODIFIER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/env/variable.hpp b/cpp/BoostParts/boost/test/utils/runtime/env/variable.hpp new file mode 100644 index 00000000..2eb038e3 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/env/variable.hpp @@ -0,0 +1,223 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 81913 $ +// +// Description : defines model of program environment variable +// *************************************************************************** + +#ifndef BOOST_RT_ENV_VARIABLE_HPP_062604GER +#define BOOST_RT_ENV_VARIABLE_HPP_062604GER + +#ifdef UNDER_CE +#error Windows CE does not support environment variables. +#endif + +// Boost.Runtime.Parameter +#include +#include +#include +#include + +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace environment { + +// ************************************************************************** // +// ************** runtime::environment::variable_data ************** // +// ************************************************************************** // + +namespace rt_env_detail { + +struct variable_data : public runtime::parameter { + cstring m_var_name; + dstring m_global_id; + argument_ptr m_value; +}; + +} // namespace rt_env_detail + +// ************************************************************************** // +// ************** runtime::environment::variable_base ************** // +// ************************************************************************** // + +class variable_base { +public: + explicit variable_base( rt_env_detail::variable_data& data ) : m_data( &data ) {} + + // arguments access + template + T const& value() const + { + return arg_value( *m_data->m_value ); + } + + template + void value( boost::optional& res ) const + { + if( has_value() ) + res = arg_value( *m_data->m_value ); + else + res.reset(); + } + + bool has_value() const { return m_data->m_value!=0; } + cstring name() const { return m_data->m_var_name; } + +protected: + // Data members + rt_env_detail::variable_data* m_data; +} ; + +// ************************************************************************** // +// ************** runtime::environment::variable ************** // +// ************************************************************************** // + +template +class variable : public variable_base { +public: + // Constructors + explicit variable( cstring var_name ); + + template + explicit variable( cstring var_name, Modifiers const& m ); + + explicit variable( rt_env_detail::variable_data& data ) + : variable_base( data ) {} + + // other variable assignment + void operator=( variable const& v ) { m_data = v.m_data; } + + // access methods + T const& value() const { return variable_base::value(); } + +#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206)) || \ + BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593)) + template + void value( boost::optional& res ) const { variable_base::value( res ); } +#else + using variable_base::value; +#endif + + // Value assignment + template + void operator=( V const& v ) + { + if( !has_value() ) + m_data->m_value.reset( new typed_argument( *m_data ) ); + + arg_value( *m_data->m_value ) = v; + + rt_env_detail::sys_write_var( m_data->m_var_name, format_stream().ref() << value() ); + } +}; // class variable + +//____________________________________________________________________________// + +template +inline std::basic_ostream& +operator<<( std::basic_ostream& os, variable const& v ) +{ + os << v.name() << '='; + + if( v.has_value() ) + os << v.value(); + + return os; +} + +//____________________________________________________________________________// + +template +inline bool +operator==( variable ev, V const& v ) +{ + return ev.has_value() && ev.value() == v; +} + +//____________________________________________________________________________// + +template +inline bool +operator==( V const& v, variable ev ) +{ + return ev.has_value() && ev.value() == v; +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( variable ev, V const& v ) +{ + return !ev.has_value() || ev.value() != v; +} + +//____________________________________________________________________________// + +template +inline bool +operator!=( V const& v, variable ev ) +{ + return !ev.has_value() || ev.value() != v; +} + +//____________________________________________________________________________// + +} // namespace environment + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +// ************************************************************************** // +// ************************************************************************** // +// Implementation + +#include + +// ************************************************************************** // +// ************** runtime::environment::variable ************** // +// ************************************************************************** // + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace environment { + +template +variable::variable( cstring var_name ) +: variable_base( environment::var( var_name ) ) +{} + +//____________________________________________________________________________// + +template +template +variable::variable( cstring var_name, Modifiers const& m ) +: variable_base( environment::var( var_name, m ) ) +{} + +//____________________________________________________________________________// + +} // namespace environment + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_ENV_VARIABLE_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/fwd.hpp b/cpp/BoostParts/boost/test/utils/runtime/fwd.hpp new file mode 100644 index 00000000..8d298d72 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/fwd.hpp @@ -0,0 +1,41 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : global framework level forward declaration +// *************************************************************************** + +#ifndef BOOST_RT_FWD_HPP_062604GER +#define BOOST_RT_FWD_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +// Boost +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +class parameter; + +class argument; +typedef shared_ptr argument_ptr; +typedef shared_ptr const_argument_ptr; + +template class value_interpreter; +template class typed_argument; + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_FWD_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/interpret_argument_value.hpp b/cpp/BoostParts/boost/test/utils/runtime/interpret_argument_value.hpp new file mode 100644 index 00000000..cbf752dd --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/interpret_argument_value.hpp @@ -0,0 +1,163 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : default algorithms for string to specific type convertions +// *************************************************************************** + +#ifndef BOOST_RT_INTERPRET_ARGUMENT_VALUE_HPP_062604GER +#define BOOST_RT_INTERPRET_ARGUMENT_VALUE_HPP_062604GER + +// Boost.Runtime.Parameter +#include +#include + +// Boost.Test +#include +#include + +// Boost +#include +#include + +// STL +// !! could we eliminate these includes? +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::interpret_argument_value ************** // +// ************************************************************************** // +// returns true if source is used false otherwise + +// generic case +template +struct interpret_argument_value_impl { + static bool _( cstring source, boost::optional& res ) + { + BOOST_RT_PARAM_TRACE( "In interpret_argument_value_impl<" << typeid(T).name() << ">" ); + + res = lexical_cast( source ); + + BOOST_RT_PARAM_TRACE( "String " << source << " is interpreted as " << *res ); + return true; + } +}; + + +//____________________________________________________________________________// + +// dstring case +template<> +struct interpret_argument_value_impl { + static bool _( cstring source, boost::optional& res ) + { + BOOST_RT_PARAM_TRACE( "In interpret_argument_value_impl" ); + + res = dstring(); + assign_op( *res, source, 0 ); + + return true; + } +}; + +//____________________________________________________________________________// + +// cstring case +template<> +struct interpret_argument_value_impl { + static bool _( cstring source, boost::optional& res ) + { + BOOST_RT_PARAM_TRACE( "In interpret_argument_value_impl" ); + + res = source; + + return true; + } +}; + +//____________________________________________________________________________// + +// specialization for type bool +template<> +struct interpret_argument_value_impl { + static bool _( cstring source, boost::optional& res ) + { + BOOST_RT_PARAM_TRACE( "In interpret_argument_value_impl" ); + + static literal_cstring YES( BOOST_RT_PARAM_CSTRING_LITERAL( "YES" ) ); + static literal_cstring Y( BOOST_RT_PARAM_CSTRING_LITERAL( "Y" ) ); + static literal_cstring NO( BOOST_RT_PARAM_CSTRING_LITERAL( "NO" ) ); + static literal_cstring N( BOOST_RT_PARAM_CSTRING_LITERAL( "N" ) ); + static literal_cstring one( BOOST_RT_PARAM_CSTRING_LITERAL( "1" ) ); + static literal_cstring zero( BOOST_RT_PARAM_CSTRING_LITERAL( "0" ) ); + + source.trim(); + + if( case_ins_eq( source, YES ) || case_ins_eq( source, Y ) || case_ins_eq( source, one ) ) { + res = true; + return true; + } + else if( case_ins_eq( source, NO ) || case_ins_eq( source, N ) || case_ins_eq( source, zero ) ) { + res = false; + return true; + } + else { + res = true; + return false; + } + } +}; + +//____________________________________________________________________________// + +template +inline bool +interpret_argument_value( cstring source, boost::optional& res, long ) +{ + return interpret_argument_value_impl::_( source, res ); +} + +//____________________________________________________________________________// + +// specialization for list of values +template +inline bool +interpret_argument_value( cstring source, boost::optional >& res, int ) +{ + BOOST_RT_PARAM_TRACE( "In interpret_argument_value>" ); + + res = std::list(); + + while( !source.is_empty() ) { + // !! should we use token_iterator + cstring::iterator single_value_end = std::find( source.begin(), source.end(), BOOST_RT_PARAM_LITERAL( ',' ) ); + + boost::optional value; + interpret_argument_value( cstring( source.begin(), single_value_end ), value, 0 ); + + res->push_back( *value ); + + source.trim_left( single_value_end + 1 ); + } + + return true; +} + +//____________________________________________________________________________// + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_INTERPRET_ARGUMENT_VALUE_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/parameter.hpp b/cpp/BoostParts/boost/test/utils/runtime/parameter.hpp new file mode 100644 index 00000000..9baf561c --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/parameter.hpp @@ -0,0 +1,38 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : abstract interface for the formal parameter +// *************************************************************************** + +#ifndef BOOST_RT_PARAMETER_HPP_062604GER +#define BOOST_RT_PARAMETER_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::parameter ************** // +// ************************************************************************** // + +class parameter { +public: + virtual ~parameter() {} +}; + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_PARAMETER_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/trace.hpp b/cpp/BoostParts/boost/test/utils/runtime/trace.hpp new file mode 100644 index 00000000..ba15eb63 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/trace.hpp @@ -0,0 +1,30 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : optional internal tracing +// *************************************************************************** + +#ifndef BOOST_RT_TRACE_HPP_062604GER +#define BOOST_RT_TRACE_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +#ifdef BOOST_RT_PARAM_DEBUG + +#include + +# define BOOST_RT_PARAM_TRACE( str ) std::cerr << str << std::endl +#else +# define BOOST_RT_PARAM_TRACE( str ) +#endif + +#endif // BOOST_RT_TRACE_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/runtime/validation.hpp b/cpp/BoostParts/boost/test/utils/runtime/validation.hpp new file mode 100644 index 00000000..ff8e4691 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/runtime/validation.hpp @@ -0,0 +1,82 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : defines exceptions and validation tools +// *************************************************************************** + +#ifndef BOOST_RT_VALIDATION_HPP_062604GER +#define BOOST_RT_VALIDATION_HPP_062604GER + +// Boost.Runtime.Parameter +#include + +// Boost.Test +#include + +// Boost +#include + +// STL +#ifdef BOOST_RT_PARAM_EXCEPTION_INHERIT_STD +#include +#endif + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +// ************************************************************************** // +// ************** runtime::logic_error ************** // +// ************************************************************************** // + +class logic_error +#ifdef BOOST_RT_PARAM_EXCEPTION_INHERIT_STD +: public std::exception +#endif +{ + typedef shared_ptr dstring_ptr; +public: + // Constructor // !! could we eliminate shared_ptr + explicit logic_error( cstring msg ) : m_msg( new dstring( msg.begin(), msg.size() ) ) {} + ~logic_error() throw() {} + + dstring const& msg() const { return *m_msg; } + virtual char_type const* what() const throw() { return m_msg->c_str(); } + +private: + dstring_ptr m_msg; +}; + +// ************************************************************************** // +// ************** runtime::report_logic_error ************** // +// ************************************************************************** // + +inline void +report_logic_error( format_stream& msg ) +{ + throw BOOST_RT_PARAM_NAMESPACE::logic_error( msg.str() ); +} + +//____________________________________________________________________________// + +#define BOOST_RT_PARAM_REPORT_LOGIC_ERROR( msg ) \ + boost::BOOST_RT_PARAM_NAMESPACE::report_logic_error( format_stream().ref() << msg ) + +#define BOOST_RT_PARAM_VALIDATE_LOGIC( b, msg ) \ + if( b ) {} else BOOST_RT_PARAM_REPORT_LOGIC_ERROR( msg ) + +//____________________________________________________________________________// + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +#endif // BOOST_RT_VALIDATION_HPP_062604GER diff --git a/cpp/BoostParts/boost/test/utils/trivial_singleton.hpp b/cpp/BoostParts/boost/test/utils/trivial_singleton.hpp new file mode 100644 index 00000000..1ce77977 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/trivial_singleton.hpp @@ -0,0 +1,74 @@ +// (C) Copyright Gennadiy Rozental 2005-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : simple helpers for creating cusom output manipulators +// *************************************************************************** + +#ifndef BOOST_TEST_TRIVIAL_SIGNLETON_HPP_020505GER +#define BOOST_TEST_TRIVIAL_SIGNLETON_HPP_020505GER + +#include +#include + +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** singleton ************** // +// ************************************************************************** // + +template +class singleton : private boost::noncopyable { +public: + static Derived& instance() { static Derived the_inst; return the_inst; } +protected: + singleton() {} + ~singleton() {} +}; + +} // namespace unit_test + +#define BOOST_TEST_SINGLETON_CONS( type ) \ +friend class boost::unit_test::singleton; \ +type() {} \ +/**/ + +#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) + +#define BOOST_TEST_SINGLETON_INST( inst ) \ +template class unit_test::singleton< BOOST_JOIN( inst, _t ) > ; \ +namespace { BOOST_JOIN( inst, _t)& inst = BOOST_JOIN( inst, _t)::instance(); } + +#elif defined(__APPLE_CC__) && defined(__GNUC__) && __GNUC__ < 4 +#define BOOST_TEST_SINGLETON_INST( inst ) \ +static BOOST_JOIN( inst, _t)& inst = BOOST_JOIN (inst, _t)::instance(); + +#else + +#define BOOST_TEST_SINGLETON_INST( inst ) \ +namespace { BOOST_JOIN( inst, _t)& inst = BOOST_JOIN( inst, _t)::instance(); } + +#endif + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_TRIVIAL_SIGNLETON_HPP_020505GER diff --git a/cpp/BoostParts/boost/test/utils/wrap_stringstream.hpp b/cpp/BoostParts/boost/test/utils/wrap_stringstream.hpp new file mode 100644 index 00000000..a3eaff1c --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/wrap_stringstream.hpp @@ -0,0 +1,164 @@ +// (C) Copyright Gennadiy Rozental 2002-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 49312 $ +// +// Description : wraps strstream and stringstream (depends with one is present) +// to provide the unified interface +// *************************************************************************** + +#ifndef BOOST_WRAP_STRINGSTREAM_HPP_071894GER +#define BOOST_WRAP_STRINGSTREAM_HPP_071894GER + +// Boost.Test +#include + +// STL +#ifdef BOOST_NO_STRINGSTREAM +#include // for std::ostrstream +#else +#include // for std::ostringstream +#endif // BOOST_NO_STRINGSTREAM + +#include + +//____________________________________________________________________________// + +namespace boost { + +// ************************************************************************** // +// ************** basic_wrap_stringstream ************** // +// ************************************************************************** // + +template +class basic_wrap_stringstream { +public: +#if defined(BOOST_CLASSIC_IOSTREAMS) + typedef std::ostringstream wrapped_stream; +#elif defined(BOOST_NO_STRINGSTREAM) + typedef std::basic_ostrstream wrapped_stream; +#else + typedef std::basic_ostringstream wrapped_stream; +#endif // BOOST_NO_STRINGSTREAM + // Access methods + basic_wrap_stringstream& ref(); + wrapped_stream& stream(); + std::basic_string const& str(); + +private: + // Data members + wrapped_stream m_stream; + std::basic_string m_str; +}; + +//____________________________________________________________________________// + +template +inline basic_wrap_stringstream& +operator<<( basic_wrap_stringstream& targ, T const& t ) +{ + targ.stream() << t; + return targ; +} + +//____________________________________________________________________________// + +template +inline typename basic_wrap_stringstream::wrapped_stream& +basic_wrap_stringstream::stream() +{ + return m_stream; +} + +//____________________________________________________________________________// + +template +inline basic_wrap_stringstream& +basic_wrap_stringstream::ref() +{ + return *this; +} + +//____________________________________________________________________________// + +template +inline std::basic_string const& +basic_wrap_stringstream::str() +{ + +#ifdef BOOST_NO_STRINGSTREAM + m_str.assign( m_stream.str(), m_stream.pcount() ); + m_stream.freeze( false ); +#else + m_str = m_stream.str(); +#endif + + return m_str; +} + +//____________________________________________________________________________// + +template +inline basic_wrap_stringstream& +operator<<( basic_wrap_stringstream& targ, basic_wrap_stringstream& src ) +{ + targ << src.str(); + return targ; +} + +//____________________________________________________________________________// + +#if BOOST_TEST_USE_STD_LOCALE + +template +inline basic_wrap_stringstream& +operator<<( basic_wrap_stringstream& targ, std::ios_base& (BOOST_TEST_CALL_DECL *man)(std::ios_base&) ) +{ + targ.stream() << man; + return targ; +} + +//____________________________________________________________________________// + +template +inline basic_wrap_stringstream& +operator<<( basic_wrap_stringstream& targ, std::basic_ostream& (BOOST_TEST_CALL_DECL *man)(std::basic_ostream&) ) +{ + targ.stream() << man; + return targ; +} + +//____________________________________________________________________________// + +template +inline basic_wrap_stringstream& +operator<<( basic_wrap_stringstream& targ, std::basic_ios& (BOOST_TEST_CALL_DECL *man)(std::basic_ios&) ) +{ + targ.stream() << man; + return targ; +} + +//____________________________________________________________________________// + +#endif + +// ************************************************************************** // +// ************** wrap_stringstream ************** // +// ************************************************************************** // + +typedef basic_wrap_stringstream wrap_stringstream; +typedef basic_wrap_stringstream wrap_wstringstream; + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_WRAP_STRINGSTREAM_HPP_071894GER diff --git a/cpp/BoostParts/boost/test/utils/xml_printer.hpp b/cpp/BoostParts/boost/test/utils/xml_printer.hpp new file mode 100644 index 00000000..7fd851d5 --- /dev/null +++ b/cpp/BoostParts/boost/test/utils/xml_printer.hpp @@ -0,0 +1,118 @@ +// (C) Copyright Gennadiy Rozental 2004-2008. +// Distributed under the 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/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision: 57992 $ +// +// Description : common code used by any agent serving as XML printer +// *************************************************************************** + +#ifndef BOOST_TEST_XML_PRINTER_HPP_071894GER +#define BOOST_TEST_XML_PRINTER_HPP_071894GER + +// Boost.Test +#include +#include +#include +#include +#include + +// Boost +#include + +// STL +#include + +#include + +//____________________________________________________________________________// + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** xml print helpers ************** // +// ************************************************************************** // + +inline void +print_escaped( std::ostream& where_to, const_string value ) +{ + static fixed_mapping char_type( + '<' , "lt", + '>' , "gt", + '&' , "amp", + '\'', "apos" , + '"' , "quot", + + 0 + ); + + BOOST_TEST_FOREACH( char, c, value ) { + char const* ref = char_type[c]; + + if( ref ) + where_to << '&' << ref << ';'; + else + where_to << c; + } +} + +//____________________________________________________________________________// + +inline void +print_escaped( std::ostream& where_to, std::string const& value ) +{ + print_escaped( where_to, const_string( value ) ); +} + +//____________________________________________________________________________// + +template +inline void +print_escaped( std::ostream& where_to, T const& value ) +{ + where_to << value; +} + +//____________________________________________________________________________// + +typedef custom_manip attr_value; + +template +inline std::ostream& +operator<<( custom_printer const& p, T const& value ) +{ + *p << "=\""; + print_escaped( *p, value ); + *p << '"'; + + return *p; +} + +//____________________________________________________________________________// + +typedef custom_manip cdata; + +inline std::ostream& +operator<<( custom_printer const& p, const_string value ) +{ + return *p << BOOST_TEST_L( "" ); +} + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +//____________________________________________________________________________// + +#include + +#endif // BOOST_TEST_XML_PRINTER_HPP_071894GER diff --git a/cpp/BoostParts/boost/timer.hpp b/cpp/BoostParts/boost/timer.hpp new file mode 100644 index 00000000..1e3571e4 --- /dev/null +++ b/cpp/BoostParts/boost/timer.hpp @@ -0,0 +1,72 @@ +// boost timer.hpp header file ---------------------------------------------// + +// Copyright Beman Dawes 1994-99. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/timer for documentation. + +// Revision History +// 01 Apr 01 Modified to use new header. (JMaddock) +// 12 Jan 01 Change to inline implementation to allow use without library +// builds. See docs for more rationale. (Beman Dawes) +// 25 Sep 99 elapsed_max() and elapsed_min() added (John Maddock) +// 16 Jul 99 Second beta +// 6 Jul 99 Initial boost version + +#ifndef BOOST_TIMER_HPP +#define BOOST_TIMER_HPP + +#include +#include +#include + +# ifdef BOOST_NO_STDC_NAMESPACE + namespace std { using ::clock_t; using ::clock; } +# endif + + +namespace boost { + +// timer -------------------------------------------------------------------// + +// A timer object measures elapsed time. + +// It is recommended that implementations measure wall clock rather than CPU +// time since the intended use is performance measurement on systems where +// total elapsed time is more important than just process or CPU time. + +// Warnings: The maximum measurable elapsed time may well be only 596.5+ hours +// due to implementation limitations. The accuracy of timings depends on the +// accuracy of timing information provided by the underlying platform, and +// this varies a great deal from platform to platform. + +class timer +{ + public: + timer() { _start_time = std::clock(); } // postcondition: elapsed()==0 +// timer( const timer& src ); // post: elapsed()==src.elapsed() +// ~timer(){} +// timer& operator=( const timer& src ); // post: elapsed()==src.elapsed() + void restart() { _start_time = std::clock(); } // post: elapsed()==0 + double elapsed() const // return elapsed time in seconds + { return double(std::clock() - _start_time) / CLOCKS_PER_SEC; } + + double elapsed_max() const // return estimated maximum value for elapsed() + // Portability warning: elapsed_max() may return too high a value on systems + // where std::clock_t overflows or resets at surprising values. + { + return (double((std::numeric_limits::max)()) + - double(_start_time)) / double(CLOCKS_PER_SEC); + } + + double elapsed_min() const // return minimum value for elapsed() + { return double(1)/double(CLOCKS_PER_SEC); } + + private: + std::clock_t _start_time; +}; // timer + +} // namespace boost + +#endif // BOOST_TIMER_HPP diff --git a/cpp/BoostParts/libs/atomic/src/lockpool.cpp b/cpp/BoostParts/libs/atomic/src/lockpool.cpp new file mode 100644 index 00000000..da8e89ad --- /dev/null +++ b/cpp/BoostParts/libs/atomic/src/lockpool.cpp @@ -0,0 +1,24 @@ +#include + +// Copyright (c) 2011 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +namespace boost { +namespace atomics { +namespace detail { + +static lockpool::lock_type lock_pool_[41]; + +// NOTE: This function must NOT be inline. Otherwise MSVC 9 will sometimes generate broken code for modulus operation which result in crashes. +BOOST_ATOMIC_DECL lockpool::lock_type& lockpool::get_lock_for(const volatile void* addr) +{ + std::size_t index = reinterpret_cast(addr) % (sizeof(lock_pool_) / sizeof(*lock_pool_)); + return lock_pool_[index]; +} + +} +} +}