218 lines
6.7 KiB
C#
218 lines
6.7 KiB
C#
// 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<TMask>
|
|
{
|
|
public TMask Mask;
|
|
public byte Shift;
|
|
}
|
|
|
|
public static ShiftInfo<ulong>[] GetShifts(ulong mask)
|
|
{
|
|
var shifts = new List<ShiftInfo<ulong>>();
|
|
|
|
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<ulong>
|
|
{
|
|
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<byte>(bits, bitsCount);
|
|
|
|
ulong? maskFound = null;
|
|
int bit1ChunksFoundMask = 0;
|
|
|
|
int arrayLength = values.Length;
|
|
|
|
var mashHash = new HashSet<ulong>();
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|