1/*2 * Licensed to the Apache Software Foundation (ASF) under one3 * or more contributor license agreements. See the NOTICE file4 * distributed with this work for additional information5 * regarding copyright ownership. The ASF licenses this file6 * to you under the Apache License, Version 2.0 (the7 * "License"); you may not use this file except in compliance8 * with the License. You may obtain a copy of the License at9 *10 * http://www.apache.org/licenses/LICENSE-2.011 *12 * Unless required by applicable law or agreed to in writing, software13 * distributed under the License is distributed on an "AS IS" BASIS,14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15 * See the License for the specific language governing permissions and16 * limitations under the License.17 */1819package org.apache.giraph.utils;
2021import java.util.BitSet;
2223/**24 * Bit set optimized for increasing longs to save storage space.25 * The general idea is that even though some keys will be added out-of-order,26 * there is a base key that keeps increasing so that the bit set doesn't get27 * very big. When there are enough set bits, the bit set gets compacted.28 * Thread-safe.29 */30publicclassIncreasingBitSet {
31/** Minimum number of bits to shift */32publicstaticfinalint MIN_BITS_TO_SHIFT = 64 * 1024;
33/** Bit set used */34private BitSet bitSet = new BitSet();
35/** Last base key (all keys < this have been accepted */36privatelong lastBaseKey = 0;
3738/**39 * Add a key if it is possible.40 *41 * @param key Key to add42 * @return True if the key was added, false otherwise43 */44publicsynchronizedboolean add(long key) {
45long remainder = key - lastBaseKey;
46 checkLegalKey(remainder);
4748if (remainder < 0) {
49return false;
50 }
51if (bitSet.get((int) remainder)) {
52return false;
53 }
54 bitSet.set((int) remainder);
55int nextClearBit = bitSet.nextClearBit(0);
56if (nextClearBit >= MIN_BITS_TO_SHIFT) {
57 bitSet = bitSet.get(nextClearBit,
58 Math.max(nextClearBit, bitSet.length()));
59 lastBaseKey += nextClearBit;
60 }
61returntrue;
62 }
6364/**65 * Get the number of set bits66 *67 * @return Number of set bits68 */69publicsynchronizedlong cardinality() {
70long size = bitSet.cardinality();
71return size + lastBaseKey;
72 }
7374/**75 * Get the size of the bit set76 *77 * @return Size of the bit set78 */79publicsynchronizedint size() {
80return bitSet.size();
81 }
8283/**84 * Check for existence of a key85 *86 * @param key Key to check for87 * @return True if the key exists, false otherwise88 */89publicsynchronizedboolean has(long key) {
90long remainder = key - lastBaseKey;
91 checkLegalKey(remainder);
9293if (remainder < 0) {
94returntrue;
95 }
96return bitSet.get((int) remainder);
97 }
9899/**100 * Get the last base key (mainly for debugging).101 *102 * @return Last base key103 */104publicsynchronizedlong getLastBaseKey() {
105return lastBaseKey;
106 }
107108/**109 * Check the remainder for validity110 *111 * @param remainder Remainder to check112 */113privatevoid checkLegalKey(long remainder) {
114if (remainder > Integer.MAX_VALUE) {
115thrownew IllegalArgumentException(
116"checkLegalKey: Impossible that to add key " +
117 (remainder + lastBaseKey) + " with base " +
118 lastBaseKey + " since the " +
119"spread is too large (> " + Integer.MAX_VALUE);
120 }
121 }
122 }