/* * ARX: Powerful Data Anonymization * Copyright 2012 - 2017 Fabian Prasser, Florian Kohlmayer and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.deidentifier.arx; import java.io.Serializable; /** * A set of rows. * * @author Fabian Prasser */ public class RowSet implements Serializable, Cloneable { /** SVUID */ private static final long serialVersionUID = 1492499772279795327L; /** Bits per unit */ private static final int ADDRESS_BITS_PER_UNIT = 6; /** Index mask */ private static final int BIT_INDEX_MASK = 63; /** * Creates a new instance * * @param data * @return */ public static RowSet create(Data data){ return new RowSet(data); } /** * Creates a new instance * * @param length * @return */ public static RowSet create(int length){ return new RowSet(length); } /** Array */ private final long[] array; /** Length of array */ private final int length; /** Number of bits set */ private int size; /** * Creates a new instance * * @param data */ private RowSet(Data data) { this.length = data.getHandle().getNumRows(); int chunks = (int) (Math.ceil((double) this.length / 64d)); this.array = new long[chunks]; } /** * Creates a new instance * * @param length */ private RowSet(int length) { this.length = length; int chunks = (int) (Math.ceil((double) this.length / 64d)); this.array = new long[chunks]; } /** * Sets a bit * * @param rowIndex */ public void add(int rowIndex) { int offset = rowIndex >> ADDRESS_BITS_PER_UNIT; long temp = array[offset]; this.array[offset] |= 1L << (rowIndex & BIT_INDEX_MASK); this.size += array[offset] != temp ? 1 : 0; } @Override public RowSet clone() { RowSet set = new RowSet(this.length); set.size = this.size; System.arraycopy(this.array, 0, set.array, 0, this.array.length); return set; } /** * Checks whether the bit is set * * @param rowIndex * @return */ public boolean contains(int rowIndex) { return ((array[rowIndex >> ADDRESS_BITS_PER_UNIT] & (1L << (rowIndex & BIT_INDEX_MASK))) != 0); } /** * Returns the number of available bits * * @return */ public int length() { return this.length; } /** * Unsets a bit * * @param rowIndex */ public void remove(int rowIndex){ int offset = rowIndex >> ADDRESS_BITS_PER_UNIT; long temp = array[offset]; this.array[offset] &= ~(1L << (rowIndex & BIT_INDEX_MASK)); this.size -= array[offset] != temp ? 1 : 0; } /** * Returns the number of bits set * * @return */ public int size() { return this.size; } /** * Swaps two bits * * @param rowIndex1 * @param rowIndex2 */ public void swap(int rowIndex1, int rowIndex2) { final boolean temp1 = contains(rowIndex1); final boolean temp2 = contains(rowIndex2); if (temp2) { add(rowIndex1); } else { remove(rowIndex1); } if (temp1) { add(rowIndex2); } else { remove(rowIndex2); } } }