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 <atomic>
21 #include <chrono>
22 
23 namespace cb {
24 /* Wrapper class around std::atomic. It provides atomic operations
25  * for std::chrono durations by operating on the underlying value
26  * obtained from the duration's count().
27  * Defaults to relaxed memory ordering, suitable for statistics.
28  */
29 template <std::memory_order MemoryOrder =
30                   std::memory_order::memory_order_relaxed>
31 class AtomicDuration {
32 public:
AtomicDuration()33     AtomicDuration() {
34         store(std::chrono::steady_clock::duration::zero());
35     }
36 
AtomicDuration(std::chrono::steady_clock::duration initial)37     AtomicDuration(std::chrono::steady_clock::duration initial) {
38         store(initial);
39     }
40 
AtomicDuration(const AtomicDuration& other)41     explicit AtomicDuration(const AtomicDuration& other) {
42         store(other.load());
43     }
44 
operator std::chrono::steady_clock::duration() const45     operator std::chrono::steady_clock::duration() const {
46         return load();
47     }
48 
load() const49     std::chrono::steady_clock::duration load() const {
50         return std::chrono::steady_clock::duration(value.load(MemoryOrder));
51     }
52 
store(std::chrono::steady_clock::duration desired)53     void store(std::chrono::steady_clock::duration desired) {
54         value.store(desired.count(), MemoryOrder);
55     }
56 
fetch_add( std::chrono::steady_clock::duration arg)57     std::chrono::steady_clock::duration fetch_add(
58             std::chrono::steady_clock::duration arg) {
59         return std::chrono::steady_clock::duration(
60                 value.fetch_add(arg.count(), MemoryOrder));
61     }
62 
fetch_sub( std::chrono::steady_clock::duration arg)63     std::chrono::steady_clock::duration fetch_sub(
64             std::chrono::steady_clock::duration arg) {
65         return std::chrono::steady_clock::duration(
66                 value.fetch_sub(arg.count(), MemoryOrder));
67     }
68 
operator =(std::chrono::steady_clock::duration val)69     AtomicDuration& operator=(std::chrono::steady_clock::duration val) {
70         store(val);
71         return *this;
72     }
73 
operator +=(std::chrono::steady_clock::duration rhs)74     AtomicDuration& operator+=(std::chrono::steady_clock::duration rhs) {
75         fetch_add(rhs);
76         return *this;
77     }
78 
operator -=(std::chrono::steady_clock::duration rhs)79     AtomicDuration& operator-=(std::chrono::steady_clock::duration rhs) {
80         fetch_sub(rhs);
81         return *this;
82     }
83 
operator ++()84     std::chrono::steady_clock::duration operator++() {
85         return fetch_add(std::chrono::steady_clock::duration(1)) +
86                std::chrono::steady_clock::duration(1);
87     }
88 
operator ++(int)89     std::chrono::steady_clock::duration operator++(int) {
90         return fetch_add(std::chrono::steady_clock::duration(1));
91     }
92 
operator --()93     std::chrono::steady_clock::duration operator--() {
94         return fetch_sub(std::chrono::steady_clock::duration(1)) -
95                std::chrono::steady_clock::duration(1);
96     }
97 
operator --(int)98     std::chrono::steady_clock::duration operator--(int) {
99         return fetch_sub(std::chrono::steady_clock::duration(1));
100     }
101 
102 private:
103     std::atomic<std::chrono::steady_clock::duration::rep> value;
104 };
105 } // namespace cb
106