api_test_helpers.hpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. // Copyright (c) 2011 Helge Bahmann
  2. // Copyright (c) 2017 - 2019 Andrey Semashev
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_ATOMIC_API_TEST_HELPERS_HPP
  8. #define BOOST_ATOMIC_API_TEST_HELPERS_HPP
  9. #include <boost/atomic.hpp>
  10. #include <cstddef>
  11. #include <cstring>
  12. #include <limits>
  13. #include <iostream>
  14. #include <boost/config.hpp>
  15. #include <boost/cstdint.hpp>
  16. #include <boost/type_traits/integral_constant.hpp>
  17. #include <boost/type_traits/is_pointer.hpp>
  18. #include <boost/type_traits/is_signed.hpp>
  19. #include <boost/type_traits/is_unsigned.hpp>
  20. #include <boost/type_traits/make_signed.hpp>
  21. #include <boost/type_traits/make_unsigned.hpp>
  22. #include <boost/type_traits/conditional.hpp>
  23. struct test_stream_type
  24. {
  25. typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
  26. typedef std::basic_ios< char, std::char_traits< char > >& (*basic_ios_manip)(std::basic_ios< char, std::char_traits< char > >&);
  27. typedef std::ostream& (*stream_manip)(std::ostream&);
  28. template< typename T >
  29. test_stream_type const& operator<< (T const& value) const
  30. {
  31. std::cerr << value;
  32. return *this;
  33. }
  34. test_stream_type const& operator<< (ios_base_manip manip) const
  35. {
  36. std::cerr << manip;
  37. return *this;
  38. }
  39. test_stream_type const& operator<< (basic_ios_manip manip) const
  40. {
  41. std::cerr << manip;
  42. return *this;
  43. }
  44. test_stream_type const& operator<< (stream_manip manip) const
  45. {
  46. std::cerr << manip;
  47. return *this;
  48. }
  49. // Make sure characters are printed as numbers if tests fail
  50. test_stream_type const& operator<< (char value) const
  51. {
  52. std::cerr << static_cast< int >(value);
  53. return *this;
  54. }
  55. test_stream_type const& operator<< (signed char value) const
  56. {
  57. std::cerr << static_cast< int >(value);
  58. return *this;
  59. }
  60. test_stream_type const& operator<< (unsigned char value) const
  61. {
  62. std::cerr << static_cast< unsigned int >(value);
  63. return *this;
  64. }
  65. test_stream_type const& operator<< (short value) const
  66. {
  67. std::cerr << static_cast< int >(value);
  68. return *this;
  69. }
  70. test_stream_type const& operator<< (unsigned short value) const
  71. {
  72. std::cerr << static_cast< unsigned int >(value);
  73. return *this;
  74. }
  75. #if defined(BOOST_HAS_INT128)
  76. // Some GCC versions don't provide output operators for __int128
  77. test_stream_type const& operator<< (boost::int128_type const& v) const
  78. {
  79. std::cerr << static_cast< long long >(v);
  80. return *this;
  81. }
  82. test_stream_type const& operator<< (boost::uint128_type const& v) const
  83. {
  84. std::cerr << static_cast< unsigned long long >(v);
  85. return *this;
  86. }
  87. #endif // defined(BOOST_HAS_INT128)
  88. #if defined(BOOST_HAS_FLOAT128)
  89. // libstdc++ does not provide output operators for __float128
  90. test_stream_type const& operator<< (boost::float128_type const& v) const
  91. {
  92. std::cerr << static_cast< double >(v);
  93. return *this;
  94. }
  95. #endif // defined(BOOST_HAS_FLOAT128)
  96. };
  97. const test_stream_type test_stream = {};
  98. #define BOOST_LIGHTWEIGHT_TEST_OSTREAM test_stream
  99. #include <boost/core/lightweight_test.hpp>
  100. #include "value_with_epsilon.hpp"
  101. /* provide helpers that exercise whether the API
  102. functions of "boost::atomic" provide the correct
  103. operational semantic in the case of sequential
  104. execution */
  105. static void
  106. test_flag_api(void)
  107. {
  108. #ifndef BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
  109. boost::atomic_flag f = BOOST_ATOMIC_FLAG_INIT;
  110. #else
  111. boost::atomic_flag f;
  112. #endif
  113. BOOST_TEST( !f.test_and_set() );
  114. BOOST_TEST( f.test_and_set() );
  115. f.clear();
  116. BOOST_TEST( !f.test_and_set() );
  117. }
  118. template<typename T>
  119. void test_base_operators(T value1, T value2, T value3)
  120. {
  121. /* explicit load/store */
  122. {
  123. boost::atomic<T> a(value1);
  124. BOOST_TEST_EQ( a.load(), value1 );
  125. }
  126. {
  127. boost::atomic<T> a(value1);
  128. a.store(value2);
  129. BOOST_TEST_EQ( a.load(), value2 );
  130. }
  131. /* overloaded assignment/conversion */
  132. {
  133. boost::atomic<T> a(value1);
  134. BOOST_TEST( value1 == a );
  135. }
  136. {
  137. boost::atomic<T> a;
  138. a = value2;
  139. BOOST_TEST( value2 == a );
  140. }
  141. /* exchange-type operators */
  142. {
  143. boost::atomic<T> a(value1);
  144. T n = a.exchange(value2);
  145. BOOST_TEST_EQ( a.load(), value2 );
  146. BOOST_TEST_EQ( n, value1 );
  147. }
  148. {
  149. boost::atomic<T> a(value1);
  150. T expected = value1;
  151. bool success = a.compare_exchange_strong(expected, value3);
  152. BOOST_TEST( success );
  153. BOOST_TEST_EQ( a.load(), value3 );
  154. BOOST_TEST_EQ( expected, value1 );
  155. }
  156. {
  157. boost::atomic<T> a(value1);
  158. T expected = value2;
  159. bool success = a.compare_exchange_strong(expected, value3);
  160. BOOST_TEST( !success );
  161. BOOST_TEST_EQ( a.load(), value1 );
  162. BOOST_TEST_EQ( expected, value1 );
  163. }
  164. {
  165. boost::atomic<T> a(value1);
  166. T expected;
  167. bool success;
  168. do {
  169. expected = value1;
  170. success = a.compare_exchange_weak(expected, value3);
  171. } while(!success);
  172. BOOST_TEST( success );
  173. BOOST_TEST_EQ( a.load(), value3 );
  174. BOOST_TEST_EQ( expected, value1 );
  175. }
  176. {
  177. boost::atomic<T> a(value1);
  178. T expected;
  179. bool success;
  180. do {
  181. expected = value2;
  182. success = a.compare_exchange_weak(expected, value3);
  183. if (expected != value2)
  184. break;
  185. } while(!success);
  186. BOOST_TEST( !success );
  187. BOOST_TEST_EQ( a.load(), value1 );
  188. BOOST_TEST_EQ( expected, value1 );
  189. }
  190. }
  191. // T requires an int constructor
  192. template <typename T>
  193. void test_constexpr_ctor()
  194. {
  195. #ifndef BOOST_NO_CXX11_CONSTEXPR
  196. const T value(0);
  197. const boost::atomic<T> tester(value);
  198. BOOST_TEST( tester == value );
  199. #endif
  200. }
  201. //! The type traits provides max and min values of type D that can be added/subtracted to T(0) without signed overflow
  202. template< typename T, typename D, bool IsSigned = boost::is_signed< D >::value >
  203. struct distance_limits
  204. {
  205. //! Difference type D promoted to the width of type T
  206. typedef typename boost::conditional<
  207. IsSigned,
  208. typename boost::make_signed< T >::type,
  209. typename boost::make_unsigned< T >::type
  210. >::type promoted_difference_type;
  211. static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  212. {
  213. return (std::numeric_limits< D >::min)();
  214. }
  215. static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  216. {
  217. return (std::numeric_limits< D >::max)();
  218. }
  219. };
  220. #if defined(BOOST_MSVC)
  221. #pragma warning(push)
  222. // 'static_cast': truncation of constant value. There is no actual truncation happening because
  223. // the cast is only performed if the value fits in the range of the result.
  224. #pragma warning(disable: 4309)
  225. #endif
  226. template< typename T, typename D >
  227. struct distance_limits< T*, D, true >
  228. {
  229. //! Difference type D promoted to the width of type T
  230. typedef std::ptrdiff_t promoted_difference_type;
  231. static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  232. {
  233. const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::min)() / static_cast< std::ptrdiff_t >(sizeof(T));
  234. const D diff = (std::numeric_limits< D >::min)();
  235. // Both values are negative. Return the closest value to zero.
  236. return diff < ptrdiff ? static_cast< D >(ptrdiff) : diff;
  237. }
  238. static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  239. {
  240. const std::ptrdiff_t ptrdiff = (std::numeric_limits< std::ptrdiff_t >::max)() / static_cast< std::ptrdiff_t >(sizeof(T));
  241. const D diff = (std::numeric_limits< D >::max)();
  242. // Both values are positive. Return the closest value to zero.
  243. return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
  244. }
  245. };
  246. template< typename T, typename D >
  247. struct distance_limits< T*, D, false >
  248. {
  249. //! Difference type D promoted to the width of type T
  250. typedef std::size_t promoted_difference_type;
  251. static D min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  252. {
  253. return (std::numeric_limits< D >::min)();
  254. }
  255. static D max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  256. {
  257. const std::size_t ptrdiff = static_cast< std::size_t >((std::numeric_limits< std::ptrdiff_t >::max)()) / sizeof(T);
  258. const D diff = (std::numeric_limits< D >::max)();
  259. return diff > ptrdiff ? static_cast< D >(ptrdiff) : diff;
  260. }
  261. };
  262. #if defined(BOOST_HAS_INT128)
  263. // At least libstdc++ does not specialize std::numeric_limits for __int128 in strict mode (i.e. with GNU extensions disabled).
  264. // So we have to specialize the limits ourself. We assume two's complement signed representation.
  265. template< typename T, bool IsSigned >
  266. struct distance_limits< T, boost::int128_type, IsSigned >
  267. {
  268. //! Difference type D promoted to the width of type T
  269. typedef boost::int128_type promoted_difference_type;
  270. static boost::int128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  271. {
  272. return -(max)() - 1;
  273. }
  274. static boost::int128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  275. {
  276. return static_cast< boost::int128_type >((~static_cast< boost::uint128_type >(0u)) >> 1);
  277. }
  278. };
  279. template< typename T, bool IsSigned >
  280. struct distance_limits< T, boost::uint128_type, IsSigned >
  281. {
  282. //! Difference type D promoted to the width of type T
  283. typedef boost::uint128_type promoted_difference_type;
  284. static boost::uint128_type min BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  285. {
  286. return 0u;
  287. }
  288. static boost::uint128_type max BOOST_PREVENT_MACRO_SUBSTITUTION () BOOST_NOEXCEPT
  289. {
  290. return ~static_cast< boost::uint128_type >(0u);
  291. }
  292. };
  293. #endif // defined(BOOST_HAS_INT128)
  294. #if defined(BOOST_MSVC)
  295. #pragma warning(pop)
  296. #endif
  297. template<typename T, typename D, typename AddType>
  298. void test_additive_operators_with_type_and_test()
  299. {
  300. #if defined(UBSAN)
  301. // clang UBSAN flags this test when AddType is a pointer as it considers subtracting from a null pointer (zero_add) an UB
  302. if (boost::is_pointer< AddType >::value)
  303. return;
  304. #endif
  305. // Note: This set of tests is extracted to a separate function because otherwise MSVC-10 for x64 generates broken code
  306. typedef typename distance_limits< T, D >::promoted_difference_type promoted_difference_type;
  307. typedef typename boost::make_unsigned< promoted_difference_type >::type unsigned_promoted_difference_type;
  308. const T zero_value = 0;
  309. const D zero_diff = 0;
  310. const D one_diff = 1;
  311. const AddType zero_add = 0;
  312. {
  313. boost::atomic<T> a(zero_value);
  314. bool f = a.add_and_test(zero_diff);
  315. BOOST_TEST_EQ( f, false );
  316. BOOST_TEST_EQ( a.load(), zero_value );
  317. f = a.add_and_test(one_diff);
  318. BOOST_TEST_EQ( f, true );
  319. BOOST_TEST_EQ( a.load(), T(zero_add + one_diff) );
  320. }
  321. {
  322. boost::atomic<T> a(zero_value);
  323. bool f = a.add_and_test((distance_limits< T, D >::max)());
  324. BOOST_TEST_EQ( f, true );
  325. BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::max)()) );
  326. }
  327. {
  328. boost::atomic<T> a(zero_value);
  329. bool f = a.add_and_test((distance_limits< T, D >::min)());
  330. BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
  331. BOOST_TEST_EQ( a.load(), T(zero_add + (distance_limits< T, D >::min)()) );
  332. }
  333. {
  334. boost::atomic<T> a(zero_value);
  335. bool f = a.sub_and_test(zero_diff);
  336. BOOST_TEST_EQ( f, false );
  337. BOOST_TEST_EQ( a.load(), zero_value );
  338. f = a.sub_and_test(one_diff);
  339. BOOST_TEST_EQ( f, true );
  340. BOOST_TEST_EQ( a.load(), T(zero_add - one_diff) );
  341. }
  342. {
  343. boost::atomic<T> a(zero_value);
  344. bool f = a.sub_and_test((distance_limits< T, D >::max)());
  345. BOOST_TEST_EQ( f, true );
  346. BOOST_TEST_EQ( a.load(), T(zero_add - (distance_limits< T, D >::max)()) );
  347. }
  348. {
  349. boost::atomic<T> a(zero_value);
  350. bool f = a.sub_and_test((distance_limits< T, D >::min)());
  351. BOOST_TEST_EQ( f, ((distance_limits< T, D >::min)() != 0) );
  352. // Be very careful as to not cause signed overflow on negation
  353. unsigned_promoted_difference_type umin = static_cast< unsigned_promoted_difference_type >(
  354. static_cast< promoted_difference_type >((distance_limits< T, D >::min)()));
  355. umin = -umin;
  356. promoted_difference_type neg_min;
  357. std::memcpy(&neg_min, &umin, sizeof(neg_min));
  358. BOOST_TEST_EQ( a.load(), T(zero_add + neg_min) );
  359. }
  360. }
  361. template<typename T, typename D, typename AddType>
  362. void test_additive_operators_with_type(T value, D delta)
  363. {
  364. /* note: the tests explicitly cast the result of any addition
  365. to the type to be tested to force truncation of the result to
  366. the correct range in case of overflow */
  367. /* explicit add/sub */
  368. {
  369. boost::atomic<T> a(value);
  370. T n = a.fetch_add(delta);
  371. BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
  372. BOOST_TEST_EQ( n, value );
  373. }
  374. {
  375. boost::atomic<T> a(value);
  376. T n = a.fetch_sub(delta);
  377. BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
  378. BOOST_TEST_EQ( n, value );
  379. }
  380. /* overloaded modify/assign*/
  381. {
  382. boost::atomic<T> a(value);
  383. T n = (a += delta);
  384. BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
  385. BOOST_TEST_EQ( n, T((AddType)value + delta) );
  386. }
  387. {
  388. boost::atomic<T> a(value);
  389. T n = (a -= delta);
  390. BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
  391. BOOST_TEST_EQ( n, T((AddType)value - delta) );
  392. }
  393. /* overloaded increment/decrement */
  394. {
  395. boost::atomic<T> a(value);
  396. T n = a++;
  397. BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
  398. BOOST_TEST_EQ( n, value );
  399. }
  400. {
  401. boost::atomic<T> a(value);
  402. T n = ++a;
  403. BOOST_TEST_EQ( a.load(), T((AddType)value + 1) );
  404. BOOST_TEST_EQ( n, T((AddType)value + 1) );
  405. }
  406. {
  407. boost::atomic<T> a(value);
  408. T n = a--;
  409. BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
  410. BOOST_TEST_EQ( n, value );
  411. }
  412. {
  413. boost::atomic<T> a(value);
  414. T n = --a;
  415. BOOST_TEST_EQ( a.load(), T((AddType)value - 1) );
  416. BOOST_TEST_EQ( n, T((AddType)value - 1) );
  417. }
  418. // Operations returning the actual resulting value
  419. {
  420. boost::atomic<T> a(value);
  421. T n = a.add(delta);
  422. BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
  423. BOOST_TEST_EQ( n, T((AddType)value + delta) );
  424. }
  425. {
  426. boost::atomic<T> a(value);
  427. T n = a.sub(delta);
  428. BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
  429. BOOST_TEST_EQ( n, T((AddType)value - delta) );
  430. }
  431. // Opaque operations
  432. {
  433. boost::atomic<T> a(value);
  434. a.opaque_add(delta);
  435. BOOST_TEST_EQ( a.load(), T((AddType)value + delta) );
  436. }
  437. {
  438. boost::atomic<T> a(value);
  439. a.opaque_sub(delta);
  440. BOOST_TEST_EQ( a.load(), T((AddType)value - delta) );
  441. }
  442. // Modify and test operations
  443. test_additive_operators_with_type_and_test< T, D, AddType >();
  444. }
  445. template<typename T, typename D>
  446. void test_additive_operators(T value, D delta)
  447. {
  448. test_additive_operators_with_type<T, D, T>(value, delta);
  449. }
  450. template< typename T >
  451. void test_negation()
  452. {
  453. {
  454. boost::atomic<T> a((T)1);
  455. T n = a.fetch_negate();
  456. BOOST_TEST_EQ( a.load(), (T)-1 );
  457. BOOST_TEST_EQ( n, (T)1 );
  458. n = a.fetch_negate();
  459. BOOST_TEST_EQ( a.load(), (T)1 );
  460. BOOST_TEST_EQ( n, (T)-1 );
  461. }
  462. {
  463. boost::atomic<T> a((T)1);
  464. T n = a.negate();
  465. BOOST_TEST_EQ( a.load(), (T)-1 );
  466. BOOST_TEST_EQ( n, (T)-1 );
  467. n = a.negate();
  468. BOOST_TEST_EQ( a.load(), (T)1 );
  469. BOOST_TEST_EQ( n, (T)1 );
  470. }
  471. {
  472. boost::atomic<T> a((T)1);
  473. a.opaque_negate();
  474. BOOST_TEST_EQ( a.load(), (T)-1 );
  475. a.opaque_negate();
  476. BOOST_TEST_EQ( a.load(), (T)1 );
  477. }
  478. {
  479. boost::atomic<T> a((T)1);
  480. bool f = a.negate_and_test();
  481. BOOST_TEST_EQ( f, true );
  482. BOOST_TEST_EQ( a.load(), (T)-1 );
  483. f = a.negate_and_test();
  484. BOOST_TEST_EQ( f, true );
  485. BOOST_TEST_EQ( a.load(), (T)1 );
  486. }
  487. {
  488. boost::atomic<T> a((T)0);
  489. bool f = a.negate_and_test();
  490. BOOST_TEST_EQ( f, false );
  491. BOOST_TEST_EQ( a.load(), (T)0 );
  492. }
  493. }
  494. template<typename T>
  495. void test_additive_wrap(T value)
  496. {
  497. {
  498. boost::atomic<T> a(value);
  499. T n = a.fetch_add(1) + (T)1;
  500. BOOST_TEST_EQ( a.load(), n );
  501. }
  502. {
  503. boost::atomic<T> a(value);
  504. T n = a.fetch_sub(1) - (T)1;
  505. BOOST_TEST_EQ( a.load(), n );
  506. }
  507. }
  508. template<typename T>
  509. void test_bit_operators(T value, T delta)
  510. {
  511. /* explicit and/or/xor */
  512. {
  513. boost::atomic<T> a(value);
  514. T n = a.fetch_and(delta);
  515. BOOST_TEST_EQ( a.load(), T(value & delta) );
  516. BOOST_TEST_EQ( n, value );
  517. }
  518. {
  519. boost::atomic<T> a(value);
  520. T n = a.fetch_or(delta);
  521. BOOST_TEST_EQ( a.load(), T(value | delta) );
  522. BOOST_TEST_EQ( n, value );
  523. }
  524. {
  525. boost::atomic<T> a(value);
  526. T n = a.fetch_xor(delta);
  527. BOOST_TEST_EQ( a.load(), T(value ^ delta) );
  528. BOOST_TEST_EQ( n, value );
  529. }
  530. {
  531. boost::atomic<T> a(value);
  532. T n = a.fetch_complement();
  533. BOOST_TEST_EQ( a.load(), T(~value) );
  534. BOOST_TEST_EQ( n, value );
  535. }
  536. /* overloaded modify/assign */
  537. {
  538. boost::atomic<T> a(value);
  539. T n = (a &= delta);
  540. BOOST_TEST_EQ( a.load(), T(value & delta) );
  541. BOOST_TEST_EQ( n, T(value & delta) );
  542. }
  543. {
  544. boost::atomic<T> a(value);
  545. T n = (a |= delta);
  546. BOOST_TEST_EQ( a.load(), T(value | delta) );
  547. BOOST_TEST_EQ( n, T(value | delta) );
  548. }
  549. {
  550. boost::atomic<T> a(value);
  551. T n = (a ^= delta);
  552. BOOST_TEST_EQ( a.load(), T(value ^ delta) );
  553. BOOST_TEST_EQ( n, T(value ^ delta) );
  554. }
  555. // Operations returning the actual resulting value
  556. {
  557. boost::atomic<T> a(value);
  558. T n = a.bitwise_and(delta);
  559. BOOST_TEST_EQ( a.load(), T(value & delta) );
  560. BOOST_TEST_EQ( n, T(value & delta) );
  561. }
  562. {
  563. boost::atomic<T> a(value);
  564. T n = a.bitwise_or(delta);
  565. BOOST_TEST_EQ( a.load(), T(value | delta) );
  566. BOOST_TEST_EQ( n, T(value | delta) );
  567. }
  568. {
  569. boost::atomic<T> a(value);
  570. T n = a.bitwise_xor(delta);
  571. BOOST_TEST_EQ( a.load(), T(value ^ delta) );
  572. BOOST_TEST_EQ( n, T(value ^ delta) );
  573. }
  574. {
  575. boost::atomic<T> a(value);
  576. T n = a.bitwise_complement();
  577. BOOST_TEST_EQ( a.load(), T(~value) );
  578. BOOST_TEST_EQ( n, T(~value) );
  579. }
  580. // Opaque operations
  581. {
  582. boost::atomic<T> a(value);
  583. a.opaque_and(delta);
  584. BOOST_TEST_EQ( a.load(), T(value & delta) );
  585. }
  586. {
  587. boost::atomic<T> a(value);
  588. a.opaque_or(delta);
  589. BOOST_TEST_EQ( a.load(), T(value | delta) );
  590. }
  591. {
  592. boost::atomic<T> a(value);
  593. a.opaque_xor(delta);
  594. BOOST_TEST_EQ( a.load(), T(value ^ delta) );
  595. }
  596. {
  597. boost::atomic<T> a(value);
  598. a.opaque_complement();
  599. BOOST_TEST_EQ( a.load(), T(~value) );
  600. }
  601. // Modify and test operations
  602. {
  603. boost::atomic<T> a((T)1);
  604. bool f = a.and_and_test((T)1);
  605. BOOST_TEST_EQ( f, true );
  606. BOOST_TEST_EQ( a.load(), T(1) );
  607. f = a.and_and_test((T)0);
  608. BOOST_TEST_EQ( f, false );
  609. BOOST_TEST_EQ( a.load(), T(0) );
  610. f = a.and_and_test((T)0);
  611. BOOST_TEST_EQ( f, false );
  612. BOOST_TEST_EQ( a.load(), T(0) );
  613. }
  614. {
  615. boost::atomic<T> a((T)0);
  616. bool f = a.or_and_test((T)0);
  617. BOOST_TEST_EQ( f, false );
  618. BOOST_TEST_EQ( a.load(), T(0) );
  619. f = a.or_and_test((T)1);
  620. BOOST_TEST_EQ( f, true );
  621. BOOST_TEST_EQ( a.load(), T(1) );
  622. f = a.or_and_test((T)1);
  623. BOOST_TEST_EQ( f, true );
  624. BOOST_TEST_EQ( a.load(), T(1) );
  625. }
  626. {
  627. boost::atomic<T> a((T)0);
  628. bool f = a.xor_and_test((T)0);
  629. BOOST_TEST_EQ( f, false );
  630. BOOST_TEST_EQ( a.load(), T(0) );
  631. f = a.xor_and_test((T)1);
  632. BOOST_TEST_EQ( f, true );
  633. BOOST_TEST_EQ( a.load(), T(1) );
  634. f = a.xor_and_test((T)1);
  635. BOOST_TEST_EQ( f, false );
  636. BOOST_TEST_EQ( a.load(), T(0) );
  637. }
  638. {
  639. boost::atomic<T> a((T)0);
  640. bool f = a.complement_and_test();
  641. BOOST_TEST_EQ( f, true );
  642. BOOST_TEST_EQ( a.load(), static_cast< T >(~static_cast< T >(0)) );
  643. f = a.complement_and_test();
  644. BOOST_TEST_EQ( f, false );
  645. BOOST_TEST_EQ( a.load(), T(0) );
  646. }
  647. // Bit test and modify operations
  648. {
  649. boost::atomic<T> a((T)42);
  650. bool f = a.bit_test_and_set(0);
  651. BOOST_TEST_EQ( f, false );
  652. BOOST_TEST_EQ( a.load(), T(43) );
  653. f = a.bit_test_and_set(1);
  654. BOOST_TEST_EQ( f, true );
  655. BOOST_TEST_EQ( a.load(), T(43) );
  656. f = a.bit_test_and_set(2);
  657. BOOST_TEST_EQ( f, false );
  658. BOOST_TEST_EQ( a.load(), T(47) );
  659. }
  660. {
  661. boost::atomic<T> a((T)42);
  662. bool f = a.bit_test_and_reset(0);
  663. BOOST_TEST_EQ( f, false );
  664. BOOST_TEST_EQ( a.load(), T(42) );
  665. f = a.bit_test_and_reset(1);
  666. BOOST_TEST_EQ( f, true );
  667. BOOST_TEST_EQ( a.load(), T(40) );
  668. f = a.bit_test_and_set(2);
  669. BOOST_TEST_EQ( f, false );
  670. BOOST_TEST_EQ( a.load(), T(44) );
  671. }
  672. {
  673. boost::atomic<T> a((T)42);
  674. bool f = a.bit_test_and_complement(0);
  675. BOOST_TEST_EQ( f, false );
  676. BOOST_TEST_EQ( a.load(), T(43) );
  677. f = a.bit_test_and_complement(1);
  678. BOOST_TEST_EQ( f, true );
  679. BOOST_TEST_EQ( a.load(), T(41) );
  680. f = a.bit_test_and_complement(2);
  681. BOOST_TEST_EQ( f, false );
  682. BOOST_TEST_EQ( a.load(), T(45) );
  683. }
  684. }
  685. template<typename T>
  686. void do_test_integral_api(boost::false_type)
  687. {
  688. BOOST_TEST(sizeof(boost::atomic<T>) >= sizeof(T));
  689. test_base_operators<T>(42, 43, 44);
  690. test_additive_operators<T, T>(42, 17);
  691. test_bit_operators<T>((T)0x5f5f5f5f5f5f5f5fULL, (T)0xf5f5f5f5f5f5f5f5ULL);
  692. /* test for unsigned overflow/underflow */
  693. test_additive_operators<T, T>((T)-1, 1);
  694. test_additive_operators<T, T>(0, 1);
  695. /* test for signed overflow/underflow */
  696. test_additive_operators<T, T>(((T)-1) >> (sizeof(T) * 8 - 1), 1);
  697. test_additive_operators<T, T>(1 + (((T)-1) >> (sizeof(T) * 8 - 1)), 1);
  698. }
  699. template<typename T>
  700. void do_test_integral_api(boost::true_type)
  701. {
  702. do_test_integral_api<T>(boost::false_type());
  703. test_additive_wrap<T>(0u);
  704. BOOST_CONSTEXPR_OR_CONST T all_ones = ~(T)0u;
  705. test_additive_wrap<T>(all_ones);
  706. BOOST_CONSTEXPR_OR_CONST T max_signed_twos_compl = all_ones >> 1;
  707. test_additive_wrap<T>(all_ones ^ max_signed_twos_compl);
  708. test_additive_wrap<T>(max_signed_twos_compl);
  709. }
  710. template<typename T>
  711. inline void test_integral_api(void)
  712. {
  713. do_test_integral_api<T>(boost::is_unsigned<T>());
  714. if (boost::is_signed<T>::value)
  715. test_negation<T>();
  716. }
  717. #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
  718. template<typename T, typename D>
  719. void test_fp_additive_operators(T value, D delta)
  720. {
  721. /* explicit add/sub */
  722. {
  723. boost::atomic<T> a(value);
  724. T n = a.fetch_add(delta);
  725. BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
  726. BOOST_TEST_EQ( n, approx(value) );
  727. }
  728. {
  729. boost::atomic<T> a(value);
  730. T n = a.fetch_sub(delta);
  731. BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
  732. BOOST_TEST_EQ( n, approx(value) );
  733. }
  734. /* overloaded modify/assign*/
  735. {
  736. boost::atomic<T> a(value);
  737. T n = (a += delta);
  738. BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
  739. BOOST_TEST_EQ( n, approx(T(value + delta)) );
  740. }
  741. {
  742. boost::atomic<T> a(value);
  743. T n = (a -= delta);
  744. BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
  745. BOOST_TEST_EQ( n, approx(T(value - delta)) );
  746. }
  747. // Operations returning the actual resulting value
  748. {
  749. boost::atomic<T> a(value);
  750. T n = a.add(delta);
  751. BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
  752. BOOST_TEST_EQ( n, approx(T(value + delta)) );
  753. }
  754. {
  755. boost::atomic<T> a(value);
  756. T n = a.sub(delta);
  757. BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
  758. BOOST_TEST_EQ( n, approx(T(value - delta)) );
  759. }
  760. // Opaque operations
  761. {
  762. boost::atomic<T> a(value);
  763. a.opaque_add(delta);
  764. BOOST_TEST_EQ( a.load(), approx(T(value + delta)) );
  765. }
  766. {
  767. boost::atomic<T> a(value);
  768. a.opaque_sub(delta);
  769. BOOST_TEST_EQ( a.load(), approx(T(value - delta)) );
  770. }
  771. }
  772. template< typename T >
  773. void test_fp_negation()
  774. {
  775. {
  776. boost::atomic<T> a((T)1);
  777. T n = a.fetch_negate();
  778. BOOST_TEST_EQ( a.load(), approx((T)-1) );
  779. BOOST_TEST_EQ( n, approx((T)1) );
  780. n = a.fetch_negate();
  781. BOOST_TEST_EQ( a.load(), approx((T)1) );
  782. BOOST_TEST_EQ( n, approx((T)-1) );
  783. }
  784. {
  785. boost::atomic<T> a((T)1);
  786. T n = a.negate();
  787. BOOST_TEST_EQ( a.load(), approx((T)-1) );
  788. BOOST_TEST_EQ( n, approx((T)-1) );
  789. n = a.negate();
  790. BOOST_TEST_EQ( a.load(), approx((T)1) );
  791. BOOST_TEST_EQ( n, approx((T)1) );
  792. }
  793. {
  794. boost::atomic<T> a((T)1);
  795. a.opaque_negate();
  796. BOOST_TEST_EQ( a.load(), approx((T)-1) );
  797. a.opaque_negate();
  798. BOOST_TEST_EQ( a.load(), approx((T)1) );
  799. }
  800. }
  801. #endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
  802. template<typename T>
  803. inline void test_floating_point_api(void)
  804. {
  805. BOOST_TEST(sizeof(boost::atomic<T>) >= sizeof(T));
  806. // Note: When support for floating point is disabled, even the base operation tests may fail because
  807. // the generic template specialization does not account for garbage in padding bits that are present in some FP types.
  808. #if !defined(BOOST_ATOMIC_NO_FLOATING_POINT)
  809. test_base_operators<T>(static_cast<T>(42.1), static_cast<T>(43.2), static_cast<T>(44.3));
  810. test_fp_additive_operators<T, T>(static_cast<T>(42.5), static_cast<T>(17.7));
  811. test_fp_additive_operators<T, T>(static_cast<T>(-42.5), static_cast<T>(-17.7));
  812. test_fp_negation<T>();
  813. #endif
  814. }
  815. template<typename T>
  816. void test_pointer_api(void)
  817. {
  818. BOOST_TEST_GE( sizeof(boost::atomic<T *>), sizeof(T *));
  819. BOOST_TEST_GE( sizeof(boost::atomic<void *>), sizeof(T *));
  820. T values[3];
  821. test_base_operators<T*>(&values[0], &values[1], &values[2]);
  822. test_additive_operators<T*>(&values[1], 1);
  823. test_base_operators<void*>(&values[0], &values[1], &values[2]);
  824. #if defined(BOOST_HAS_INTPTR_T)
  825. boost::atomic<void *> ptr;
  826. boost::atomic<boost::intptr_t> integral;
  827. BOOST_TEST_EQ( ptr.is_lock_free(), integral.is_lock_free() );
  828. #endif
  829. }
  830. enum test_enum
  831. {
  832. foo, bar, baz
  833. };
  834. static void
  835. test_enum_api(void)
  836. {
  837. test_base_operators(foo, bar, baz);
  838. }
  839. template<typename T>
  840. struct test_struct
  841. {
  842. typedef T value_type;
  843. value_type i;
  844. inline bool operator==(const test_struct & c) const {return i == c.i;}
  845. inline bool operator!=(const test_struct & c) const {return i != c.i;}
  846. };
  847. template< typename Char, typename Traits, typename T >
  848. inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct< T > const& s)
  849. {
  850. test_stream << "{" << s.i << "}";
  851. return strm;
  852. }
  853. template<typename T>
  854. void
  855. test_struct_api(void)
  856. {
  857. T a = {1}, b = {2}, c = {3};
  858. test_base_operators(a, b, c);
  859. {
  860. boost::atomic<T> sa;
  861. boost::atomic<typename T::value_type> si;
  862. BOOST_TEST_EQ( sa.is_lock_free(), si.is_lock_free() );
  863. }
  864. }
  865. template<typename T>
  866. struct test_struct_x2
  867. {
  868. typedef T value_type;
  869. value_type i, j;
  870. inline bool operator==(const test_struct_x2 & c) const {return i == c.i && j == c.j;}
  871. inline bool operator!=(const test_struct_x2 & c) const {return i != c.i && j != c.j;}
  872. };
  873. template< typename Char, typename Traits, typename T >
  874. inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_x2< T > const& s)
  875. {
  876. test_stream << "{" << s.i << ", " << s.j << "}";
  877. return strm;
  878. }
  879. template<typename T>
  880. void
  881. test_struct_x2_api(void)
  882. {
  883. T a = {1, 1}, b = {2, 2}, c = {3, 3};
  884. test_base_operators(a, b, c);
  885. }
  886. struct large_struct
  887. {
  888. long data[64];
  889. inline bool operator==(const large_struct & c) const
  890. {
  891. return std::memcmp(data, &c.data, sizeof(data)) == 0;
  892. }
  893. inline bool operator!=(const large_struct & c) const
  894. {
  895. return std::memcmp(data, &c.data, sizeof(data)) != 0;
  896. }
  897. };
  898. template< typename Char, typename Traits >
  899. inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, large_struct const&)
  900. {
  901. strm << "[large_struct]";
  902. return strm;
  903. }
  904. static void
  905. test_large_struct_api(void)
  906. {
  907. large_struct a = {{1}}, b = {{2}}, c = {{3}};
  908. test_base_operators(a, b, c);
  909. }
  910. struct test_struct_with_ctor
  911. {
  912. typedef unsigned int value_type;
  913. value_type i;
  914. test_struct_with_ctor() : i(0x01234567) {}
  915. inline bool operator==(const test_struct_with_ctor & c) const {return i == c.i;}
  916. inline bool operator!=(const test_struct_with_ctor & c) const {return i != c.i;}
  917. };
  918. template< typename Char, typename Traits >
  919. inline std::basic_ostream< Char, Traits >& operator<< (std::basic_ostream< Char, Traits >& strm, test_struct_with_ctor const&)
  920. {
  921. strm << "[test_struct_with_ctor]";
  922. return strm;
  923. }
  924. static void
  925. test_struct_with_ctor_api(void)
  926. {
  927. {
  928. test_struct_with_ctor s;
  929. boost::atomic<test_struct_with_ctor> sa;
  930. // Check that the default constructor was called
  931. BOOST_TEST( sa.load() == s );
  932. }
  933. test_struct_with_ctor a, b, c;
  934. a.i = 1;
  935. b.i = 2;
  936. c.i = 3;
  937. test_base_operators(a, b, c);
  938. }
  939. #endif