| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed 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 com.android.internal.util; |
| |
| import android.annotation.Nullable; |
| import android.text.TextUtils; |
| |
| import java.nio.ByteBuffer; |
| import java.util.Arrays; |
| import java.util.Objects; |
| import java.util.UUID; |
| import java.util.function.IntFunction; |
| |
| /** |
| * A utility class for handling unsigned integers and unsigned arithmetics, as well as syntactic |
| * sugar methods for ByteBuffer. Useful for networking and packet manipulations. |
| * {@hide} |
| */ |
| public final class BitUtils { |
| private BitUtils() {} |
| |
| public static boolean maskedEquals(long a, long b, long mask) { |
| return (a & mask) == (b & mask); |
| } |
| |
| public static boolean maskedEquals(byte a, byte b, byte mask) { |
| return (a & mask) == (b & mask); |
| } |
| |
| public static boolean maskedEquals(byte[] a, byte[] b, @Nullable byte[] mask) { |
| if (a == null || b == null) return a == b; |
| Preconditions.checkArgument(a.length == b.length, "Inputs must be of same size"); |
| if (mask == null) return Arrays.equals(a, b); |
| Preconditions.checkArgument(a.length == mask.length, "Mask must be of same size as inputs"); |
| for (int i = 0; i < mask.length; i++) { |
| if (!maskedEquals(a[i], b[i], mask[i])) return false; |
| } |
| return true; |
| } |
| |
| public static boolean maskedEquals(UUID a, UUID b, @Nullable UUID mask) { |
| if (mask == null) { |
| return Objects.equals(a, b); |
| } |
| return maskedEquals(a.getLeastSignificantBits(), b.getLeastSignificantBits(), |
| mask.getLeastSignificantBits()) |
| && maskedEquals(a.getMostSignificantBits(), b.getMostSignificantBits(), |
| mask.getMostSignificantBits()); |
| } |
| |
| public static int[] unpackBits(long val) { |
| int size = Long.bitCount(val); |
| int[] result = new int[size]; |
| int index = 0; |
| int bitPos = 0; |
| while (val > 0) { |
| if ((val & 1) == 1) result[index++] = bitPos; |
| val = val >> 1; |
| bitPos++; |
| } |
| return result; |
| } |
| |
| public static long packBits(int[] bits) { |
| long packed = 0; |
| for (int b : bits) { |
| packed |= (1 << b); |
| } |
| return packed; |
| } |
| |
| public static int uint8(byte b) { |
| return b & 0xff; |
| } |
| |
| public static int uint16(short s) { |
| return s & 0xffff; |
| } |
| |
| public static int uint16(byte hi, byte lo) { |
| return ((hi & 0xff) << 8) | (lo & 0xff); |
| } |
| |
| public static long uint32(int i) { |
| return i & 0xffffffffL; |
| } |
| |
| public static int bytesToBEInt(byte[] bytes) { |
| return (uint8(bytes[0]) << 24) |
| + (uint8(bytes[1]) << 16) |
| + (uint8(bytes[2]) << 8) |
| + (uint8(bytes[3])); |
| } |
| |
| public static int bytesToLEInt(byte[] bytes) { |
| return Integer.reverseBytes(bytesToBEInt(bytes)); |
| } |
| |
| public static int getUint8(ByteBuffer buffer, int position) { |
| return uint8(buffer.get(position)); |
| } |
| |
| public static int getUint16(ByteBuffer buffer, int position) { |
| return uint16(buffer.getShort(position)); |
| } |
| |
| public static long getUint32(ByteBuffer buffer, int position) { |
| return uint32(buffer.getInt(position)); |
| } |
| |
| public static void put(ByteBuffer buffer, int position, byte[] bytes) { |
| final int original = buffer.position(); |
| buffer.position(position); |
| buffer.put(bytes); |
| buffer.position(original); |
| } |
| |
| public static boolean isBitSet(long flags, int bitIndex) { |
| return (flags & bitAt(bitIndex)) != 0; |
| } |
| |
| public static long bitAt(int bitIndex) { |
| return 1L << bitIndex; |
| } |
| |
| public static String flagsToString(int flags, IntFunction<String> getFlagName) { |
| StringBuilder builder = new StringBuilder(); |
| int count = 0; |
| while (flags != 0) { |
| final int flag = 1 << Integer.numberOfTrailingZeros(flags); |
| flags &= ~flag; |
| if (count > 0) builder.append(", "); |
| builder.append(getFlagName.apply(flag)); |
| count++; |
| } |
| TextUtils.wrap(builder, "[", "]"); |
| return builder.toString(); |
| } |
| } |