Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
4.4KB

  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.
  14. //
  15. // SPDX-License-Identifier: Apache-2.0
  16. //
  17. #pragma once
  18. #include <type_traits>
  19. #include <atomic>
  20. #include <cstdint>
  21. namespace ysfx {
  22. //------------------------------------------------------------------------------
  23. // sync_bitset64: A lock-free synchronized bitset of size 64
  24. //
  25. // This is implemented by a single qword on 64-bit machine, otherwise a pair of
  26. // dwords on 32-bit machine, which is to ensure lock-freedom.
  27. //
  28. // This bitset is synchronized but not atomic; a thread might see a
  29. // partially updated set after a modification. Conceptually, it can be seen as
  30. // atomic on individual bit flips (that is, masking operations do not race).
  31. class sync_bitset64_single;
  32. class sync_bitset64_dual;
  33. // could use std::atomic::is_always_lock_free on C++17 and up
  34. using sync_bitset64 = std::conditional<
  35. sizeof(intptr_t) <= 4, sync_bitset64_dual, sync_bitset64_single>::type;
  36. //------------------------------------------------------------------------------
  37. class sync_bitset64_single {
  38. public:
  39. uint64_t load() const
  40. {
  41. return bits_.load(std::memory_order_relaxed);
  42. }
  43. void store(uint64_t value)
  44. {
  45. bits_.store(value, std::memory_order_relaxed);
  46. }
  47. uint64_t exchange(uint64_t value)
  48. {
  49. return bits_.exchange(value, std::memory_order_relaxed);
  50. }
  51. uint64_t fetch_or(uint64_t value)
  52. {
  53. return bits_.fetch_or(value, std::memory_order_relaxed);
  54. }
  55. uint64_t fetch_and(uint64_t value)
  56. {
  57. return bits_.fetch_and(value, std::memory_order_relaxed);
  58. }
  59. uint64_t fetch_xor(uint64_t value)
  60. {
  61. return bits_.fetch_xor(value, std::memory_order_relaxed);
  62. }
  63. void operator|=(uint64_t value)
  64. {
  65. fetch_or(value);
  66. }
  67. void operator&=(uint64_t value)
  68. {
  69. fetch_and(value);
  70. }
  71. void operator^=(uint64_t value)
  72. {
  73. fetch_xor(value);
  74. }
  75. private:
  76. std::atomic<uint64_t> bits_{0};
  77. };
  78. //------------------------------------------------------------------------------
  79. class sync_bitset64_dual {
  80. public:
  81. uint64_t load() const
  82. {
  83. return join(lobits_.load(std::memory_order_relaxed),
  84. hibits_.load(std::memory_order_relaxed));
  85. }
  86. void store(uint64_t value)
  87. {
  88. lobits_.store(lo(value), std::memory_order_relaxed);
  89. hibits_.store(hi(value), std::memory_order_relaxed);
  90. }
  91. uint64_t exchange(uint64_t value)
  92. {
  93. return join(lobits_.exchange(lo(value), std::memory_order_relaxed),
  94. hibits_.exchange(hi(value), std::memory_order_relaxed));
  95. }
  96. uint64_t fetch_or(uint64_t value)
  97. {
  98. return join(lobits_.fetch_or(lo(value), std::memory_order_relaxed),
  99. hibits_.fetch_or(hi(value), std::memory_order_relaxed));
  100. }
  101. uint64_t fetch_and(uint64_t value)
  102. {
  103. return join(lobits_.fetch_and(lo(value), std::memory_order_relaxed),
  104. hibits_.fetch_and(hi(value), std::memory_order_relaxed));
  105. }
  106. uint64_t fetch_xor(uint64_t value)
  107. {
  108. return join(lobits_.fetch_xor(lo(value), std::memory_order_relaxed),
  109. hibits_.fetch_xor(hi(value), std::memory_order_relaxed));
  110. }
  111. void operator|=(uint64_t value)
  112. {
  113. fetch_or(value);
  114. }
  115. void operator&=(uint64_t value)
  116. {
  117. fetch_and(value);
  118. }
  119. void operator^=(uint64_t value)
  120. {
  121. fetch_xor(value);
  122. }
  123. private:
  124. static constexpr uint64_t join(uint32_t lo, uint32_t hi)
  125. {
  126. return (uint64_t)lo | ((uint64_t)hi << 32);
  127. }
  128. static constexpr uint32_t lo(uint64_t value)
  129. {
  130. return (uint32_t)(value & 0xFFFFFFFFu);
  131. }
  132. static constexpr uint32_t hi(uint64_t value)
  133. {
  134. return (uint32_t)(value >> 32);
  135. }
  136. private:
  137. std::atomic<uint32_t> lobits_{0};
  138. std::atomic<uint32_t> hibits_{0};
  139. };
  140. } // namespace ysfx