1 /* 2 * Copyright (c) 2017, 2018, 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 package test.java.nio.Buffer; 24 25 import android.platform.test.annotations.LargeTest; 26 27 import org.testng.Assert; 28 import org.testng.annotations.DataProvider; 29 import org.testng.annotations.Test; 30 31 import java.lang.invoke.MethodHandle; 32 import java.lang.invoke.MethodHandles; 33 import java.lang.invoke.MethodType; 34 import java.nio.Buffer; 35 import java.nio.ByteBuffer; 36 import java.nio.ByteOrder; 37 import java.nio.CharBuffer; 38 import java.nio.DoubleBuffer; 39 import java.nio.FloatBuffer; 40 import java.nio.IntBuffer; 41 import java.nio.LongBuffer; 42 import java.nio.ShortBuffer; 43 import java.util.HashMap; 44 import java.util.Map; 45 import java.util.function.BiFunction; 46 import java.util.function.LongFunction; 47 import java.util.stream.IntStream; 48 49 /* 50 * @test 51 * @bug 8193085 8199773 52 * @summary tests for buffer equals and compare 53 * @run testng EqualsCompareTest 54 */ 55 56 public class EqualsCompareTest { 57 58 // Maximum width in bits 59 static final int MAX_WIDTH = 512; 60 61 static final Map<Class, Integer> typeToWidth; 62 63 static { 64 typeToWidth = new HashMap<>(); typeToWidth.put(byte.class, Byte.SIZE)65 typeToWidth.put(byte.class, Byte.SIZE); typeToWidth.put(short.class, Short.SIZE)66 typeToWidth.put(short.class, Short.SIZE); typeToWidth.put(char.class, Character.SIZE)67 typeToWidth.put(char.class, Character.SIZE); typeToWidth.put(int.class, Integer.SIZE)68 typeToWidth.put(int.class, Integer.SIZE); typeToWidth.put(long.class, Long.SIZE)69 typeToWidth.put(long.class, Long.SIZE); typeToWidth.put(float.class, Float.SIZE)70 typeToWidth.put(float.class, Float.SIZE); typeToWidth.put(double.class, Double.SIZE)71 typeToWidth.put(double.class, Double.SIZE); 72 } 73 arraySizeFor(Class<?> type)74 static int arraySizeFor(Class<?> type) { 75 assert type.isPrimitive(); 76 return 4 * MAX_WIDTH / typeToWidth.get(type); 77 } 78 79 enum BufferKind { 80 HEAP, 81 HEAP_VIEW, 82 DIRECT; 83 } 84 85 static abstract class BufferType<T extends Buffer, E> { 86 final BufferKind k; 87 final Class<?> bufferType; 88 final Class<?> elementType; 89 90 final MethodHandle eq; 91 final MethodHandle cmp; 92 final MethodHandle mismtch; 93 94 final MethodHandle getter; 95 final MethodHandle setter; 96 BufferType(BufferKind k, Class<T> bufferType, Class<?> elementType)97 BufferType(BufferKind k, Class<T> bufferType, Class<?> elementType) { 98 this.k = k; 99 this.bufferType = bufferType; 100 this.elementType = elementType; 101 102 var lookup = MethodHandles.lookup(); 103 try { 104 eq = lookup.findVirtual(bufferType, "equals", MethodType.methodType(boolean.class, Object.class)); 105 cmp = lookup.findVirtual(bufferType, "compareTo", MethodType.methodType(int.class, bufferType)); 106 mismtch = lookup.findVirtual(bufferType, "mismatch", MethodType.methodType(int.class, bufferType)); 107 108 getter = lookup.findVirtual(bufferType, "get", MethodType.methodType(elementType, int.class)); 109 setter = lookup.findVirtual(bufferType, "put", MethodType.methodType(bufferType, int.class, elementType)); 110 } 111 catch (Exception e) { 112 throw new AssertionError(e); 113 } 114 } 115 116 @Override toString()117 public String toString() { 118 return bufferType.getName() + " " + k; 119 } 120 construct(int length)121 T construct(int length) { 122 return construct(length, ByteOrder.BIG_ENDIAN); 123 } 124 construct(int length, ByteOrder bo)125 abstract T construct(int length, ByteOrder bo); 126 127 @SuppressWarnings("unchecked") slice(T a, int from, int to, boolean dupOtherwiseSlice)128 T slice(T a, int from, int to, boolean dupOtherwiseSlice) { 129 a = (T) a.position(from).limit(to); 130 return (T) (dupOtherwiseSlice ? a.duplicate() : a.slice()); 131 } 132 133 @SuppressWarnings("unchecked") get(T a, int i)134 E get(T a, int i) { 135 try { 136 return (E) getter.invoke(a, i); 137 } 138 catch (RuntimeException | Error e) { 139 throw e; 140 } 141 catch (Throwable t) { 142 throw new Error(t); 143 } 144 } 145 set(T a, int i, Object v)146 void set(T a, int i, Object v) { 147 try { 148 setter.invoke(a, i, convert(v)); 149 } 150 catch (RuntimeException | Error e) { 151 throw e; 152 } 153 catch (Throwable t) { 154 throw new Error(t); 155 } 156 } 157 convert(Object o)158 abstract Object convert(Object o); 159 equals(T a, T b)160 boolean equals(T a, T b) { 161 try { 162 return (boolean) eq.invoke(a, b); 163 } 164 catch (RuntimeException | Error e) { 165 throw e; 166 } 167 catch (Throwable t) { 168 throw new Error(t); 169 } 170 } 171 compare(T a, T b)172 int compare(T a, T b) { 173 try { 174 return (int) cmp.invoke(a, b); 175 } 176 catch (RuntimeException | Error e) { 177 throw e; 178 } 179 catch (Throwable t) { 180 throw new Error(t); 181 } 182 } 183 pairWiseEquals(T a, T b)184 boolean pairWiseEquals(T a, T b) { 185 if (a.remaining() != b.remaining()) 186 return false; 187 int p = a.position(); 188 for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) 189 if (!get(a, i).equals(get(b, j))) 190 return false; 191 return true; 192 } 193 mismatch(T a, T b)194 int mismatch(T a, T b) { 195 try { 196 return (int) mismtch.invoke(a, b); 197 } 198 catch (RuntimeException | Error e) { 199 throw e; 200 } 201 catch (Throwable t) { 202 throw new Error(t); 203 } 204 } 205 206 static class Bytes extends BufferType<ByteBuffer, Byte> { Bytes(BufferKind k)207 Bytes(BufferKind k) { 208 super(k, ByteBuffer.class, byte.class); 209 } 210 211 @Override construct(int length, ByteOrder bo)212 ByteBuffer construct(int length, ByteOrder bo) { 213 switch (k) { 214 case DIRECT: 215 return ByteBuffer.allocateDirect(length).order(bo); 216 default: 217 case HEAP_VIEW: 218 case HEAP: 219 return ByteBuffer.allocate(length).order(bo); 220 } 221 } 222 223 @Override convert(Object o)224 Object convert(Object o) { 225 return o instanceof Integer 226 ? ((Integer) o).byteValue() 227 : o; 228 } 229 } 230 231 static class Chars extends BufferType<CharBuffer, Character> { Chars(BufferKind k)232 Chars(BufferKind k) { 233 super(k, CharBuffer.class, char.class); 234 } 235 236 @Override construct(int length, ByteOrder bo)237 CharBuffer construct(int length, ByteOrder bo) { 238 switch (k) { 239 case DIRECT: 240 return ByteBuffer.allocateDirect(length * Character.BYTES). 241 order(bo). 242 asCharBuffer(); 243 case HEAP_VIEW: 244 return ByteBuffer.allocate(length * Character.BYTES). 245 order(bo). 246 asCharBuffer(); 247 default: 248 case HEAP: 249 return CharBuffer.allocate(length); 250 } 251 } 252 253 @Override convert(Object o)254 Object convert(Object o) { 255 return o instanceof Integer 256 ? (char) ((Integer) o).intValue() 257 : o; 258 } 259 transformToStringBuffer(CharBuffer c)260 CharBuffer transformToStringBuffer(CharBuffer c) { 261 char[] chars = new char[c.remaining()]; 262 c.get(chars); 263 return CharBuffer.wrap(new String(chars)); 264 } 265 } 266 267 static class Shorts extends BufferType<ShortBuffer, Short> { Shorts(BufferKind k)268 Shorts(BufferKind k) { 269 super(k, ShortBuffer.class, short.class); 270 } 271 272 @Override construct(int length, ByteOrder bo)273 ShortBuffer construct(int length, ByteOrder bo) { 274 switch (k) { 275 case DIRECT: 276 return ByteBuffer.allocateDirect(length * Short.BYTES). 277 order(bo). 278 asShortBuffer(); 279 case HEAP_VIEW: 280 return ByteBuffer.allocate(length * Short.BYTES). 281 order(bo). 282 asShortBuffer(); 283 default: 284 case HEAP: 285 return ShortBuffer.allocate(length); 286 } 287 } 288 289 @Override convert(Object o)290 Object convert(Object o) { 291 return o instanceof Integer 292 ? ((Integer) o).shortValue() 293 : o; 294 } 295 } 296 297 static class Ints extends BufferType<IntBuffer, Integer> { Ints(BufferKind k)298 Ints(BufferKind k) { 299 super(k, IntBuffer.class, int.class); 300 } 301 302 @Override construct(int length, ByteOrder bo)303 IntBuffer construct(int length, ByteOrder bo) { 304 switch (k) { 305 case DIRECT: 306 return ByteBuffer.allocateDirect(length * Integer.BYTES). 307 order(bo). 308 asIntBuffer(); 309 case HEAP_VIEW: 310 return ByteBuffer.allocate(length * Integer.BYTES). 311 order(bo). 312 asIntBuffer(); 313 default: 314 case HEAP: 315 return IntBuffer.allocate(length); 316 } 317 } 318 convert(Object o)319 Object convert(Object o) { 320 return o; 321 } 322 } 323 324 static class Floats extends BufferType<FloatBuffer, Float> { Floats(BufferKind k)325 Floats(BufferKind k) { 326 super(k, FloatBuffer.class, float.class); 327 } 328 329 @Override construct(int length, ByteOrder bo)330 FloatBuffer construct(int length, ByteOrder bo) { 331 switch (k) { 332 case DIRECT: 333 return ByteBuffer.allocateDirect(length * Float.BYTES). 334 order(bo). 335 asFloatBuffer(); 336 case HEAP_VIEW: 337 return ByteBuffer.allocate(length * Float.BYTES). 338 order(bo). 339 asFloatBuffer(); 340 default: 341 case HEAP: 342 return FloatBuffer.allocate(length); 343 } 344 } 345 346 @Override convert(Object o)347 Object convert(Object o) { 348 return o instanceof Integer 349 ? ((Integer) o).floatValue() 350 : o; 351 } 352 353 @Override pairWiseEquals(FloatBuffer a, FloatBuffer b)354 boolean pairWiseEquals(FloatBuffer a, FloatBuffer b) { 355 if (a.remaining() != b.remaining()) 356 return false; 357 int p = a.position(); 358 for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) { 359 float av = a.get(i); 360 float bv = b.get(j); 361 if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv))) 362 return false; 363 } 364 return true; 365 } 366 } 367 368 static class Longs extends BufferType<LongBuffer, Long> { Longs(BufferKind k)369 Longs(BufferKind k) { 370 super(k, LongBuffer.class, long.class); 371 } 372 373 @Override construct(int length, ByteOrder bo)374 LongBuffer construct(int length, ByteOrder bo) { 375 switch (k) { 376 case DIRECT: 377 return ByteBuffer.allocateDirect(length * Long.BYTES). 378 order(bo). 379 asLongBuffer(); 380 case HEAP_VIEW: 381 return ByteBuffer.allocate(length * Long.BYTES). 382 order(bo). 383 asLongBuffer(); 384 default: 385 case HEAP: 386 return LongBuffer.allocate(length); 387 } 388 } 389 390 @Override convert(Object o)391 Object convert(Object o) { 392 return o instanceof Integer 393 ? ((Integer) o).longValue() 394 : o; 395 } 396 } 397 398 static class Doubles extends BufferType<DoubleBuffer, Double> { Doubles(BufferKind k)399 Doubles(BufferKind k) { 400 super(k, DoubleBuffer.class, double.class); 401 } 402 403 @Override construct(int length, ByteOrder bo)404 DoubleBuffer construct(int length, ByteOrder bo) { 405 switch (k) { 406 case DIRECT: 407 return ByteBuffer.allocateDirect(length * Double.BYTES). 408 order(bo). 409 asDoubleBuffer(); 410 case HEAP_VIEW: 411 return ByteBuffer.allocate(length * Double.BYTES). 412 order(bo). 413 asDoubleBuffer(); 414 default: 415 case HEAP: 416 return DoubleBuffer.allocate(length); 417 } 418 } 419 420 @Override convert(Object o)421 Object convert(Object o) { 422 return o instanceof Integer 423 ? ((Integer) o).doubleValue() 424 : o; 425 } 426 427 @Override pairWiseEquals(DoubleBuffer a, DoubleBuffer b)428 boolean pairWiseEquals(DoubleBuffer a, DoubleBuffer b) { 429 if (a.remaining() != b.remaining()) 430 return false; 431 int p = a.position(); 432 for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) { 433 double av = a.get(i); 434 double bv = b.get(j); 435 if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv))) 436 return false; 437 } 438 return true; 439 } 440 } 441 } 442 443 static Object[][] bufferTypes; 444 445 @DataProvider bufferTypesProvider()446 public static Object[][] bufferTypesProvider() { 447 if (bufferTypes == null) { 448 bufferTypes = new Object[][]{ 449 {new BufferType.Bytes(BufferKind.HEAP)}, 450 {new BufferType.Bytes(BufferKind.DIRECT)}, 451 {new BufferType.Chars(BufferKind.HEAP)}, 452 {new BufferType.Chars(BufferKind.HEAP_VIEW)}, 453 {new BufferType.Chars(BufferKind.DIRECT)}, 454 {new BufferType.Shorts(BufferKind.HEAP)}, 455 {new BufferType.Shorts(BufferKind.HEAP_VIEW)}, 456 {new BufferType.Shorts(BufferKind.DIRECT)}, 457 {new BufferType.Ints(BufferKind.HEAP)}, 458 {new BufferType.Ints(BufferKind.HEAP_VIEW)}, 459 {new BufferType.Ints(BufferKind.DIRECT)}, 460 {new BufferType.Floats(BufferKind.HEAP)}, 461 {new BufferType.Floats(BufferKind.HEAP_VIEW)}, 462 {new BufferType.Floats(BufferKind.DIRECT)}, 463 {new BufferType.Longs(BufferKind.HEAP)}, 464 {new BufferType.Longs(BufferKind.HEAP_VIEW)}, 465 {new BufferType.Longs(BufferKind.DIRECT)}, 466 {new BufferType.Doubles(BufferKind.HEAP)}, 467 {new BufferType.Doubles(BufferKind.HEAP_VIEW)}, 468 {new BufferType.Doubles(BufferKind.DIRECT)}, 469 }; 470 } 471 return bufferTypes; 472 } 473 474 475 static Object[][] floatbufferTypes; 476 477 @DataProvider floatBufferTypesProvider()478 public static Object[][] floatBufferTypesProvider() { 479 if (floatbufferTypes == null) { 480 LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb); 481 LongFunction<Object> bToD = Double::longBitsToDouble; 482 483 floatbufferTypes = new Object[][]{ 484 // canonical and non-canonical NaNs 485 // If conversion is a signalling NaN it may be subject to conversion to a 486 // quiet NaN on some processors, even if a copy is performed 487 // The tests assume that if conversion occurs it does not convert to the 488 // canonical NaN 489 new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x7fc00000L, 0x7f800001L, bTof}, 490 new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x7fc00000L, 0x7f800001L, bTof}, 491 new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x7fc00000L, 0x7f800001L, bTof}, 492 new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD}, 493 new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD}, 494 new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD}, 495 496 // +0.0 and -0.0 497 new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x0L, 0x80000000L, bTof}, 498 new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x0L, 0x80000000L, bTof}, 499 new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x0L, 0x80000000L, bTof}, 500 new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x0L, 0x8000000000000000L, bToD}, 501 new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x0L, 0x8000000000000000L, bToD}, 502 new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x0L, 0x8000000000000000L, bToD}, 503 }; 504 } 505 return floatbufferTypes; 506 } 507 508 509 static Object[][] charBufferTypes; 510 511 @DataProvider charBufferTypesProvider()512 public static Object[][] charBufferTypesProvider() { 513 if (charBufferTypes == null) { 514 charBufferTypes = new Object[][]{ 515 {new BufferType.Chars(BufferKind.HEAP)}, 516 {new BufferType.Chars(BufferKind.HEAP_VIEW)}, 517 {new BufferType.Chars(BufferKind.DIRECT)}, 518 }; 519 } 520 return charBufferTypes; 521 } 522 523 524 // Tests all primitive buffers 525 @LargeTest 526 @Test(dataProvider = "bufferTypesProvider") testBuffers(BufferType<Buffer, Buffer> bufferType)527 public void testBuffers(BufferType<Buffer, Buffer> bufferType) { 528 // Test with buffers of the same byte order (BE) 529 BiFunction<BufferType<Buffer, Buffer>, Integer, Buffer> constructor = (at, s) -> { 530 Buffer a = at.construct(s); 531 for (int x = 0; x < s; x++) { 532 at.set(a, x, x % 8); 533 } 534 return a; 535 }; 536 537 // Test with buffers of different byte order 538 if (bufferType.elementType != byte.class && 539 (bufferType.k == BufferKind.HEAP_VIEW || 540 bufferType.k == BufferKind.DIRECT)) { 541 542 BiFunction<BufferType<Buffer, Buffer>, Integer, Buffer> leConstructor = (at, s) -> { 543 Buffer a = at.construct(s, ByteOrder.LITTLE_ENDIAN); 544 for (int x = 0; x < s; x++) { 545 at.set(a, x, x % 8); 546 } 547 return a; 548 }; 549 testBufferType(bufferType, constructor, leConstructor); 550 } 551 } 552 553 // Tests float and double buffers with edge-case values (NaN, -0.0, +0.0) 554 @LargeTest 555 @Test(dataProvider = "floatBufferTypesProvider") testFloatBuffers( BufferType<Buffer, Float> bufferType, long rawBitsA, long rawBitsB, LongFunction<Object> bitsToFloat)556 public void testFloatBuffers( 557 BufferType<Buffer, Float> bufferType, 558 long rawBitsA, long rawBitsB, 559 LongFunction<Object> bitsToFloat) { 560 Object av = bitsToFloat.apply(rawBitsA); 561 Object bv = bitsToFloat.apply(rawBitsB); 562 563 BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allAs = (at, s) -> { 564 Buffer b = at.construct(s); 565 for (int x = 0; x < s; x++) { 566 at.set(b, x, av); 567 } 568 return b; 569 }; 570 571 BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allBs = (at, s) -> { 572 Buffer b = at.construct(s); 573 for (int x = 0; x < s; x++) { 574 at.set(b, x, bv); 575 } 576 return b; 577 }; 578 579 BiFunction<BufferType<Buffer, Float>, Integer, Buffer> halfBs = (at, s) -> { 580 Buffer b = at.construct(s); 581 for (int x = 0; x < s / 2; x++) { 582 at.set(b, x, bv); 583 } 584 for (int x = s / 2; x < s; x++) { 585 at.set(b, x, 1); 586 } 587 return b; 588 }; 589 590 // Validation check 591 int size = arraySizeFor(bufferType.elementType); 592 Assert.assertTrue(bufferType.pairWiseEquals(allAs.apply(bufferType, size), 593 allBs.apply(bufferType, size))); 594 Assert.assertTrue(bufferType.equals(allAs.apply(bufferType, size), 595 allBs.apply(bufferType, size))); 596 597 testBufferType(bufferType, allAs, allBs); 598 testBufferType(bufferType, allAs, halfBs); 599 } 600 601 // Tests CharBuffer for region sources and CharSequence sources 602 @LargeTest 603 @Test(dataProvider = "charBufferTypesProvider") testCharBuffers(BufferType.Chars charBufferType)604 public void testCharBuffers(BufferType.Chars charBufferType) { 605 606 BiFunction<BufferType.Chars, Integer, CharBuffer> constructor = (at, s) -> { 607 CharBuffer a = at.construct(s); 608 for (int x = 0; x < s; x++) { 609 at.set(a, x, x % 8); 610 } 611 return a; 612 }; 613 614 BiFunction<BufferType.Chars, Integer, CharBuffer> constructorX = constructor. 615 andThen(charBufferType::transformToStringBuffer); 616 617 testBufferType(charBufferType, constructor, constructorX); 618 } 619 620 621 <B extends Buffer, E, BT extends BufferType<B, E>> testBufferType(BT bt, BiFunction<BT, Integer, B> aConstructor, BiFunction<BT, Integer, B> bConstructor)622 void testBufferType(BT bt, 623 BiFunction<BT, Integer, B> aConstructor, 624 BiFunction<BT, Integer, B> bConstructor) { 625 int n = arraySizeFor(bt.elementType); 626 627 for (boolean dupOtherwiseSlice : new boolean[]{ false, true }) { 628 for (int s : ranges(0, n)) { 629 B a = aConstructor.apply(bt, s); 630 B b = bConstructor.apply(bt, s); 631 632 for (int aFrom : ranges(0, s)) { 633 for (int aTo : ranges(aFrom, s)) { 634 int aLength = aTo - aFrom; 635 636 B as = aLength != s 637 ? bt.slice(a, aFrom, aTo, dupOtherwiseSlice) 638 : a; 639 640 for (int bFrom : ranges(0, s)) { 641 for (int bTo : ranges(bFrom, s)) { 642 int bLength = bTo - bFrom; 643 644 B bs = bLength != s 645 ? bt.slice(b, bFrom, bTo, dupOtherwiseSlice) 646 : b; 647 648 boolean eq = bt.pairWiseEquals(as, bs); 649 Assert.assertEquals(bt.equals(as, bs), eq); 650 Assert.assertEquals(bt.equals(bs, as), eq); 651 if (eq) { 652 Assert.assertEquals(bt.compare(as, bs), 0); 653 Assert.assertEquals(bt.compare(bs, as), 0); 654 655 // If buffers are equal, there shall be no mismatch 656 Assert.assertEquals(bt.mismatch(as, bs), -1); 657 Assert.assertEquals(bt.mismatch(bs, as), -1); 658 } 659 else { 660 int aCb = bt.compare(as, bs); 661 int bCa = bt.compare(bs, as); 662 int v = Integer.signum(aCb) * Integer.signum(bCa); 663 Assert.assertTrue(v == -1); 664 665 int aMs = bt.mismatch(as, bs); 666 int bMs = bt.mismatch(bs, as); 667 Assert.assertNotEquals(aMs, -1); 668 Assert.assertEquals(aMs, bMs); 669 } 670 } 671 } 672 if (aLength > 0 && !a.isReadOnly()) { 673 for (int i = aFrom; i < aTo; i++) { 674 B c = aConstructor.apply(bt, a.capacity()); 675 B cs = aLength != s 676 ? bt.slice(c, aFrom, aTo, dupOtherwiseSlice) 677 : c; 678 679 // Create common prefix with a length of i - aFrom 680 bt.set(c, i, -1); 681 682 Assert.assertFalse(bt.equals(c, a)); 683 684 int cCa = bt.compare(cs, as); 685 int aCc = bt.compare(as, cs); 686 int v = Integer.signum(cCa) * Integer.signum(aCc); 687 Assert.assertTrue(v == -1); 688 689 int cMa = bt.mismatch(cs, as); 690 int aMc = bt.mismatch(as, cs); 691 Assert.assertEquals(cMa, aMc); 692 Assert.assertEquals(cMa, i - aFrom); 693 } 694 } 695 } 696 } 697 } 698 } 699 } 700 ranges(int from, int to)701 static int[] ranges(int from, int to) { 702 int width = to - from; 703 switch (width) { 704 case 0: 705 return new int[]{}; 706 case 1: 707 return new int[]{from, to}; 708 case 2: 709 return new int[]{from, from + 1, to}; 710 case 3: 711 return new int[]{from, from + 1, from + 2, to}; 712 default: 713 return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to) 714 .filter(i -> i >= from && i <= to) 715 .distinct().toArray(); 716 } 717 } 718 } 719