Skip to content

Commit

Permalink
Impl ArrayChangelog
Browse files Browse the repository at this point in the history
  • Loading branch information
ArchLeaders committed May 6, 2024
1 parent e96b288 commit 09c184b
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 1 deletion.
19 changes: 19 additions & 0 deletions src/BymlLibrary/Byml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public enum BymlNodeType : byte
Int64 = 0xD4,
UInt64 = 0xD5,
Double = 0xD6,
ArrayChangelog = 0xFD,
Changelog = 0xFE,
Null = 0xFF,
}
Expand Down Expand Up @@ -101,6 +102,8 @@ public static Byml FromImmutable(in ImmutableByml byml, in ImmutableByml root)
=> new(byml.GetHashMap32().ToMutable(root)),
BymlNodeType.HashMap64
=> new(byml.GetHashMap64().ToMutable(root)),
BymlNodeType.ArrayChangelog
=> new(byml.GetArrayChangelog().ToMutable(root)),
BymlNodeType.String
=> new(root.StringTable[byml.GetStringIndex()].ToManaged()),
BymlNodeType.Binary
Expand Down Expand Up @@ -207,6 +210,18 @@ public Byml(BymlHashMap64 hashMap64)
Value = hashMap64;
}

public static implicit operator Byml(Dictionary<int, Byml> hashMap32) => new(hashMap32);
public Byml(IDictionary<int, Byml> arrayChangelog) : this(new BymlArrayChangelog(arrayChangelog))
{
}

public static implicit operator Byml(BymlArrayChangelog arrayChangelog) => new(arrayChangelog);
public Byml(BymlArrayChangelog arrayChangelog)
{
Type = BymlNodeType.ArrayChangelog;
Value = arrayChangelog;
}

