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