// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; namespace CodeGenerator.HttpUtilities { internal class HttpUtilitiesGeneratorHelpers { public class ShiftInfo { public TMask Mask; public byte Shift; } public static ShiftInfo[] GetShifts(ulong mask) { var shifts = new List>(); const ulong one = 0x01; ulong currentMask = 0; int currentBitsCount = 0; int lastShift = 0; for (int i = 0; i < sizeof(ulong) * 8; i++) { var currentBitMask = one << i; bool isCurrentBit0 = (currentBitMask & mask) == 0; if (isCurrentBit0 == false) { currentMask |= currentBitMask; currentBitsCount++; } else if (currentBitsCount > 0) { var currentShift = (byte)(i - currentBitsCount - lastShift); shifts.Add(new ShiftInfo { Mask = currentMask, Shift = currentShift }); lastShift = currentShift; currentMask = 0; currentBitsCount = 0; } } return shifts.ToArray(); } public static ulong? SearchKeyByLookThroughMaskCombinations(ulong[] values, byte bitsIndexStart, byte bitsLength, byte bitsCount) { if (bitsIndexStart + bitsLength > sizeof(ulong) * 8) { throw new ArgumentOutOfRangeException(nameof(bitsIndexStart)); } if (bitsLength < bitsCount || bitsCount == 0) { throw new ArgumentOutOfRangeException(nameof(bitsCount)); } var bits = new byte[bitsLength]; for (byte i = bitsIndexStart; i < bitsIndexStart + bitsLength; i++) { bits[i - bitsIndexStart] = i; } var combinations = new CombinationsWithoutRepetition(bits, bitsCount); ulong? maskFound = null; int bit1ChunksFoundMask = 0; int arrayLength = values.Length; var mashHash = new HashSet(); while (combinations.MoveNext()) { var bitsCombination = combinations.Current; ulong currentMask = 0; for (int i = 0; i < bitsCombination.Length; i++) { var index = bitsCombination[i]; const ulong oneBit = 0x01; currentMask |= oneBit << index; } mashHash.Clear(); bool invalidMask = false; for (int j = 0; j < arrayLength; j++) { var tmp = values[j] & currentMask; bool alreadyExists = mashHash.Add(tmp) == false; if (alreadyExists) { invalidMask = true; break; } } if (invalidMask == false) { var bit1Chunks = CountBit1Chunks(currentMask); if (maskFound.HasValue) { if (bit1ChunksFoundMask > bit1Chunks) { maskFound = currentMask; bit1ChunksFoundMask = bit1Chunks; if (bit1ChunksFoundMask == 0) { return maskFound; } } } else { maskFound = currentMask; bit1ChunksFoundMask = bit1Chunks; if (bit1ChunksFoundMask == 0) { return maskFound; } } } } return maskFound; } public static int CountBit1Chunks(ulong mask) { int currentBitsCount = 0; int chunks = 0; for (int i = 0; i < sizeof(ulong) * 8; i++) { const ulong oneBit = 0x01; var currentBitMask = oneBit << i; bool isCurrentBit0 = (currentBitMask & mask) == 0; if (isCurrentBit0 == false) { currentBitsCount++; } else if (currentBitsCount > 0) { chunks++; currentBitsCount = 0; } } return chunks; } public static string GeHexString(byte[] array, string prefix, string separator) { var result = new StringBuilder(); int i = 0; for (; i < array.Length - 1; i++) { result.AppendFormat("{0}{1:x2}", prefix, array[i]); result.Append(separator); } if (array.Length > 0) { result.AppendFormat("{0}{1:x2}", prefix, array[i]); } return result.ToString(); } public static string MaskToString(ulong mask) { var maskSizeInBIts = Math.Log(mask, 2); var hexMaskSize = Math.Ceiling(maskSizeInBIts / 4.0); return string.Format("0x{0:X" + hexMaskSize + "}", mask); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int CountBits(ulong v) { const ulong Mask01010101 = 0x5555555555555555UL; const ulong Mask00110011 = 0x3333333333333333UL; const ulong Mask00001111 = 0x0F0F0F0F0F0F0F0FUL; const ulong Mask00000001 = 0x0101010101010101UL; v = v - ((v >> 1) & Mask01010101); v = (v & Mask00110011) + ((v >> 2) & Mask00110011); return (int)(unchecked(((v + (v >> 4)) & Mask00001111) * Mask00000001) >> 56); } public static string MaskToHexString(ulong mask) { var maskSizeInBIts = Math.Log(mask, 2); var hexMaskSize = (byte)Math.Ceiling(maskSizeInBIts / 4); return string.Format("0x{0:X" + (hexMaskSize == 0 ? 1 : hexMaskSize) + "}", mask); } } }