HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
global_state.hpp
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "cast.hpp"
8#include <atomic>
9#include <type_traits>
10#include <bit>
11
12hi_warning_push();
13// C26490: Don't use reinterpret_cast
14// Need it for allow the use of enum in an atomic operation.
15hi_warning_ignore_msvc(26490);
16
17namespace hi::inline v1 {
18enum class global_state_type : uint64_t {
19 log_debug = 0x01,
20 log_info = 0x02,
21 log_statistics = 0x04,
22 log_trace = 0x08,
23 log_audit = 0x10,
24 log_warning = 0x20,
25 log_error = 0x40,
26 log_fatal = 0x80,
27
28 log_mask = log_debug | log_info | log_statistics | log_trace | log_audit | log_warning | log_error | log_fatal,
29
30 log_level_default = log_audit | log_error | log_fatal,
31 log_level_fatal = log_audit | log_fatal,
32 log_level_error = log_trace | log_error | log_level_fatal,
33 log_level_warning = log_warning | log_level_error,
34 log_level_info = log_info | log_statistics | log_level_warning,
35 log_level_debug = log_debug | log_level_info,
36
37 log_is_running = 0x1'00,
38 time_stamp_utc_is_running = 0x2'00,
39
40 system_is_running = 0x1'000000'00,
41 system_is_shutting_down = 0x2'000000'00,
42 system_mask = system_is_running | system_is_shutting_down,
43};
44
45[[nodiscard]] constexpr global_state_type operator|(global_state_type lhs, global_state_type rhs) noexcept
46{
47 return static_cast<global_state_type>(to_underlying(lhs) | to_underlying(rhs));
48}
49
50[[nodiscard]] constexpr global_state_type operator&(global_state_type lhs, global_state_type rhs) noexcept
51{
52 return static_cast<global_state_type>(to_underlying(lhs) & to_underlying(rhs));
53}
54
55[[nodiscard]] constexpr global_state_type operator~(global_state_type rhs) noexcept
56{
57 return static_cast<global_state_type>(~to_underlying(rhs));
58}
59
60[[nodiscard]] constexpr bool to_bool(global_state_type rhs) noexcept
61{
62 return to_bool(to_underlying(rhs));
63}
64
65[[nodiscard]] constexpr bool is_system_running(global_state_type rhs) noexcept
66{
67 return (rhs & global_state_type::system_mask) == global_state_type::system_is_running;
68}
69
70[[nodiscard]] constexpr bool is_system_shutting_down(global_state_type rhs) noexcept
71{
72 return to_bool(rhs & global_state_type::system_is_shutting_down);
73}
74
75} // namespace hi::inline v1
76
77template<>
78struct std::atomic<hi::global_state_type> {
79 using value_type = hi::global_state_type;
82
83 static constexpr bool is_always_lock_free = atomic_type::is_always_lock_free;
84
85 constexpr atomic() noexcept = default;
86 atomic(atomic const&) = delete;
87 atomic(atomic&&) = delete;
88 atomic& operator=(atomic const&) = delete;
89 atomic& operator=(atomic&&) = delete;
90
91 constexpr atomic(value_type desired) noexcept : v(to_underlying(desired)) {}
92
93 [[nodiscard]] bool is_lock_free() const noexcept
94 {
95 return v.is_lock_free();
96 }
97
98 void store(value_type desired, std::memory_order order = std::memory_order::seq_cst) noexcept
99 {
100 return v.store(hi::to_underlying(desired), order);
101 }
102
103 [[nodiscard]] value_type load(std::memory_order order = std::memory_order::seq_cst) const noexcept
104 {
105 return static_cast<value_type>(v.load(order));
106 }
107
108 [[nodiscard]] value_type exchange(value_type desired, std::memory_order order = std::memory_order::seq_cst) noexcept
109 {
110 return static_cast<value_type>(v.exchange(hi::to_underlying(desired), order));
111 }
112
113 [[nodiscard]] bool
114 compare_exchange_weak(value_type& expected, value_type desired, std::memory_order success, std::memory_order failure) noexcept
115 {
116 return v.compare_exchange_weak(
117 reinterpret_cast<underlying_type_t<value_type>&>(expected), hi::to_underlying(desired), success, failure);
118 }
119
120 [[nodiscard]] bool
121 compare_exchange_weak(value_type& expected, value_type desired, std::memory_order order = std::memory_order::seq_cst) noexcept
122 {
123 return compare_exchange_weak(expected, desired, order, order);
124 }
125
126 [[nodiscard]] bool compare_exchange_strong(
127 value_type& expected,
128 value_type desired,
129 std::memory_order success,
130 std::memory_order failure) noexcept
131 {
132 return v.compare_exchange_weak(
133 reinterpret_cast<underlying_type_t<value_type>&>(expected), hi::to_underlying(desired), success, failure);
134 }
135
136 [[nodiscard]] bool compare_exchange_strong(
137 value_type& expected,
138 value_type desired,
139 std::memory_order order = std::memory_order::seq_cst) noexcept
140 {
141 return compare_exchange_strong(expected, desired, order, order);
142 }
143
144 value_type fetch_and(value_type arg, std::memory_order order = std::memory_order::seq_cst) noexcept
145 {
146 return static_cast<value_type>(v.fetch_and(hi::to_underlying(arg), order));
147 }
148
149 value_type fetch_or(value_type arg, std::memory_order order = std::memory_order::seq_cst) noexcept
150 {
151 return static_cast<value_type>(v.fetch_or(hi::to_underlying(arg), order));
152 }
153
154 operator value_type() const noexcept
155 {
156 return load();
157 }
158
159 value_type operator=(value_type desired) noexcept
160 {
161 store(desired);
162 return desired;
163 }
164
165 value_type operator|=(value_type arg) noexcept
166 {
167 return fetch_or(arg) | arg;
168 }
169
170 value_type operator&=(value_type arg) noexcept
171 {
172 return fetch_and(arg) & arg;
173 }
174};
175
176namespace hi::inline v1 {
177
187inline std::atomic<global_state_type> global_state = global_state_type::log_level_default;
188
189[[nodiscard]] inline bool is_system_running() noexcept
190{
191 return is_system_running(global_state.load(std::memory_order::relaxed));
192}
193
194[[nodiscard]] inline bool is_system_shutting_down() noexcept
195{
196 return is_system_shutting_down(global_state.load(std::memory_order::relaxed));
197}
198
199inline void set_log_level(global_state_type log_level) noexcept
200{
201 // Only the log_* bits should be set.
202 hi_assert(not to_bool(log_level & ~global_state_type::log_mask));
203
204 // First enable bits, then disable bits.
205 global_state |= log_level;
206 global_state &= (~global_state_type::log_mask | log_level);
207}
208
215inline bool global_state_disable(global_state_type subsystem, std::memory_order order = std::memory_order::seq_cst) noexcept
216{
217 hi_assert(std::popcount(to_underlying(subsystem)) == 1);
218 return to_bool(global_state.fetch_and(~subsystem, order) & subsystem);
219}
220
227inline bool global_state_enable(global_state_type subsystem, std::memory_order order = std::memory_order::seq_cst) noexcept
228{
229 hi_assert(std::popcount(to_underlying(subsystem)) == 1);
230 return to_bool(global_state.fetch_or(subsystem, order) & subsystem);
231}
232
233} // namespace hi::inline v1
234
235hi_warning_pop();
#define hi_assert(expression)
Assert if expression is true.
Definition assert.hpp:86
DOXYGEN BUG.
Definition algorithm.hpp:15
bool global_state_disable(global_state_type subsystem, std::memory_order order=std::memory_order::seq_cst) noexcept
Disable a subsystem.
Definition global_state.hpp:215
constexpr alignment operator|(horizontal_alignment lhs, vertical_alignment rhs) noexcept
Combine vertical and horizontal alignment.
Definition alignment.hpp:216
std::atomic< global_state_type > global_state
The global state of the hikogui framework.
Definition global_state.hpp:187
bool global_state_enable(global_state_type subsystem, std::memory_order order=std::memory_order::seq_cst) noexcept
Enable a subsystem.
Definition global_state.hpp:227
The HikoGUI namespace.
Definition ascii.hpp:19
T compare_exchange_weak(T... args)
T exchange(T... args)
T fetch_and(T... args)
T fetch_or(T... args)
T is_lock_free(T... args)
T load(T... args)
T operator=(T... args)
T operator|=(T... args)
T store(T... args)