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 | |
35 | template < typename TYPE > |
36 | class atomic_stat { |
37 | public: |
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 | |
90 | private: |
91 | std::atomic<TYPE> value_; |
92 | }; |
93 | |
94 | #endif // _atomic_stat_h_ |
95 | |