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.

183 lines
5.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. #if ! DOXYGEN
  19. namespace juce
  20. {
  21. template <size_t requiredFlagBitsPerItem>
  22. class FlagCache
  23. {
  24. using FlagType = uint32_t;
  25. public:
  26. FlagCache() = default;
  27. explicit FlagCache (size_t items)
  28. : flags (divCeil (items, groupsPerWord))
  29. {
  30. std::fill (flags.begin(), flags.end(), 0);
  31. }
  32. void set (size_t index, FlagType bits)
  33. {
  34. const auto flagIndex = index / groupsPerWord;
  35. jassert (flagIndex < flags.size());
  36. const auto groupIndex = index - (flagIndex * groupsPerWord);
  37. flags[flagIndex].fetch_or (moveToGroupPosition (bits, groupIndex), std::memory_order_acq_rel);
  38. }
  39. /* Calls the supplied callback for any entries with non-zero flags, and
  40. sets all flags to zero.
  41. */
  42. template <typename Callback>
  43. void ifSet (Callback&& callback)
  44. {
  45. for (size_t flagIndex = 0; flagIndex < flags.size(); ++flagIndex)
  46. {
  47. const auto prevFlags = flags[flagIndex].exchange (0, std::memory_order_acq_rel);
  48. for (size_t group = 0; group < groupsPerWord; ++group)
  49. {
  50. const auto masked = moveFromGroupPosition (prevFlags, group);
  51. if (masked != 0)
  52. callback ((flagIndex * groupsPerWord) + group, masked);
  53. }
  54. }
  55. }
  56. void clear()
  57. {
  58. std::fill (flags.begin(), flags.end(), 0);
  59. }
  60. private:
  61. /* Given the flags for a single item, and a group index, shifts the flags
  62. so that they are positioned at the appropriate location for that group
  63. index.
  64. e.g. If the flag type is a uint32_t, and there are 2 flags per item,
  65. then each uint32_t will hold flags for 16 items. The flags for item 0
  66. are the least significant two bits; the flags for item 15 are the most
  67. significant two bits.
  68. */
  69. static constexpr FlagType moveToGroupPosition (FlagType ungrouped, size_t groupIndex)
  70. {
  71. return (ungrouped & groupMask) << (groupIndex * bitsPerFlagGroup);
  72. }
  73. /* Given a set of grouped flags for multiple items, and a group index,
  74. extracts the flags set for an item at that group index.
  75. e.g. If the flag type is a uint32_t, and there are 2 flags per item,
  76. then each uint32_t will hold flags for 16 items. Asking for groupIndex
  77. 0 will return the least significant two bits; asking for groupIndex 15
  78. will return the most significant two bits.
  79. */
  80. static constexpr FlagType moveFromGroupPosition (FlagType grouped, size_t groupIndex)
  81. {
  82. return (grouped >> (groupIndex * bitsPerFlagGroup)) & groupMask;
  83. }
  84. static constexpr size_t findNextPowerOfTwoImpl (size_t n, size_t shift)
  85. {
  86. return shift == 32 ? n : findNextPowerOfTwoImpl (n | (n >> shift), shift * 2);
  87. }
  88. static constexpr size_t findNextPowerOfTwo (size_t value)
  89. {
  90. return findNextPowerOfTwoImpl (value - 1, 1) + 1;
  91. }
  92. static constexpr size_t divCeil (size_t a, size_t b)
  93. {
  94. return (a / b) + ((a % b) != 0);
  95. }
  96. static constexpr size_t bitsPerFlagGroup = findNextPowerOfTwo (requiredFlagBitsPerItem);
  97. static constexpr size_t groupsPerWord = (8 * sizeof (FlagType)) / bitsPerFlagGroup;
  98. static constexpr FlagType groupMask = ((FlagType) 1 << requiredFlagBitsPerItem) - 1;
  99. std::vector<std::atomic<FlagType>> flags;
  100. };
  101. template <size_t requiredFlagBitsPerItem>
  102. class FlaggedFloatCache
  103. {
  104. public:
  105. FlaggedFloatCache() = default;
  106. explicit FlaggedFloatCache (size_t sizeIn)
  107. : values (sizeIn),
  108. flags (sizeIn)
  109. {
  110. std::fill (values.begin(), values.end(), 0.0f);
  111. }
  112. size_t size() const noexcept { return values.size(); }
  113. void setValue (size_t index, float value)
  114. {
  115. jassert (index < size());
  116. values[index].store (value, std::memory_order_relaxed);
  117. }
  118. void setBits (size_t index, uint32_t bits) { flags.set (index, bits); }
  119. void setValueAndBits (size_t index, float value, uint32_t bits)
  120. {
  121. setValue (index, value);
  122. setBits (index, bits);
  123. }
  124. float get (size_t index) const noexcept
  125. {
  126. jassert (index < size());
  127. return values[index].load (std::memory_order_relaxed);
  128. }
  129. /* Calls the supplied callback for any entries which have been modified
  130. since the last call to this function.
  131. */
  132. template <typename Callback>
  133. void ifSet (Callback&& callback)
  134. {
  135. flags.ifSet ([this, &callback] (size_t groupIndex, uint32_t bits)
  136. {
  137. callback (groupIndex, values[groupIndex].load (std::memory_order_relaxed), bits);
  138. });
  139. }
  140. private:
  141. std::vector<std::atomic<float>> values;
  142. FlagCache<requiredFlagBitsPerItem> flags;
  143. };
  144. } // namespace juce
  145. #endif