2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
23 ==============================================================================
31 template <size_t requiredFlagBitsPerItem
>
34 using FlagType
= uint32_t;
37 FlagCache() = default;
39 explicit FlagCache (size_t items
)
40 : flags (divCeil (items
, groupsPerWord
))
42 std::fill (flags
.begin(), flags
.end(), 0);
45 void set (size_t index
, FlagType bits
)
47 const auto flagIndex
= index
/ groupsPerWord
;
48 jassert (flagIndex
< flags
.size());
49 const auto groupIndex
= index
- (flagIndex
* groupsPerWord
);
50 flags
[flagIndex
].fetch_or (moveToGroupPosition (bits
, groupIndex
), std::memory_order_acq_rel
);
53 /* Calls the supplied callback for any entries with non-zero flags, and
54 sets all flags to zero.
56 template <typename Callback
>
57 void ifSet (Callback
&& callback
)
59 for (size_t flagIndex
= 0; flagIndex
< flags
.size(); ++flagIndex
)
61 const auto prevFlags
= flags
[flagIndex
].exchange (0, std::memory_order_acq_rel
);
63 for (size_t group
= 0; group
< groupsPerWord
; ++group
)
65 const auto masked
= moveFromGroupPosition (prevFlags
, group
);
68 callback ((flagIndex
* groupsPerWord
) + group
, masked
);
75 std::fill (flags
.begin(), flags
.end(), 0);
79 /* Given the flags for a single item, and a group index, shifts the flags
80 so that they are positioned at the appropriate location for that group
83 e.g. If the flag type is a uint32_t, and there are 2 flags per item,
84 then each uint32_t will hold flags for 16 items. The flags for item 0
85 are the least significant two bits; the flags for item 15 are the most
88 static constexpr FlagType
moveToGroupPosition (FlagType ungrouped
, size_t groupIndex
)
90 return (ungrouped
& groupMask
) << (groupIndex
* bitsPerFlagGroup
);
93 /* Given a set of grouped flags for multiple items, and a group index,
94 extracts the flags set for an item at that group index.
96 e.g. If the flag type is a uint32_t, and there are 2 flags per item,
97 then each uint32_t will hold flags for 16 items. Asking for groupIndex
98 0 will return the least significant two bits; asking for groupIndex 15
99 will return the most significant two bits.
101 static constexpr FlagType
moveFromGroupPosition (FlagType grouped
, size_t groupIndex
)
103 return (grouped
>> (groupIndex
* bitsPerFlagGroup
)) & groupMask
;
106 static constexpr size_t findNextPowerOfTwoImpl (size_t n
, size_t shift
)
108 return shift
== 32 ? n
: findNextPowerOfTwoImpl (n
| (n
>> shift
), shift
* 2);
111 static constexpr size_t findNextPowerOfTwo (size_t value
)
113 return findNextPowerOfTwoImpl (value
- 1, 1) + 1;
116 static constexpr size_t divCeil (size_t a
, size_t b
)
118 return (a
/ b
) + ((a
% b
) != 0);
121 static constexpr size_t bitsPerFlagGroup
= findNextPowerOfTwo (requiredFlagBitsPerItem
);
122 static constexpr size_t groupsPerWord
= (8 * sizeof (FlagType
)) / bitsPerFlagGroup
;
123 static constexpr FlagType groupMask
= ((FlagType
) 1 << requiredFlagBitsPerItem
) - 1;
125 std::vector
<std::atomic
<FlagType
>> flags
;
128 template <size_t requiredFlagBitsPerItem
>
129 class FlaggedFloatCache
132 FlaggedFloatCache() = default;
134 explicit FlaggedFloatCache (size_t sizeIn
)
138 std::fill (values
.begin(), values
.end(), 0.0f
);
141 size_t size() const noexcept
{ return values
.size(); }
143 void setValue (size_t index
, float value
)
145 jassert (index
< size());
146 values
[index
].store (value
, std::memory_order_relaxed
);
149 void setBits (size_t index
, uint32_t bits
) { flags
.set (index
, bits
); }
151 void setValueAndBits (size_t index
, float value
, uint32_t bits
)
153 setValue (index
, value
);
154 setBits (index
, bits
);
157 float get (size_t index
) const noexcept
159 jassert (index
< size());
160 return values
[index
].load (std::memory_order_relaxed
);
163 /* Calls the supplied callback for any entries which have been modified
164 since the last call to this function.
166 template <typename Callback
>
167 void ifSet (Callback
&& callback
)
169 flags
.ifSet ([this, &callback
] (size_t groupIndex
, uint32_t bits
)
171 callback (groupIndex
, values
[groupIndex
].load (std::memory_order_relaxed
), bits
);
176 std::vector
<std::atomic
<float>> values
;
177 FlagCache
<requiredFlagBitsPerItem
> flags
;