| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.ignite.internal.binary; |
| |
| import java.util.Arrays; |
| |
| import org.apache.ignite.binary.BinaryObject; |
| import org.apache.ignite.binary.BinaryObjectException; |
| import org.apache.ignite.internal.util.typedef.internal.S; |
| |
| /** |
| * Identity resolver implementation which compares raw array content of the binary object. |
| * <p> |
| * Hash code is calculated in the same way as {@link Arrays#hashCode(byte[])} does. |
| */ |
| public class BinaryArrayIdentityResolver extends BinaryAbstractIdentityResolver { |
| /** Singleton instance */ |
| private static final BinaryArrayIdentityResolver INSTANCE = new BinaryArrayIdentityResolver(); |
| |
| /** |
| * Get singleton instance. |
| * |
| * @return Singleton instance. |
| */ |
| public static BinaryArrayIdentityResolver instance() { |
| return INSTANCE; |
| } |
| |
| /** |
| * Default constructor. |
| */ |
| public BinaryArrayIdentityResolver() { |
| // No-op. |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected int hashCode0(BinaryObject obj) { |
| int hash = 1; |
| |
| if (obj instanceof BinaryObjectExImpl) { |
| BinaryObjectExImpl ex = (BinaryObjectExImpl)obj; |
| |
| int start = ex.dataStartOffset(); |
| int end = ex.footerStartOffset(); |
| |
| if (ex.hasArray()) { |
| // Handle heap object. |
| byte[] data = ex.array(); |
| |
| for (int i = start; i < end; i++) |
| hash = 31 * hash + data[i]; |
| } |
| else { |
| // Handle offheap object. |
| long ptr = ex.offheapAddress(); |
| |
| for (int i = start; i < end; i++) |
| hash = 31 * hash + BinaryPrimitives.readByte(ptr, i); |
| } |
| } |
| else if (obj instanceof BinaryEnumObjectImpl) { |
| int ord = obj.enumOrdinal(); |
| |
| // Construct hash as if it was an int serialized in little-endian form. |
| hash = 31 * hash + (ord & 0x000000FF); |
| hash = 31 * hash + (ord & 0x0000FF00); |
| hash = 31 * hash + (ord & 0x00FF0000); |
| hash = 31 * hash + (ord & 0xFF000000); |
| } |
| else |
| throw new BinaryObjectException("Array identity resolver cannot be used with provided BinaryObject " + |
| "implementation: " + obj.getClass().getName()); |
| |
| return hash; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected boolean equals0(BinaryObject o1, BinaryObject o2) { |
| if (o1 instanceof BinaryObjectEx && o2 instanceof BinaryObjectEx) { |
| BinaryObjectEx ex1 = (BinaryObjectEx)o1; |
| BinaryObjectEx ex2 = (BinaryObjectEx)o2; |
| |
| if (ex1.typeId() != ex2.typeId()) |
| return false; |
| |
| if (ex1 instanceof BinaryObjectExImpl) { |
| // Handle regular object. |
| assert ex2 instanceof BinaryObjectExImpl; |
| |
| BinaryObjectExImpl exx1 = (BinaryObjectExImpl)ex1; |
| BinaryObjectExImpl exx2 = (BinaryObjectExImpl)ex2; |
| |
| if (exx1.hasArray()) |
| return exx2.hasArray() ? equalsHeap(exx1, exx2) : equalsHeapOffheap(exx1, exx2); |
| else |
| return exx2.hasArray() ? equalsHeapOffheap(exx2, exx1) : equalsOffheap(exx1, exx2); |
| } |
| else { |
| // Handle enums. |
| assert ex1 instanceof BinaryEnumObjectImpl; |
| assert ex2 instanceof BinaryEnumObjectImpl; |
| |
| return ex1.enumOrdinal() == ex2.enumOrdinal(); |
| } |
| } |
| |
| BinaryObject o = o1 instanceof BinaryObjectEx ? o2 : o1; |
| |
| throw new BinaryObjectException("Array identity resolver cannot be used with provided BinaryObject " + |
| "implementation: " + o.getClass().getName()); |
| } |
| |
| /** |
| * Compare two heap objects. |
| * |
| * @param o1 Object 1. |
| * @param o2 Object 2. |
| * @return Result. |
| */ |
| private static boolean equalsHeap(BinaryObjectExImpl o1, BinaryObjectExImpl o2) { |
| byte[] arr1 = o1.array(); |
| byte[] arr2 = o2.array(); |
| |
| assert arr1 != null && arr2 != null; |
| |
| int i = o1.dataStartOffset(); |
| int j = o2.dataStartOffset(); |
| |
| int end = o1.footerStartOffset(); |
| |
| // Check length. |
| if (end - i != o2.footerStartOffset() - j) |
| return false; |
| |
| for (; i < end; i++, j++) { |
| if (arr1[i] != arr2[j]) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Compare heap and offheap objects. |
| * |
| * @param o1 Object 1 (heap). |
| * @param o2 Object 2 (offheap). |
| * @return Result. |
| */ |
| private static boolean equalsHeapOffheap(BinaryObjectExImpl o1, BinaryObjectExImpl o2) { |
| byte[] arr1 = o1.array(); |
| long ptr2 = o2.offheapAddress(); |
| |
| assert arr1 != null && ptr2 != 0; |
| |
| int i = o1.dataStartOffset(); |
| int j = o2.dataStartOffset(); |
| |
| int end = o1.footerStartOffset(); |
| |
| // Check length. |
| if (end - i != o2.footerStartOffset() - j) |
| return false; |
| |
| for (; i < end; i++, j++) { |
| if (arr1[i] != BinaryPrimitives.readByte(ptr2, j)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Compare two offheap objects. |
| * |
| * @param o1 Object 1. |
| * @param o2 Object 2. |
| * @return Result. |
| */ |
| private static boolean equalsOffheap(BinaryObjectExImpl o1, BinaryObjectExImpl o2) { |
| long ptr1 = o1.offheapAddress(); |
| long ptr2 = o2.offheapAddress(); |
| |
| assert ptr1 != 0 && ptr2 != 0; |
| |
| int i = o1.dataStartOffset(); |
| int j = o2.dataStartOffset(); |
| |
| int end = o1.footerStartOffset(); |
| |
| // Check length. |
| if (end - i != o2.footerStartOffset() - j) |
| return false; |
| |
| for (; i < end; i++, j++) { |
| if (BinaryPrimitives.readByte(ptr1, i) != BinaryPrimitives.readByte(ptr2, j)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public String toString() { |
| return S.toString(BinaryArrayIdentityResolver.class, this); |
| } |
| } |