1/* This is an atomic integer abstract data type, for high-performance
2 tracking of a single stat. It intentionally permits inconsistent
3 atomic operations and reads, for better performance. This means
4 that, though no data should ever be lost by this stat, reads of it
5 at any time may not include all changes up to any particular point.
6
7 So, values read from these may only be approximately correct.
8
9 If your use-case will fail under these conditions, do not use this.
10
11 Copyright (C) 2012 - 2014 Steaphan Greene <steaphan@gmail.com>
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 as published by the Free Software Foundation; either version 2
16 of the License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the
25 Free Software Foundation, Inc.
26 51 Franklin Street, Fifth Floor
27 Boston, MA 02110-1301, USA.
28*/
29
30#ifndef _atomic_stat_h_
31#define _atomic_stat_h_
32
33#include <atomic>
34
35template < typename TYPE >
36class atomic_stat {
37public:
38 // Initialize value to the default for the type
39 atomic_stat() : value_(TYPE()) {};
40
41 // This enforces a strict order, as all absolute sets should
42 void clear() {
43 value_.store(TYPE(), std::memory_order_seq_cst);
44 };
45
46 // Reads can get any valid value, it doesn't matter which, exactly
47 TYPE load() const {
48 return value_.load(std::memory_order_relaxed);
49 };
50
51 // This only supplies relative arithmetic operations
52 // These are all done atomically, and so can show up in any order
53 void inc(const TYPE &other) {
54 value_.fetch_add(other, std::memory_order_relaxed);
55 };
56
57 void dec(const TYPE &other) {
58 value_.fetch_sub(other, std::memory_order_relaxed);
59 };
60
61 void inc() {
62 value_.fetch_add(1, std::memory_order_relaxed);
63 };
64
65 void dec() {
66 value_.fetch_sub(1, std::memory_order_relaxed);
67 };
68
69 // This will make one attempt to set the value to the max of
70 // the current value, and the passed-in value. It can fail
71 // for any reason, and we only try it once.
72 void set_max_maybe(const TYPE &new_val) {
73 TYPE old_val = value_;
74 if (new_val > old_val) {
75 value_.compare_exchange_weak(old_val, new_val,
76 std::memory_order_relaxed,
77 std::memory_order_relaxed);
78 }
79 };
80
81 // This will make one attempt to assign the value to the passed-in
82 // value. It can fail for any reason, and we only try it once.
83 void set_maybe(const TYPE &new_val) {
84 TYPE old_val = value_;
85 value_.compare_exchange_weak(old_val, new_val,
86 std::memory_order_relaxed,
87 std::memory_order_relaxed);
88 };
89
90private:
91 std::atomic<TYPE> value_;
92};
93
94#endif // _atomic_stat_h_
95