Add initial bits for Qt6 support
[carla.git] / source / modules / ysfx / sources / utility / sync_bitset.hpp
blob064c4b18d289bf783d93b80178153a544bf60d54
1 // Copyright 2021 Jean Pierre Cimalando
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 // SPDX-License-Identifier: Apache-2.0
18 #pragma once
19 #include <type_traits>
20 #include <atomic>
21 #include <cstdint>
23 namespace ysfx {
25 //------------------------------------------------------------------------------
26 // sync_bitset64: A lock-free synchronized bitset of size 64
28 // This is implemented by a single qword on 64-bit machine, otherwise a pair of
29 // dwords on 32-bit machine, which is to ensure lock-freedom.
31 // This bitset is synchronized but not atomic; a thread might see a
32 // partially updated set after a modification. Conceptually, it can be seen as
33 // atomic on individual bit flips (that is, masking operations do not race).
35 class sync_bitset64_single;
36 class sync_bitset64_dual;
38 // could use std::atomic::is_always_lock_free on C++17 and up
39 using sync_bitset64 = std::conditional<
40 sizeof(intptr_t) <= 4, sync_bitset64_dual, sync_bitset64_single>::type;
42 //------------------------------------------------------------------------------
43 class sync_bitset64_single {
44 public:
45 uint64_t load() const
47 return bits_.load(std::memory_order_relaxed);
50 void store(uint64_t value)
52 bits_.store(value, std::memory_order_relaxed);
55 uint64_t exchange(uint64_t value)
57 return bits_.exchange(value, std::memory_order_relaxed);
60 uint64_t fetch_or(uint64_t value)
62 return bits_.fetch_or(value, std::memory_order_relaxed);
65 uint64_t fetch_and(uint64_t value)
67 return bits_.fetch_and(value, std::memory_order_relaxed);
70 uint64_t fetch_xor(uint64_t value)
72 return bits_.fetch_xor(value, std::memory_order_relaxed);
75 void operator|=(uint64_t value)
77 fetch_or(value);
80 void operator&=(uint64_t value)
82 fetch_and(value);
85 void operator^=(uint64_t value)
87 fetch_xor(value);
90 private:
91 std::atomic<uint64_t> bits_{0};
94 //------------------------------------------------------------------------------
95 class sync_bitset64_dual {
96 public:
97 uint64_t load() const
99 return join(lobits_.load(std::memory_order_relaxed),
100 hibits_.load(std::memory_order_relaxed));
103 void store(uint64_t value)
105 lobits_.store(lo(value), std::memory_order_relaxed);
106 hibits_.store(hi(value), std::memory_order_relaxed);
109 uint64_t exchange(uint64_t value)
111 return join(lobits_.exchange(lo(value), std::memory_order_relaxed),
112 hibits_.exchange(hi(value), std::memory_order_relaxed));
115 uint64_t fetch_or(uint64_t value)
117 return join(lobits_.fetch_or(lo(value), std::memory_order_relaxed),
118 hibits_.fetch_or(hi(value), std::memory_order_relaxed));
121 uint64_t fetch_and(uint64_t value)
123 return join(lobits_.fetch_and(lo(value), std::memory_order_relaxed),
124 hibits_.fetch_and(hi(value), std::memory_order_relaxed));
127 uint64_t fetch_xor(uint64_t value)
129 return join(lobits_.fetch_xor(lo(value), std::memory_order_relaxed),
130 hibits_.fetch_xor(hi(value), std::memory_order_relaxed));
133 void operator|=(uint64_t value)
135 fetch_or(value);
138 void operator&=(uint64_t value)
140 fetch_and(value);
143 void operator^=(uint64_t value)
145 fetch_xor(value);
148 private:
149 static constexpr uint64_t join(uint32_t lo, uint32_t hi)
151 return (uint64_t)lo | ((uint64_t)hi << 32);
154 static constexpr uint32_t lo(uint64_t value)
156 return (uint32_t)(value & 0xFFFFFFFFu);
159 static constexpr uint32_t hi(uint64_t value)
161 return (uint32_t)(value >> 32);
164 private:
165 std::atomic<uint32_t> lobits_{0};
166 std::atomic<uint32_t> hibits_{0};
169 } // namespace ysfx