12d971aa5SEugen-Alexandru Virtan/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
22d971aa5SEugen-Alexandru Virtan/*
32d971aa5SEugen-Alexandru Virtan *     Copyright 2017 Couchbase, Inc.
42d971aa5SEugen-Alexandru Virtan *
52d971aa5SEugen-Alexandru Virtan *   Licensed under the Apache License, Version 2.0 (the "License");
62d971aa5SEugen-Alexandru Virtan *   you may not use this file except in compliance with the License.
72d971aa5SEugen-Alexandru Virtan *   You may obtain a copy of the License at
82d971aa5SEugen-Alexandru Virtan *
92d971aa5SEugen-Alexandru Virtan *       http://www.apache.org/licenses/LICENSE-2.0
102d971aa5SEugen-Alexandru Virtan *
112d971aa5SEugen-Alexandru Virtan *   Unless required by applicable law or agreed to in writing, software
122d971aa5SEugen-Alexandru Virtan *   distributed under the License is distributed on an "AS IS" BASIS,
132d971aa5SEugen-Alexandru Virtan *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
142d971aa5SEugen-Alexandru Virtan *   See the License for the specific language governing permissions and
152d971aa5SEugen-Alexandru Virtan *   limitations under the License.
162d971aa5SEugen-Alexandru Virtan */
172d971aa5SEugen-Alexandru Virtan
182d971aa5SEugen-Alexandru Virtan#pragma once
192d971aa5SEugen-Alexandru Virtan
202d971aa5SEugen-Alexandru Virtan#include <atomic>
21116bd58eSTrond Norbye#include <chrono>
222d971aa5SEugen-Alexandru Virtan
232d971aa5SEugen-Alexandru Virtannamespace cb {
242d971aa5SEugen-Alexandru Virtan/* Wrapper class around std::atomic. It provides atomic operations
252d971aa5SEugen-Alexandru Virtan * for std::chrono durations by operating on the underlying value
262d971aa5SEugen-Alexandru Virtan * obtained from the duration's count().
27f42ec1e9SDave Rigby * Defaults to relaxed memory ordering, suitable for statistics.
282d971aa5SEugen-Alexandru Virtan */
29f42ec1e9SDave Rigbytemplate <std::memory_order MemoryOrder =
30f42ec1e9SDave Rigby                  std::memory_order::memory_order_relaxed>
312d971aa5SEugen-Alexandru Virtanclass AtomicDuration {
322d971aa5SEugen-Alexandru Virtanpublic:
332d971aa5SEugen-Alexandru Virtan    AtomicDuration() {
34116bd58eSTrond Norbye        store(std::chrono::steady_clock::duration::zero());
352d971aa5SEugen-Alexandru Virtan    }
362d971aa5SEugen-Alexandru Virtan
37116bd58eSTrond Norbye    AtomicDuration(std::chrono::steady_clock::duration initial) {
382d971aa5SEugen-Alexandru Virtan        store(initial);
392d971aa5SEugen-Alexandru Virtan    }
402d971aa5SEugen-Alexandru Virtan
412d971aa5SEugen-Alexandru Virtan    explicit AtomicDuration(const AtomicDuration& other) {
422d971aa5SEugen-Alexandru Virtan        store(other.load());
432d971aa5SEugen-Alexandru Virtan    }
442d971aa5SEugen-Alexandru Virtan
45116bd58eSTrond Norbye    operator std::chrono::steady_clock::duration() const {
462d971aa5SEugen-Alexandru Virtan        return load();
472d971aa5SEugen-Alexandru Virtan    }
482d971aa5SEugen-Alexandru Virtan
49116bd58eSTrond Norbye    std::chrono::steady_clock::duration load() const {
50f42ec1e9SDave Rigby        return std::chrono::steady_clock::duration(value.load(MemoryOrder));
512d971aa5SEugen-Alexandru Virtan    }
522d971aa5SEugen-Alexandru Virtan
53116bd58eSTrond Norbye    void store(std::chrono::steady_clock::duration desired) {
54f42ec1e9SDave Rigby        value.store(desired.count(), MemoryOrder);
552d971aa5SEugen-Alexandru Virtan    }
562d971aa5SEugen-Alexandru Virtan
57116bd58eSTrond Norbye    std::chrono::steady_clock::duration fetch_add(
58116bd58eSTrond Norbye            std::chrono::steady_clock::duration arg) {
59116bd58eSTrond Norbye        return std::chrono::steady_clock::duration(
60f42ec1e9SDave Rigby                value.fetch_add(arg.count(), MemoryOrder));
612d971aa5SEugen-Alexandru Virtan    }
622d971aa5SEugen-Alexandru Virtan
63116bd58eSTrond Norbye    std::chrono::steady_clock::duration fetch_sub(
64116bd58eSTrond Norbye            std::chrono::steady_clock::duration arg) {
65116bd58eSTrond Norbye        return std::chrono::steady_clock::duration(
66f42ec1e9SDave Rigby                value.fetch_sub(arg.count(), MemoryOrder));
672d971aa5SEugen-Alexandru Virtan    }
682d971aa5SEugen-Alexandru Virtan
69116bd58eSTrond Norbye    AtomicDuration& operator=(std::chrono::steady_clock::duration val) {
702d971aa5SEugen-Alexandru Virtan        store(val);
712d971aa5SEugen-Alexandru Virtan        return *this;
722d971aa5SEugen-Alexandru Virtan    }
732d971aa5SEugen-Alexandru Virtan
74116bd58eSTrond Norbye    AtomicDuration& operator+=(std::chrono::steady_clock::duration rhs) {
752d971aa5SEugen-Alexandru Virtan        fetch_add(rhs);
762d971aa5SEugen-Alexandru Virtan        return *this;
772d971aa5SEugen-Alexandru Virtan    }
782d971aa5SEugen-Alexandru Virtan
79116bd58eSTrond Norbye    AtomicDuration& operator-=(std::chrono::steady_clock::duration rhs) {
802d971aa5SEugen-Alexandru Virtan        fetch_sub(rhs);
812d971aa5SEugen-Alexandru Virtan        return *this;
822d971aa5SEugen-Alexandru Virtan    }
832d971aa5SEugen-Alexandru Virtan
84116bd58eSTrond Norbye    std::chrono::steady_clock::duration operator++() {
85116bd58eSTrond Norbye        return fetch_add(std::chrono::steady_clock::duration(1)) +
86116bd58eSTrond Norbye               std::chrono::steady_clock::duration(1);
872d971aa5SEugen-Alexandru Virtan    }
882d971aa5SEugen-Alexandru Virtan
89116bd58eSTrond Norbye    std::chrono::steady_clock::duration operator++(int) {
90116bd58eSTrond Norbye        return fetch_add(std::chrono::steady_clock::duration(1));
912d971aa5SEugen-Alexandru Virtan    }
922d971aa5SEugen-Alexandru Virtan
93116bd58eSTrond Norbye    std::chrono::steady_clock::duration operator--() {
94116bd58eSTrond Norbye        return fetch_sub(std::chrono::steady_clock::duration(1)) -
95116bd58eSTrond Norbye               std::chrono::steady_clock::duration(1);
962d971aa5SEugen-Alexandru Virtan    }
972d971aa5SEugen-Alexandru Virtan
98116bd58eSTrond Norbye    std::chrono::steady_clock::duration operator--(int) {
99116bd58eSTrond Norbye        return fetch_sub(std::chrono::steady_clock::duration(1));
1002d971aa5SEugen-Alexandru Virtan    }
1012d971aa5SEugen-Alexandru Virtan
1022d971aa5SEugen-Alexandru Virtanprivate:
103116bd58eSTrond Norbye    std::atomic<std::chrono::steady_clock::duration::rep> value;
1042d971aa5SEugen-Alexandru Virtan};
105acda8ff3STrond Norbye} // namespace cb
106