File tree Expand file tree Collapse file tree 2 files changed +46
-0
lines changed
main/java/org/neo4j/gds/core/utils/paged
test/java/org/neo4j/gds/core/utils/paged Expand file tree Collapse file tree 2 files changed +46
-0
lines changed Original file line number Diff line number Diff line change 2424
2525import java .util .concurrent .atomic .AtomicLongArray ;
2626import java .util .concurrent .atomic .AtomicReference ;
27+ import java .util .function .LongConsumer ;
2728
2829public final class HugeAtomicPagedBitSet {
2930
@@ -149,6 +150,28 @@ public long cardinality() {
149150 return setBitCount ;
150151 }
151152
153+ public void forEachSetBit (LongConsumer consumer ) {
154+ final Pages pages = this .pages .get ();
155+ final long pageCount = pages .length ();
156+ final long pageSize = this .pageSize ;
157+
158+ long base = 0 ;
159+
160+ for (int pageIndex = 0 ; pageIndex < pageCount ; pageIndex ++) {
161+ var page = pages .getPage (pageIndex );
162+ for (int wordIndex = 0 ; wordIndex < pageSize ; wordIndex ++) {
163+ long word = page .get (wordIndex );
164+
165+ while (word != 0 ) {
166+ long next = Long .numberOfTrailingZeros (word );
167+ consumer .accept (Long .SIZE * (base + wordIndex ) + next );
168+ word = word ^ Long .lowestOneBit (word );
169+ }
170+ }
171+ base += pageSize ;
172+ }
173+ }
174+
152175 public long capacity () {
153176 return pages .get ().length () * (1L << pageShift );
154177 }
Original file line number Diff line number Diff line change 2626import org .neo4j .gds .core .concurrency .RunWithConcurrency ;
2727import org .neo4j .gds .core .utils .partition .PartitionUtils ;
2828
29+ import java .util .HashSet ;
2930import java .util .List ;
3031import java .util .Optional ;
32+ import java .util .concurrent .ThreadLocalRandom ;
33+ import java .util .stream .Collectors ;
34+ import java .util .stream .IntStream ;
3135import java .util .stream .Stream ;
3236
3337import static org .assertj .core .api .Assertions .assertThat ;
@@ -120,6 +124,25 @@ void testCardinality(HugeAtomicPagedBitSet atomicBitSet) {
120124 assertThat (atomicBitSet .cardinality ()).isEqualTo (3 );
121125 }
122126
127+ @ ParameterizedTest
128+ @ MethodSource ("bitsets" )
129+ void testForEachSetBit (HugeAtomicPagedBitSet atomicBitSet ) {
130+ var rng = ThreadLocalRandom .current ();
131+ long bound = 42 * (1L << PAGE_SHIFT_BITS ) + 42 ;
132+
133+ var expected = IntStream
134+ .range (0 , 10_000 )
135+ .mapToLong (__ -> rng .nextLong (0 , bound ))
136+ .boxed ()
137+ .peek (atomicBitSet ::set )
138+ .collect (Collectors .toSet ());
139+
140+ var actual = new HashSet <Long >();
141+ atomicBitSet .forEachSetBit (actual ::add );
142+
143+ assertThat (actual ).isEqualTo (expected );
144+ }
145+
123146 @ Test
124147 void writingAndGrowingShouldBeThreadSafe () {
125148 int concurrency = 8 ;
You can’t perform that action at this time.
0 commit comments