1 package org.apache.lucene.util.packed;
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 import org.apache.lucene.store.*;
21 import org.apache.lucene.util.LuceneTestCase;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Random;
26 import java.io.IOException;
28 public class TestPackedInts extends LuceneTestCase {
29 public void testBitsRequired() throws Exception {
30 assertEquals(61, PackedInts.bitsRequired((long)Math.pow(2, 61)-1));
31 assertEquals(61, PackedInts.bitsRequired(0x1FFFFFFFFFFFFFFFL));
32 assertEquals(62, PackedInts.bitsRequired(0x3FFFFFFFFFFFFFFFL));
33 assertEquals(63, PackedInts.bitsRequired(0x7FFFFFFFFFFFFFFFL));
36 public void testMaxValues() throws Exception {
37 assertEquals("1 bit -> max == 1",
38 1, PackedInts.maxValue(1));
39 assertEquals("2 bit -> max == 3",
40 3, PackedInts.maxValue(2));
41 assertEquals("8 bit -> max == 255",
42 255, PackedInts.maxValue(8));
43 assertEquals("63 bit -> max == Long.MAX_VALUE",
44 Long.MAX_VALUE, PackedInts.maxValue(63));
45 assertEquals("64 bit -> max == Long.MAX_VALUE (same as for 63 bit)",
46 Long.MAX_VALUE, PackedInts.maxValue(64));
49 public void testPackedInts() throws IOException {
51 for (int iter = 0; iter < num; iter++) {
53 for(int nbits=1;nbits<63;nbits++) {
54 final int valueCount = 100+random.nextInt(500);
55 final Directory d = newDirectory();
57 IndexOutput out = d.createOutput("out.bin");
58 PackedInts.Writer w = PackedInts.getWriter(
59 out, valueCount, nbits);
61 final long[] values = new long[valueCount];
62 for(int i=0;i<valueCount;i++) {
63 long v = random.nextLong() % ceil;
71 final long fp = out.getFilePointer();
74 IndexInput in = d.openInput("out.bin");
75 PackedInts.Reader r = PackedInts.getReader(in);
76 assertEquals(fp, in.getFilePointer());
77 for(int i=0;i<valueCount;i++) {
78 assertEquals("index=" + i + " ceil=" + ceil + " valueCount="
79 + valueCount + " nbits=" + nbits + " for "
80 + r.getClass().getSimpleName(), values[i], r.get(i));
90 public void testControlledEquality() {
91 final int VALUE_COUNT = 255;
92 final int BITS_PER_VALUE = 8;
94 List<PackedInts.Mutable> packedInts =
95 createPackedInts(VALUE_COUNT, BITS_PER_VALUE);
96 for (PackedInts.Mutable packedInt: packedInts) {
97 for (int i = 0 ; i < packedInt.size() ; i++) {
98 packedInt.set(i, i+1);
101 assertListEquality(packedInts);
104 public void testRandomEquality() {
105 final int[] VALUE_COUNTS = new int[]{0, 1, 5, 8, 100, 500};
106 final int MIN_BITS_PER_VALUE = 1;
107 final int MAX_BITS_PER_VALUE = 64;
109 for (int valueCount: VALUE_COUNTS) {
110 for (int bitsPerValue = MIN_BITS_PER_VALUE ;
111 bitsPerValue <= MAX_BITS_PER_VALUE ;
113 assertRandomEquality(valueCount, bitsPerValue, random.nextLong());
118 private void assertRandomEquality(int valueCount, int bitsPerValue, long randomSeed) {
119 List<PackedInts.Mutable> packedInts = createPackedInts(valueCount, bitsPerValue);
120 for (PackedInts.Mutable packedInt: packedInts) {
122 fill(packedInt, (long)(Math.pow(2, bitsPerValue)-1), randomSeed);
123 } catch (Exception e) {
124 e.printStackTrace(System.err);
126 "Exception while filling %s: valueCount=%d, bitsPerValue=%s",
127 packedInt.getClass().getSimpleName(),
128 valueCount, bitsPerValue));
131 assertListEquality(packedInts);
134 private List<PackedInts.Mutable> createPackedInts(
135 int valueCount, int bitsPerValue) {
136 List<PackedInts.Mutable> packedInts = new ArrayList<PackedInts.Mutable>();
137 if (bitsPerValue <= 8) {
138 packedInts.add(new Direct8(valueCount));
140 if (bitsPerValue <= 16) {
141 packedInts.add(new Direct16(valueCount));
143 if (bitsPerValue <= 31) {
144 packedInts.add(new Packed32(valueCount, bitsPerValue));
146 if (bitsPerValue <= 32) {
147 packedInts.add(new Direct32(valueCount));
149 if (bitsPerValue <= 63) {
150 packedInts.add(new Packed64(valueCount, bitsPerValue));
152 packedInts.add(new Direct64(valueCount));
156 private void fill(PackedInts.Mutable packedInt, long maxValue, long randomSeed) {
157 Random rnd2 = new Random(randomSeed);
159 for (int i = 0 ; i < packedInt.size() ; i++) {
160 long value = Math.abs(rnd2.nextLong() % maxValue);
161 packedInt.set(i, value);
162 assertEquals(String.format(
163 "The set/get of the value at index %d should match for %s",
164 i, packedInt.getClass().getSimpleName()),
165 value, packedInt.get(i));
169 private void assertListEquality(
170 List<? extends PackedInts.Reader> packedInts) {
171 assertListEquality("", packedInts);
174 private void assertListEquality(
175 String message, List<? extends PackedInts.Reader> packedInts) {
176 if (packedInts.size() == 0) {
179 PackedInts.Reader base = packedInts.get(0);
180 int valueCount = base.size();
181 for (PackedInts.Reader packedInt: packedInts) {
182 assertEquals(message + ". The number of values should be the same ",
183 valueCount, packedInt.size());
185 for (int i = 0 ; i < valueCount ; i++) {
186 for (int j = 1 ; j < packedInts.size() ; j++) {
187 assertEquals(String.format(
188 "%s. The value at index %d should be the same for %s and %s",
189 message, i, base.getClass().getSimpleName(),
190 packedInts.get(j).getClass().getSimpleName()),
191 base.get(i), packedInts.get(j).get(i));
196 public void testSingleValue() throws Exception {
197 Directory dir = newDirectory();
198 IndexOutput out = dir.createOutput("out");
199 PackedInts.Writer w = PackedInts.getWriter(out, 1, 8);
202 final long end = out.getFilePointer();
205 IndexInput in = dir.openInput("out");
206 PackedInts.getReader(in);
207 assertEquals(end, in.getFilePointer());
213 public void testSecondaryBlockChange() throws IOException {
214 PackedInts.Mutable mutable = new Packed64(26, 5);
216 assertEquals("The value #24 should be correct", 31, mutable.get(24));
218 assertEquals("The value #24 should remain unchanged", 31, mutable.get(24));
222 Check if the structures properly handle the case where
223 index * bitsPerValue > Integer.MAX_VALUE
225 NOTE: this test allocates 256 MB
227 public void testIntOverflow() {
228 int INDEX = (int)Math.pow(2, 30)+1;
231 Packed32 p32 = new Packed32(INDEX, BITS);
233 assertEquals("The value at position " + (INDEX-1)
234 + " should be correct for Packed32", 1, p32.get(INDEX-1));
235 p32 = null; // To free the 256MB used
237 Packed64 p64 = new Packed64(INDEX, BITS);
239 assertEquals("The value at position " + (INDEX-1)
240 + " should be correct for Packed64", 1, p64.get(INDEX-1));