mirror of
https://github.com/boostorg/atomic.git
synced 2026-01-19 04:02:09 +00:00
Added support for atomic floating point operations.
The support includes: - The standard fetch_add/fetch_sub operations. - Extra operations: (fetch_/opaque_)negate, (opaque_)add/sub. - Extra capability macros: BOOST_ATOMIC_FLOAT/DOUBLE/LONG_DOUBLE_LOCK_FREE. The atomic operations are currently implemented on top of the integer-based backends and thus are mostly CAS-based. The CAS operations perform binary comparisons, and as such have different behavior wrt. special FP values like NaN and signed zero than normal C++. The support for floating point types is optional and can be disabled by defining BOOST_ATOMIC_NO_FLOATING_POINT. This can be useful if on a certain platform parameters of the floating point types cannot be deduced from the compiler-defined or system macros (in which case the compilation fails). http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0020r6.html
This commit is contained in:
109
doc/atomic.qbk
109
doc/atomic.qbk
@@ -375,6 +375,9 @@ The following macros affect library behavior:
|
||||
of this instruction, so running the library code on older CPUs will result in crashes, unless
|
||||
this macro is defined. Note that the macro does not affect MSVC, GCC and compatible compilers
|
||||
because the library infers this information from the compiler-defined macros.]]
|
||||
[[`BOOST_ATOMIC_NO_FLOATING_POINT`] [When defined, support for floating point operations is disabled.
|
||||
Floating point types shall be treated similar to trivially copyable structs and no capability macros
|
||||
will be defined.]]
|
||||
[[`BOOST_ATOMIC_FORCE_FALLBACK`] [When defined, all operations are implemented with locks.
|
||||
This is mostly used for testing and should not be used in real world projects.]]
|
||||
[[`BOOST_ATOMIC_DYN_LINK` and `BOOST_ALL_DYN_LINK`] [Control library linking. If defined,
|
||||
@@ -535,7 +538,8 @@ examples of the types compatible with this requirement:
|
||||
Note that classes with virtual functions or virtual base classes
|
||||
do not satisfy the requirements. Also be warned
|
||||
that structures with "padding" between data members may compare
|
||||
non-equal via [^memcmp] even though all members are equal.
|
||||
non-equal via [^memcmp] even though all members are equal. This may also be
|
||||
the case with some floating point types, which include padding bits themselves.
|
||||
|
||||
[section:interface_atomic_generic [^boost::atomic<['T]>] template class]
|
||||
|
||||
@@ -780,9 +784,90 @@ constraint which always defaults to `memory_order_seq_cst`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:interface_atomic_floating_point [^boost::atomic<['floating-point]>] template class]
|
||||
|
||||
[note The support for floating point types is optional and can be disabled by defining `BOOST_ATOMIC_NO_FLOATING_POINT`.]
|
||||
|
||||
In addition to the operations applicable to all atomic objects,
|
||||
[^boost::atomic<['F]>] for floating point
|
||||
types [^['F]] supports the following operations,
|
||||
which correspond to [^std::atomic<['F]>]:
|
||||
|
||||
[table
|
||||
[[Syntax] [Description]]
|
||||
[
|
||||
[`F fetch_add(F v, memory_order order)`]
|
||||
[Add `v` to variable, returning previous value]
|
||||
]
|
||||
[
|
||||
[`F fetch_sub(F v, memory_order order)`]
|
||||
[Subtract `v` from variable, returning previous value]
|
||||
]
|
||||
]
|
||||
|
||||
Additionally, as a [*Boost.Atomic] extension, the following operations are also provided:
|
||||
|
||||
[table
|
||||
[[Syntax] [Description]]
|
||||
[
|
||||
[`F fetch_negate(memory_order order)`]
|
||||
[Change the sign of the value stored in the variable, returning previous value]
|
||||
]
|
||||
[
|
||||
[`F negate(memory_order order)`]
|
||||
[Change the sign of the value stored in the variable, returning the result]
|
||||
]
|
||||
[
|
||||
[`F add(F v, memory_order order)`]
|
||||
[Add `v` to variable, returning the result]
|
||||
]
|
||||
[
|
||||
[`F sub(F v, memory_order order)`]
|
||||
[Subtract `v` from variable, returning the result]
|
||||
]
|
||||
[
|
||||
[`void opaque_negate(memory_order order)`]
|
||||
[Change the sign of the value stored in the variable, returning nothing]
|
||||
]
|
||||
[
|
||||
[`void opaque_add(F v, memory_order order)`]
|
||||
[Add `v` to variable, returning nothing]
|
||||
]
|
||||
[
|
||||
[`void opaque_sub(F v, memory_order order)`]
|
||||
[Subtract `v` from variable, returning nothing]
|
||||
]
|
||||
]
|
||||
|
||||
`order` always has `memory_order_seq_cst` as default parameter.
|
||||
|
||||
The [^opaque_['op]] variants of the operations
|
||||
may result in a more efficient code on some architectures because
|
||||
the original value of the atomic variable is not preserved.
|
||||
|
||||
In addition to these explicit operations, each
|
||||
[^boost::atomic<['F]>] object also supports operators `+=` and `-=`.
|
||||
Avoid using these operators, as they do not allow to specify a memory ordering
|
||||
constraint which always defaults to `memory_order_seq_cst`.
|
||||
|
||||
When using atomic operations with floating point types, bear in mind that [*Boost.Atomic]
|
||||
always performs bitwise comparison of the stored values. This means that operations like
|
||||
`compare_exchange*` may fail if the stored value and comparand have different binary representation,
|
||||
even if they would normally compare equal. This is typically the case when either of the numbers
|
||||
is [@https://en.wikipedia.org/wiki/Denormal_number denormalized]. This also means that the behavior
|
||||
with regard to special floating point values like NaN and signed zero is also different from normal C++.
|
||||
|
||||
Another source of the problem is padding bits that are added to some floating point types for alignment.
|
||||
One wide-spread example of that is Intel x87 extended double format, which is typically stored as 80 bits
|
||||
of value padded with 16 or 48 unused bits. These padding bits are often uninitialized and contain garbage,
|
||||
which makes two equal numbers have different binary representation. The library accounts for the known
|
||||
such cases, but it is possible that some exotic platforms exist that are not covered yet.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:interface_atomic_pointer [^boost::atomic<['pointer]>] template class]
|
||||
|
||||
In addition to the operations applicable to all atomic object,
|
||||
In addition to the operations applicable to all atomic objects,
|
||||
[^boost::atomic<['P]>] for pointer
|
||||
types [^['P]] (other than pointers to [^void], function or member pointers) support
|
||||
the following operations, which correspond to [^std::atomic<['P]>]:
|
||||
@@ -1027,6 +1112,26 @@ to indicate whether the corresponding operations are lock-free or not.
|
||||
|
||||
In the table above, `intN_type` is a type that fits storage of contiguous `N` bits, suitably aligned for atomic operations.
|
||||
|
||||
For floating-point types the following macros are similarly defined:
|
||||
|
||||
[table
|
||||
[[Macro] [Description]]
|
||||
[
|
||||
[`BOOST_ATOMIC_FLOAT_LOCK_FREE`]
|
||||
[Indicate whether `atomic<float>` is lock-free.]
|
||||
]
|
||||
[
|
||||
[`BOOST_ATOMIC_DOUBLE_LOCK_FREE`]
|
||||
[Indicate whether `atomic<double>` is lock-free.]
|
||||
]
|
||||
[
|
||||
[`BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE`]
|
||||
[Indicate whether `atomic<long double>` is lock-free.]
|
||||
]
|
||||
]
|
||||
|
||||
These macros are not defined when support for floating point types is disabled by user.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#include <boost/atomic/detail/atomic_template.hpp>
|
||||
#include <boost/atomic/detail/operations.hpp>
|
||||
#include <boost/atomic/detail/extra_operations.hpp>
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
#include <boost/atomic/detail/fp_operations.hpp>
|
||||
#include <boost/atomic/detail/extra_fp_operations.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
@@ -81,6 +85,12 @@ using atomics::atomic_uint_fast64_t;
|
||||
using atomics::atomic_intmax_t;
|
||||
using atomics::atomic_uintmax_t;
|
||||
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
using atomics::atomic_float_t;
|
||||
using atomics::atomic_double_t;
|
||||
using atomics::atomic_long_double_t;
|
||||
#endif
|
||||
|
||||
using atomics::atomic_size_t;
|
||||
using atomics::atomic_ptrdiff_t;
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/platform.hpp>
|
||||
#include <boost/atomic/detail/int_sizes.hpp>
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
#include <boost/atomic/detail/float_sizes.hpp>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_EMULATED)
|
||||
#include BOOST_ATOMIC_DETAIL_BACKEND_HEADER(boost/atomic/detail/caps_)
|
||||
@@ -150,6 +153,52 @@
|
||||
#define BOOST_ATOMIC_FLAG_LOCK_FREE BOOST_ATOMIC_BOOL_LOCK_FREE
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
|
||||
#if !defined(BOOST_ATOMIC_FLOAT_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT)
|
||||
#if BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 2
|
||||
#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 4
|
||||
#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 8
|
||||
#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 16
|
||||
#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE
|
||||
#else
|
||||
#define BOOST_ATOMIC_FLOAT_LOCK_FREE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DOUBLE_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE)
|
||||
#if BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 2
|
||||
#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 4
|
||||
#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 8
|
||||
#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 16
|
||||
#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE
|
||||
#else
|
||||
#define BOOST_ATOMIC_DOUBLE_LOCK_FREE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE)
|
||||
#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 2
|
||||
#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 4
|
||||
#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 8
|
||||
#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE
|
||||
#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 16
|
||||
#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE
|
||||
#else
|
||||
#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
|
||||
#ifndef BOOST_ATOMIC_THREAD_FENCE
|
||||
#define BOOST_ATOMIC_THREAD_FENCE 0
|
||||
#endif
|
||||
|
||||
42
include/boost/atomic/detail/addressof.hpp
Normal file
42
include/boost/atomic/detail/addressof.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/addressof.hpp
|
||||
*
|
||||
* This header defines \c addressof helper function
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_
|
||||
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
template< typename T >
|
||||
BOOST_FORCEINLINE T* addressof(T& value) BOOST_NOEXCEPT
|
||||
{
|
||||
// Note: The point of using a local struct as the intermediate type instead of char is to avoid gcc warnings
|
||||
// if T is a const volatile char*:
|
||||
// warning: casting 'const volatile char* const' to 'const volatile char&' does not dereference pointer
|
||||
// The local struct makes sure T is not related to the cast target type.
|
||||
struct opaque_type;
|
||||
return reinterpret_cast< T* >(&const_cast< opaque_type& >(reinterpret_cast< const volatile opaque_type& >(value)));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_
|
||||
@@ -28,8 +28,14 @@
|
||||
#include <boost/atomic/detail/type_traits/is_signed.hpp>
|
||||
#include <boost/atomic/detail/type_traits/is_integral.hpp>
|
||||
#include <boost/atomic/detail/type_traits/is_function.hpp>
|
||||
#include <boost/atomic/detail/type_traits/is_floating_point.hpp>
|
||||
#include <boost/atomic/detail/type_traits/conditional.hpp>
|
||||
#include <boost/atomic/detail/type_traits/integral_constant.hpp>
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
#include <boost/atomic/detail/bitwise_fp_cast.hpp>
|
||||
#include <boost/atomic/detail/fp_operations_fwd.hpp>
|
||||
#include <boost/atomic/detail/extra_fp_operations_fwd.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
@@ -74,32 +80,37 @@ struct classify_pointer< T, true >
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template< typename T, bool IsInt = atomics::detail::is_integral< T >::value >
|
||||
template< typename T, bool IsInt = atomics::detail::is_integral< T >::value, bool IsFloat = atomics::detail::is_floating_point< T >::value >
|
||||
struct classify
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct classify< T, true > { typedef int type; };
|
||||
struct classify< T, true, false > { typedef int type; };
|
||||
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
template< typename T >
|
||||
struct classify< T, false, true > { typedef float type; };
|
||||
#endif
|
||||
|
||||
template< typename T >
|
||||
struct classify< T*, false > { typedef typename classify_pointer< T >::type type; };
|
||||
struct classify< T*, false, false > { typedef typename classify_pointer< T >::type type; };
|
||||
|
||||
template< >
|
||||
struct classify< void*, false > { typedef void type; };
|
||||
struct classify< void*, false, false > { typedef void type; };
|
||||
|
||||
template< >
|
||||
struct classify< const void*, false > { typedef void type; };
|
||||
struct classify< const void*, false, false > { typedef void type; };
|
||||
|
||||
template< >
|
||||
struct classify< volatile void*, false > { typedef void type; };
|
||||
struct classify< volatile void*, false, false > { typedef void type; };
|
||||
|
||||
template< >
|
||||
struct classify< const volatile void*, false > { typedef void type; };
|
||||
struct classify< const volatile void*, false, false > { typedef void type; };
|
||||
|
||||
template< typename T, typename U >
|
||||
struct classify< T U::*, false > { typedef void type; };
|
||||
struct classify< T U::*, false, false > { typedef void type; };
|
||||
|
||||
|
||||
template< typename T, typename Kind >
|
||||
@@ -243,7 +254,7 @@ protected:
|
||||
typename operations::aligned_storage_type m_storage;
|
||||
|
||||
public:
|
||||
BOOST_DEFAULTED_FUNCTION(base_atomic(), {})
|
||||
BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_NOEXCEPT, {})
|
||||
BOOST_CONSTEXPR explicit base_atomic(value_type v) BOOST_NOEXCEPT : m_storage(v) {}
|
||||
|
||||
// Standard methods
|
||||
@@ -567,7 +578,7 @@ protected:
|
||||
operations::aligned_storage_type m_storage;
|
||||
|
||||
public:
|
||||
BOOST_DEFAULTED_FUNCTION(base_atomic(), {})
|
||||
BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_NOEXCEPT, {})
|
||||
BOOST_CONSTEXPR explicit base_atomic(value_type v) BOOST_NOEXCEPT : m_storage(v) {}
|
||||
|
||||
// Standard methods
|
||||
@@ -661,6 +672,185 @@ private:
|
||||
};
|
||||
|
||||
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
|
||||
//! Implementation for floating point types
|
||||
template< typename T >
|
||||
class base_atomic< T, float >
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T difference_type;
|
||||
|
||||
protected:
|
||||
typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations;
|
||||
typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations;
|
||||
typedef atomics::detail::fp_operations< extra_operations, value_type, operations::storage_size > fp_operations;
|
||||
typedef atomics::detail::extra_fp_operations< fp_operations, value_type, operations::storage_size > extra_fp_operations;
|
||||
typedef value_type value_arg_type;
|
||||
|
||||
public:
|
||||
typedef typename operations::storage_type storage_type;
|
||||
|
||||
private:
|
||||
typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage;
|
||||
|
||||
protected:
|
||||
typename operations::aligned_storage_type m_storage;
|
||||
|
||||
public:
|
||||
BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_NOEXCEPT, {})
|
||||
BOOST_FORCEINLINE explicit base_atomic(value_type v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_fp_cast< storage_type >(v)) {}
|
||||
|
||||
BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(order != memory_order_consume);
|
||||
BOOST_ASSERT(order != memory_order_acquire);
|
||||
BOOST_ASSERT(order != memory_order_acq_rel);
|
||||
|
||||
operations::store(m_storage.value, atomics::detail::bitwise_fp_cast< storage_type >(v), order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(order != memory_order_release);
|
||||
BOOST_ASSERT(order != memory_order_acq_rel);
|
||||
|
||||
return atomics::detail::bitwise_fp_cast< value_type >(operations::load(m_storage.value, order));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return fp_operations::fetch_add(m_storage.value, v, order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return fp_operations::fetch_sub(m_storage.value, v, order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return atomics::detail::bitwise_fp_cast< value_type >(operations::exchange(m_storage.value, atomics::detail::bitwise_fp_cast< storage_type >(v), order));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(failure_order != memory_order_release);
|
||||
BOOST_ASSERT(failure_order != memory_order_acq_rel);
|
||||
BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
|
||||
|
||||
return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage());
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(failure_order != memory_order_release);
|
||||
BOOST_ASSERT(failure_order != memory_order_acq_rel);
|
||||
BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order));
|
||||
|
||||
return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage());
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order));
|
||||
}
|
||||
|
||||
// Boost.Atomic extensions
|
||||
BOOST_FORCEINLINE value_type fetch_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return extra_fp_operations::fetch_negate(m_storage.value, order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return extra_fp_operations::add(m_storage.value, v, order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return extra_fp_operations::sub(m_storage.value, v, order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE value_type negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return extra_fp_operations::negate(m_storage.value, order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
extra_fp_operations::opaque_add(m_storage.value, v, order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
extra_fp_operations::opaque_sub(m_storage.value, v, order);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE void opaque_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
extra_fp_operations::opaque_negate(m_storage.value, order);
|
||||
}
|
||||
|
||||
// Operators
|
||||
BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return add(v);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
return sub(v);
|
||||
}
|
||||
|
||||
BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&))
|
||||
BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&))
|
||||
|
||||
private:
|
||||
BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
|
||||
return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order);
|
||||
#else
|
||||
return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type());
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type old_value = atomics::detail::bitwise_fp_cast< storage_type >(expected);
|
||||
const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order);
|
||||
expected = atomics::detail::bitwise_fp_cast< value_type >(old_value);
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS)
|
||||
return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order);
|
||||
#else
|
||||
return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type());
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type old_value = atomics::detail::bitwise_fp_cast< storage_type >(expected);
|
||||
const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order);
|
||||
expected = atomics::detail::bitwise_fp_cast< value_type >(old_value);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
|
||||
|
||||
//! Implementation for pointers to object types
|
||||
template< typename T >
|
||||
class base_atomic< T*, void* >
|
||||
@@ -692,7 +882,7 @@ protected:
|
||||
typename operations::aligned_storage_type m_storage;
|
||||
|
||||
public:
|
||||
BOOST_DEFAULTED_FUNCTION(base_atomic(), {})
|
||||
BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_NOEXCEPT, {})
|
||||
BOOST_FORCEINLINE explicit base_atomic(value_type const& v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< uintptr_storage_type >(v))
|
||||
{
|
||||
}
|
||||
@@ -879,7 +1069,7 @@ public:
|
||||
static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = base_type::operations::is_always_lock_free;
|
||||
|
||||
public:
|
||||
BOOST_DEFAULTED_FUNCTION(atomic(), BOOST_NOEXCEPT {})
|
||||
BOOST_DEFAULTED_FUNCTION(atomic() BOOST_NOEXCEPT, {})
|
||||
|
||||
// NOTE: The constructor is made explicit because gcc 4.7 complains that
|
||||
// operator=(value_arg_type) is considered ambiguous with operator=(atomic const&)
|
||||
@@ -967,6 +1157,12 @@ typedef atomic< uint_fast64_t > atomic_uint_fast64_t;
|
||||
typedef atomic< intmax_t > atomic_intmax_t;
|
||||
typedef atomic< uintmax_t > atomic_uintmax_t;
|
||||
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
typedef atomic< float > atomic_float_t;
|
||||
typedef atomic< double > atomic_double_t;
|
||||
typedef atomic< long double > atomic_long_double_t;
|
||||
#endif
|
||||
|
||||
typedef atomic< std::size_t > atomic_size_t;
|
||||
typedef atomic< std::ptrdiff_t > atomic_ptrdiff_t;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define BOOST_ATOMIC_DETAIL_BITWISE_CAST_HPP_INCLUDED_
|
||||
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/addressof.hpp>
|
||||
#include <boost/atomic/detail/string_ops.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
@@ -33,17 +34,6 @@ namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
template< typename T >
|
||||
BOOST_FORCEINLINE T* addressof(T& value) BOOST_NOEXCEPT
|
||||
{
|
||||
// Note: The point of using a local struct as the intermediate type instead of char is to avoid gcc warnings
|
||||
// if T is a const volatile char*:
|
||||
// warning: casting 'const volatile char* const' to 'const volatile char&' does not dereference pointer
|
||||
// The local struct makes sure T is not related to the cast target type.
|
||||
struct opaque_type;
|
||||
return reinterpret_cast< T* >(&const_cast< opaque_type& >(reinterpret_cast< const volatile opaque_type& >(value)));
|
||||
}
|
||||
|
||||
template< typename To, typename From >
|
||||
BOOST_FORCEINLINE To bitwise_cast(From const& from) BOOST_NOEXCEPT
|
||||
{
|
||||
|
||||
108
include/boost/atomic/detail/bitwise_fp_cast.hpp
Normal file
108
include/boost/atomic/detail/bitwise_fp_cast.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/bitwise_fp_cast.hpp
|
||||
*
|
||||
* This header defines \c bitwise_fp_cast used to convert between storage and floating point value types
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/addressof.hpp>
|
||||
#include <boost/atomic/detail/string_ops.hpp>
|
||||
#include <boost/atomic/detail/float_sizes.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC+0) >= 40600
|
||||
#pragma GCC diagnostic push
|
||||
// missing initializer for member var
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
/*!
|
||||
* \brief The type trait returns the size of the value of the specified floating point type
|
||||
*
|
||||
* This size may be less than <tt>sizeof(T)</tt> if the implementation uses padding bytes for a particular FP type. This is
|
||||
* often the case with 80-bit extended double, which is stored in 12 or 16 bytes with padding filled with garbage.
|
||||
*/
|
||||
template< typename T >
|
||||
struct value_sizeof
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST std::size_t value = sizeof(T);
|
||||
};
|
||||
|
||||
#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE)
|
||||
template< >
|
||||
struct value_sizeof< float >
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE)
|
||||
template< >
|
||||
struct value_sizeof< double >
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE)
|
||||
template< >
|
||||
struct value_sizeof< long double >
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE;
|
||||
};
|
||||
#endif
|
||||
|
||||
template< typename T >
|
||||
struct value_sizeof< const T > : value_sizeof< T > {};
|
||||
|
||||
template< typename T >
|
||||
struct value_sizeof< volatile T > : value_sizeof< T > {};
|
||||
|
||||
template< typename T >
|
||||
struct value_sizeof< const volatile T > : value_sizeof< T > {};
|
||||
|
||||
|
||||
template< typename To, typename From >
|
||||
BOOST_FORCEINLINE To bitwise_fp_cast(From const& from) BOOST_NOEXCEPT
|
||||
{
|
||||
struct
|
||||
{
|
||||
To to;
|
||||
}
|
||||
value = {};
|
||||
BOOST_ATOMIC_DETAIL_MEMCPY
|
||||
(
|
||||
atomics::detail::addressof(value.to),
|
||||
atomics::detail::addressof(from),
|
||||
(atomics::detail::value_sizeof< From >::value < sizeof(To) ? atomics::detail::value_sizeof< From >::value : sizeof(To))
|
||||
);
|
||||
return value.to;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC+0) >= 40600
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_
|
||||
@@ -82,6 +82,12 @@
|
||||
#define BOOST_ATOMIC_DETAIL_IS_CONSTANT(x) false
|
||||
#endif
|
||||
|
||||
#if (defined(__BYTE_ORDER__) && defined(__FLOAT_WORD_ORDER__) && (__BYTE_ORDER__+0) == (__FLOAT_WORD_ORDER__+0)) ||\
|
||||
defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
|
||||
// This macro indicates that integer and floating point endianness is the same
|
||||
#define BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH
|
||||
#endif
|
||||
|
||||
// Deprecated symbols markup
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(_MSC_VER)
|
||||
#if (_MSC_VER) >= 1400
|
||||
|
||||
28
include/boost/atomic/detail/extra_fp_operations.hpp
Normal file
28
include/boost/atomic/detail/extra_fp_operations.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/extra_fp_operations.hpp
|
||||
*
|
||||
* This header defines extra floating point atomic operations, including the generic version.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_
|
||||
|
||||
#include <boost/atomic/detail/extra_fp_ops_generic.hpp>
|
||||
#include <boost/atomic/detail/extra_fp_ops_emulated.hpp>
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_GENERIC)
|
||||
#include BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_HEADER(boost/atomic/detail/extra_fp_ops_)
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_
|
||||
35
include/boost/atomic/detail/extra_fp_operations_fwd.hpp
Normal file
35
include/boost/atomic/detail/extra_fp_operations_fwd.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/extra_fp_operations_fwd.hpp
|
||||
*
|
||||
* This header contains forward declaration of the \c extra_fp_operations template.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
template< typename Base, typename Value, std::size_t Size, bool = Base::is_always_lock_free >
|
||||
struct extra_fp_operations;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_
|
||||
107
include/boost/atomic/detail/extra_fp_ops_emulated.hpp
Normal file
107
include/boost/atomic/detail/extra_fp_ops_emulated.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/extra_fp_ops_emulated.hpp
|
||||
*
|
||||
* This header contains emulated (lock-based) implementation of the extra floating point atomic operations.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/bitwise_fp_cast.hpp>
|
||||
#include <boost/atomic/detail/extra_fp_operations_fwd.hpp>
|
||||
#include <boost/atomic/detail/lockpool.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
//! Generic implementation of extra floating point operations
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct emulated_extra_fp_operations :
|
||||
public Base
|
||||
{
|
||||
typedef Base base_type;
|
||||
typedef typename base_type::storage_type storage_type;
|
||||
typedef Value value_type;
|
||||
|
||||
static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type& s = const_cast< storage_type& >(storage);
|
||||
lockpool::scoped_lock lock(&storage);
|
||||
value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
|
||||
value_type new_val = -old_val;
|
||||
s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
return old_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type& s = const_cast< storage_type& >(storage);
|
||||
lockpool::scoped_lock lock(&storage);
|
||||
value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
|
||||
value_type new_val = -old_val;
|
||||
s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
return new_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE value_type add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type& s = const_cast< storage_type& >(storage);
|
||||
lockpool::scoped_lock lock(&storage);
|
||||
value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
|
||||
value_type new_val = old_val + v;
|
||||
s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
return new_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE value_type sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type& s = const_cast< storage_type& >(storage);
|
||||
lockpool::scoped_lock lock(&storage);
|
||||
value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
|
||||
value_type new_val = old_val - v;
|
||||
s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
return new_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
fetch_negate(storage, order);
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
base_type::fetch_add(storage, v, order);
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
base_type::fetch_sub(storage, v, order);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct extra_fp_operations< Base, Value, Size, false > :
|
||||
public emulated_extra_fp_operations< Base, Value, Size >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_
|
||||
189
include/boost/atomic/detail/extra_fp_ops_generic.hpp
Normal file
189
include/boost/atomic/detail/extra_fp_ops_generic.hpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/extra_fp_ops_generic.hpp
|
||||
*
|
||||
* This header contains generic implementation of the extra floating point atomic operations.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_GENERIC_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_GENERIC_HPP_INCLUDED_
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/bitwise_fp_cast.hpp>
|
||||
#include <boost/atomic/detail/storage_type.hpp>
|
||||
#include <boost/atomic/detail/extra_fp_operations_fwd.hpp>
|
||||
#include <boost/atomic/detail/type_traits/is_iec559.hpp>
|
||||
#include <boost/atomic/detail/type_traits/is_integral.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC+0) >= 60000
|
||||
#pragma GCC diagnostic push
|
||||
// ignoring attributes on template argument X - this warning is because we need to pass storage_type as a template argument; no problem in this case
|
||||
#pragma GCC diagnostic ignored "-Wignored-attributes"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
//! Negate implementation
|
||||
template<
|
||||
typename Base,
|
||||
typename Value,
|
||||
std::size_t Size
|
||||
#if defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH)
|
||||
, bool = atomics::detail::is_iec559< Value >::value && atomics::detail::is_integral< typename Base::storage_type >::value
|
||||
#endif
|
||||
>
|
||||
struct generic_extra_fp_negate :
|
||||
public Base
|
||||
{
|
||||
typedef Base base_type;
|
||||
typedef typename base_type::storage_type storage_type;
|
||||
typedef Value value_type;
|
||||
|
||||
static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type old_storage, new_storage;
|
||||
value_type old_val, new_val;
|
||||
atomics::detail::non_atomic_load(storage, old_storage);
|
||||
do
|
||||
{
|
||||
old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage);
|
||||
new_val = -old_val;
|
||||
new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
}
|
||||
while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed));
|
||||
return old_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type old_storage, new_storage;
|
||||
value_type old_val, new_val;
|
||||
atomics::detail::non_atomic_load(storage, old_storage);
|
||||
do
|
||||
{
|
||||
old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage);
|
||||
new_val = -old_val;
|
||||
new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
}
|
||||
while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed));
|
||||
return new_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
fetch_negate(storage, order);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH)
|
||||
|
||||
//! Negate implementation for IEEE 754 / IEC 559 floating point types. We leverage the fact that the sign bit is the most significant bit in the value.
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct generic_extra_fp_negate< Base, Value, Size, true > :
|
||||
public Base
|
||||
{
|
||||
typedef Base base_type;
|
||||
typedef typename base_type::storage_type storage_type;
|
||||
typedef Value value_type;
|
||||
|
||||
//! The mask with only one sign bit set to 1
|
||||
static BOOST_CONSTEXPR_OR_CONST storage_type sign_mask = static_cast< storage_type >(1u) << (atomics::detail::value_sizeof< value_type >::value * 8u - 1u);
|
||||
|
||||
static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
return atomics::detail::bitwise_fp_cast< value_type >(base_type::fetch_xor(storage, sign_mask, order));
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
return atomics::detail::bitwise_fp_cast< value_type >(base_type::bitwise_xor(storage, sign_mask, order));
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
base_type::opaque_xor(storage, sign_mask, order);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH)
|
||||
|
||||
//! Generic implementation of floating point operations
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct generic_extra_fp_operations :
|
||||
public generic_extra_fp_negate< Base, Value, Size >
|
||||
{
|
||||
typedef generic_extra_fp_negate< Base, Value, Size > base_type;
|
||||
typedef typename base_type::storage_type storage_type;
|
||||
typedef Value value_type;
|
||||
|
||||
static BOOST_FORCEINLINE value_type add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type old_storage, new_storage;
|
||||
value_type old_val, new_val;
|
||||
atomics::detail::non_atomic_load(storage, old_storage);
|
||||
do
|
||||
{
|
||||
old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage);
|
||||
new_val = old_val + v;
|
||||
new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
}
|
||||
while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed));
|
||||
return new_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE value_type sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type old_storage, new_storage;
|
||||
value_type old_val, new_val;
|
||||
atomics::detail::non_atomic_load(storage, old_storage);
|
||||
do
|
||||
{
|
||||
old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage);
|
||||
new_val = old_val - v;
|
||||
new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
}
|
||||
while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed));
|
||||
return new_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
base_type::fetch_add(storage, v, order);
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
base_type::fetch_sub(storage, v, order);
|
||||
}
|
||||
};
|
||||
|
||||
// Default extra_fp_operations template definition will be used unless specialized for a specific platform
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct extra_fp_operations< Base, Value, Size, true > :
|
||||
public generic_extra_fp_operations< Base, Value, Size >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC+0) >= 60000
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_
|
||||
142
include/boost/atomic/detail/float_sizes.hpp
Normal file
142
include/boost/atomic/detail/float_sizes.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/float_sizes.hpp
|
||||
*
|
||||
* This header defines macros for testing buitin floating point type sizes
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_
|
||||
|
||||
#include <float.h>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// Detect value sizes of the different floating point types. The value sizes may be less than the corresponding type sizes
|
||||
// if the type contains padding bits. This is typical e.g. with 80-bit extended float types, which are often represented as 128-bit types.
|
||||
// See: https://en.wikipedia.org/wiki/IEEE_754
|
||||
// For Intel x87 extended double see: https://en.wikipedia.org/wiki/Extended_precision#x86_Architecture_Extended_Precision_Format
|
||||
// For IBM extended double (a.k.a. double-double) see: https://en.wikipedia.org/wiki/Long_double#Implementations, https://gcc.gnu.org/wiki/Ieee128PowerPC
|
||||
#if (FLT_RADIX+0) == 2
|
||||
|
||||
#if ((FLT_MANT_DIG+0) == 11) && ((FLT_MAX_EXP+0) == 16) // IEEE 754 binary16
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 2
|
||||
#elif ((FLT_MANT_DIG+0) == 24) && ((FLT_MAX_EXP+0) == 128) // IEEE 754 binary32
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 4
|
||||
#elif ((FLT_MANT_DIG+0) == 53) && ((FLT_MAX_EXP+0) == 1024) // IEEE 754 binary64
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 8
|
||||
#elif ((FLT_MANT_DIG+0) == 64) && ((FLT_MAX_EXP+0) == 16384) // x87 extended double
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 10
|
||||
#elif ((FLT_MANT_DIG+0) == 106) && ((FLT_MAX_EXP+0) == 1024) // IBM extended double
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16
|
||||
#elif ((FLT_MANT_DIG+0) == 113) && ((FLT_MAX_EXP+0) == 16384) // IEEE 754 binary128
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16
|
||||
#elif ((FLT_MANT_DIG+0) == 237) && ((FLT_MAX_EXP+0) == 262144) // IEEE 754 binary256
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 32
|
||||
#endif
|
||||
|
||||
#if ((DBL_MANT_DIG+0) == 11) && ((DBL_MAX_EXP+0) == 16) // IEEE 754 binary16
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 2
|
||||
#elif ((DBL_MANT_DIG+0) == 24) && ((DBL_MAX_EXP+0) == 128) // IEEE 754 binary32
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 4
|
||||
#elif ((DBL_MANT_DIG+0) == 53) && ((DBL_MAX_EXP+0) == 1024) // IEEE 754 binary64
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 8
|
||||
#elif ((DBL_MANT_DIG+0) == 64) && ((DBL_MAX_EXP+0) == 16384) // x87 extended double
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 10
|
||||
#elif ((DBL_MANT_DIG+0) == 106) && ((DBL_MAX_EXP+0) == 1024) // IBM extended double
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16
|
||||
#elif ((DBL_MANT_DIG+0) == 113) && ((DBL_MAX_EXP+0) == 16384) // IEEE 754 binary128
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16
|
||||
#elif ((DBL_MANT_DIG+0) == 237) && ((DBL_MAX_EXP+0) == 262144) // IEEE 754 binary256
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 32
|
||||
#endif
|
||||
|
||||
#if ((LDBL_MANT_DIG+0) == 11) && ((LDBL_MAX_EXP+0) == 16) // IEEE 754 binary16
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 2
|
||||
#elif ((LDBL_MANT_DIG+0) == 24) && ((LDBL_MAX_EXP+0) == 128) // IEEE 754 binary32
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 4
|
||||
#elif ((LDBL_MANT_DIG+0) == 53) && ((LDBL_MAX_EXP+0) == 1024) // IEEE 754 binary64
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 8
|
||||
#elif ((LDBL_MANT_DIG+0) == 64) && ((LDBL_MAX_EXP+0) == 16384) // x87 extended double
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 10
|
||||
#elif ((LDBL_MANT_DIG+0) == 106) && ((LDBL_MAX_EXP+0) == 1024) // IBM extended double
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16
|
||||
#elif ((LDBL_MANT_DIG+0) == 113) && ((LDBL_MAX_EXP+0) == 16384) // IEEE 754 binary128
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16
|
||||
#elif ((LDBL_MANT_DIG+0) == 237) && ((LDBL_MAX_EXP+0) == 262144) // IEEE 754 binary256
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 32
|
||||
#endif
|
||||
|
||||
#elif (FLT_RADIX+0) == 10
|
||||
|
||||
#if ((FLT_MANT_DIG+0) == 7) && ((FLT_MAX_EXP+0) == 97) // IEEE 754 decimal32
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 4
|
||||
#elif ((FLT_MANT_DIG+0) == 16) && ((FLT_MAX_EXP+0) == 385) // IEEE 754 decimal64
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 8
|
||||
#elif ((FLT_MANT_DIG+0) == 34) && ((FLT_MAX_EXP+0) == 6145) // IEEE 754 decimal128
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16
|
||||
#endif
|
||||
|
||||
#if ((DBL_MANT_DIG+0) == 7) && ((DBL_MAX_EXP+0) == 97) // IEEE 754 decimal32
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 4
|
||||
#elif ((DBL_MANT_DIG+0) == 16) && ((DBL_MAX_EXP+0) == 385) // IEEE 754 decimal64
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 8
|
||||
#elif ((DBL_MANT_DIG+0) == 34) && ((DBL_MAX_EXP+0) == 6145) // IEEE 754 decimal128
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16
|
||||
#endif
|
||||
|
||||
#if ((LDBL_MANT_DIG+0) == 7) && ((LDBL_MAX_EXP+0) == 97) // IEEE 754 decimal32
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 4
|
||||
#elif ((LDBL_MANT_DIG+0) == 16) && ((LDBL_MAX_EXP+0) == 385) // IEEE 754 decimal64
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 8
|
||||
#elif ((LDBL_MANT_DIG+0) == 34) && ((LDBL_MAX_EXP+0) == 6145) // IEEE 754 decimal128
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// GCC and compatible compilers define internal macros with builtin type traits
|
||||
#if defined(__SIZEOF_FLOAT__)
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT __SIZEOF_FLOAT__
|
||||
#endif
|
||||
#if defined(__SIZEOF_DOUBLE__)
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE __SIZEOF_DOUBLE__
|
||||
#endif
|
||||
#if defined(__SIZEOF_LONG_DOUBLE__)
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE __SIZEOF_LONG_DOUBLE__
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE)
|
||||
|
||||
#define BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(x)\
|
||||
((x) == 1u ? 1u : ((x) == 2u ? 2u : ((x) <= 4u ? 4u : ((x) <= 8u ? 8u : ((x) <= 16u ? 16u : ((x) <= 32u ? 32u : (x)))))))
|
||||
|
||||
// Make our best guess. These sizes may not be accurate, but they are good enough to estimate the size of the storage required to hold these types.
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE)
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE)
|
||||
#endif
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE)
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE)
|
||||
#endif
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE)
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE)
|
||||
#endif
|
||||
|
||||
#endif // !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE)
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) ||\
|
||||
!defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) ||\
|
||||
!defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE)
|
||||
#error Boost.Atomic: Failed to determine builtin floating point type sizes, the target platform is not supported. Please, report to the developers (patches are welcome).
|
||||
#endif
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_
|
||||
28
include/boost/atomic/detail/fp_operations.hpp
Normal file
28
include/boost/atomic/detail/fp_operations.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/fp_operations.hpp
|
||||
*
|
||||
* This header defines floating point atomic operations, including the generic version.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_
|
||||
|
||||
#include <boost/atomic/detail/fp_ops_generic.hpp>
|
||||
#include <boost/atomic/detail/fp_ops_emulated.hpp>
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_FP_BACKEND_GENERIC)
|
||||
#include BOOST_ATOMIC_DETAIL_FP_BACKEND_HEADER(boost/atomic/detail/fp_ops_)
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_
|
||||
35
include/boost/atomic/detail/fp_operations_fwd.hpp
Normal file
35
include/boost/atomic/detail/fp_operations_fwd.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/fp_operations_fwd.hpp
|
||||
*
|
||||
* This header contains forward declaration of the \c fp_operations template.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
template< typename Base, typename Value, std::size_t Size, bool = Base::is_always_lock_free >
|
||||
struct fp_operations;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_
|
||||
72
include/boost/atomic/detail/fp_ops_emulated.hpp
Normal file
72
include/boost/atomic/detail/fp_ops_emulated.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/fp_ops_emulated.hpp
|
||||
*
|
||||
* This header contains emulated (lock-based) implementation of the floating point atomic operations.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/bitwise_fp_cast.hpp>
|
||||
#include <boost/atomic/detail/fp_operations_fwd.hpp>
|
||||
#include <boost/atomic/detail/lockpool.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
//! Generic implementation of floating point operations
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct emulated_fp_operations :
|
||||
public Base
|
||||
{
|
||||
typedef Base base_type;
|
||||
typedef typename base_type::storage_type storage_type;
|
||||
typedef Value value_type;
|
||||
|
||||
static BOOST_FORCEINLINE value_type fetch_add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type& s = const_cast< storage_type& >(storage);
|
||||
lockpool::scoped_lock lock(&storage);
|
||||
value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
|
||||
value_type new_val = old_val + v;
|
||||
s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
return old_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE value_type fetch_sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type& s = const_cast< storage_type& >(storage);
|
||||
lockpool::scoped_lock lock(&storage);
|
||||
value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
|
||||
value_type new_val = old_val - v;
|
||||
s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
return old_val;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct fp_operations< Base, Value, Size, false > :
|
||||
public emulated_fp_operations< Base, Value, Size >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_
|
||||
83
include/boost/atomic/detail/fp_ops_generic.hpp
Normal file
83
include/boost/atomic/detail/fp_ops_generic.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/fp_ops_generic.hpp
|
||||
*
|
||||
* This header contains generic implementation of the floating point atomic operations.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#include <boost/atomic/detail/bitwise_fp_cast.hpp>
|
||||
#include <boost/atomic/detail/storage_type.hpp>
|
||||
#include <boost/atomic/detail/fp_operations_fwd.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
//! Generic implementation of floating point operations
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct generic_fp_operations :
|
||||
public Base
|
||||
{
|
||||
typedef Base base_type;
|
||||
typedef typename base_type::storage_type storage_type;
|
||||
typedef Value value_type;
|
||||
|
||||
static BOOST_FORCEINLINE value_type fetch_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type old_storage, new_storage;
|
||||
value_type old_val, new_val;
|
||||
atomics::detail::non_atomic_load(storage, old_storage);
|
||||
do
|
||||
{
|
||||
old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage);
|
||||
new_val = old_val + v;
|
||||
new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
}
|
||||
while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed));
|
||||
return old_val;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE value_type fetch_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
|
||||
{
|
||||
storage_type old_storage, new_storage;
|
||||
value_type old_val, new_val;
|
||||
atomics::detail::non_atomic_load(storage, old_storage);
|
||||
do
|
||||
{
|
||||
old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage);
|
||||
new_val = old_val - v;
|
||||
new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
|
||||
}
|
||||
while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed));
|
||||
return old_val;
|
||||
}
|
||||
};
|
||||
|
||||
// Default fp_operations template definition will be used unless specialized for a specific platform
|
||||
template< typename Base, typename Value, std::size_t Size >
|
||||
struct fp_operations< Base, Value, Size, true > :
|
||||
public generic_fp_operations< Base, Value, Size >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_
|
||||
@@ -39,7 +39,7 @@
|
||||
#if defined(__SIZEOF_POINTER__)
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER __SIZEOF_POINTER__
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_M_AMD64) || defined(_M_IA64)
|
||||
#if defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_IA64)
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER 8
|
||||
#else
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER 4
|
||||
@@ -117,7 +117,7 @@
|
||||
#include <wchar.h>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#if defined(_MSC_VER) && ( _MSC_VER <= 1310 || defined(UNDER_CE) && _MSC_VER <= 1500 )
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= 1310 || defined(UNDER_CE) && _MSC_VER <= 1500)
|
||||
// MSVC 7.1 and MSVC 8 (arm) define WCHAR_MAX to a value not suitable for constant expressions
|
||||
#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 2
|
||||
#elif (WCHAR_MAX + 0) == 0xff || (WCHAR_MAX + 0) == 0x7f
|
||||
@@ -134,7 +134,7 @@
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_SHORT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_INT) ||\
|
||||
!defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LLONG) ||\
|
||||
!defined(BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T)
|
||||
#error Boost.Atomic: Failed to determine builtin integer sizes, the target platform is not supported. Please, report to the developers.
|
||||
#error Boost.Atomic: Failed to determine builtin integer sizes, the target platform is not supported. Please, report to the developers (patches are welcome).
|
||||
#endif
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_INT_SIZES_HPP_INCLUDED_
|
||||
|
||||
@@ -140,12 +140,24 @@
|
||||
#define BOOST_ATOMIC_EMULATED
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_FP_BACKEND)
|
||||
#define BOOST_ATOMIC_DETAIL_FP_BACKEND generic
|
||||
#define BOOST_ATOMIC_DETAIL_FP_BACKEND_GENERIC
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_BACKEND)
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND generic
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_GENERIC
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND)
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND generic
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_GENERIC
|
||||
#endif
|
||||
|
||||
#define BOOST_ATOMIC_DETAIL_BACKEND_HEADER(prefix) <BOOST_JOIN(prefix, BOOST_ATOMIC_DETAIL_BACKEND).hpp>
|
||||
#define BOOST_ATOMIC_DETAIL_FP_BACKEND_HEADER(prefix) <BOOST_JOIN(prefix, BOOST_ATOMIC_DETAIL_FP_BACKEND).hpp>
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_HEADER(prefix) <BOOST_JOIN(prefix, BOOST_ATOMIC_DETAIL_EXTRA_BACKEND).hpp>
|
||||
#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_HEADER(prefix) <BOOST_JOIN(prefix, BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND).hpp>
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_PLATFORM_HPP_INCLUDED_
|
||||
|
||||
@@ -196,11 +196,8 @@ struct make_storage_type< 16u >
|
||||
template< typename T >
|
||||
struct storage_size_of
|
||||
{
|
||||
enum _
|
||||
{
|
||||
size = sizeof(T),
|
||||
value = (size == 3 ? 4 : (size >= 5 && size <= 7 ? 8 : (size >= 9 && size <= 15 ? 16 : size)))
|
||||
};
|
||||
static BOOST_CONSTEXPR_OR_CONST std::size_t size = sizeof(T);
|
||||
static BOOST_CONSTEXPR_OR_CONST std::size_t value = (size == 3u ? 4u : (size >= 5u && size <= 7u ? 8u : (size >= 9u && size <= 15u ? 16u : size)));
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -27,9 +27,13 @@
|
||||
#if __has_builtin(__builtin_memcmp)
|
||||
#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP
|
||||
#endif
|
||||
#if __has_builtin(__builtin_memset)
|
||||
#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET
|
||||
#endif
|
||||
#elif defined(BOOST_GCC)
|
||||
#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY
|
||||
#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP
|
||||
#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY)
|
||||
@@ -44,7 +48,13 @@
|
||||
#define BOOST_ATOMIC_DETAIL_MEMCMP std::memcmp
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY) || !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP)
|
||||
#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET)
|
||||
#define BOOST_ATOMIC_DETAIL_MEMSET __builtin_memset
|
||||
#else
|
||||
#define BOOST_ATOMIC_DETAIL_MEMSET std::memset
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY) || !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP) || !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET)
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/type_traits/is_floating_point.hpp
|
||||
*
|
||||
* This header defines \c is_floating_point type trait
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_
|
||||
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_HDR_TYPE_TRAITS)
|
||||
#include <type_traits>
|
||||
#else
|
||||
#include <boost/type_traits/is_floating_point.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_HDR_TYPE_TRAITS)
|
||||
using std::is_floating_point;
|
||||
#else
|
||||
using boost::is_floating_point;
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_
|
||||
47
include/boost/atomic/detail/type_traits/is_iec559.hpp
Normal file
47
include/boost/atomic/detail/type_traits/is_iec559.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2018 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file atomic/detail/type_traits/is_iec559.hpp
|
||||
*
|
||||
* This header defines \c is_iec559 type trait
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_
|
||||
#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_
|
||||
|
||||
#include <limits>
|
||||
#include <boost/atomic/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace atomics {
|
||||
namespace detail {
|
||||
|
||||
template< typename T >
|
||||
struct is_iec559
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST bool value = !!std::numeric_limits< T >::is_iec559;
|
||||
};
|
||||
|
||||
#if defined(BOOST_HAS_FLOAT128)
|
||||
// libstdc++ does not specialize numeric_limits for __float128
|
||||
template< >
|
||||
struct is_iec559< boost::float128_type >
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST bool value = true;
|
||||
};
|
||||
#endif // defined(BOOST_HAS_FLOAT128)
|
||||
|
||||
} // namespace detail
|
||||
} // namespace atomics
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2011 Helge Bahmann
|
||||
// Copyright (c) 2017 Andrey Semashev
|
||||
// Copyright (c) 2017 - 2018 Andrey Semashev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -88,6 +88,14 @@ struct test_stream_type
|
||||
return *this;
|
||||
}
|
||||
#endif // defined(BOOST_HAS_INT128)
|
||||
#if defined(BOOST_HAS_FLOAT128)
|
||||
// libstdc++ does not provide output operators for __float128
|
||||
test_stream_type const& operator<< (boost::float128_type const& v) const
|
||||
{
|
||||
std::cerr << static_cast< double >(v);
|
||||
return *this;
|
||||
}
|
||||
#endif // defined(BOOST_HAS_FLOAT128)
|
||||
};
|
||||
|
||||
const test_stream_type test_stream = {};
|
||||
@@ -96,6 +104,8 @@ const test_stream_type test_stream = {};
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include "value_with_epsilon.hpp"
|
||||
|
||||
/* provide helpers that exercise whether the API
|
||||
functions of "boost::atomic" provide the correct
|
||||
operational semantic in the case of sequential
|
||||
@@ -738,7 +748,7 @@ void test_bit_operators(T value, T delta)
|
||||
template<typename T>
|
||||
void do_test_integral_api(boost::false_type)
|
||||
{
|
||||
BOOST_TEST( sizeof(boost::atomic<T>) >= sizeof(T));
|
||||
BOOST_TEST(sizeof(boost::atomic<T>) >= sizeof(T));
|
||||
|
||||
test_base_operators<T>(42, 43, 44);
|
||||
test_additive_operators<T, T>(42, 17);
|
||||
@@ -774,6 +784,123 @@ inline void test_integral_api(void)
|
||||
test_negation<T>();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
|
||||
template<typename T, typename D>
|
||||
void test_fp_additive_operators(T value, D delta)
|
||||
{
|
||||
/* explicit add/sub */
|
||||
{
|
||||
boost::atomic<T> a(value);
|
||||
T n = a.fetch_add(delta);
|
||||
BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
|
||||
BOOST_TEST_EQ( n, approx(value) );
|
||||
}
|
||||
|
||||
{
|
||||
boost::atomic<T> a(value);
|
||||
T n = a.fetch_sub(delta);
|
||||
BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
|
||||
BOOST_TEST_EQ( n, approx(value) );
|
||||
}
|
||||
|
||||
/* overloaded modify/assign*/
|
||||
{
|
||||
boost::atomic<T> a(value);
|
||||
T n = (a += delta);
|
||||
BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
|
||||
BOOST_TEST_EQ( n, approx(T(value + delta)) );
|
||||
}
|
||||
|
||||
{
|
||||
boost::atomic<T> a(value);
|
||||
T n = (a -= delta);
|
||||
BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
|
||||
BOOST_TEST_EQ( n, approx(T(value - delta)) );
|
||||
}
|
||||
|
||||
// Operations returning the actual resulting value
|
||||
{
|
||||
boost::atomic<T> a(value);
|
||||
T n = a.add(delta);
|
||||
BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
|
||||
BOOST_TEST_EQ( n, approx(T(value + delta)) );
|
||||
}
|
||||
|
||||
{
|
||||
boost::atomic<T> a(value);
|
||||
T n = a.sub(delta);
|
||||
BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
|
||||
BOOST_TEST_EQ( n, approx(T(value - delta)) );
|
||||
}
|
||||
|
||||
// Opaque operations
|
||||
{
|
||||
boost::atomic<T> a(value);
|
||||
a.opaque_add(delta);
|
||||
BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
|
||||
}
|
||||
|
||||
{
|
||||
boost::atomic<T> a(value);
|
||||
a.opaque_sub(delta);
|
||||
BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
void test_fp_negation()
|
||||
{
|
||||
{
|
||||
boost::atomic<T> a((T)1);
|
||||
T n = a.fetch_negate();
|
||||
BOOST_TEST_EQ( a.load(), approx((T)-1) );
|
||||
BOOST_TEST_EQ( n, approx((T)1) );
|
||||
|
||||
n = a.fetch_negate();
|
||||
BOOST_TEST_EQ( a.load(), approx((T)1) );
|
||||
BOOST_TEST_EQ( n, approx((T)-1) );
|
||||
}
|
||||
{
|
||||
boost::atomic<T> a((T)1);
|
||||
T n = a.negate();
|
||||
BOOST_TEST_EQ( a.load(), approx((T)-1) );
|
||||
BOOST_TEST_EQ( n, approx((T)-1) );
|
||||
|
||||
n = a.negate();
|
||||
BOOST_TEST_EQ( a.load(), approx((T)1) );
|
||||
BOOST_TEST_EQ( n, approx((T)1) );
|
||||
}
|
||||
{
|
||||
boost::atomic<T> a((T)1);
|
||||
a.opaque_negate();
|
||||
BOOST_TEST_EQ( a.load(), approx((T)-1) );
|
||||
|
||||
a.opaque_negate();
|
||||
BOOST_TEST_EQ( a.load(), approx((T)1) );
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
|
||||
template<typename T>
|
||||
inline void test_floating_point_api(void)
|
||||
{
|
||||
BOOST_TEST(sizeof(boost::atomic<T>) >= sizeof(T));
|
||||
|
||||
// Note: When support for floating point is disabled, even the base operation tests may fail because
|
||||
// the generic template specialization does not account for garbage in padding bits that are present in some FP types.
|
||||
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
|
||||
test_base_operators<T>(42, 43, 44);
|
||||
|
||||
test_fp_additive_operators<T, T>(42, 17);
|
||||
test_fp_additive_operators<T, T>(-42, -17);
|
||||
|
||||
test_fp_negation<T>();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void test_pointer_api(void)
|
||||
{
|
||||
|
||||
@@ -35,6 +35,17 @@ int main(int, char *[])
|
||||
test_integral_api<boost::int64_t>();
|
||||
test_integral_api<long long>();
|
||||
test_integral_api<unsigned long long>();
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
test_integral_api<boost::int128_type>();
|
||||
test_integral_api<boost::uint128_type>();
|
||||
#endif
|
||||
|
||||
test_floating_point_api<float>();
|
||||
test_floating_point_api<double>();
|
||||
test_floating_point_api<long double>();
|
||||
#if defined(BOOST_HAS_FLOAT128)
|
||||
test_floating_point_api<boost::float128_type>();
|
||||
#endif
|
||||
|
||||
test_pointer_api<int>();
|
||||
|
||||
|
||||
@@ -191,6 +191,26 @@ int main(int, char *[])
|
||||
verify_lock_free<void *>("void *", BOOST_ATOMIC_POINTER_LOCK_FREE, EXPECT_SHORT_LOCK_FREE);
|
||||
verify_lock_free<bool>("bool", BOOST_ATOMIC_BOOL_LOCK_FREE, EXPECT_BOOL_LOCK_FREE);
|
||||
|
||||
#ifndef BOOST_ATOMIC_NO_FLOATING_POINT
|
||||
|
||||
verify_lock_free<float>("float", BOOST_ATOMIC_FLOAT_LOCK_FREE,
|
||||
sizeof(float) == 1 ? EXPECT_CHAR_LOCK_FREE : (sizeof(float) == 2 ? EXPECT_SHORT_LOCK_FREE :
|
||||
(sizeof(float) <= 4 ? EXPECT_INT_LOCK_FREE : (sizeof(float) <= 8 ? EXPECT_LLONG_LOCK_FREE : (sizeof(float) <= 16 ? EXPECT_INT128_LOCK_FREE : 0)))));
|
||||
|
||||
verify_lock_free<double>("double", BOOST_ATOMIC_DOUBLE_LOCK_FREE,
|
||||
sizeof(double) == 1 ? EXPECT_CHAR_LOCK_FREE : (sizeof(double) == 2 ? EXPECT_SHORT_LOCK_FREE :
|
||||
(sizeof(double) <= 4 ? EXPECT_INT_LOCK_FREE : (sizeof(double) <= 8 ? EXPECT_LLONG_LOCK_FREE : (sizeof(double) <= 16 ? EXPECT_INT128_LOCK_FREE : 0)))));
|
||||
|
||||
verify_lock_free<long double>("long double", BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE,
|
||||
sizeof(long double) == 1 ? EXPECT_CHAR_LOCK_FREE : (sizeof(long double) == 2 ? EXPECT_SHORT_LOCK_FREE :
|
||||
(sizeof(long double) <= 4 ? EXPECT_INT_LOCK_FREE : (sizeof(long double) <= 8 ? EXPECT_LLONG_LOCK_FREE : (sizeof(long double) <= 16 ? EXPECT_INT128_LOCK_FREE : 0)))));
|
||||
|
||||
#ifdef BOOST_HAS_FLOAT128
|
||||
verify_lock_free<boost::float128_type>("float128", BOOST_ATOMIC_INT128_LOCK_FREE, EXPECT_INT128_LOCK_FREE);
|
||||
#endif
|
||||
|
||||
#endif // BOOST_ATOMIC_NO_FLOATING_POINT
|
||||
|
||||
bool any_lock_free =
|
||||
BOOST_ATOMIC_CHAR_LOCK_FREE > 0 ||
|
||||
BOOST_ATOMIC_SHORT_LOCK_FREE > 0 ||
|
||||
|
||||
@@ -45,6 +45,13 @@ int main(int, char *[])
|
||||
test_constexpr_ctor<long>();
|
||||
test_constexpr_ctor<int*>();
|
||||
|
||||
test_floating_point_api<float>();
|
||||
test_floating_point_api<double>();
|
||||
test_floating_point_api<long double>();
|
||||
#if defined(BOOST_HAS_FLOAT128)
|
||||
test_floating_point_api<boost::float128_type>();
|
||||
#endif
|
||||
|
||||
test_pointer_api<int>();
|
||||
|
||||
test_enum_api();
|
||||
|
||||
78
test/value_with_epsilon.hpp
Normal file
78
test/value_with_epsilon.hpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2018 Andrey Semashev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_ATOMIC_TESTS_VALUE_WITH_EPSILON_H_INCLUDED_
|
||||
#define BOOST_ATOMIC_TESTS_VALUE_WITH_EPSILON_H_INCLUDED_
|
||||
|
||||
#include <limits>
|
||||
#include <iosfwd>
|
||||
|
||||
template< typename T >
|
||||
class value_with_epsilon
|
||||
{
|
||||
private:
|
||||
T m_value;
|
||||
T m_epsilon;
|
||||
|
||||
public:
|
||||
value_with_epsilon(T value, T epsilon) : m_value(value), m_epsilon(epsilon) {}
|
||||
|
||||
T value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
T epsilon() const
|
||||
{
|
||||
return m_epsilon;
|
||||
}
|
||||
|
||||
bool equal(T value) const
|
||||
{
|
||||
return value >= (m_value - m_epsilon) && value <= (m_value + m_epsilon);
|
||||
}
|
||||
|
||||
friend bool operator== (T left, value_with_epsilon< T > const& right)
|
||||
{
|
||||
return right.equal(left);
|
||||
}
|
||||
friend bool operator== (value_with_epsilon< T > const& left, T right)
|
||||
{
|
||||
return left.equal(right);
|
||||
}
|
||||
|
||||
friend bool operator!= (T left, value_with_epsilon< T > const& right)
|
||||
{
|
||||
return !right.equal(left);
|
||||
}
|
||||
friend bool operator!= (value_with_epsilon< T > const& left, T right)
|
||||
{
|
||||
return !left.equal(right);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Char, typename Traits, typename T >
|
||||
inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, value_with_epsilon< T > const& val)
|
||||
{
|
||||
// Note: libstdc++ does not provide output operators for __float128. There may also be no operators for long double.
|
||||
// We don't use such floating point values in our tests where the cast would matter.
|
||||
strm << static_cast< double >(val.value()) << " (+/-" << static_cast< double >(val.epsilon()) << ")";
|
||||
return strm;
|
||||
}
|
||||
|
||||
template< typename T, typename U >
|
||||
inline value_with_epsilon< T > approx(T value, U epsilon)
|
||||
{
|
||||
return value_with_epsilon< T >(value, static_cast< T >(epsilon));
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline value_with_epsilon< T > approx(T value)
|
||||
{
|
||||
return value_with_epsilon< T >(value, static_cast< T >(0.0000001));
|
||||
}
|
||||
|
||||
#endif // BOOST_ATOMIC_TESTS_VALUE_WITH_EPSILON_H_INCLUDED_
|
||||
Reference in New Issue
Block a user