// Copyright (c) 2011 Helge Bahmann
+// Copyright (c) 2017 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at
#define BOOST_ATOMIC_API_TEST_HELPERS_HPP
#include <boost/atomic.hpp>
+#include <cstddef>
#include <cstring>
+#include <limits>
+#include <iostream>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
-#include <boost/core/lightweight_test.hpp>
#include <boost/type_traits/integral_constant.hpp>
+#include <boost/type_traits/is_signed.hpp>
#include <boost/type_traits/is_unsigned.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)
+};
+
+const test_stream_type test_stream = {};
+
+#define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream
+
+#include <boost/core/lightweight_test.hpp>
+
/* provide helpers that exercise whether the API
functions of "boost::atomic" provide the correct
operational semantic in the case of sequential
/* explicit load/store */
{
boost::atomic<T> a(value1);
- BOOST_TEST( a.load() == value1 );
+ BOOST_TEST_EQ( a.load(), value1 );
}
{
boost::atomic<T> a(value1);
a.store(value2);
- BOOST_TEST( a.load() == value2 );
+ BOOST_TEST_EQ( a.load(), value2 );
}
/* overloaded assignment/conversion */
{
boost::atomic<T> a(value1);
T n = a.exchange(value2);
- BOOST_TEST( a.load() == value2 && n == value1 );
+ BOOST_TEST_EQ( a.load(), value2 );
+ BOOST_TEST_EQ( n, value1 );
}
{
T expected = value1;
bool success = a.compare_exchange_strong(expected, value3);
BOOST_TEST( success );
- BOOST_TEST( a.load() == value3 && expected == value1 );
+ BOOST_TEST_EQ( a.load(), value3 );
+ BOOST_TEST_EQ( expected, value1 );
}
{
T expected = value2;
bool success = a.compare_exchange_strong(expected, value3);
BOOST_TEST( !success );
- BOOST_TEST( a.load() == value1 && expected == value1 );
+ BOOST_TEST_EQ( a.load(), value1 );
+ BOOST_TEST_EQ( expected, value1 );
}
{
success = a.compare_exchange_weak(expected, value3);
} while(!success);
BOOST_TEST( success );
- BOOST_TEST( a.load() == value3 && expected == value1 );
+ BOOST_TEST_EQ( a.load(), value3 );
+ BOOST_TEST_EQ( expected, value1 );
}
{
break;
} while(!success);
BOOST_TEST( !success );
- BOOST_TEST( a.load() == value1 && expected == value1 );
+ BOOST_TEST_EQ( a.load(), value1 );
+ BOOST_TEST_EQ( expected, value1 );
}
}
#endif
}
+//! The type traits provides max and min values of type D that can be added/subtracted to T(0) without signed overflow
+template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value >
+struct distance_limits
+{
+ static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ return (std::numeric_limits< D >::min)();
+ }
+ static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ return (std::numeric_limits< D >::max)();
+ }
+};
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+// 'static_cast': truncation of constant value. There is no actual truncation happening because
+// the cast is only performed if the value fits in the range of the result.
+#pragma warning(disable: 4309)
+#endif
+
+template< typename T, typename D >
+struct distance_limits< T*, D, true >
+{
+ static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::min)() / static_cast< std::ptrdiff_t >(sizeof(T));
+ const D diff = (std::numeric_limits< D >::min)();
+ // Both values are negative. Return the closest value to zero.
+ return diff < ptrdiff ? static_cast< D >(ptrdiff) : diff;
+ }
+ static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::max)() / static_cast< std::ptrdiff_t >(sizeof(T));
+ const D diff = (std::numeric_limits< D >::max)();
+ // Both values are positive. Return the closest value to zero.
+ return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
+ }
+};
+
+template< typename T, typename D >
+struct distance_limits< T*, D, false >
+{
+ static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ return (std::numeric_limits< D >::min)();
+ }
+ static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ const std::size_t ptrdiff = static_cast< std::size_t >((std::numeric_limits< std::ptrdiff_t >::max)()) / sizeof(T);
+ const D diff = (std::numeric_limits< D >::max)();
+ return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
+ }
+};
+
+#if defined(BOOST_HAS_INT128)
+
+// At least libstdc++ does not specialize std::numeric_limits for __int128 in strict mode (i.e. with GNU extensions disabled).
+// So we have to specialize the limits ourself. We assume two's complement signed representation.
+template< typename T, bool IsSigned >
+struct distance_limits< T, boost::int128_type, IsSigned >
+{
+ static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ return -(max)() - 1;
+ }
+ static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
+ }
+};
+
+template< typename T, bool IsSigned >
+struct distance_limits< T, boost::uint128_type, IsSigned >
+{
+ static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ return 0u;
+ }
+ static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
+ {
+ return ~static_cast< boost::uint128_type >(0u);
+ }
+};
+
+#endif // defined(BOOST_HAS_INT128)
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+template<typename T, typename D, typename AddType>
+void test_additive_operators_with_type_and_test()
+{
+ // Note: This set of tests is extracted to a separate function because otherwise MSVC-10 for x64 generates broken code
+ const T zero_value = 0;
+ const D zero_diff = 0;
+ const D one_diff = 1;
+ const AddType zero_add = 0;
+ {
+ boost::atomic<T> a(zero_value);
+ bool f = a.add_and_test(zero_diff);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), zero_value );
+
+ f = a.add_and_test(one_diff);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(zero_add + one_diff) );
+ }
+ {
+ boost::atomic<T> a(zero_value);
+ bool f = a.add_and_test((distance_limits< T, D >::max)());
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) );
+ }
+ {
+ boost::atomic<T> a(zero_value);
+ 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)()) );
+ }
+
+ {
+ boost::atomic<T> a(zero_value);
+ bool f = a.sub_and_test(zero_diff);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), zero_value );
+
+ f = a.sub_and_test(one_diff);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(zero_add - one_diff) );
+ }
+ {
+ boost::atomic<T> a(zero_value);
+ bool f = a.sub_and_test((distance_limits< T, D >::max)());
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) );
+ }
+ {
+ boost::atomic<T> a(zero_value);
+ bool f = a.sub_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)()) );
+ }
+}
+
template<typename T, typename D, typename AddType>
void test_additive_operators_with_type(T value, D delta)
{
{
boost::atomic<T> a(value);
T n = a.fetch_add(delta);
- BOOST_TEST( a.load() == T((AddType)value + delta) );
- BOOST_TEST( n == value );
+ BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
+ BOOST_TEST_EQ( n, value );
}
{
boost::atomic<T> a(value);
T n = a.fetch_sub(delta);
- BOOST_TEST( a.load() == T((AddType)value - delta) );
- BOOST_TEST( n == value );
+ BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
+ BOOST_TEST_EQ( n, value );
}
/* overloaded modify/assign*/
{
boost::atomic<T> a(value);
T n = (a += delta);
- BOOST_TEST( a.load() == T((AddType)value + delta) );
- BOOST_TEST( n == T((AddType)value + delta) );
+ BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
+ BOOST_TEST_EQ( n, T((AddType)value + delta) );
}
{
boost::atomic<T> a(value);
T n = (a -= delta);
- BOOST_TEST( a.load() == T((AddType)value - delta) );
- BOOST_TEST( n == T((AddType)value - delta) );
+ BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
+ BOOST_TEST_EQ( n, T((AddType)value - delta) );
}
/* overloaded increment/decrement */
{
boost::atomic<T> a(value);
T n = a++;
- BOOST_TEST( a.load() == T((AddType)value + 1) );
- BOOST_TEST( n == value );
+ BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
+ BOOST_TEST_EQ( n, value );
}
{
boost::atomic<T> a(value);
T n = ++a;
- BOOST_TEST( a.load() == T((AddType)value + 1) );
- BOOST_TEST( n == T((AddType)value + 1) );
+ BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
+ BOOST_TEST_EQ( n, T((AddType)value + 1) );
}
{
boost::atomic<T> a(value);
T n = a--;
- BOOST_TEST( a.load() == T((AddType)value - 1) );
- BOOST_TEST( n == value );
+ BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
+ BOOST_TEST_EQ( n, value );
}
{
boost::atomic<T> a(value);
T n = --a;
- BOOST_TEST( a.load() == T((AddType)value - 1) );
- BOOST_TEST( n == T((AddType)value - 1) );
+ BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
+ BOOST_TEST_EQ( n, T((AddType)value - 1) );
}
+
+ // Opaque operations
+ {
+ boost::atomic<T> a(value);
+ a.opaque_add(delta);
+ BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
+ }
+
+ {
+ boost::atomic<T> a(value);
+ a.opaque_sub(delta);
+ BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
+ }
+
+ // Modify and test operations
+ test_additive_operators_with_type_and_test< T, D, AddType >();
}
template<typename T, typename D>
test_additive_operators_with_type<T, D, T>(value, delta);
}
+template< typename T >
+void test_negation()
+{
+ {
+ boost::atomic<T> a((T)1);
+ T n = a.fetch_negate();
+ BOOST_TEST_EQ( a.load(), (T)-1 );
+ BOOST_TEST_EQ( n, (T)1 );
+
+ n = a.fetch_negate();
+ BOOST_TEST_EQ( a.load(), (T)1 );
+ BOOST_TEST_EQ( n, (T)-1 );
+ }
+ {
+ boost::atomic<T> a((T)1);
+ a.opaque_negate();
+ BOOST_TEST_EQ( a.load(), (T)-1 );
+
+ a.opaque_negate();
+ BOOST_TEST_EQ( a.load(), (T)1 );
+ }
+}
+
template<typename T>
void test_additive_wrap(T value)
{
{
boost::atomic<T> a(value);
- T n = a.fetch_add(1) + 1;
- BOOST_TEST( a.compare_exchange_strong(n, n) );
+ T n = a.fetch_add(1) + (T)1;
+ BOOST_TEST_EQ( a.load(), n );
}
{
boost::atomic<T> a(value);
- T n = a.fetch_sub(1) - 1;
- BOOST_TEST( a.compare_exchange_strong(n, n) );
+ T n = a.fetch_sub(1) - (T)1;
+ BOOST_TEST_EQ( a.load(), n );
}
}
{
boost::atomic<T> a(value);
T n = a.fetch_and(delta);
- BOOST_TEST( a.load() == T(value & delta) );
- BOOST_TEST( n == value );
+ BOOST_TEST_EQ( a.load(), T(value & delta) );
+ BOOST_TEST_EQ( n, value );
}
{
boost::atomic<T> a(value);
T n = a.fetch_or(delta);
- BOOST_TEST( a.load() == T(value | delta) );
- BOOST_TEST( n == value );
+ BOOST_TEST_EQ( a.load(), T(value | delta) );
+ BOOST_TEST_EQ( n, value );
}
{
boost::atomic<T> a(value);
T n = a.fetch_xor(delta);
- BOOST_TEST( a.load() == T(value ^ delta) );
- BOOST_TEST( n == value );
+ BOOST_TEST_EQ( a.load(), T(value ^ delta) );
+ BOOST_TEST_EQ( n, value );
+ }
+
+ {
+ boost::atomic<T> a(value);
+ T n = a.fetch_complement();
+ BOOST_TEST_EQ( a.load(), T(~value) );
+ BOOST_TEST_EQ( n, value );
}
/* overloaded modify/assign */
{
boost::atomic<T> a(value);
T n = (a &= delta);
- BOOST_TEST( a.load() == T(value & delta) );
- BOOST_TEST( n == T(value & delta) );
+ BOOST_TEST_EQ( a.load(), T(value & delta) );
+ BOOST_TEST_EQ( n, T(value & delta) );
}
{
boost::atomic<T> a(value);
T n = (a |= delta);
- BOOST_TEST( a.load() == T(value | delta) );
- BOOST_TEST( n == T(value | delta) );
+ BOOST_TEST_EQ( a.load(), T(value | delta) );
+ BOOST_TEST_EQ( n, T(value | delta) );
}
{
boost::atomic<T> a(value);
T n = (a ^= delta);
- BOOST_TEST( a.load() == T(value ^ delta) );
- BOOST_TEST( n == T(value ^ delta) );
+ BOOST_TEST_EQ( a.load(), T(value ^ delta) );
+ BOOST_TEST_EQ( n, T(value ^ delta) );
+ }
+
+ // Opaque operations
+ {
+ boost::atomic<T> a(value);
+ a.opaque_and(delta);
+ BOOST_TEST_EQ( a.load(), T(value & delta) );
+ }
+
+ {
+ boost::atomic<T> a(value);
+ a.opaque_or(delta);
+ BOOST_TEST_EQ( a.load(), T(value | delta) );
+ }
+
+ {
+ boost::atomic<T> a(value);
+ a.opaque_xor(delta);
+ BOOST_TEST_EQ( a.load(), T(value ^ delta) );
+ }
+
+ {
+ boost::atomic<T> a(value);
+ a.opaque_complement();
+ BOOST_TEST_EQ( a.load(), T(~value) );
+ }
+
+ // Modify and test operations
+ {
+ boost::atomic<T> a((T)1);
+ bool f = a.and_and_test((T)1);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(1) );
+
+ f = a.and_and_test((T)0);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), T(0) );
+
+ f = a.and_and_test((T)0);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), T(0) );
+ }
+
+ {
+ boost::atomic<T> a((T)0);
+ bool f = a.or_and_test((T)0);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), T(0) );
+
+ f = a.or_and_test((T)1);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(1) );
+
+ f = a.or_and_test((T)1);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(1) );
+ }
+
+ {
+ boost::atomic<T> a((T)0);
+ bool f = a.xor_and_test((T)0);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), T(0) );
+
+ f = a.xor_and_test((T)1);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(1) );
+
+ f = a.xor_and_test((T)1);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), T(0) );
+ }
+
+ // Bit test and modify operations
+ {
+ boost::atomic<T> a((T)42);
+ bool f = a.bit_test_and_set(0);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(43) );
+
+ f = a.bit_test_and_set(1);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), T(43) );
+
+ f = a.bit_test_and_set(2);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(47) );
+ }
+
+ {
+ boost::atomic<T> a((T)42);
+ bool f = a.bit_test_and_reset(0);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(42) );
+
+ f = a.bit_test_and_reset(1);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), T(40) );
+
+ f = a.bit_test_and_set(2);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(44) );
+ }
+
+ {
+ boost::atomic<T> a((T)42);
+ bool f = a.bit_test_and_complement(0);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(43) );
+
+ f = a.bit_test_and_complement(1);
+ BOOST_TEST_EQ( f, true );
+ BOOST_TEST_EQ( a.load(), T(41) );
+
+ f = a.bit_test_and_complement(2);
+ BOOST_TEST_EQ( f, false );
+ BOOST_TEST_EQ( a.load(), T(45) );
}
}
do_test_integral_api<T>(boost::false_type());
test_additive_wrap<T>(0u);
- test_additive_wrap<T>(~(T)0u);
- test_additive_wrap<T>((~(T)0u) << (sizeof(T) * 8 - 1));
- test_additive_wrap<T>(~((~(T)0u) << (sizeof(T) * 8 - 1)));
+ BOOST_CONSTEXPR_OR_CONST T all_ones = ~(T)0u;
+ test_additive_wrap<T>(all_ones);
+ BOOST_CONSTEXPR_OR_CONST T max_signed_twos_compl = all_ones >> 1;
+ test_additive_wrap<T>(all_ones ^ max_signed_twos_compl);
+ test_additive_wrap<T>(max_signed_twos_compl);
}
template<typename T>
inline void test_integral_api(void)
{
do_test_integral_api<T>(boost::is_unsigned<T>());
+
+ if (boost::is_signed<T>::value)
+ test_negation<T>();
}
template<typename T>
void test_pointer_api(void)
{
- BOOST_TEST( sizeof(boost::atomic<T *>) >= sizeof(T *));
- BOOST_TEST( sizeof(boost::atomic<void *>) >= sizeof(T *));
+ BOOST_TEST_GE( sizeof(boost::atomic<T *>), sizeof(T *));
+ BOOST_TEST_GE( sizeof(boost::atomic<void *>), sizeof(T *));
T values[3];
test_additive_operators<T*>(&values[1], 1);
test_base_operators<void*>(&values[0], &values[1], &values[2]);
- test_additive_operators_with_type<void*, int, char*>(&values[1], 1);
#if defined(BOOST_HAS_INTPTR_T)
boost::atomic<void *> ptr;
boost::atomic<boost::intptr_t> integral;
- BOOST_TEST( ptr.is_lock_free() == integral.is_lock_free() );
+ BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() );
#endif
}
-enum test_enum {
+enum test_enum
+{
foo, bar, baz
};
}
template<typename T>
-struct test_struct {
+struct test_struct
+{
typedef T value_type;
value_type i;
inline bool operator==(const test_struct & c) const {return i == c.i;}
inline bool operator!=(const test_struct & c) const {return i != c.i;}
};
+template< typename Char, typename Traits, typename T >
+inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct< T > const& s)
+{
+ test_stream << "{" << s.i << "}";
+ return strm;
+}
+
template<typename T>
void
test_struct_api(void)
{
boost::atomic<T> sa;
boost::atomic<typename T::value_type> si;
- BOOST_TEST( sa.is_lock_free() == si.is_lock_free() );
+ BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
}
}
template<typename T>
-struct test_struct_x2 {
+struct test_struct_x2
+{
typedef T value_type;
value_type i, j;
inline bool operator==(const test_struct_x2 & c) const {return i == c.i && j == c.j;}
inline bool operator!=(const test_struct_x2 & c) const {return i != c.i && j != c.j;}
};
+template< typename Char, typename Traits, typename T >
+inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_x2< T > const& s)
+{
+ test_stream << "{" << s.i << ", " << s.j << "}";
+ return strm;
+}
+
template<typename T>
void
test_struct_x2_api(void)
test_base_operators(a, b, c);
}
-struct large_struct {
+struct large_struct
+{
long data[64];
inline bool operator==(const large_struct & c) const
}
};
+template< typename Char, typename Traits >
+inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
+{
+ strm << "[large_struct]";
+ return strm;
+}
+
static void
test_large_struct_api(void)
{
test_base_operators(a, b, c);
}
-struct test_struct_with_ctor {
+struct test_struct_with_ctor
+{
typedef unsigned int value_type;
value_type i;
test_struct_with_ctor() : i(0x01234567) {}
inline bool operator!=(const test_struct_with_ctor & c) const {return i != c.i;}
};
+template< typename Char, typename Traits >
+inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_with_ctor const&)
+{
+ strm << "[test_struct_with_ctor]";
+ return strm;
+}
+
static void
test_struct_with_ctor_api(void)
{