-
Notifications
You must be signed in to change notification settings - Fork 0
/
atomic_struct.h
137 lines (116 loc) · 4.71 KB
/
atomic_struct.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright © 2016 zendo (734181759@qq.com). All rights reserved.
#pragma once
#include <memory>
namespace zendo
{
namespace details
{
template<size_t> struct atomic_struct_raw;
template<> struct atomic_struct_raw<1>{ using type = uint8_t; };
template<> struct atomic_struct_raw<2>{ using type = uint16_t; };
template<> struct atomic_struct_raw<3>{ using type = uint32_t; };
template<> struct atomic_struct_raw<4>{ using type = uint32_t; };
template<> struct atomic_struct_raw<5>{ using type = uint64_t; };
template<> struct atomic_struct_raw<6>{ using type = uint64_t; };
template<> struct atomic_struct_raw<7>{ using type = uint64_t; };
template<> struct atomic_struct_raw<8>{ using type = uint64_t; };
inline std::memory_order default_failure_memory_order(std::memory_order order)
{
switch (order)
{
case std::memory_order_acq_rel:
return std::memory_order_acquire;
case std::memory_order_release:
return std::memory_order_relaxed;
default:
return order;
}
}
}
template<typename T, template<typename> class Atomic = std::atomic>
class atomic_struct
{
public:
using value_type = T;
using raw_type = typename details::atomic_struct_raw<sizeof(T)>::type;
using atomic_type = Atomic<raw_type>;
static_assert(alignof(value_type) <= alignof(raw_type), "");
static_assert(sizeof(value_type) <= sizeof(raw_type), "");
static_assert(std::is_trivial<value_type>::value || std::is_trivially_copyable<T>::value, "");
private:
atomic_type data_;
static raw_type encode(value_type value) noexcept
{
raw_type ret = 0;
memcpy(&ret, &value, sizeof(value_type));
return ret;
}
static value_type decode(raw_type raw) noexcept
{
value_type ret;
memcpy(&ret, &raw, sizeof(value_type));
return ret;
}
public:
atomic_struct() = default;
~atomic_struct() = default;
atomic_struct(const atomic_struct&) = delete;
atomic_struct& operator= (const atomic_struct&) = delete;
constexpr atomic_struct(value_type value) noexcept
: data_(encode(value))
{
}
bool is_lock_free() const noexcept
{
return data_.is_lock_free();
}
bool compare_exchange_strong(value_type& expected, value_type value, std::memory_order order = std::memory_order_seq_cst) noexcept
{
return compare_exchange_strong(expected, value, order, details::default_failure_memory_order(order));
}
bool compare_exchange_strong(value_type& expected, value_type value, std::memory_order success, std::memory_order failure) noexcept
{
raw_type data = encode(expected);
if(data_.compare_exchange_strong(data, encode(value), success, failure))
{
return true;
}
expected = decode(data);
return false;
}
bool compare_exchange_weak(value_type& expected, value_type value, std::memory_order order = std::memory_order_seq_cst) noexcept
{
return compare_exchange_weak(expected, value, order, details::default_failure_memory_order(order));
}
bool compare_exchange_weak(value_type& expected, value_type value, std::memory_order success, std::memory_order failure) noexcept
{
raw_type data = encode(expected);
if(data_.compare_exchange_weak(data, encode(value), success, failure))
{
return true;
}
expected = decode(data);
return false;
}
value_type exchange(value_type value, std::memory_order order = std::memory_order_seq_cst) noexcept
{
return decode(data_.exchange(encode(value), order));
}
operator value_type() const noexcept
{
return decode(data_);
}
value_type load(std::memory_order order = std::memory_order_seq_cst) const noexcept
{
return decode(data_.load(order));
}
value_type operator= (value_type value) noexcept
{
return decode(data_ = encode(value));
}
void store(value_type value, std::memory_order order = std::memory_order_seq_cst) noexcept
{
data_.store(encode(value), order);
}
};
}