mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Automatically resize the romfs dictionary
This commit is contained in:
parent
d2f7aa52dc
commit
c1beb9d1fd
4 changed files with 53 additions and 36 deletions
|
@ -52,40 +52,20 @@ namespace LibHac
|
|||
return (candidate == 2);
|
||||
}
|
||||
|
||||
public static int GetHashTableEntryCount(int entries)
|
||||
{
|
||||
uint count = (uint) entries;
|
||||
if (entries < 3)
|
||||
count = 3;
|
||||
else if (count < 19)
|
||||
count |= 1;
|
||||
else
|
||||
{
|
||||
while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || count % 11 == 0 || count % 13 == 0 || count % 17 == 0)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return (int) count;
|
||||
}
|
||||
|
||||
public static int GetPrime(int min)
|
||||
{
|
||||
if (min < 0)
|
||||
throw new ArgumentException(nameof(min));
|
||||
|
||||
// RomFS dictionaries choose from all possible primes
|
||||
|
||||
//for (int i = 0; i < Primes.Length; i++)
|
||||
//{
|
||||
// int prime = Primes[i];
|
||||
// if (prime >= min)
|
||||
// return prime;
|
||||
//}
|
||||
for (int i = 0; i < Primes.Length; i++)
|
||||
{
|
||||
int prime = Primes[i];
|
||||
if (prime >= min)
|
||||
return prime;
|
||||
}
|
||||
|
||||
//outside of our predefined table.
|
||||
//compute the hard way.
|
||||
|
||||
for (int i = (min | 1); i < int.MaxValue; i += 2)
|
||||
{
|
||||
if (IsPrime(i) && ((i - 1) % HashPrime != 0))
|
||||
|
@ -109,5 +89,19 @@ namespace LibHac
|
|||
|
||||
return GetPrime(newSize);
|
||||
}
|
||||
|
||||
public static int GetRomFsPrime(int min)
|
||||
{
|
||||
if (min < 3) return 3;
|
||||
if (min < 19) return min | 1;
|
||||
|
||||
for (int i = (min | 1); i < int.MaxValue; i += 2)
|
||||
{
|
||||
if (i % 2 != 0 && i % 3 != 0 && i % 5 != 0 && i % 7 != 0 && i % 11 != 0 && i % 13 != 0 && i % 17 != 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,8 @@ namespace LibHac.IO.RomFs
|
|||
DirectoryTable = new RomFsDictionary<DirectoryRomEntry>(DirHashTableStorage, DirEntryTableStorage);
|
||||
}
|
||||
|
||||
public HierarchicalRomFileTable() : this(0, 0) { }
|
||||
|
||||
public HierarchicalRomFileTable(int directoryCapacity, int fileCapacity)
|
||||
{
|
||||
FileTable = new RomFsDictionary<FileRomEntry>(fileCapacity);
|
||||
|
@ -155,6 +157,12 @@ namespace LibHac.IO.RomFs
|
|||
CreateDirectoryRecursive(GetUtf8Bytes(path));
|
||||
}
|
||||
|
||||
public void TrimExcess()
|
||||
{
|
||||
DirectoryTable.TrimExcess();
|
||||
FileTable.TrimExcess();
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> GetUtf8Bytes(string value)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(value).AsSpan();
|
||||
|
|
|
@ -16,17 +16,14 @@ namespace LibHac.IO.RomFs
|
|||
|
||||
public RomFsBuilder(IFileSystem input)
|
||||
{
|
||||
DirectoryEntry[] entries = input.EnumerateEntries().ToArray();
|
||||
int fileCount = entries.Count(x => x.Type == DirectoryEntryType.File);
|
||||
int dirCount = entries.Count(x => x.Type == DirectoryEntryType.Directory);
|
||||
|
||||
FileTable = new HierarchicalRomFileTable(dirCount, fileCount);
|
||||
FileTable = new HierarchicalRomFileTable();
|
||||
var fileInfo = new RomFileInfo();
|
||||
|
||||
long offset = 0;
|
||||
|
||||
foreach (DirectoryEntry file in entries.Where(x => x.Type == DirectoryEntryType.File).OrderBy(x => x.FullPath, StringComparer.Ordinal))
|
||||
foreach (DirectoryEntry file in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)
|
||||
.OrderBy(x => x.FullPath, StringComparer.Ordinal))
|
||||
{
|
||||
var fileInfo = new RomFileInfo();
|
||||
fileInfo.Offset = offset;
|
||||
fileInfo.Length = file.Size;
|
||||
|
||||
|
@ -41,6 +38,8 @@ namespace LibHac.IO.RomFs
|
|||
|
||||
FileTable.CreateFile(file.FullPath, ref fileInfo);
|
||||
}
|
||||
|
||||
FileTable.TrimExcess();
|
||||
}
|
||||
|
||||
public IStorage Build()
|
||||
|
|
|
@ -27,9 +27,11 @@ namespace LibHac.IO.RomFs
|
|||
_count = CountEntries();
|
||||
}
|
||||
|
||||
public RomFsDictionary() : this(0) { }
|
||||
|
||||
public RomFsDictionary(int capacity)
|
||||
{
|
||||
int size = HashHelpers.GetHashTableEntryCount(capacity);
|
||||
int size = HashHelpers.GetRomFsPrime(capacity);
|
||||
|
||||
Buckets = new int[size];
|
||||
Buckets.AsSpan().Fill(-1);
|
||||
|
@ -83,7 +85,7 @@ namespace LibHac.IO.RomFs
|
|||
public int Add(ref RomEntryKey key, ref T value)
|
||||
{
|
||||
ref T entry = ref AddOrGet(ref key, out int offset, out bool alreadyExists, out _);
|
||||
|
||||
|
||||
if (alreadyExists)
|
||||
{
|
||||
throw new ArgumentException("Key already exists in dictionary.");
|
||||
|
@ -124,6 +126,12 @@ namespace LibHac.IO.RomFs
|
|||
Buckets[bucket] = newOffset;
|
||||
_count++;
|
||||
|
||||
if (Buckets.Length < _count)
|
||||
{
|
||||
Resize();
|
||||
entry = ref GetEntryReference(newOffset, out name, key.Name.Length);
|
||||
}
|
||||
|
||||
return ref entry.Value;
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +218,9 @@ namespace LibHac.IO.RomFs
|
|||
return count;
|
||||
}
|
||||
|
||||
public void Resize(int newSize)
|
||||
private void Resize() => Resize(HashHelpers.ExpandPrime(_count));
|
||||
|
||||
private void Resize(int newSize)
|
||||
{
|
||||
var newBuckets = new int[newSize];
|
||||
newBuckets.AsSpan().Fill(-1);
|
||||
|
@ -231,6 +241,12 @@ namespace LibHac.IO.RomFs
|
|||
Buckets = newBuckets;
|
||||
}
|
||||
|
||||
public void TrimExcess()
|
||||
{
|
||||
Resize(HashHelpers.GetRomFsPrime(_count));
|
||||
SetCapacity(_length);
|
||||
}
|
||||
|
||||
private ref RomFsEntry GetEntryReference(int offset)
|
||||
{
|
||||
return ref MemoryMarshal.Cast<byte, RomFsEntry>(Entries.AsSpan(offset))[0];
|
||||
|
|
Loading…
Reference in a new issue