1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2017 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 
18 #pragma once
19 
20 #include "config.h"
21 
22 #include <platform/processclock.h>
23 #include <atomic>
24 
25 namespace cb {
26 /* Wrapper class around std::atomic. It provides atomic operations
27  * for std::chrono durations by operating on the underlying value
28  * obtained from the duration's count().
29  * It uses relaxed memory ordering, so it is suitable for statistics use only.
30  */
31 class AtomicDuration {
32 public:
AtomicDuration()33     AtomicDuration() {
34         store(ProcessClock::duration::zero());
35     }
36 
AtomicDuration(ProcessClock::duration initial)37     AtomicDuration(ProcessClock::duration initial) {
38         store(initial);
39     }
40 
AtomicDuration(const AtomicDuration& other)41     explicit AtomicDuration(const AtomicDuration& other) {
42         store(other.load());
43     }
44 
operator ProcessClock::duration() const45     operator ProcessClock::duration() const {
46         return load();
47     }
48 
load() const49     ProcessClock::duration load() const {
50         return ProcessClock::duration(value.load(std::memory_order_relaxed));
51     }
52 
store(ProcessClock::duration desired)53     void store(ProcessClock::duration desired) {
54         value.store(desired.count(), std::memory_order_relaxed);
55     }
56 
fetch_add(ProcessClock::duration arg)57     ProcessClock::duration fetch_add(ProcessClock::duration arg) {
58         return ProcessClock::duration(
59                 value.fetch_add(arg.count(), std::memory_order_relaxed));
60     }
61 
fetch_sub(ProcessClock::duration arg)62     ProcessClock::duration fetch_sub(ProcessClock::duration arg) {
63         return ProcessClock::duration(
64                 value.fetch_sub(arg.count(), std::memory_order_relaxed));
65     }
66 
operator =(ProcessClock::duration val)67     AtomicDuration& operator=(ProcessClock::duration val) {
68         store(val);
69         return *this;
70     }
71 
operator +=(ProcessClock::duration rhs)72     AtomicDuration& operator+=(ProcessClock::duration rhs) {
73         fetch_add(rhs);
74         return *this;
75     }
76 
operator -=(ProcessClock::duration rhs)77     AtomicDuration& operator-=(ProcessClock::duration rhs) {
78         fetch_sub(rhs);
79         return *this;
80     }
81 
operator ++()82     ProcessClock::duration operator++() {
83         return fetch_add(ProcessClock::duration(1)) + ProcessClock::duration(1);
84     }
85 
operator ++(int)86     ProcessClock::duration operator++(int) {
87         return fetch_add(ProcessClock::duration(1));
88     }
89 
operator --()90     ProcessClock::duration operator--() {
91         return fetch_sub(ProcessClock::duration(1)) - ProcessClock::duration(1);
92     }
93 
operator --(int)94     ProcessClock::duration operator--(int) {
95         return fetch_sub(ProcessClock::duration(1));
96     }
97 
98 private:
99     std::atomic<ProcessClock::duration::rep> value;
100 };
101 }