MB-19281: [BP] Add template class RelaxedAtomic<>
[ep-engine.git] / src / relaxed_atomic.h
1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2015 Couchbase, Inc.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #pragma once
18
19 #include "atomic.h"
20
21 namespace Couchbase {
22
23     /**
24      * The RelaxedAtomic class wraps std::atomic<> and operates with
25      * relaxed memory ordering.
26      */
27     template<typename T>
28     class RelaxedAtomic {
29     public:
30         RelaxedAtomic() {
31             value.store(0, memory_order_relaxed);
32         }
33
34         RelaxedAtomic(const T& initial) {
35             value.store(initial, memory_order_relaxed);
36         }
37
38         explicit RelaxedAtomic(const RelaxedAtomic& other) {
39             value.store(other.value.load(memory_order_relaxed),
40                         memory_order_relaxed);
41         }
42
43         operator T() const {
44             return value.load(memory_order_relaxed);
45         }
46
47         T load() const {
48             return value.load(memory_order_relaxed);
49         }
50
51         RelaxedAtomic& operator=(const RelaxedAtomic& rhs) {
52             value.store(rhs.load(), memory_order_relaxed);
53             return *this;
54         }
55
56         RelaxedAtomic& operator+=(const T rhs) {
57             value.fetch_add(rhs, memory_order_relaxed);
58             return *this;
59         }
60
61         RelaxedAtomic& operator+=(const RelaxedAtomic& rhs) {
62             value.fetch_add(rhs.value.load(memory_order_relaxed),
63                             memory_order_relaxed);
64             return *this;
65         }
66
67         RelaxedAtomic& operator-=(const T rhs) {
68             value.fetch_sub(rhs, memory_order_relaxed);
69             return *this;
70         }
71
72         RelaxedAtomic& operator-=(const RelaxedAtomic& rhs) {
73             value.fetch_sub(rhs.value.load(memory_order_relaxed),
74                             memory_order_relaxed);
75             return *this;
76         }
77
78         T operator++() {
79             return value.fetch_add(1, memory_order_relaxed) + 1;
80         }
81
82         T operator++(int) {
83             return value.fetch_add(1, memory_order_relaxed);
84         }
85
86         T operator--() {
87             return value.fetch_sub(1, memory_order_relaxed) - 1;
88         }
89
90         T operator--(int) {
91             return value.fetch_sub(1, memory_order_relaxed);
92         }
93
94         RelaxedAtomic& operator=(T val) {
95             value.store(val, memory_order_relaxed);
96             return *this;
97         }
98
99         void reset() {
100             value.store(0, memory_order_relaxed);
101         }
102
103         void setIfGreater(const T& val) {
104             do {
105                 T currval = value.load(memory_order_relaxed);
106                 if (val > currval) {
107                     if (value.compare_exchange_weak(currval, val,
108                                                     memory_order_relaxed)) {
109                         break;
110                     }
111                 } else {
112                     break;
113                 }
114             } while (true);
115         }
116
117         void setIfGreater(const RelaxedAtomic& val) {
118             setIfGreater(val.load());
119         }
120
121     private:
122         AtomicValue<T> value;
123     };
124 }