HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
global_state.hpp
Go to the documentation of this file.
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
9#pragma once
10
11#include "../utility/utility.hpp"
12#include "../macros.hpp"
13#include <utility>
14#include <atomic>
15#include <type_traits>
16#include <bit>
17
18hi_export_module(hikogui.concurrency.global_state);
19
20
21hi_warning_push();
22// C26490: Don't use reinterpret_cast
23// Need it for allow the use of enum in an atomic operation.
24hi_warning_ignore_msvc(26490);
25
26hi_export namespace hi { inline namespace v1 {
27
32enum class global_state_type : uint64_t {
33 log_debug = 0x01,
34 log_info = 0x02,
35 log_statistics = 0x04,
36 log_trace = 0x08,
37 log_audit = 0x10,
38 log_warning = 0x20,
39 log_error = 0x40,
40 log_fatal = 0x80,
41
42 log_mask = log_debug | log_info | log_statistics | log_trace | log_audit | log_warning | log_error | log_fatal,
43
44 log_level_default = log_audit | log_error | log_fatal,
45 log_level_fatal = log_audit | log_fatal,
46 log_level_error = log_trace | log_error | log_level_fatal,
47 log_level_warning = log_warning | log_level_error,
48 log_level_info = log_info | log_statistics | log_level_warning,
49 log_level_debug = log_debug | log_level_info,
50
51 log_is_running = 0x1'00,
52 time_stamp_utc_is_running = 0x2'00,
53
54 system_is_running = 0x1'000000'00,
55 system_is_shutting_down = 0x2'000000'00,
56 system_mask = system_is_running | system_is_shutting_down,
57};
58
59[[nodiscard]] constexpr global_state_type operator|(global_state_type lhs, global_state_type rhs) noexcept
60{
61 return static_cast<global_state_type>(std::to_underlying(lhs) | std::to_underlying(rhs));
62}
63
64[[nodiscard]] constexpr global_state_type operator&(global_state_type lhs, global_state_type rhs) noexcept
65{
66 return static_cast<global_state_type>(std::to_underlying(lhs) & std::to_underlying(rhs));
67}
68
69[[nodiscard]] constexpr global_state_type operator~(global_state_type rhs) noexcept
70{
71 return static_cast<global_state_type>(~std::to_underlying(rhs));
72}
73
74[[nodiscard]] constexpr bool to_bool(global_state_type rhs) noexcept
75{
76 return to_bool(std::to_underlying(rhs));
77}
78
79[[nodiscard]] constexpr bool is_system_running(global_state_type rhs) noexcept
80{
81 return (rhs & global_state_type::system_mask) == global_state_type::system_is_running;
82}
83
84[[nodiscard]] constexpr bool is_system_shutting_down(global_state_type rhs) noexcept
85{
86 return to_bool(rhs & global_state_type::system_is_shutting_down);
87}
88
89}} // namespace hi::v1
90
91template<>
92struct std::atomic<hi::global_state_type> {
96
97 constexpr static bool is_always_lock_free = atomic_type::is_always_lock_free;
98
99 constexpr atomic() noexcept = default;
100 atomic(atomic const&) = delete;
101 atomic(atomic&&) = delete;
102 atomic& operator=(atomic const&) = delete;
103 atomic& operator=(atomic&&) = delete;
104
105 constexpr atomic(value_type desired) noexcept : v(std::to_underlying(desired)) {}
106
107 [[nodiscard]] bool is_lock_free() const noexcept
108 {
109 return v.is_lock_free();
110 }
111
112 void store(value_type desired, std::memory_order order = std::memory_order::seq_cst) noexcept
113 {
114 return v.store(std::to_underlying(desired), order);
115 }
116
117 [[nodiscard]] value_type load(std::memory_order order = std::memory_order::seq_cst) const noexcept
118 {
119 return static_cast<value_type>(v.load(order));
120 }
121
122 [[nodiscard]] value_type exchange(value_type desired, std::memory_order order = std::memory_order::seq_cst) noexcept
123 {
124 return static_cast<value_type>(v.exchange(std::to_underlying(desired), order));
125 }
126
127 [[nodiscard]] bool
128 compare_exchange_weak(value_type& expected, value_type desired, std::memory_order success, std::memory_order failure) noexcept
129 {
130 return v.compare_exchange_weak(
131 reinterpret_cast<underlying_type_t<value_type>&>(expected), std::to_underlying(desired), success, failure);
132 }
133
134 [[nodiscard]] bool
135 compare_exchange_weak(value_type& expected, value_type desired, std::memory_order order = std::memory_order::seq_cst) noexcept
136 {
137 return compare_exchange_weak(expected, desired, order, order);
138 }
139
140 [[nodiscard]] bool compare_exchange_strong(
141 value_type& expected,
142 value_type desired,
143 std::memory_order success,
144 std::memory_order failure) noexcept
145 {
147 reinterpret_cast<underlying_type_t<value_type>&>(expected), std::to_underlying(desired), success, failure);
148 }
149
150 [[nodiscard]] bool compare_exchange_strong(
151 value_type& expected,
152 value_type desired,
153 std::memory_order order = std::memory_order::seq_cst) noexcept
154 {
155 return compare_exchange_strong(expected, desired, order, order);
156 }
157
158 value_type fetch_and(value_type arg, std::memory_order order = std::memory_order::seq_cst) noexcept
159 {
160 return static_cast<value_type>(v.fetch_and(std::to_underlying(arg), order));
161 }
162
163 value_type fetch_or(value_type arg, std::memory_order order = std::memory_order::seq_cst) noexcept
164 {
165 return static_cast<value_type>(v.fetch_or(std::to_underlying(arg), order));
166 }
167
168 operator value_type() const noexcept
169 {
170 return load();
171 }
172
173 value_type operator=(value_type desired) noexcept
174 {
175 store(desired);
176 return desired;
177 }
178
179 value_type operator|=(value_type arg) noexcept
180 {
181 return fetch_or(arg) | arg;
182 }
183
184 value_type operator&=(value_type arg) noexcept
185 {
186 return fetch_and(arg) & arg;
187 }
188};
189
190hi_export namespace hi { inline namespace v1 {
191
203inline std::atomic<global_state_type> global_state = global_state_type::log_level_default;
204
211[[nodiscard]] inline bool is_system_running() noexcept
212{
213 return is_system_running(global_state.load(std::memory_order::relaxed));
214}
215
222[[nodiscard]] inline bool is_system_shutting_down() noexcept
223{
224 return is_system_shutting_down(global_state.load(std::memory_order::relaxed));
225}
226
232inline void set_log_level(global_state_type log_level) noexcept
233{
234 // Only the log_* bits should be set.
235 hi_assert(not to_bool(log_level & ~global_state_type::log_mask));
236
237 // First enable bits, then disable bits.
238 global_state |= log_level;
239 global_state &= (~global_state_type::log_mask | log_level);
240}
241
249inline bool global_state_disable(global_state_type subsystem, std::memory_order order = std::memory_order::seq_cst) noexcept
250{
251 hi_assert(std::popcount(std::to_underlying(subsystem)) == 1);
252 return to_bool(global_state.fetch_and(~subsystem, order) & subsystem);
253}
254
262inline bool global_state_enable(global_state_type subsystem, std::memory_order order = std::memory_order::seq_cst) noexcept
263{
264 hi_assert(std::popcount(std::to_underlying(subsystem)) == 1);
265 return to_bool(global_state.fetch_or(subsystem, order) & subsystem);
266}
267
268}} // namespace hi::v1
269
270hi_warning_pop();
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:262
bool is_system_running() noexcept
Check if the HikoGUI system is running.
Definition global_state.hpp:211
std::atomic< global_state_type > global_state
The global state of the hikogui framework.
Definition global_state.hpp:203
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:249
global_state_type
The flag-type used for global state.
Definition global_state.hpp:32
bool is_system_shutting_down() noexcept
Check if the HikoGUI system is being shut down.
Definition global_state.hpp:222
void set_log_level(global_state_type log_level) noexcept
Set the logging level.
Definition global_state.hpp:232
STL namespace.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
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)