2024-03-16 12:40:37 +08:00
|
|
|
|
using System;
|
2024-11-19 12:00:09 +08:00
|
|
|
|
using System.Data.SqlTypes;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using TValue = System.Int32;
|
|
|
|
|
|
2024-03-16 13:54:50 +08:00
|
|
|
|
namespace DCFApixels.DragonECS.Graphs.Internal
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
public sealed unsafe class SparseMatrix
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
|
|
|
|
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
|
|
|
|
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
|
|
|
|
|
2024-11-18 17:42:52 +08:00
|
|
|
|
private const int CHAIN_LENGTH_THRESHOLD = 5;
|
2024-11-19 11:46:23 +08:00
|
|
|
|
private const float CHAIN_LENGTH_THRESHOLD_CAPCITY_THRESHOLD = 0.65f;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
|
2024-11-19 11:46:23 +08:00
|
|
|
|
private int* _buckets;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
private Entry* _entries;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
private int _capacity;
|
2024-11-18 17:42:52 +08:00
|
|
|
|
private int _count_Threshold;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
|
|
|
|
|
private int _count;
|
|
|
|
|
|
|
|
|
|
private int _freeList;
|
|
|
|
|
private int _freeCount;
|
|
|
|
|
|
|
|
|
|
private int _modBitMask;
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
public int Count
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
get { return _count; }
|
|
|
|
|
}
|
|
|
|
|
public int Capacity
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
get { return _capacity; }
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public SparseMatrix(int minCapacity = MIN_CAPACITY)
|
|
|
|
|
{
|
|
|
|
|
minCapacity = NormalizeCapacity(minCapacity);
|
2024-11-19 11:46:23 +08:00
|
|
|
|
_buckets = UnmanagedArrayUtility.New<int>(minCapacity);
|
2024-11-18 21:31:52 +08:00
|
|
|
|
_entries = UnmanagedArrayUtility.NewAndInit<Entry>(minCapacity);
|
2024-03-16 12:40:37 +08:00
|
|
|
|
for (int i = 0; i < minCapacity; i++)
|
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
_buckets[i] = -1;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
|
|
|
|
|
|
|
|
|
|
_count = 0;
|
|
|
|
|
_freeList = 0;
|
|
|
|
|
_freeCount = 0;
|
|
|
|
|
|
2024-11-18 17:42:52 +08:00
|
|
|
|
SetCapacity(minCapacity);
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
2024-11-18 21:31:52 +08:00
|
|
|
|
~SparseMatrix()
|
|
|
|
|
{
|
|
|
|
|
UnmanagedArrayUtility.Free(_buckets);
|
|
|
|
|
UnmanagedArrayUtility.Free(_entries);
|
|
|
|
|
}
|
2024-03-16 12:40:37 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Add/TryAdd/Set
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public void Add(int x, int y, TValue value)
|
|
|
|
|
{
|
2024-11-18 21:31:52 +08:00
|
|
|
|
unchecked
|
|
|
|
|
{
|
|
|
|
|
long key = KeyUtility.FromXY(x, y);
|
2024-03-16 12:40:37 +08:00
|
|
|
|
#if DEBUG
|
2024-11-19 11:46:23 +08:00
|
|
|
|
if (FindEntry(key) >= 0)
|
|
|
|
|
{
|
|
|
|
|
Throw.ArgumentException("Has(x, y) is true");
|
|
|
|
|
}
|
2024-03-16 12:40:37 +08:00
|
|
|
|
#endif
|
2024-11-19 11:46:23 +08:00
|
|
|
|
int hash = IntHashes.hashes[y] ^ x;
|
|
|
|
|
AddInternal(key, hash, value);
|
2024-11-18 21:31:52 +08:00
|
|
|
|
}
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool TryAdd(int x, int y, TValue value)
|
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
unchecked
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
long key = KeyUtility.FromXY(x, y);
|
|
|
|
|
int hash = IntHashes.hashes[y] ^ x;
|
|
|
|
|
if (FindEntry(x, y) >= 0)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
AddInternal(key, hash, value);
|
|
|
|
|
return true;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public void Set(int x, int y, TValue value)
|
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
unchecked
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
long key = KeyUtility.FromXY(x, y);
|
|
|
|
|
int hash = IntHashes.hashes[y] ^ x;
|
|
|
|
|
int targetBucket = hash & _modBitMask;
|
|
|
|
|
|
|
|
|
|
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
if (_entries[i].hash == hash && _entries[i].key == key)
|
|
|
|
|
{
|
|
|
|
|
_entries[i].value = value;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
2024-11-19 11:46:23 +08:00
|
|
|
|
AddInternal(key, hash, value);
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-19 11:46:23 +08:00
|
|
|
|
private void AddInternal(long key, int hash, int value)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-18 21:31:52 +08:00
|
|
|
|
unchecked
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
int targetBucket = hash & _modBitMask;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
int index;
|
|
|
|
|
if (_freeCount == 0)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
if (_count > _count_Threshold)
|
|
|
|
|
{
|
2024-11-18 21:31:52 +08:00
|
|
|
|
Resize();
|
|
|
|
|
// обновляем под новое значение _modBitMask
|
2024-11-19 11:46:23 +08:00
|
|
|
|
targetBucket = hash & _modBitMask;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
}
|
|
|
|
|
//index = Interlocked.Increment(ref _count);
|
|
|
|
|
index = _count++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
index = _freeList;
|
|
|
|
|
_freeList = _entries[index].next;
|
|
|
|
|
_freeCount--;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
2024-11-18 21:31:52 +08:00
|
|
|
|
if (_freeCount < 0) { Throw.UndefinedException(); }
|
2024-03-16 12:40:37 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
2024-11-19 11:46:23 +08:00
|
|
|
|
ref int basket = ref _buckets[targetBucket];
|
2024-11-18 21:31:52 +08:00
|
|
|
|
ref Entry entry = ref _entries[index];
|
2024-03-16 12:40:37 +08:00
|
|
|
|
|
2024-11-19 11:46:23 +08:00
|
|
|
|
entry.hash = hash;
|
|
|
|
|
entry.next = basket;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
entry.key = key;
|
|
|
|
|
entry.value = value;
|
2024-11-19 11:46:23 +08:00
|
|
|
|
basket = index;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region FindEntry/Has
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private int FindEntry(int x, int y)
|
|
|
|
|
{
|
2024-11-18 21:31:52 +08:00
|
|
|
|
long key = KeyUtility.FromXY(x, y);
|
2024-11-19 11:46:23 +08:00
|
|
|
|
int hash = IntHashes.hashes[y] ^ x;
|
|
|
|
|
for (int i = _buckets[hash & _modBitMask]; i >= 0; i = _entries[i].next)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
if (_entries[i].hash == hash && _entries[i].key == key)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool HasKey(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
return FindEntry(x, y) >= 0;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region GetValue/TryGetValue
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public TValue GetValue(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
int index = FindEntry(x, y);
|
|
|
|
|
#if DEBUG
|
2024-03-16 14:13:43 +08:00
|
|
|
|
if (index < 0) { Throw.KeyNotFound(); }
|
2024-03-16 12:40:37 +08:00
|
|
|
|
#endif
|
|
|
|
|
return _entries[index].value;
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool TryGetValue(int x, int y, out TValue value)
|
|
|
|
|
{
|
|
|
|
|
int index = FindEntry(x, y);
|
|
|
|
|
if (index < 0)
|
|
|
|
|
{
|
|
|
|
|
value = default;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
value = _entries[index].value;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region TryDel
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool TryDel(int x, int y)
|
|
|
|
|
{
|
2024-11-18 21:31:52 +08:00
|
|
|
|
long key = KeyUtility.FromXY(x, y);
|
2024-11-19 11:46:23 +08:00
|
|
|
|
int hash = IntHashes.hashes[y] ^ x;
|
|
|
|
|
int targetBucket = hash & _modBitMask;
|
|
|
|
|
ref int basket = ref _buckets[targetBucket];
|
2024-03-16 12:40:37 +08:00
|
|
|
|
|
|
|
|
|
int last = -1;
|
2024-11-19 11:46:23 +08:00
|
|
|
|
for (int i = basket; i >= 0; last = i, i = _entries[i].next)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
if (_entries[i].hash == hash && _entries[i].key == key)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
|
|
|
|
if (last < 0)
|
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
basket = _entries[i].next;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_entries[last].next = _entries[i].next;
|
|
|
|
|
}
|
|
|
|
|
_entries[i].next = _freeList;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
_entries[i].key = default; //Key.Null;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
_entries[i].value = default;
|
|
|
|
|
_freeList = i;
|
|
|
|
|
_freeCount++;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Clear
|
|
|
|
|
public void Clear()
|
|
|
|
|
{
|
|
|
|
|
if (_count > 0)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < _capacity; i++)
|
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
_buckets[i] = -1;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < _capacity; i++)
|
|
|
|
|
{
|
|
|
|
|
_entries[i] = default;
|
|
|
|
|
}
|
|
|
|
|
_count = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Resize
|
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
|
|
|
private void Resize()
|
|
|
|
|
{
|
|
|
|
|
int newSize = _capacity << 1;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
Console.WriteLine($"Resize {newSize}");
|
2024-03-16 12:40:37 +08:00
|
|
|
|
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
|
|
|
|
|
|
2024-03-17 13:43:15 +08:00
|
|
|
|
//newBuckets create and ini
|
2024-11-19 11:46:23 +08:00
|
|
|
|
int* newBuckets = UnmanagedArrayUtility.New<int>(newSize);
|
2024-03-17 13:43:15 +08:00
|
|
|
|
for (int i = 0; i < newSize; i++)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
newBuckets[i] = -1;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
2024-03-17 13:43:15 +08:00
|
|
|
|
//END newBuckets create and ini
|
2024-03-16 12:40:37 +08:00
|
|
|
|
|
2024-11-18 21:31:52 +08:00
|
|
|
|
Entry* newEntries = UnmanagedArrayUtility.ResizeAndInit<Entry>(_entries, _capacity, newSize);
|
2024-03-16 12:40:37 +08:00
|
|
|
|
for (int i = 0; i < _count; i++)
|
|
|
|
|
{
|
2024-11-18 21:31:52 +08:00
|
|
|
|
if (newEntries[i].key >= 0)
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
2024-03-18 02:45:25 +08:00
|
|
|
|
ref Entry entry = ref newEntries[i];
|
2024-11-19 11:46:23 +08:00
|
|
|
|
ref int basket = ref newBuckets[entry.hash & _modBitMask];
|
|
|
|
|
entry.next = basket;
|
|
|
|
|
basket = i;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-17 13:43:15 +08:00
|
|
|
|
|
2024-11-18 21:31:52 +08:00
|
|
|
|
UnmanagedArrayUtility.Free(_buckets);
|
2024-03-18 02:45:25 +08:00
|
|
|
|
_buckets = newBuckets;
|
|
|
|
|
_entries = newEntries;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
|
2024-11-18 17:42:52 +08:00
|
|
|
|
SetCapacity(newSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetCapacity(int newSize)
|
|
|
|
|
{
|
2024-03-16 12:40:37 +08:00
|
|
|
|
_capacity = newSize;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
_count_Threshold = (int)(_capacity * CHAIN_LENGTH_THRESHOLD_CAPCITY_THRESHOLD);
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private static int NormalizeCapacity(int capacity)
|
|
|
|
|
{
|
|
|
|
|
int result = MIN_CAPACITY;
|
2024-03-18 02:45:25 +08:00
|
|
|
|
while (result < capacity) { result <<= 1; }
|
2024-03-16 12:40:37 +08:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Utils
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
|
|
|
private struct Entry
|
|
|
|
|
{
|
|
|
|
|
public int next; // Index of next entry, -1 if last
|
2024-11-18 21:31:52 +08:00
|
|
|
|
public long key;
|
2024-11-19 11:46:23 +08:00
|
|
|
|
public int hash;
|
2024-03-16 12:40:37 +08:00
|
|
|
|
public TValue value;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
public override string ToString() { return key == 0 ? "NULL" : $"{key} {value}"; }
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-11-18 21:31:52 +08:00
|
|
|
|
public static class KeyUtility
|
2024-03-16 12:40:37 +08:00
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-18 21:31:52 +08:00
|
|
|
|
public static long FromXY(int x, int y)
|
2024-03-18 02:45:25 +08:00
|
|
|
|
{
|
|
|
|
|
unchecked
|
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
return ((long)x << 32) | (long)y;
|
2024-03-18 02:45:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-18 17:42:52 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-18 21:31:52 +08:00
|
|
|
|
private static int Mixing(int v)
|
2024-03-18 02:45:25 +08:00
|
|
|
|
{
|
2024-11-18 17:42:52 +08:00
|
|
|
|
unchecked
|
|
|
|
|
{
|
2024-11-19 11:46:23 +08:00
|
|
|
|
int i = v;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
v *= 3571;
|
2024-11-19 11:46:23 +08:00
|
|
|
|
|
|
|
|
|
v ^= v << 13;
|
|
|
|
|
v ^= v >> 17;
|
|
|
|
|
v ^= v << 5;
|
|
|
|
|
//v = (v >> 28) + v ^ i;
|
2024-11-18 21:31:52 +08:00
|
|
|
|
return v;
|
2024-11-18 17:42:52 +08:00
|
|
|
|
}
|
2024-03-18 02:45:25 +08:00
|
|
|
|
}
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
2024-11-19 11:46:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static unsafe class IntHashes
|
|
|
|
|
{
|
|
|
|
|
public static int* hashes = null;
|
|
|
|
|
public static int length = 0;
|
|
|
|
|
public static void InitFor(int count)
|
|
|
|
|
{
|
|
|
|
|
unchecked
|
|
|
|
|
{
|
2024-11-19 12:00:09 +08:00
|
|
|
|
const decimal G1 = 1.6180339887498948482045868383m;
|
|
|
|
|
const uint Q32_MAX = uint.MaxValue;
|
|
|
|
|
const uint X1_Q32 = (uint)(1m / G1 * Q32_MAX) + 1;
|
|
|
|
|
|
2024-11-19 11:46:23 +08:00
|
|
|
|
//count = GetHighBitNumber((uint)count) << 1;
|
|
|
|
|
|
|
|
|
|
if (count <= length) { return; }
|
|
|
|
|
|
|
|
|
|
if (hashes != null)
|
|
|
|
|
{
|
|
|
|
|
UnmanagedArrayUtility.Free(hashes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hashes = UnmanagedArrayUtility.New<int>(count);
|
|
|
|
|
|
|
|
|
|
uint state = 3571U;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
{
|
2024-11-19 12:00:09 +08:00
|
|
|
|
//state ^= state << 13;
|
|
|
|
|
//state ^= state >> 17;
|
|
|
|
|
//state ^= state << 5;
|
|
|
|
|
|
|
|
|
|
state = X1_Q32 * state;
|
2024-11-19 11:46:23 +08:00
|
|
|
|
|
|
|
|
|
//int v = Mixing(i);
|
|
|
|
|
hashes[i] = (int)state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count = length;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private static int Mixing(int v)
|
|
|
|
|
{
|
|
|
|
|
unchecked
|
|
|
|
|
{
|
|
|
|
|
int i = v;
|
|
|
|
|
v *= 3571;
|
|
|
|
|
//if(i % 3 == 0)
|
|
|
|
|
//{
|
|
|
|
|
// v ^= (v << 13) | 8191;
|
|
|
|
|
//}
|
|
|
|
|
//else
|
|
|
|
|
//{
|
|
|
|
|
// v ^= (v << 13);
|
|
|
|
|
//}
|
|
|
|
|
v ^= (v << 13);
|
|
|
|
|
v ^= v >> 17;
|
|
|
|
|
//if (i % 5 == 0)
|
|
|
|
|
//{
|
|
|
|
|
// v ^= (v << 5) | 15;
|
|
|
|
|
//}
|
|
|
|
|
//else
|
|
|
|
|
//{
|
|
|
|
|
// v ^= (v << 5);
|
|
|
|
|
//}
|
|
|
|
|
v ^= (v << 5);
|
|
|
|
|
|
|
|
|
|
//v = (v >> 28) + v ^ i;
|
|
|
|
|
return v;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public static int GetHighBitNumber(uint bits)
|
|
|
|
|
{
|
|
|
|
|
if (bits == 0)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
int bit = 0;
|
|
|
|
|
if ((bits & 0xFFFF0000) != 0)
|
|
|
|
|
{
|
|
|
|
|
bits >>= 16;
|
|
|
|
|
bit |= 16;
|
|
|
|
|
}
|
|
|
|
|
if ((bits & 0xFF00) != 0)
|
|
|
|
|
{
|
|
|
|
|
bits >>= 8;
|
|
|
|
|
bit |= 8;
|
|
|
|
|
}
|
|
|
|
|
if ((bits & 0xF0) != 0)
|
|
|
|
|
{
|
|
|
|
|
bits >>= 4;
|
|
|
|
|
bit |= 4;
|
|
|
|
|
}
|
|
|
|
|
if ((bits & 0xC) != 0)
|
|
|
|
|
{
|
|
|
|
|
bits >>= 2;
|
|
|
|
|
bit |= 2;
|
|
|
|
|
}
|
|
|
|
|
if ((bits & 0x2) != 0)
|
|
|
|
|
{
|
|
|
|
|
bit |= 1;
|
|
|
|
|
}
|
|
|
|
|
return bit;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-16 12:40:37 +08:00
|
|
|
|
}
|