• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package test.java.lang;
25 
26 import org.testng.Assert;
27 import org.testng.annotations.DataProvider;
28 import org.testng.annotations.Test;
29 
30 import java.util.function.Supplier;
31 import java.util.random.RandomGenerator;
32 
33 public abstract class AbstractCompressExpandTest {
34 
testCompress(int i, int mask)35     static int testCompress(int i, int mask) {
36         int result = 0;
37         int rpos = 0;
38         while (mask != 0) {
39             if ((mask & 1) != 0) {
40                 result |= (i & 1) << rpos;
41                 rpos++; // conditional increment
42             }
43             i >>>= 1; // unconditional shift-out
44             mask >>>= 1;
45         }
46         return result;
47     }
48 
testExpand(int i, int mask)49     static int testExpand(int i, int mask) {
50         int result = 0;
51         int rpos = 0;
52         while (mask != 0) {
53             if ((mask & 1) != 0) {
54                 result |= (i & 1) << rpos;
55                 i >>>= 1; // conditional shift-out
56             }
57             rpos++; // unconditional increment
58             mask >>>= 1;
59         }
60         return result;
61     }
62 
testCompress(long i, long mask)63     static long testCompress(long i, long mask) {
64         long result = 0;
65         int rpos = 0;
66         while (mask != 0) {
67             if ((mask & 1) != 0) {
68                 result |= (i & 1) << rpos++;
69             }
70             i >>>= 1;
71             mask >>>= 1;
72         }
73         return result;
74     }
75 
testExpand(long i, long mask)76     static long testExpand(long i, long mask) {
77         long result = 0;
78         int rpos = 0;
79         while (mask != 0) {
80             if ((mask & 1) != 0) {
81                 result |= (i & 1) << rpos;
82                 i >>>= 1;
83             }
84             rpos++;
85             mask >>>= 1;
86         }
87         return result;
88     }
89 
actualCompress(int i, int mask)90     abstract int actualCompress(int i, int mask);
91 
actualExpand(int i, int mask)92     abstract int actualExpand(int i, int mask);
93 
expectedCompress(int i, int mask)94     abstract int expectedCompress(int i, int mask);
95 
expectedExpand(int i, int mask)96     abstract int expectedExpand(int i, int mask);
97 
actualCompress(long i, long mask)98     abstract long actualCompress(long i, long mask);
99 
actualExpand(long i, long mask)100     abstract long actualExpand(long i, long mask);
101 
expectedCompress(long i, long mask)102     abstract long expectedCompress(long i, long mask);
103 
expectedExpand(long i, long mask)104     abstract long expectedExpand(long i, long mask);
105 
106     static int SIZE = 1024;
107 
supplierWithToString(Supplier<T> s, String name)108     <T> Supplier<T> supplierWithToString(Supplier<T> s, String name) {
109         return new Supplier<>() {
110             @Override
111             public T get() {
112                 return s.get();
113             }
114 
115             @Override
116             public String toString() {
117                 return name;
118             }
119         };
120     }
121 
122     @DataProvider
123     Object[][] maskIntProvider() {
124         RandomGenerator rg = RandomGenerator.getDefault();
125 
126         return new Object[][]{
127                 {supplierWithToString(() -> rg.ints(SIZE).toArray(), "random masks")},
128                 {supplierWithToString(this::contiguousMasksInt, "contiguous masks")}
129         };
130     }
131 
132     @DataProvider
133     Object[][] maskLongProvider() {
134         RandomGenerator rg = RandomGenerator.getDefault();
135 
136         return new Object[][]{
137                 {supplierWithToString(() -> rg.longs(SIZE).toArray(), "random masks")},
138                 {supplierWithToString(this::contiguousMasksLong, "contiguous masks")}
139         };
140     }
141 
142     int[] contiguousMasksInt() {
143         int size = 32 * (32 + 1) / 2 + 1; // 528 + 1
144         int[] masks = new int[size];
145 
146         int i = 0;
147         masks[i++] = 0;
148         for (int len = 1; len < 32; len++) {
149             for (int pos = 0; pos <= 32 - len; pos++) {
150                 masks[i++] = ((1 << len) - 1) << pos;
151             }
152         }
153         masks[i++] = -1;
154 
155         assert i == masks.length;
156         return masks;
157     }
158 
159     long[] contiguousMasksLong() {
160         int size = 64 * (64 + 1) / 2 + 1; // 2080 + 1
161         long[] masks = new long[size];
162 
163 
164         int i = 0;
165         masks[i++] = 0L;
166         for (int len = 1; len < 64; len++) {
167             for (int pos = 0; pos <= 64 - len; pos++) {
168                 masks[i++] = ((1L << len) - 1) << pos;
169             }
170         }
171         masks[i++] = -1L;
172 
173         assert i == masks.length;
174         return masks;
175     }
176 
177 
178     @Test(dataProvider = "maskIntProvider")
179     public void testCompressInt(Supplier<int[]> maskProvider) {
180         RandomGenerator rg = RandomGenerator.getDefault();
181 
182         int[] values = rg.ints(SIZE).toArray();
183         int[] masks = maskProvider.get();
184 
185         for (int i : values) {
186             for (int m : masks) {
187                 int actual = actualCompress(i, m);
188                 int expected = expectedCompress(i, m);
189                 if (actual != expected) {
190                     print(i, m, actual, expected);
191                 }
192                 Assert.assertEquals(actual, expected);
193             }
194         }
195     }
196 
197     @Test(dataProvider = "maskIntProvider")
198     public void testExpandInt(Supplier<int[]> maskProvider) {
199         RandomGenerator rg = RandomGenerator.getDefault();
200 
201         int[] values = rg.ints(SIZE).toArray();
202         int[] masks = maskProvider.get();
203 
204         for (int i : values) {
205             for (int m : masks) {
206                 int actual = actualExpand(i, m);
207                 int expected = expectedExpand(i, m);
208                 if (actual != expected) {
209                     print(i, m, actual, expected);
210                 }
211                 Assert.assertEquals(actual, expected);
212             }
213         }
214     }
215 
216     @Test(dataProvider = "maskIntProvider")
217     public void testCompressExpandInt(Supplier<int[]> maskProvider) {
218         RandomGenerator rg = RandomGenerator.getDefault();
219 
220         int[] values = rg.ints(SIZE).toArray();
221         int[] masks = maskProvider.get();
222 
223         for (int i : values) {
224             for (int m : masks) {
225                 {
226                     int a = actualCompress(actualExpand(i, m), m);
227                     Assert.assertEquals(a, normalizeCompressedValue(i, m));
228 
229                     int b = actualCompress(actualExpand(i, ~m), ~m);
230                     Assert.assertEquals(b, normalizeCompressedValue(i, ~m));
231                 }
232 
233                 {
234                     int a = actualExpand(actualCompress(i, m), m);
235                     // Clear unset mask bits
236                     Assert.assertEquals(a, i & m);
237 
238                     int b = actualExpand(actualCompress(i, ~m), ~m);
239                     Assert.assertEquals(a & b, 0);
240                     Assert.assertEquals(a | b, i);
241                 }
242             }
243         }
244     }
245 
246     @Test
247     public void testContiguousMasksInt() {
248         RandomGenerator rg = RandomGenerator.getDefault();
249 
250         int[] values = rg.ints(SIZE).toArray();
251 
252         for (int i : values) {
253             assertContiguousMask(i, 0, 0L);
254             for (int len = 1; len < 32; len++) {
255                 for (int pos = 0; pos <= 32 - len; pos++) {
256                     int mask = ((1 << len) - 1) << pos;
257 
258                     assertContiguousMask(i, pos, mask);
259                 }
260             }
261             assertContiguousMask(i, 0, -1L);
262         }
263     }
264 
265     void assertContiguousMask(int i, int pos, int mask) {
266         Assert.assertEquals(actualCompress(i, mask), (i & mask) >>> pos);
267         Assert.assertEquals(actualExpand(i, mask), (i << pos) & mask);
268     }
269 
270     @Test(dataProvider = "maskLongProvider")
271     public void testCompressLong(Supplier<long[]> maskProvider) {
272         RandomGenerator rg = RandomGenerator.getDefault();
273 
274         long[] values = rg.longs(SIZE).toArray();
275         long[] masks = maskProvider.get();
276 
277         for (long i : values) {
278             for (long m : masks) {
279                 long actual = actualCompress(i, m);
280                 long expected = expectedCompress(i, m);
281                 if (actual != expected) {
282                     print(i, m, actual, expected);
283                 }
284                 Assert.assertEquals(actual, expected);
285             }
286         }
287     }
288 
289     @Test(dataProvider = "maskLongProvider")
290     public void testExpandLong(Supplier<long[]> maskProvider) {
291         RandomGenerator rg = RandomGenerator.getDefault();
292 
293         long[] values = rg.longs(SIZE).toArray();
294         long[] masks = maskProvider.get();
295 
296         for (long i : values) {
297             for (long m : masks) {
298                 long actual = actualExpand(i, m);
299                 long expected = expectedExpand(i, m);
300                 if (actual != expected) {
301                     print(i, m, actual, expected);
302                 }
303                 Assert.assertEquals(actual, expected);
304             }
305         }
306     }
307 
308     @Test(dataProvider = "maskLongProvider")
309     public void testCompressExpandLong(Supplier<long[]> maskProvider) {
310         RandomGenerator rg = RandomGenerator.getDefault();
311 
312         long[] values = rg.longs(SIZE).toArray();
313         long[] masks = maskProvider.get();
314 
315         for (long i : values) {
316             for (long m : masks) {
317                 {
318                     long a = actualCompress(actualExpand(i, m), m);
319                     Assert.assertEquals(a, normalizeCompressedValue(i, m));
320 
321                     long b = actualCompress(actualExpand(i, ~m), ~m);
322                     Assert.assertEquals(b, normalizeCompressedValue(i, ~m));
323                 }
324 
325                 {
326                     long a = actualExpand(actualCompress(i, m), m);
327                     // Clear unset mask bits
328                     Assert.assertEquals(a, i & m);
329 
330                     long b = actualExpand(actualCompress(i, ~m), ~m);
331                     Assert.assertEquals(a & b, 0);
332                     Assert.assertEquals(a | b, i);
333                 }
334             }
335         }
336     }
337 
338     @Test
339     public void testContiguousMasksLong() {
340         RandomGenerator rg = RandomGenerator.getDefault();
341 
342         long[] values = rg.longs(SIZE).toArray();
343 
344         for (long i : values) {
345             assertContiguousMask(i, 0, 0L);
346             for (int len = 1; len < 64; len++) {
347                 for (int pos = 0; pos <= 64 - len; pos++) {
348                     long mask = ((1L << len) - 1) << pos;
349 
350                     assertContiguousMask(i, pos, mask);
351                 }
352             }
353             assertContiguousMask(i, 0, -1L);
354         }
355     }
356 
357     void assertContiguousMask(long i, int pos, long mask) {
358         Assert.assertEquals(actualCompress(i, mask), (i & mask) >>> pos);
359         Assert.assertEquals(actualExpand(i, mask), (i << pos) & mask);
360     }
361 
362     static int normalizeCompressedValue(int i, int mask) {
363         int mbc = Integer.bitCount(mask);
364         if (mbc != 32) {
365             return i & ((1 << mbc) - 1);
366         } else {
367             return i;
368         }
369     }
370 
371     static long normalizeCompressedValue(long i, long mask) {
372         int mbc = Long.bitCount(mask);
373         if (mbc != 64) {
374             return i & ((1L << mbc) - 1);
375         } else {
376             return i;
377         }
378     }
379 
380     static void print(int i, int m, int actual, int expected) {
381         System.out.println(String.format("i = %s", Integer.toBinaryString(i)));
382         System.out.println(String.format("m = %s", Integer.toBinaryString(m)));
383         System.out.println(String.format("a = %s", Integer.toBinaryString(actual)));
384         System.out.println(String.format("e = %s", Integer.toBinaryString(expected)));
385     }
386 
387     static void print(long i, long m, long actual, long expected) {
388         System.out.println(String.format("i = %s", Long.toBinaryString(i)));
389         System.out.println(String.format("m = %s", Long.toBinaryString(m)));
390         System.out.println(String.format("a = %s", Long.toBinaryString(actual)));
391         System.out.println(String.format("e = %s", Long.toBinaryString(expected)));
392     }
393 }
394