public static implicit operator Byml(Byml[] array) => new(array);
public Byml(IEnumerable<Byml> array)
{
Expand Down Expand Up @@ -325,6 +340,10 @@ public BymlHashMap32 GetHashMap32()
public BymlHashMap64 GetHashMap64()
=> Get<BymlHashMap64>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BymlArrayChangelog GetArrayChangelog()
=> Get<BymlArrayChangelog>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BymlArray GetArray()
=> Get<BymlArray>();
Expand Down
1 change: 1 addition & 0 deletions src/BymlLibrary/Extensions/BymlNodeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static bool IsContainerType(this BymlNodeType type)
return type is
BymlNodeType.HashMap32 or
BymlNodeType.HashMap64 or
BymlNodeType.ArrayChangelog or
BymlNodeType.RelocatedHashMap32 or
BymlNodeType.RelocatedHashMap64 or
BymlNodeType.Array or
Expand Down
8 changes: 8 additions & 0 deletions src/BymlLibrary/ImmutableByml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ ref BymlContainer header
return new ImmutableBymlArray(_data, _value.Offset, header.Count);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ImmutableBymlArrayChangelog GetArrayChangelog()
{
ref BymlContainer header
= ref CheckContainerHeader(BymlNodeType.ArrayChangelog);
return new ImmutableBymlArrayChangelog(_data, _value.Offset, header.Count);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ImmutableBymlMap GetMap()
{
Expand Down
106 changes: 106 additions & 0 deletions src/BymlLibrary/Nodes/Containers/BymlArrayChangelog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using BymlLibrary.Extensions;
using BymlLibrary.Writers;
using BymlLibrary.Yaml;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using VYaml.Emitter;

namespace BymlLibrary.Nodes.Containers;

public class BymlArrayChangelog : SortedDictionary<int, Byml>, IBymlNode
{
public BymlArrayChangelog()
{
}

public BymlArrayChangelog(IDictionary<int, Byml> values) : base(values)
{
}

public void EmitYaml(ref Utf8YamlEmitter emitter)
{
emitter.Tag("!array_changelog");
emitter.BeginMapping((Count < Byml.YamlConfig.InlineContainerMaxCount && !HasContainerNodes()) switch {
true => MappingStyle.Flow,
false => MappingStyle.Block,
});

foreach (var (hash, node) in this) {
emitter.WriteInt32(hash);
BymlYamlWriter.Write(ref emitter, node);
}

emitter.EndMapping();
}

public bool HasContainerNodes()
{
foreach (var (_, node) in this) {
if (node.Type.IsContainerType()) {
return true;
}
}

return false;
}

public int GetValueHash()
{
HashCode hashCode = new();
foreach (var (key, node) in this) {
hashCode.Add(key);
hashCode.Add(Byml.ValueEqualityComparer.Default.GetHashCode(node));
}

return hashCode.ToHashCode();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
int IBymlNode.Collect(in BymlWriter writer)
{
HashCode hashCode = new();
foreach (var (key, node) in this) {
hashCode.Add(key);
hashCode.Add(writer.Collect(node));
}

return hashCode.ToHashCode();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
void IBymlNode.Write(BymlWriter context, Action<Byml> write)
{
context.WriteContainerHeader(BymlNodeType.ArrayChangelog, Count);
foreach (var (key, node) in this) {
context.Writer.Write(key);
write(node);
}

foreach (Byml node in Values) {
context.Writer.Write(node.Type);
}

context.Writer.Align(4);
}

public class ValueEqualityComparer : IEqualityComparer<BymlArrayChangelog>
{
public bool Equals(BymlArrayChangelog? x, BymlArrayChangelog? y)
{
if (x is null || y is null) {
return y == x;
}

if (x.Count != y.Count) {
return false;
}

return x.Keys.SequenceEqual(y.Keys) && x.Values.SequenceEqual(y.Values, Byml.ValueEqualityComparer.Default);
}

public int GetHashCode([DisallowNull] BymlArrayChangelog obj)
{
throw new NotImplementedException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public readonly ref struct ImmutableBymlHashMap32(Span<byte> data, int offset, i
/// </summary>
private readonly Span<BymlNodeType> _types = count == 0 ? []
: data[(offset + BymlContainer.SIZE + (Entry.SIZE * count))..]
.ReadSpan<BymlNodeType>(count + 1);
.ReadSpan<BymlNodeType>(count);

public readonly ImmutableBymlHashMap32Entry this[int index] {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
using BymlLibrary.Extensions;
using BymlLibrary.Nodes.Containers;
using BymlLibrary.Structures;
using BymlLibrary.Yaml;
using Revrs;
using Revrs.Extensions;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using VYaml.Emitter;

namespace BymlLibrary.Nodes.Immutable.Containers;

public readonly ref struct ImmutableBymlArrayChangelog(Span<byte> data, int offset, int count)
{
/// <summary>
/// Span of the BYMl data
/// </summary>
private readonly Span<byte> _data = data;

/// <summary>
/// The container item count
/// </summary>
public readonly int Count = count;

/// <summary>
/// Container offset entries
/// </summary>
private readonly Span<Entry> _entries = count == 0 ? []
: data[(offset + BymlContainer.SIZE)..]
.ReadSpan<Entry>(count);

/// <summary>
/// Container entry types
/// </summary>
private readonly Span<BymlNodeType> _types = count == 0 ? []
: data[(offset + BymlContainer.SIZE + (Entry.SIZE * count))..]
.ReadSpan<BymlNodeType>(count);

public readonly ImmutableBymlArrayChangelogEntry this[int index] {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
Entry entry = _entries[index];
return new(entry.Index, _data, entry.Value, _types[index]);
}
}

[StructLayout(LayoutKind.Sequential, Pack = 4, Size = SIZE)]
private readonly struct Entry
{
public const int SIZE = 8;

public readonly int Index;
public readonly int Value;

public class Reverser : IStructReverser
{
public static void Reverse(in Span<byte> slice)
{
slice[0..4].Reverse();
slice[4..8].Reverse();
}
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Enumerator GetEnumerator()
=> new(this);

[method: MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref struct Enumerator(ImmutableBymlArrayChangelog container)
{
private readonly ImmutableBymlArrayChangelog _container = container;
private int _index = -1;

public readonly ImmutableBymlArrayChangelogEntry Current {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _container[_index];
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (++_index >= _container.Count) {
return false;
}

return true;
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BymlArrayChangelog ToMutable(in ImmutableByml root)
{
BymlArrayChangelog arrayChangelog = [];
foreach (var (key, value) in this) {
arrayChangelog[key] = Byml.FromImmutable(value, root);
}

return arrayChangelog;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe void EmitYaml(ref Utf8YamlEmitter emitter, in ImmutableByml root)
{
emitter.Tag("!array-changelog");
emitter.BeginMapping((Count < Byml.YamlConfig.InlineContainerMaxCount && !HasContainerNodes()) switch {
true => MappingStyle.Flow,
false => MappingStyle.Block,
});

foreach (var (index, node) in this) {
emitter.WriteInt32(index);
BymlYamlWriter.Write(ref emitter, node, root);
}

emitter.EndMapping();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool HasContainerNodes()
{
foreach (var (_, node) in this) {
if (node.Type.IsContainerType()) {
return true;
}
}

return false;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Reverse(ref RevrsReader reader, int offset, int count, in HashSet<int> reversedOffsets)
{
for (int i = 0; i < count; i++) {
Entry entry = reader.Read<Entry, Entry.Reverser>(
offset + BymlContainer.SIZE + (Entry.SIZE * i)
);

ImmutableByml.ReverseNode(ref reader, entry.Value,
reader.Read<BymlNodeType>(offset + BymlContainer.SIZE + (Entry.SIZE * count) + i),
reversedOffsets
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace BymlLibrary.Nodes.Immutable.Containers;

public readonly ref struct ImmutableBymlArrayChangelogEntry(int index, Span<byte> data, int value, BymlNodeType type)
{
public readonly int Index = index;
public readonly ImmutableByml Node = new(data, value, type);

public void Deconstruct(out int index, out ImmutableByml node)
{
index = Index;
node = Node;
}
}
15 changes: 15 additions & 0 deletions src/BymlLibrary/Yaml/BymlYamlReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ private static Byml ParseMap(ref YamlParser parser)
"h32" => ParseHashMap32(ref parser),
"h64" => ParseHashMap64(ref parser),
"file" => ParseFile(ref parser),
"array-changelog" => ParseArrayChangelog(ref parser),
_ => throw new InvalidDataException($"""
Unexpected YAML map tag '{tag}' (expected '!h32', '!h64' or '!!file')
"""),
Expand Down Expand Up @@ -161,6 +162,20 @@ private static Byml ParseHashMap64(ref YamlParser parser)
return map;
}

[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static Byml ParseArrayChangelog(ref YamlParser parser)
{
BymlArrayChangelog arrayChangelog = [];
parser.SkipAfter(ParseEventType.MappingStart);

while (parser.CurrentEventType is not ParseEventType.MappingEnd) {
arrayChangelog[parser.ReadScalarAsInt32()] = Parse(ref parser);
}

parser.SkipAfter(ParseEventType.MappingEnd);
return arrayChangelog;
}

[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static Byml ParseFile(ref YamlParser parser)
{
Expand Down
3 changes: 3 additions & 0 deletions src/BymlLibrary/Yaml/BymlYamlWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public static void Write(ref Utf8YamlEmitter emitter, in ImmutableByml byml, in
case BymlNodeType.HashMap64:
byml.GetHashMap64().EmitYaml(ref emitter, root);
break;
case BymlNodeType.ArrayChangelog:
byml.GetArrayChangelog().EmitYaml(ref emitter, root);
break;
case BymlNodeType.String:
WriteRawString(ref emitter, byml.GetStringIndex(), root.StringTable);
break;
Expand Down

0 comments on commit 09c184b

Please sign in to comment.