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);
|
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)
|
public static int GetPrime(int min)
|
||||||
{
|
{
|
||||||
if (min < 0)
|
if (min < 0)
|
||||||
throw new ArgumentException(nameof(min));
|
throw new ArgumentException(nameof(min));
|
||||||
|
|
||||||
// RomFS dictionaries choose from all possible primes
|
for (int i = 0; i < Primes.Length; i++)
|
||||||
|
{
|
||||||
//for (int i = 0; i < Primes.Length; i++)
|
int prime = Primes[i];
|
||||||
//{
|
if (prime >= min)
|
||||||
// int prime = Primes[i];
|
return prime;
|
||||||
// if (prime >= min)
|
}
|
||||||
// return prime;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//outside of our predefined table.
|
//outside of our predefined table.
|
||||||
//compute the hard way.
|
//compute the hard way.
|
||||||
|
|
||||||
for (int i = (min | 1); i < int.MaxValue; i += 2)
|
for (int i = (min | 1); i < int.MaxValue; i += 2)
|
||||||
{
|
{
|
||||||
if (IsPrime(i) && ((i - 1) % HashPrime != 0))
|
if (IsPrime(i) && ((i - 1) % HashPrime != 0))
|
||||||
|
@ -109,5 +89,19 @@ namespace LibHac
|
||||||
|
|
||||||
return GetPrime(newSize);
|
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);
|
DirectoryTable = new RomFsDictionary<DirectoryRomEntry>(DirHashTableStorage, DirEntryTableStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HierarchicalRomFileTable() : this(0, 0) { }
|
||||||
|
|
||||||
public HierarchicalRomFileTable(int directoryCapacity, int fileCapacity)
|
public HierarchicalRomFileTable(int directoryCapacity, int fileCapacity)
|
||||||
{
|
{
|
||||||
FileTable = new RomFsDictionary<FileRomEntry>(fileCapacity);
|
FileTable = new RomFsDictionary<FileRomEntry>(fileCapacity);
|
||||||
|
@ -155,6 +157,12 @@ namespace LibHac.IO.RomFs
|
||||||
CreateDirectoryRecursive(GetUtf8Bytes(path));
|
CreateDirectoryRecursive(GetUtf8Bytes(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TrimExcess()
|
||||||
|
{
|
||||||
|
DirectoryTable.TrimExcess();
|
||||||
|
FileTable.TrimExcess();
|
||||||
|
}
|
||||||
|
|
||||||
private static ReadOnlySpan<byte> GetUtf8Bytes(string value)
|
private static ReadOnlySpan<byte> GetUtf8Bytes(string value)
|
||||||
{
|
{
|
||||||
return Encoding.UTF8.GetBytes(value).AsSpan();
|
return Encoding.UTF8.GetBytes(value).AsSpan();
|
||||||
|
|
|
@ -16,17 +16,14 @@ namespace LibHac.IO.RomFs
|
||||||
|
|
||||||
public RomFsBuilder(IFileSystem input)
|
public RomFsBuilder(IFileSystem input)
|
||||||
{
|
{
|
||||||
DirectoryEntry[] entries = input.EnumerateEntries().ToArray();
|
FileTable = new HierarchicalRomFileTable();
|
||||||
int fileCount = entries.Count(x => x.Type == DirectoryEntryType.File);
|
var fileInfo = new RomFileInfo();
|
||||||
int dirCount = entries.Count(x => x.Type == DirectoryEntryType.Directory);
|
|
||||||
|
|
||||||
FileTable = new HierarchicalRomFileTable(dirCount, fileCount);
|
|
||||||
|
|
||||||
long offset = 0;
|
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.Offset = offset;
|
||||||
fileInfo.Length = file.Size;
|
fileInfo.Length = file.Size;
|
||||||
|
|
||||||
|
@ -41,6 +38,8 @@ namespace LibHac.IO.RomFs
|
||||||
|
|
||||||
FileTable.CreateFile(file.FullPath, ref fileInfo);
|
FileTable.CreateFile(file.FullPath, ref fileInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileTable.TrimExcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage Build()
|
public IStorage Build()
|
||||||
|
|
|
@ -27,9 +27,11 @@ namespace LibHac.IO.RomFs
|
||||||
_count = CountEntries();
|
_count = CountEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RomFsDictionary() : this(0) { }
|
||||||
|
|
||||||
public RomFsDictionary(int capacity)
|
public RomFsDictionary(int capacity)
|
||||||
{
|
{
|
||||||
int size = HashHelpers.GetHashTableEntryCount(capacity);
|
int size = HashHelpers.GetRomFsPrime(capacity);
|
||||||
|
|
||||||
Buckets = new int[size];
|
Buckets = new int[size];
|
||||||
Buckets.AsSpan().Fill(-1);
|
Buckets.AsSpan().Fill(-1);
|
||||||
|
@ -83,7 +85,7 @@ namespace LibHac.IO.RomFs
|
||||||
public int Add(ref RomEntryKey key, ref T value)
|
public int Add(ref RomEntryKey key, ref T value)
|
||||||
{
|
{
|
||||||
ref T entry = ref AddOrGet(ref key, out int offset, out bool alreadyExists, out _);
|
ref T entry = ref AddOrGet(ref key, out int offset, out bool alreadyExists, out _);
|
||||||
|
|
||||||
if (alreadyExists)
|
if (alreadyExists)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Key already exists in dictionary.");
|
throw new ArgumentException("Key already exists in dictionary.");
|
||||||
|
@ -124,6 +126,12 @@ namespace LibHac.IO.RomFs
|
||||||
Buckets[bucket] = newOffset;
|
Buckets[bucket] = newOffset;
|
||||||
_count++;
|
_count++;
|
||||||
|
|
||||||
|
if (Buckets.Length < _count)
|
||||||
|
{
|
||||||
|
Resize();
|
||||||
|
entry = ref GetEntryReference(newOffset, out name, key.Name.Length);
|
||||||
|
}
|
||||||
|
|
||||||
return ref entry.Value;
|
return ref entry.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +218,9 @@ namespace LibHac.IO.RomFs
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Resize(int newSize)
|
private void Resize() => Resize(HashHelpers.ExpandPrime(_count));
|
||||||
|
|
||||||
|
private void Resize(int newSize)
|
||||||
{
|
{
|
||||||
var newBuckets = new int[newSize];
|
var newBuckets = new int[newSize];
|
||||||
newBuckets.AsSpan().Fill(-1);
|
newBuckets.AsSpan().Fill(-1);
|
||||||
|
@ -231,6 +241,12 @@ namespace LibHac.IO.RomFs
|
||||||
Buckets = newBuckets;
|
Buckets = newBuckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TrimExcess()
|
||||||
|
{
|
||||||
|
Resize(HashHelpers.GetRomFsPrime(_count));
|
||||||
|
SetCapacity(_length);
|
||||||
|
}
|
||||||
|
|
||||||
private ref RomFsEntry GetEntryReference(int offset)
|
private ref RomFsEntry GetEntryReference(int offset)
|
||||||
{
|
{
|
||||||
return ref MemoryMarshal.Cast<byte, RomFsEntry>(Entries.AsSpan(offset))[0];
|
return ref MemoryMarshal.Cast<byte, RomFsEntry>(Entries.AsSpan(offset))[0];
|
||||||
|
|
Loading…
Reference in a new issue