mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Improve rom file table read/write performance
This commit is contained in:
parent
b99bb84e9c
commit
5457a81068
3 changed files with 56 additions and 68 deletions
|
@ -308,5 +308,19 @@ namespace LibHac.IO.RomFs
|
||||||
return DirectoryTable.ContainsKey(ref key) ||
|
return DirectoryTable.ContainsKey(ref key) ||
|
||||||
FileTable.ContainsKey(ref key);
|
FileTable.ContainsKey(ref key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
|
private struct DirectoryRomEntry
|
||||||
|
{
|
||||||
|
public int NextSibling;
|
||||||
|
public FindPosition Pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
|
private struct FileRomEntry
|
||||||
|
{
|
||||||
|
public int NextSibling;
|
||||||
|
public RomFileInfo Info;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace LibHac.IO.RomFs
|
namespace LibHac.IO.RomFs
|
||||||
|
@ -47,7 +46,7 @@ namespace LibHac.IO.RomFs
|
||||||
|
|
||||||
if (i >= 0)
|
if (i >= 0)
|
||||||
{
|
{
|
||||||
GetEntryInternal(i, out RomFsEntry<T> entry);
|
ref RomFsEntry entry = ref GetEntryReference(i);
|
||||||
|
|
||||||
value = new RomKeyValuePair<T> { Key = key, Value = entry.Value, Offset = i };
|
value = new RomKeyValuePair<T> { Key = key, Value = entry.Value, Offset = i };
|
||||||
return true;
|
return true;
|
||||||
|
@ -67,7 +66,9 @@ namespace LibHac.IO.RomFs
|
||||||
|
|
||||||
value = new RomKeyValuePair<T>();
|
value = new RomKeyValuePair<T>();
|
||||||
|
|
||||||
GetEntryInternal(offset, out RomFsEntry<T> entry, out value.Key.Name);
|
ref RomFsEntry entry = ref GetEntryReference(offset, out Span<byte> name);
|
||||||
|
|
||||||
|
value.Key.Name = name;
|
||||||
value.Value = entry.Value;
|
value.Value = entry.Value;
|
||||||
value.Key.Parent = entry.Parent;
|
value.Key.Parent = entry.Parent;
|
||||||
return true;
|
return true;
|
||||||
|
@ -78,9 +79,8 @@ namespace LibHac.IO.RomFs
|
||||||
int i = FindEntry(ref key);
|
int i = FindEntry(ref key);
|
||||||
if (i < 0) return false;
|
if (i < 0) return false;
|
||||||
|
|
||||||
GetEntryInternal(i, out RomFsEntry<T> entry);
|
ref RomFsEntry entry = ref GetEntryReference(i);
|
||||||
entry.Value = value;
|
entry.Value = value;
|
||||||
SetEntryInternal(i, ref entry);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -99,13 +99,14 @@ namespace LibHac.IO.RomFs
|
||||||
int bucket = (int)(hashCode % Buckets.Length);
|
int bucket = (int)(hashCode % Buckets.Length);
|
||||||
int newOffset = FindOffsetForInsert(ref key);
|
int newOffset = FindOffsetForInsert(ref key);
|
||||||
|
|
||||||
var entry = new RomFsEntry<T>();
|
ref RomFsEntry entry = ref GetEntryReference(newOffset, out Span<byte> name, key.Name.Length);
|
||||||
|
|
||||||
entry.Next = Buckets[bucket];
|
entry.Next = Buckets[bucket];
|
||||||
entry.Parent = key.Parent;
|
entry.Parent = key.Parent;
|
||||||
entry.KeyLength = key.Name.Length;
|
entry.KeyLength = key.Name.Length;
|
||||||
entry.Value = value;
|
entry.Value = value;
|
||||||
|
|
||||||
SetEntryInternal(newOffset, ref entry, ref key.Name);
|
key.Name.CopyTo(name);
|
||||||
|
|
||||||
Buckets[bucket] = newOffset;
|
Buckets[bucket] = newOffset;
|
||||||
_count++;
|
_count++;
|
||||||
|
@ -135,7 +136,7 @@ namespace LibHac.IO.RomFs
|
||||||
|
|
||||||
while (i != -1)
|
while (i != -1)
|
||||||
{
|
{
|
||||||
GetEntryInternal(i, out RomFsEntry<T> entry, out ReadOnlySpan<byte> name);
|
ref RomFsEntry entry = ref GetEntryReference(i, out Span<byte> name);
|
||||||
|
|
||||||
if (key.Parent == entry.Parent && key.Name.SequenceEqual(name))
|
if (key.Parent == entry.Parent && key.Name.SequenceEqual(name))
|
||||||
{
|
{
|
||||||
|
@ -148,35 +149,6 @@ namespace LibHac.IO.RomFs
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetEntryInternal(int offset, out RomFsEntry<T> outEntry)
|
|
||||||
{
|
|
||||||
outEntry = MemoryMarshal.Read<RomFsEntry<T>>(Entries.AsSpan(offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetEntryInternal(int offset, out RomFsEntry<T> outEntry, out ReadOnlySpan<byte> entryName)
|
|
||||||
{
|
|
||||||
GetEntryInternal(offset, out outEntry);
|
|
||||||
|
|
||||||
if (outEntry.KeyLength > 0x300)
|
|
||||||
{
|
|
||||||
throw new InvalidDataException("Rom entry name is too long.");
|
|
||||||
}
|
|
||||||
|
|
||||||
entryName = Entries.AsSpan(offset + _sizeOfEntry, outEntry.KeyLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetEntryInternal(int offset, ref RomFsEntry<T> entry)
|
|
||||||
{
|
|
||||||
MemoryMarshal.Write(Entries.AsSpan(offset), ref entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetEntryInternal(int offset, ref RomFsEntry<T> entry, ref ReadOnlySpan<byte> entryName)
|
|
||||||
{
|
|
||||||
MemoryMarshal.Write(Entries.AsSpan(offset), ref entry);
|
|
||||||
|
|
||||||
entryName.CopyTo(Entries.AsSpan(offset + _sizeOfEntry, entry.KeyLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureCapacityBytes(int value)
|
private void EnsureCapacityBytes(int value)
|
||||||
{
|
{
|
||||||
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
|
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
|
@ -229,14 +201,12 @@ namespace LibHac.IO.RomFs
|
||||||
newBuckets.AsSpan().Fill(-1);
|
newBuckets.AsSpan().Fill(-1);
|
||||||
|
|
||||||
List<int> offsets = GetEntryOffsets();
|
List<int> offsets = GetEntryOffsets();
|
||||||
var key = new RomEntryKey();
|
|
||||||
|
|
||||||
for (int i = 0; i < offsets.Count; i++)
|
for (int i = 0; i < offsets.Count; i++)
|
||||||
{
|
{
|
||||||
ref RomFsEntry<T> entry = ref GetEntryReference(offsets[i], out key.Name);
|
ref RomFsEntry entry = ref GetEntryReference(offsets[i], out Span<byte> name);
|
||||||
key.Parent = entry.Parent;
|
|
||||||
|
|
||||||
uint hashCode = key.GetRomHashCode();
|
uint hashCode = RomEntryKey.GetRomHashCode(entry.Parent, name);
|
||||||
int bucket = (int)(hashCode % newSize);
|
int bucket = (int)(hashCode % newSize);
|
||||||
|
|
||||||
entry.Next = newBuckets[bucket];
|
entry.Next = newBuckets[bucket];
|
||||||
|
@ -246,14 +216,27 @@ namespace LibHac.IO.RomFs
|
||||||
Buckets = newBuckets;
|
Buckets = newBuckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ref RomFsEntry<T> GetEntryReference(int offset, out ReadOnlySpan<byte> name)
|
private ref RomFsEntry GetEntryReference(int offset)
|
||||||
{
|
{
|
||||||
ref RomFsEntry<T> entry = ref MemoryMarshal.Cast<byte, RomFsEntry<T>>(Entries.AsSpan(offset))[0];
|
return ref MemoryMarshal.Cast<byte, RomFsEntry>(Entries.AsSpan(offset))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private ref RomFsEntry GetEntryReference(int offset, out Span<byte> name)
|
||||||
|
{
|
||||||
|
ref RomFsEntry entry = ref MemoryMarshal.Cast<byte, RomFsEntry>(Entries.AsSpan(offset))[0];
|
||||||
|
|
||||||
name = Entries.AsSpan(offset + _sizeOfEntry, entry.KeyLength);
|
name = Entries.AsSpan(offset + _sizeOfEntry, entry.KeyLength);
|
||||||
return ref entry;
|
return ref entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ref RomFsEntry GetEntryReference(int offset, out Span<byte> name, int nameLength)
|
||||||
|
{
|
||||||
|
ref RomFsEntry entry = ref MemoryMarshal.Cast<byte, RomFsEntry>(Entries.AsSpan(offset))[0];
|
||||||
|
|
||||||
|
name = Entries.AsSpan(offset + _sizeOfEntry, nameLength);
|
||||||
|
return ref entry;
|
||||||
|
}
|
||||||
|
|
||||||
private List<int> GetEntryOffsets()
|
private List<int> GetEntryOffsets()
|
||||||
{
|
{
|
||||||
var offsets = new List<int>(_count);
|
var offsets = new List<int>(_count);
|
||||||
|
@ -277,5 +260,14 @@ namespace LibHac.IO.RomFs
|
||||||
}
|
}
|
||||||
|
|
||||||
private int EstimateEntryTableSize(int count) => (_sizeOfEntry + 0x10) * count; // Estimate 0x10 bytes per name
|
private int EstimateEntryTableSize(int count) => (_sizeOfEntry + 0x10) * count; // Estimate 0x10 bytes per name
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
|
private struct RomFsEntry
|
||||||
|
{
|
||||||
|
public int Parent;
|
||||||
|
public T Value;
|
||||||
|
public int Next;
|
||||||
|
public int KeyLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,14 @@ namespace LibHac.IO.RomFs
|
||||||
|
|
||||||
public uint GetRomHashCode()
|
public uint GetRomHashCode()
|
||||||
{
|
{
|
||||||
uint hash = 123456789 ^ (uint)Parent;
|
return GetRomHashCode(Parent, Name);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (byte c in Name)
|
public static uint GetRomHashCode(int parent, ReadOnlySpan<byte> name)
|
||||||
|
{
|
||||||
|
uint hash = 123456789 ^ (uint)parent;
|
||||||
|
|
||||||
|
foreach (byte c in name)
|
||||||
{
|
{
|
||||||
hash = c ^ ((hash << 27) | (hash >> 5));
|
hash = c ^ ((hash << 27) | (hash >> 5));
|
||||||
}
|
}
|
||||||
|
@ -34,22 +39,6 @@ namespace LibHac.IO.RomFs
|
||||||
public T Value;
|
public T Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
||||||
public struct RomFsEntry<T> where T : unmanaged
|
|
||||||
{
|
|
||||||
public int Parent;
|
|
||||||
public T Value;
|
|
||||||
public int Next;
|
|
||||||
public int KeyLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
||||||
public struct FileRomEntry
|
|
||||||
{
|
|
||||||
public int NextSibling;
|
|
||||||
public RomFileInfo Info;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct RomFileInfo
|
public struct RomFileInfo
|
||||||
{
|
{
|
||||||
|
@ -57,13 +46,6 @@ namespace LibHac.IO.RomFs
|
||||||
public long Length;
|
public long Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
||||||
public struct DirectoryRomEntry
|
|
||||||
{
|
|
||||||
public int NextSibling;
|
|
||||||
public FindPosition Pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct FindPosition
|
public struct FindPosition
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue