MeloNX/src/Ryujinx.Horizon/Sdk/Ngc/Detail/SimilarFormTable.cs
gdkchan 01c2b8097c
Implement NGC service (#5681)
* Implement NGC service

* Use raw byte arrays instead of string for _wordSeparators

* Silence IDE0230 for _wordSeparators

* Try to silence warning about _rangeValuesCount not being read on SparseSet

* Make AcType enum private

* Add abstract methods and one TODO that I forgot

* PR feedback

* More PR feedback

* More PR feedback
2023-09-27 19:21:26 +02:00

133 lines
3.7 KiB
C#

using System;
namespace Ryujinx.Horizon.Sdk.Ngc.Detail
{
class SimilarFormTable
{
private int _similarTableStringLength;
private int _canonicalTableStringLength;
private int _count;
private byte[][] _similarTable;
private byte[][] _canonicalTable;
public bool Import(ref BinaryReader reader)
{
if (!reader.Read(out _similarTableStringLength) ||
!reader.Read(out _canonicalTableStringLength) ||
!reader.Read(out _count))
{
return false;
}
_similarTable = new byte[_count][];
_canonicalTable = new byte[_count][];
if (_count < 1)
{
return true;
}
for (int tableIndex = 0; tableIndex < _count; tableIndex++)
{
if (reader.AllocateAndReadArray(ref _similarTable[tableIndex], _similarTableStringLength) != _similarTableStringLength ||
reader.AllocateAndReadArray(ref _canonicalTable[tableIndex], _canonicalTableStringLength) != _canonicalTableStringLength)
{
return false;
}
}
return true;
}
public ReadOnlySpan<byte> FindCanonicalString(ReadOnlySpan<byte> similarFormString)
{
int lowerBound = 0;
int upperBound = _count;
for (int charIndex = 0; charIndex < similarFormString.Length; charIndex++)
{
byte character = similarFormString[charIndex];
int newLowerBound = GetLowerBound(character, charIndex, lowerBound - 1, upperBound - 1);
if (newLowerBound < 0 || _similarTable[newLowerBound][charIndex] != character)
{
return ReadOnlySpan<byte>.Empty;
}
int newUpperBound = GetUpperBound(character, charIndex, lowerBound - 1, upperBound - 1);
if (newUpperBound < 0)
{
newUpperBound = upperBound;
}
lowerBound = newLowerBound;
upperBound = newUpperBound;
}
return _canonicalTable[lowerBound];
}
private int GetLowerBound(byte character, int charIndex, int left, int right)
{
while (right - left > 1)
{
int range = right + left;
if (range < 0)
{
range++;
}
int middle = range / 2;
if (character <= _similarTable[middle][charIndex])
{
right = middle;
}
else
{
left = middle;
}
}
if (_similarTable[right][charIndex] < character)
{
return -1;
}
return right;
}
private int GetUpperBound(byte character, int charIndex, int left, int right)
{
while (right - left > 1)
{
int range = right + left;
if (range < 0)
{
range++;
}
int middle = range / 2;
if (_similarTable[middle][charIndex] <= character)
{
left = middle;
}
else
{
right = middle;
}
}
if (_similarTable[right][charIndex] <= character)
{
return -1;
}
return right;
}
}
}