@@ -53,36 +53,116 @@ private HugeAtomicBitSet(HugeAtomicLongArray bits, long numBits, int remainder)
5353 * Returns the state of the bit at the given index.
5454 */
5555 public boolean get (long index ) {
56- return HugeAtomicBitSetOps .get (bits , numBits , index );
56+ assert (index < numBits );
57+ long wordIndex = index / NUM_BITS ;
58+ int bitIndex = (int ) (index % NUM_BITS );
59+ long bitmask = 1L << bitIndex ;
60+ return (bits .get (wordIndex ) & bitmask ) != 0 ;
5761 }
5862
5963 /**
6064 * Sets the bit at the given index to true.
6165 */
6266 public void set (long index ) {
63- HugeAtomicBitSetOps .set (bits , numBits , index );
67+ assert (index < numBits );
68+
69+ long wordIndex = index / NUM_BITS ;
70+ int bitIndex = (int ) (index % NUM_BITS );
71+ long bitmask = 1L << bitIndex ;
72+
73+ long oldWord = bits .get (wordIndex );
74+ while (true ) {
75+ long newWord = oldWord | bitmask ;
76+ if (newWord == oldWord ) {
77+ // nothing to set
78+ return ;
79+ }
80+ long currentWord = bits .compareAndExchange (wordIndex , oldWord , newWord );
81+ if (currentWord == oldWord ) {
82+ // CAS successful
83+ return ;
84+ }
85+ // CAS unsuccessful, try again
86+ oldWord = currentWord ;
87+ }
6488 }
6589
6690 /**
6791 * Sets the bits from the startIndex (inclusive) to the endIndex (exclusive).
6892 */
6993 public void set (long startIndex , long endIndex ) {
70- HugeAtomicBitSetOps .setRange (bits , numBits , startIndex , endIndex );
94+ assert (startIndex <= endIndex );
95+ assert (endIndex <= numBits );
96+
97+ long startWordIndex = startIndex / NUM_BITS ;
98+ // since endIndex is exclusive, we need the word before that index
99+ long endWordIndex = (endIndex - 1 ) / NUM_BITS ;
100+
101+ long startBitMask = -1L << startIndex ;
102+ long endBitMask = -1L >>> -endIndex ;
103+
104+ if (startWordIndex == endWordIndex ) {
105+ // set within single word
106+ setWord (bits , startWordIndex , startBitMask & endBitMask );
107+ } else {
108+ // set within range
109+ setWord (bits , startWordIndex , startBitMask );
110+ for (long wordIndex = startWordIndex + 1 ; wordIndex < endWordIndex ; wordIndex ++) {
111+ bits .set (wordIndex , -1L );
112+ }
113+ setWord (bits , endWordIndex , endBitMask );
114+ }
71115 }
72116
73117 /**
74118 * Sets a bit and returns the previous value.
75119 * The index should be less than the BitSet size.
76120 */
77121 public boolean getAndSet (long index ) {
78- return HugeAtomicBitSetOps .getAndSet (bits , numBits , index );
122+ assert (index < numBits );
123+
124+ long wordIndex = index / NUM_BITS ;
125+ int bitIndex = (int ) (index % NUM_BITS );
126+ long bitmask = 1L << bitIndex ;
127+
128+ long oldWord = bits .get (wordIndex );
129+ while (true ) {
130+ long newWord = oldWord | bitmask ;
131+ if (newWord == oldWord ) {
132+ // already set
133+ return true ;
134+ }
135+ long currentWord = bits .compareAndExchange (wordIndex , oldWord , newWord );
136+ if (currentWord == oldWord ) {
137+ // CAS successful
138+ return false ;
139+ }
140+ // CAS unsuccessful, try again
141+ oldWord = currentWord ;
142+ }
79143 }
80144
81145 /**
82146 * Toggles the bit at the given index.
83147 */
84148 public void flip (long index ) {
85- HugeAtomicBitSetOps .flip (bits , numBits , index );
149+ assert (index < numBits );
150+
151+ long wordIndex = index / NUM_BITS ;
152+ int bitIndex = (int ) (index % NUM_BITS );
153+ long bitmask = 1L << bitIndex ;
154+
155+ long oldWord = bits .get (wordIndex );
156+ while (true ) {
157+ long newWord = oldWord ^ bitmask ;
158+ long currentWord = bits .compareAndExchange (wordIndex , oldWord , newWord );
159+ if (currentWord == oldWord ) {
160+ // CAS successful
161+ return ;
162+ }
163+ // CAS unsuccessful, try again
164+ oldWord = currentWord ;
165+ }
86166 }
87167
88168 /**
@@ -91,7 +171,23 @@ public void flip(long index) {
91171 * This method is not thread-safe.
92172 */
93173 public void forEachSetBit (LongConsumer consumer ) {
94- HugeAtomicBitSetOps .forEachSetBit (bits , consumer );
174+ var cursor = bits .initCursor (bits .newCursor ());
175+
176+ while (cursor .next ()) {
177+ long [] block = cursor .array ;
178+ int offset = cursor .offset ;
179+ int limit = cursor .limit ;
180+ long base = cursor .base ;
181+
182+ for (int i = offset ; i < limit ; i ++) {
183+ long word = block [i ];
184+ while (word != 0 ) {
185+ long next = Long .numberOfTrailingZeros (word );
186+ consumer .accept (Long .SIZE * (base + i ) + next );
187+ word = word ^ Long .lowestOneBit (word );
188+ }
189+ }
190+ }
95191 }
96192
97193 /**
@@ -100,7 +196,13 @@ public void forEachSetBit(LongConsumer consumer) {
100196 * Note: this method is not thread-safe.
101197 */
102198 public long cardinality () {
103- return HugeAtomicBitSetOps .cardinality (bits );
199+ long setBitCount = 0 ;
200+
201+ for (long wordIndex = 0 ; wordIndex < bits .size (); wordIndex ++) {
202+ setBitCount += Long .bitCount (bits .get (wordIndex ));
203+ }
204+
205+ return setBitCount ;
104206 }
105207
106208 /**
@@ -109,7 +211,12 @@ public long cardinality() {
109211 * Note: this method is not thread-safe.
110212 */
111213 public boolean isEmpty () {
112- return HugeAtomicBitSetOps .isEmpty (bits );
214+ for (long wordIndex = 0 ; wordIndex < bits .size (); wordIndex ++) {
215+ if (Long .bitCount (bits .get (wordIndex )) > 0 ) {
216+ return false ;
217+ }
218+ }
219+ return true ;
113220 }
114221
115222 /**
@@ -118,7 +225,12 @@ public boolean isEmpty() {
118225 * Note: this method is not thread-safe.
119226 */
120227 public boolean allSet () {
121- return HugeAtomicBitSetOps .allSet (bits , remainder );
228+ for (long wordIndex = 0 ; wordIndex < bits .size () - 1 ; wordIndex ++) {
229+ if (Long .bitCount (bits .get (wordIndex )) < NUM_BITS ) {
230+ return false ;
231+ }
232+ }
233+ return Long .bitCount (bits .get (bits .size () - 1 )) >= (long ) remainder ;
122234 }
123235
124236 /**
@@ -134,13 +246,50 @@ public long size() {
134246 * Note: this method is not thread-safe.
135247 */
136248 public void clear () {
137- HugeAtomicBitSetOps . clear ( bits );
249+ bits . setAll ( 0 );
138250 }
139251
140252 /**
141253 * Resets the bit at the given index.
142254 */
143255 public void clear (long index ) {
144- HugeAtomicBitSetOps .clear (bits , numBits , index );
256+ assert (index < numBits );
257+
258+ long wordIndex = index / NUM_BITS ;
259+ int bitIndex = (int ) (index % NUM_BITS );
260+ long bitmask = ~(1L << bitIndex );
261+
262+ long oldWord = bits .get (wordIndex );
263+ while (true ) {
264+ long newWord = oldWord & bitmask ;
265+ if (newWord == oldWord ) {
266+ // already cleared
267+ return ;
268+ }
269+ long currentWord = bits .compareAndExchange (wordIndex , oldWord , newWord );
270+ if (currentWord == oldWord ) {
271+ // CAS successful
272+ return ;
273+ }
274+ // CAS unsuccessful, try again
275+ oldWord = currentWord ;
276+ }
277+ }
278+
279+ private static void setWord (HugeAtomicLongArray bits , long wordIndex , long bitMask ) {
280+ var oldWord = bits .get (wordIndex );
281+ while (true ) {
282+ var newWord = oldWord | bitMask ;
283+ if (newWord == oldWord ) {
284+ // already set
285+ return ;
286+ }
287+ var currentWord = bits .compareAndExchange (wordIndex , oldWord , newWord );
288+ if (currentWord == oldWord ) {
289+ // CAX successful
290+ return ;
291+ }
292+ oldWord = currentWord ;
293+ }
145294 }
146295}
0 commit comments