1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * Copyright (c) 2018 Andrey Semashev
7  */
8 /*!
9  * \file   atomic/detail/extra_fp_ops_emulated.hpp
10  *
11  * This header contains emulated (lock-based) implementation of the extra floating point atomic operations.
12  */
13 
14 #ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_
15 #define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_
16 
17 #include <cstddef>
18 #include <boost/static_assert.hpp>
19 #include <boost/memory_order.hpp>
20 #include <boost/atomic/detail/config.hpp>
21 #include <boost/atomic/detail/bitwise_fp_cast.hpp>
22 #include <boost/atomic/detail/extra_fp_operations_fwd.hpp>
23 #include <boost/atomic/detail/header.hpp>
24 
25 #ifdef BOOST_HAS_PRAGMA_ONCE
26 #pragma once
27 #endif
28 
29 namespace boost {
30 namespace atomics {
31 namespace detail {
32 
33 //! Emulated implementation of extra floating point operations
34 template< typename Base, typename Value, std::size_t Size >
35 struct extra_fp_operations_emulated :
36     public Base
37 {
38     typedef Base base_type;
39     typedef typename base_type::storage_type storage_type;
40     typedef Value value_type;
41     typedef typename base_type::scoped_lock scoped_lock;
42 
fetch_negateboost::atomics::detail::extra_fp_operations_emulated43     static value_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT
44     {
45         BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
46         storage_type& s = const_cast< storage_type& >(storage);
47         scoped_lock lock(&storage);
48         value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
49         value_type new_val = -old_val;
50         s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
51         return old_val;
52     }
53 
negateboost::atomics::detail::extra_fp_operations_emulated54     static value_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT
55     {
56         BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
57         storage_type& s = const_cast< storage_type& >(storage);
58         scoped_lock lock(&storage);
59         value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
60         value_type new_val = -old_val;
61         s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
62         return new_val;
63     }
64 
addboost::atomics::detail::extra_fp_operations_emulated65     static value_type add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT
66     {
67         BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
68         storage_type& s = const_cast< storage_type& >(storage);
69         scoped_lock lock(&storage);
70         value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
71         value_type new_val = old_val + v;
72         s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
73         return new_val;
74     }
75 
subboost::atomics::detail::extra_fp_operations_emulated76     static value_type sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT
77     {
78         BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
79         storage_type& s = const_cast< storage_type& >(storage);
80         scoped_lock lock(&storage);
81         value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s);
82         value_type new_val = old_val - v;
83         s = atomics::detail::bitwise_fp_cast< storage_type >(new_val);
84         return new_val;
85     }
86 
opaque_negateboost::atomics::detail::extra_fp_operations_emulated87     static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
88     {
89         BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
90         fetch_negate(storage, order);
91     }
92 
opaque_addboost::atomics::detail::extra_fp_operations_emulated93     static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
94     {
95         BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
96         base_type::fetch_add(storage, v, order);
97     }
98 
opaque_subboost::atomics::detail::extra_fp_operations_emulated99     static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT
100     {
101         BOOST_STATIC_ASSERT_MSG(!base_type::is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
102         base_type::fetch_sub(storage, v, order);
103     }
104 };
105 
106 template< typename Base, typename Value, std::size_t Size >
107 struct extra_fp_operations< Base, Value, Size, false > :
108     public extra_fp_operations_emulated< Base, Value, Size >
109 {
110 };
111 
112 } // namespace detail
113 } // namespace atomics
114 } // namespace boost
115 
116 #include <boost/atomic/detail/footer.hpp>
117 
118 #endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_
119