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