#include <cstring>
#include <cstdlib>
#include <limits>
+#include <vector>
#include <iostream>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/type.hpp>
+#include <boost/core/enable_if.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/make_signed.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/conditional.hpp>
-#include "aligned_object.hpp"
-
-struct test_stream_type
-{
- typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
- typedef std::basic_ios< char, std::char_traits< char > >& (*basic_ios_manip)(std::basic_ios< char, std::char_traits< char > >&);
- typedef std::ostream& (*stream_manip)(std::ostream&);
-
- template< typename T >
- test_stream_type const& operator<< (T const& value) const
- {
- std::cerr << value;
- return *this;
- }
-
- test_stream_type const& operator<< (ios_base_manip manip) const
- {
- std::cerr << manip;
- return *this;
- }
- test_stream_type const& operator<< (basic_ios_manip manip) const
- {
- std::cerr << manip;
- return *this;
- }
- test_stream_type const& operator<< (stream_manip manip) const
- {
- std::cerr << manip;
- return *this;
- }
-
- // Make sure characters are printed as numbers if tests fail
- test_stream_type const& operator<< (char value) const
- {
- std::cerr << static_cast< int >(value);
- return *this;
- }
- test_stream_type const& operator<< (signed char value) const
- {
- std::cerr << static_cast< int >(value);
- return *this;
- }
- test_stream_type const& operator<< (unsigned char value) const
- {
- std::cerr << static_cast< unsigned int >(value);
- return *this;
- }
- test_stream_type const& operator<< (short value) const
- {
- std::cerr << static_cast< int >(value);
- return *this;
- }
- test_stream_type const& operator<< (unsigned short value) const
- {
- std::cerr << static_cast< unsigned int >(value);
- return *this;
- }
-
-#if defined(BOOST_HAS_INT128)
- // Some GCC versions don't provide output operators for __int128
- test_stream_type const& operator<< (boost::int128_type const& v) const
- {
- std::cerr << static_cast< long long >(v);
- return *this;
- }
- test_stream_type const& operator<< (boost::uint128_type const& v) const
- {
- std::cerr << static_cast< unsigned long long >(v);
- 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 = {};
-
-#define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream
-
-#include <boost/core/lightweight_test.hpp>
+#include "lightweight_test_stream.hpp"
#include "value_with_epsilon.hpp"
+#include "atomic_wrapper.hpp"
const unsigned int max_weak_cas_loops = 1000;
-//! Wrapper type for atomic template
template< typename T >
-struct atomic_wrapper
+struct is_atomic :
+ public boost::false_type
{
- typedef boost::atomic< T > atomic_type;
-
- atomic_type a;
+};
- BOOST_DEFAULTED_FUNCTION(atomic_wrapper(), {})
- explicit atomic_wrapper(T const& value) : a(value) {}
+template< typename T >
+struct is_atomic< boost::atomic< T > > :
+ public boost::true_type
+{
};
-//! Wrapper type for atomic_ref template
template< typename T >
-struct atomic_ref_wrapper
+struct is_atomic< boost::ipc_atomic< T > > :
+ public boost::true_type
{
- typedef boost::atomic_ref< T > atomic_type;
+};
- aligned_object< T, atomic_type::required_alignment > object;
- atomic_type a;
+template< typename T >
+struct is_atomic_ref :
+ public boost::false_type
+{
+};
- atomic_ref_wrapper() : a(object.get()) {}
- explicit atomic_ref_wrapper(T const& value) : object(value), a(object.get()) {}
+template< typename T >
+struct is_atomic_ref< boost::atomic_ref< T > > :
+ public boost::true_type
+{
};
-/* provide helpers that exercise whether the API
-functions of "boost::atomic" provide the correct
-operational semantic in the case of sequential
-execution */
+template< typename T >
+struct is_atomic_ref< boost::ipc_atomic_ref< T > > :
+ public boost::true_type
+{
+};
+template< typename Flag >
inline void test_flag_api(void)
{
#ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
- boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT;
+ Flag f = BOOST_ATOMIC_FLAG_INIT;
#else
- boost::atomic_flag f;
+ Flag f;
#endif
BOOST_TEST( !f.test() );
}
template< typename T >
-inline void test_atomic_type_traits(boost::type< boost::atomic< T > >)
+inline typename boost::enable_if< is_atomic< T > >::type test_atomic_type_traits(boost::type< T >)
{
- BOOST_TEST_GE(sizeof(boost::atomic< T >), sizeof(T));
+ BOOST_TEST_GE(sizeof(T), sizeof(typename T::value_type));
}
template< typename T >
-inline void test_atomic_type_traits(boost::type< boost::atomic_ref< T > >)
+inline typename boost::enable_if< is_atomic_ref< T > >::type test_atomic_type_traits(boost::type< T >)
{
- if (boost::atomic_ref< T >::is_always_lock_free)
+ if (T::is_always_lock_free)
{
- BOOST_TEST_GE(boost::atomic_ref< T >::required_alignment, boost::alignment_of< T >::value);
+ BOOST_TEST_GE(T::required_alignment, boost::alignment_of< typename T::value_type >::value);
}
else
{
// Lock-based implementation should not require alignment higher than alignof(T)
- BOOST_TEST_EQ(boost::atomic_ref< T >::required_alignment, boost::alignment_of< T >::value);
+ BOOST_TEST_EQ(T::required_alignment, boost::alignment_of< typename T::value_type >::value);
}
}
// explicit load/store
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
BOOST_TEST_EQ( a.load(), value1 );
}
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.store(value2);
BOOST_TEST_EQ( a.load(), value2 );
}
// overloaded assignment/conversion
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
BOOST_TEST( value1 == a );
}
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a = value2;
BOOST_TEST( value2 == a );
}
// exchange-type operators
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.exchange(value2);
BOOST_TEST_EQ( a.load(), value2 );
BOOST_TEST_EQ( n, value1 );
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T expected = value1;
bool success = a.compare_exchange_strong(expected, value3);
BOOST_TEST( success );
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T expected = value2;
bool success = a.compare_exchange_strong(expected, value3);
BOOST_TEST( !success );
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T expected;
unsigned int loops = 0;
bool success = false;
{
Wrapper<T> wrapper(value1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T expected;
unsigned int loops = 0;
bool success = false;
const AddType zero_add = 0;
{
Wrapper<T> wrapper(zero_value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.add_and_test(zero_diff);
BOOST_TEST_EQ( f, false );
BOOST_TEST_EQ( a.load(), zero_value );
}
{
Wrapper<T> wrapper(zero_value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.add_and_test((distance_limits< T, D >::max)());
BOOST_TEST_EQ( f, true );
BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) );
}
{
Wrapper<T> wrapper(zero_value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.add_and_test((distance_limits< T, D >::min)());
BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::min)()) );
{
Wrapper<T> wrapper(zero_value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.sub_and_test(zero_diff);
BOOST_TEST_EQ( f, false );
BOOST_TEST_EQ( a.load(), zero_value );
}
{
Wrapper<T> wrapper(zero_value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.sub_and_test((distance_limits< T, D >::max)());
BOOST_TEST_EQ( f, true );
BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) );
}
{
Wrapper<T> wrapper(zero_value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.sub_and_test((distance_limits< T, D >::min)());
BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
// Be very careful as to not cause signed overflow on negation
// explicit add/sub
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_add(delta);
BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
BOOST_TEST_EQ( n, value );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_sub(delta);
BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
BOOST_TEST_EQ( n, value );
}
+ // add/sub with an immediate
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_add(1);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_sub(1);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_add(76);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + 76) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_sub(76);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - 76) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ if ((std::numeric_limits< D >::max)() >= 4097)
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_add((D)4097);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + (D)4097) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ if ((std::numeric_limits< D >::max)() >= 4097)
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_sub((D)4097);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - (D)4097) );
+ BOOST_TEST_EQ( n, value );
+ }
+
// overloaded modify/assign
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = (a += delta);
BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
BOOST_TEST_EQ( n, T((AddType)value + delta) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = (a -= delta);
BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
BOOST_TEST_EQ( n, T((AddType)value - delta) );
// overloaded increment/decrement
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a++;
BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
BOOST_TEST_EQ( n, value );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = ++a;
BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
BOOST_TEST_EQ( n, T((AddType)value + 1) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a--;
BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
BOOST_TEST_EQ( n, value );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = --a;
BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
BOOST_TEST_EQ( n, T((AddType)value - 1) );
// Operations returning the actual resulting value
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.add(delta);
BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
BOOST_TEST_EQ( n, T((AddType)value + delta) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.sub(delta);
BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
BOOST_TEST_EQ( n, T((AddType)value - delta) );
}
+ // The same with an immediate
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.add(1);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
+ BOOST_TEST_EQ( n, T((AddType)value + 1) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.sub(1);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
+ BOOST_TEST_EQ( n, T((AddType)value - 1) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.add(76);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + 76) );
+ BOOST_TEST_EQ( n, T((AddType)value + 76) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.sub(76);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - 76) );
+ BOOST_TEST_EQ( n, T((AddType)value - 76) );
+ }
+
+ if ((std::numeric_limits< D >::max)() >= 4097)
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.add((D)4097);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + (D)4097) );
+ BOOST_TEST_EQ( n, T((AddType)value + (D)4097) );
+ }
+
+ if ((std::numeric_limits< D >::max)() >= 4097)
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.sub((D)4097);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - (D)4097) );
+ BOOST_TEST_EQ( n, T((AddType)value - (D)4097) );
+ }
+
// Opaque operations
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_add(delta);
BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
}
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_sub(delta);
BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
}
+ // The same with an immediate
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_add(1);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_sub(1);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_add(76);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + 76) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_sub(76);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - 76) );
+ }
+
+ if ((std::numeric_limits< D >::max)() >= 4097)
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_add((D)4097);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + (D)4097) );
+ }
+
+ if ((std::numeric_limits< D >::max)() >= 4097)
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_sub((D)4097);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - (D)4097) );
+ }
+
// Modify and test operations
test_additive_operators_with_type_and_test< Wrapper, T, D, AddType >();
}
{
{
Wrapper<T> wrapper((T)1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_negate();
BOOST_TEST_EQ( a.load(), (T)-1 );
BOOST_TEST_EQ( n, (T)1 );
}
{
Wrapper<T> wrapper((T)1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.negate();
BOOST_TEST_EQ( a.load(), (T)-1 );
BOOST_TEST_EQ( n, (T)-1 );
}
{
Wrapper<T> wrapper((T)1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_negate();
BOOST_TEST_EQ( a.load(), (T)-1 );
}
{
Wrapper<T> wrapper((T)1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.negate_and_test();
BOOST_TEST_EQ( f, true );
BOOST_TEST_EQ( a.load(), (T)-1 );
}
{
Wrapper<T> wrapper((T)0);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.negate_and_test();
BOOST_TEST_EQ( f, false );
BOOST_TEST_EQ( a.load(), (T)0 );
{
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_add(1) + (T)1;
BOOST_TEST_EQ( a.load(), n );
}
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_sub(1) - (T)1;
BOOST_TEST_EQ( a.load(), n );
}
// explicit and/or/xor
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_and(delta);
BOOST_TEST_EQ( a.load(), T(value & delta) );
BOOST_TEST_EQ( n, value );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_or(delta);
BOOST_TEST_EQ( a.load(), T(value | delta) );
BOOST_TEST_EQ( n, value );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_xor(delta);
BOOST_TEST_EQ( a.load(), T(value ^ delta) );
BOOST_TEST_EQ( n, value );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_complement();
BOOST_TEST_EQ( a.load(), T(~value) );
BOOST_TEST_EQ( n, value );
}
+ // and/or/xor with an immediate. The immediates below are chosen to either be encodable in an instruction or not for various target architectures.
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_and((T)1);
+ BOOST_TEST_EQ( a.load(), T(value & (T)1) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_or((T)1);
+ BOOST_TEST_EQ( a.load(), T(value | (T)1) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_xor((T)1);
+ BOOST_TEST_EQ( a.load(), T(value ^ (T)1) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ // The following constants are not encodable in AArch64
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_and((T)76);
+ BOOST_TEST_EQ( a.load(), T(value & (T)76) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_or((T)76);
+ BOOST_TEST_EQ( a.load(), T(value | (T)76) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.fetch_xor((T)76);
+ BOOST_TEST_EQ( a.load(), T(value ^ (T)76) );
+ BOOST_TEST_EQ( n, value );
+ }
+
// overloaded modify/assign
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = (a &= delta);
BOOST_TEST_EQ( a.load(), T(value & delta) );
BOOST_TEST_EQ( n, T(value & delta) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = (a |= delta);
BOOST_TEST_EQ( a.load(), T(value | delta) );
BOOST_TEST_EQ( n, T(value | delta) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = (a ^= delta);
BOOST_TEST_EQ( a.load(), T(value ^ delta) );
BOOST_TEST_EQ( n, T(value ^ delta) );
// Operations returning the actual resulting value
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.bitwise_and(delta);
BOOST_TEST_EQ( a.load(), T(value & delta) );
BOOST_TEST_EQ( n, T(value & delta) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.bitwise_or(delta);
BOOST_TEST_EQ( a.load(), T(value | delta) );
BOOST_TEST_EQ( n, T(value | delta) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.bitwise_xor(delta);
BOOST_TEST_EQ( a.load(), T(value ^ delta) );
BOOST_TEST_EQ( n, T(value ^ delta) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.bitwise_complement();
BOOST_TEST_EQ( a.load(), T(~value) );
BOOST_TEST_EQ( n, T(~value) );
}
+ // The same with an immediate
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.bitwise_and((T)1);
+ BOOST_TEST_EQ( a.load(), T(value & (T)1) );
+ BOOST_TEST_EQ( n, T(value & (T)1) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.bitwise_or((T)1);
+ BOOST_TEST_EQ( a.load(), T(value | (T)1) );
+ BOOST_TEST_EQ( n, T(value | (T)1) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.bitwise_xor((T)1);
+ BOOST_TEST_EQ( a.load(), T(value ^ (T)1) );
+ BOOST_TEST_EQ( n, T(value ^ (T)1) );
+ }
+
+ // The following constants are not encodable in AArch64
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.bitwise_and((T)76);
+ BOOST_TEST_EQ( a.load(), T(value & (T)76) );
+ BOOST_TEST_EQ( n, T(value & (T)76) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.bitwise_or((T)76);
+ BOOST_TEST_EQ( a.load(), T(value | (T)76) );
+ BOOST_TEST_EQ( n, T(value | (T)76) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ T n = a.bitwise_xor((T)76);
+ BOOST_TEST_EQ( a.load(), T(value ^ (T)76) );
+ BOOST_TEST_EQ( n, T(value ^ (T)76) );
+ }
+
// Opaque operations
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_and(delta);
BOOST_TEST_EQ( a.load(), T(value & delta) );
}
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_or(delta);
BOOST_TEST_EQ( a.load(), T(value | delta) );
}
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_xor(delta);
BOOST_TEST_EQ( a.load(), T(value ^ delta) );
}
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_complement();
BOOST_TEST_EQ( a.load(), T(~value) );
}
+ // The same with an immediate
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_and((T)1);
+ BOOST_TEST_EQ( a.load(), T(value & (T)1) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_or((T)1);
+ BOOST_TEST_EQ( a.load(), T(value | (T)1) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_xor((T)1);
+ BOOST_TEST_EQ( a.load(), T(value ^ (T)1) );
+ }
+
+ // The following constants are not encodable in AArch64
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_and((T)76);
+ BOOST_TEST_EQ( a.load(), T(value & (T)76) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_or((T)76);
+ BOOST_TEST_EQ( a.load(), T(value | (T)76) );
+ }
+
+ {
+ Wrapper<T> wrapper(value);
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
+ a.opaque_xor((T)76);
+ BOOST_TEST_EQ( a.load(), T(value ^ (T)76) );
+ }
+
// Modify and test operations
{
Wrapper<T> wrapper((T)1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.and_and_test((T)1);
BOOST_TEST_EQ( f, true );
BOOST_TEST_EQ( a.load(), T(1) );
{
Wrapper<T> wrapper((T)0);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.or_and_test((T)0);
BOOST_TEST_EQ( f, false );
BOOST_TEST_EQ( a.load(), T(0) );
{
Wrapper<T> wrapper((T)0);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.xor_and_test((T)0);
BOOST_TEST_EQ( f, false );
BOOST_TEST_EQ( a.load(), T(0) );
{
Wrapper<T> wrapper((T)0);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.complement_and_test();
BOOST_TEST_EQ( f, true );
BOOST_TEST_EQ( a.load(), static_cast< T >(~static_cast< T >(0)) );
// Bit test and modify operations
{
Wrapper<T> wrapper((T)42);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.bit_test_and_set(0);
BOOST_TEST_EQ( f, false );
BOOST_TEST_EQ( a.load(), T(43) );
{
Wrapper<T> wrapper((T)42);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.bit_test_and_reset(0);
BOOST_TEST_EQ( f, false );
BOOST_TEST_EQ( a.load(), T(42) );
{
Wrapper<T> wrapper((T)42);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
bool f = a.bit_test_and_complement(0);
BOOST_TEST_EQ( f, false );
BOOST_TEST_EQ( a.load(), T(43) );
{
unsigned int runtime_bit_index = std::rand() & 7u;
Wrapper<T> wrapper((T)42);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.bit_test_and_set(runtime_bit_index);
a.bit_test_and_reset(runtime_bit_index);
test_negation< Wrapper, T >();
}
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_integral_api(boost::true_type)
+{
+ test_integral_api< Wrapper, T >();
+}
+
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_integral_api(boost::false_type)
+{
+}
+
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_integral_api(void)
+{
+ test_lock_free_integral_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
+}
+
#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
template< template< typename > class Wrapper, typename T, typename D >
// explicit add/sub
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_add(delta);
BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
BOOST_TEST_EQ( n, approx(value) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_sub(delta);
BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
BOOST_TEST_EQ( n, approx(value) );
// overloaded modify/assign
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = (a += delta);
BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
BOOST_TEST_EQ( n, approx(T(value + delta)) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
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
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.add(delta);
BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
BOOST_TEST_EQ( n, approx(T(value + delta)) );
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.sub(delta);
BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
BOOST_TEST_EQ( n, approx(T(value - delta)) );
// Opaque operations
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_add(delta);
BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
}
{
Wrapper<T> wrapper(value);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_sub(delta);
BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
}
{
{
Wrapper<T> wrapper((T)1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.fetch_negate();
BOOST_TEST_EQ( a.load(), approx((T)-1) );
BOOST_TEST_EQ( n, approx((T)1) );
}
{
Wrapper<T> wrapper((T)1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
T n = a.negate();
BOOST_TEST_EQ( a.load(), approx((T)-1) );
BOOST_TEST_EQ( n, approx((T)-1) );
}
{
Wrapper<T> wrapper((T)1);
- typename Wrapper<T>::atomic_type& a = wrapper.a;
+ typename Wrapper<T>::atomic_reference_type a = wrapper.a;
a.opaque_negate();
BOOST_TEST_EQ( a.load(), approx((T)-1) );
#endif
}
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_floating_point_api(boost::true_type)
+{
+ test_floating_point_api< Wrapper, T >();
+}
+
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_floating_point_api(boost::false_type)
+{
+}
+
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_floating_point_api(void)
+{
+ test_lock_free_floating_point_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
+}
+
template< template< typename > class Wrapper, typename T >
void test_pointer_api(void)
{
- T values[3];
+ std::vector< T > values;
+ values.resize(5000); // make the vector large enough to accommodate pointer arithmetics in the additive tests
test_base_operators< Wrapper, T* >(&values[0], &values[1], &values[2]);
- test_additive_operators< Wrapper, T*>(&values[1], 1);
+ test_additive_operators< Wrapper, T* >(&values[1], 1);
- test_base_operators< Wrapper, void*>(&values[0], &values[1], &values[2]);
+ test_base_operators< Wrapper, void* >(&values[0], &values[1], &values[2]);
#if defined(BOOST_HAS_INTPTR_T)
Wrapper<void*> wrapper_ptr;
- typename Wrapper<void*>::atomic_type& ptr = wrapper_ptr.a;
+ typename Wrapper<void*>::atomic_reference_type ptr = wrapper_ptr.a;
Wrapper<boost::intptr_t> wrapper_integral;
- typename Wrapper<boost::intptr_t>::atomic_type& integral = wrapper_integral.a;
+ typename Wrapper<boost::intptr_t>::atomic_reference_type integral = wrapper_integral.a;
BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() );
#endif
}
foo, bar, baz
};
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_pointer_api(boost::true_type)
+{
+ test_pointer_api< Wrapper, T >();
+}
+
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_pointer_api(boost::false_type)
+{
+}
+
+template< template< typename > class Wrapper, typename T >
+inline void test_lock_free_pointer_api(void)
+{
+ test_lock_free_pointer_api< Wrapper, T >(boost::integral_constant< bool, Wrapper< T >::atomic_type::is_always_lock_free >());
+}
+
+
template< template< typename > class Wrapper >
void test_enum_api(void)
{
test_base_operators< Wrapper >(foo, bar, baz);
}
+template< template< typename > class Wrapper >
+inline void test_lock_free_enum_api(boost::true_type)
+{
+ test_enum_api< Wrapper >();
+}
+
+template< template< typename > class Wrapper >
+inline void test_lock_free_enum_api(boost::false_type)
+{
+}
+
+template< template< typename > class Wrapper >
+inline void test_lock_free_enum_api(void)
+{
+ test_lock_free_enum_api< Wrapper >(boost::integral_constant< bool, Wrapper< test_enum >::atomic_type::is_always_lock_free >());
+}
+
+
template< typename T >
struct test_struct
{
{
Wrapper<T> wrapper_sa;
- typename Wrapper<T>::atomic_type& sa = wrapper_sa.a;
+ typename Wrapper<T>::atomic_reference_type sa = wrapper_sa.a;
Wrapper<typename T::value_type> wrapper_si;
- typename Wrapper<typename T::value_type>::atomic_type& si = wrapper_si.a;
+ typename Wrapper<typename T::value_type>::atomic_reference_type si = wrapper_si.a;
BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
}
}
{
test_struct_with_ctor s;
Wrapper<test_struct_with_ctor> wrapper_sa;
- typename Wrapper<test_struct_with_ctor>::atomic_type& sa = wrapper_sa.a;
+ typename Wrapper<test_struct_with_ctor>::atomic_reference_type sa = wrapper_sa.a;
// Check that the default constructor was called
BOOST_TEST( sa.load() == s );
}