Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serializer cleanup #103

Merged
merged 6 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public IndexSegmentABenchmarks()
for (int a = 1; a < 100; a++)
{
var prefix = new KeyPrefix(EntityId.From(42), AttributeId.From((ushort)a), TxId.From(42), false,
ValueTags.Null);
ValueTag.Null);
builder.Add(new Datom(prefix, ReadOnlyMemory<byte>.Empty));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public IndexSegmentEBenchmarks()
for (var a = 0; a < 20; a++)
{
builder.Add(new Datom(new KeyPrefix(EntityId.From((ulong)e), AttributeId.From((ushort)a), TxId.From((ulong)(e + a)), false,
ValueTags.Null), ReadOnlyMemory<byte>.Empty));
ValueTag.Null), ReadOnlyMemory<byte>.Empty));
}
}

Expand Down
165 changes: 33 additions & 132 deletions src/NexusMods.MnemonicDB.Abstractions/Attribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,10 @@ namespace NexusMods.MnemonicDB.Abstractions;
/// Interface for a specific attribute
/// </summary>
/// <typeparam name="TValueType"></typeparam>
public abstract partial class Attribute<TValueType, TLowLevelType> : IAttribute<TValueType>
public abstract class Attribute<TValueType, TLowLevelType> : IAttribute<TValueType>
{
private const int MaxStackAlloc = 128;
private static Encoding AsciiEncoding = Encoding.ASCII;

private static Encoding Utf8Encoding = Encoding.UTF8;

protected Attribute(
ValueTags lowLevelType,
ValueTag lowLevelType,
string ns,
string name,
bool isIndexed = false,
Expand All @@ -44,116 +39,14 @@ protected Attribute(
/// Converts a high-level value to a low-level value
/// </summary>
protected abstract TLowLevelType ToLowLevel(TValueType value);

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(byte value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(ushort value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(uint value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}


/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(string value, ValueTags tag, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(ReadOnlySpan<byte> value, ValueTags tag, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + tag + " on attribute " + Id);
}


/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(ulong value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}


/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(UInt128 value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(short value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(int value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(long value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(Int128 value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

/// <summary>
/// Converts a low-level value to a high-level value
/// </summary>
protected virtual TValueType FromLowLevel(float value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}


/// <summary>
/// Converts a low-level value to a high-level value
/// Converts a high-level value to a low-level value
/// </summary>
protected virtual TValueType FromLowLevel(double value, ValueTags tags, AttributeResolver resolver)
{
throw new NotSupportedException("Unsupported low-level type " + value + " on attribute " + Id);
}

protected abstract TValueType FromLowLevel(TLowLevelType value, AttributeResolver resolver);

/// <inheritdoc />
public ValueTags LowLevelType { get; }
public ValueTag LowLevelType { get; }

/// <inheritdoc />
public Symbol Id { get; }
Expand All @@ -174,7 +67,7 @@ protected virtual TValueType FromLowLevel(double value, ValueTags tags, Attribut
public Type ValueType => typeof(TValueType);

/// <inheritdoc />
public bool IsReference => LowLevelType == ValueTags.Reference;
public bool IsReference => LowLevelType == ValueTag.Reference;

/// <inheritdoc />
IReadDatom IAttribute.Resolve(in KeyPrefix prefix, ReadOnlySpan<byte> valueSpan, AttributeResolver resolver)
Expand All @@ -198,6 +91,27 @@ public ReadDatom Resolve(in Datom datom, AttributeResolver resolver)
var prefix = datom.Prefix;
return new ReadDatom(in prefix, ReadValue(datom.ValueSpan, datom.Prefix.ValueTag, resolver), this);
}

/// <summary>
/// Reads the high level value from the given span
/// </summary>
public TValueType ReadValue(ReadOnlySpan<byte> span, ValueTag tag, AttributeResolver resolver)
{
return FromLowLevel(tag.Read<TLowLevelType>(span), resolver);
}

/// <summary>
/// Write a datom for this attribute to the given writer
/// </summary>
public void Write<TWriter>(EntityId entityId, AttributeCache cache, TValueType value, TxId txId, bool isRetract, TWriter writer)
where TWriter : IBufferWriter<byte>
{
var prefix = new KeyPrefix(entityId, cache.GetAttributeId(Id), txId, isRetract, LowLevelType);
var span = writer.GetSpan(KeyPrefix.Size);
MemoryMarshal.Write(span, prefix);
writer.Advance(KeyPrefix.Size);
LowLevelType.Write(ToLowLevel(value), writer);
}

/// <summary>
/// Returns true if the attribute is present on the entity
Expand All @@ -216,23 +130,7 @@ public bool IsIn<T>(T entity)
{
return entity.IndexSegment.Contains(this);
}

/// <inheritdoc />
public virtual void Remap(Func<EntityId, EntityId> remapper, Span<byte> valueSpan)
{
if (LowLevelType == ValueTags.Reference)
{
var id = MemoryMarshal.Read<EntityId>(valueSpan);
var newId = remapper(id);
MemoryMarshal.Write(valueSpan, newId);
}
}

private void ThrowKeyNotFoundException(EntityId id)
{
throw new KeyNotFoundException($"Attribute {Id} not found on entity {id}");
}


/// <summary>
/// Adds a datom to the active transaction for this entity that adds the given value to this attribute
/// </summary>
Expand Down Expand Up @@ -274,6 +172,9 @@ public override string ToString()
/// </summary>
public readonly record struct ReadDatom : IReadDatom
{
/// <summary>
/// The key prefix for this datom, contains the E, A, T, IsRetract and ValueTag values for this datom
/// </summary>
public readonly KeyPrefix Prefix;

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions src/NexusMods.MnemonicDB.Abstractions/AttributeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ public void Reset(IDb db)
_symbols = newSymbols;

var types = db.Datoms(AttributeDefinition.ValueType);
var newTypes = new ValueTags[maxIndex];
var newTypes = new ValueTag[maxIndex];
var newIsReference = new BitArray(maxIndex);
foreach (var datom in types)
{
var id = datom.E.Value;
var type = AttributeDefinition.ValueType.ReadValue(datom.ValueSpan, datom.Prefix.ValueTag, null!);
newTypes[id] = type;
newIsReference[(int)id] = type == ValueTags.Reference;
newIsReference[(int)id] = type == ValueTag.Reference;
}
_isReference = newIsReference;

Expand Down
37 changes: 0 additions & 37 deletions src/NexusMods.MnemonicDB.Abstractions/Attributes/BlobAttribute.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,11 @@ namespace NexusMods.MnemonicDB.Abstractions.Attributes;
/// <summary>
/// Used to mark the cardinality of an attribute in the database
/// </summary>
public class CardinalityAttribute(string ns, string name) : ScalarAttribute<Cardinality, byte>(ValueTags.UInt8, ns, name)
public sealed class CardinalityAttribute(string ns, string name) : ScalarAttribute<Cardinality, byte>(ValueTag.UInt8, ns, name)
{
/// <inheritdoc />
protected override byte ToLowLevel(Cardinality value)
{
return (byte)value;
}
protected override byte ToLowLevel(Cardinality value) => (byte)value;

/// <inheritdoc />
protected override Cardinality FromLowLevel(byte value, ValueTags tags, AttributeResolver resolver)
{
return (Cardinality)value;
}
protected override Cardinality FromLowLevel(byte value, AttributeResolver resolver) => (Cardinality)value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace NexusMods.MnemonicDB.Abstractions.Attributes;
/// <summary>
/// An attribute that represents a collection of values
/// </summary>
public abstract class CollectionAttribute<TValue, TLowLevel>(ValueTags tag, string ns, string name)
public abstract class CollectionAttribute<TValue, TLowLevel>(ValueTag tag, string ns, string name)
: Attribute<TValue, TLowLevel>(tag, ns, name, cardinality: Cardinality.Many)
{

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ namespace NexusMods.MnemonicDB.Abstractions.Attributes;
/// </summary>
/// <param name="ns"></param>
/// <param name="name"></param>
public class MarkerAttribute(string ns, string name) : Attribute<Null, Null>(ValueTags.Null, ns, name)
public class MarkerAttribute(string ns, string name) : Attribute<Null, Null>(ValueTag.Null, ns, name)
{
/// <inheritdoc />
protected override Null ToLowLevel(Null value)
{
return value;
}
protected override Null ToLowLevel(Null value) => value;

/// <inheritdoc />
protected override Null FromLowLevel(Null value, AttributeResolver resolver) => value;

/// <summary>
/// Returns true if the entity contains the attribute.
Expand Down
Loading
Loading