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

Added ReferenceCounter, Tests and Fixed GetHashCode #4

Merged
merged 9 commits into from
Oct 13, 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
96 changes: 96 additions & 0 deletions src/NeoEvents.VirtualMachine.Types/Array.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Licensed to the "Neo Events" under one or more agreements.
// The "Neo Events" licenses this file to you under the GPL-3.0 license.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace NeoEvents.VirtualMachine.Types;

[DebuggerDisplay("Type={Type}, Count={Count}")]
public class Array(
IEnumerable<PrimitiveType>? items = default)
: CompoundType(), ICollection<PrimitiveType>, IReadOnlyCollection<PrimitiveType>, IReadOnlyList<PrimitiveType>
{
public override int Count => ArrayItems.Count;
public override ICollection<PrimitiveType> Items => ArrayItems;
public override StackItemType Type => StackItemType.Array;
public override ReadOnlyMemory<byte> Memory => GetMemory();

protected private readonly List<PrimitiveType> ArrayItems = items switch
{
null => [],
List<PrimitiveType> list => list,
_ => [.. items],
};

public PrimitiveType this[int index]
{
get => ArrayItems[index];
set
{
if (IsReadOnly) throw new NotSupportedException();
ArrayItems[index] = value;
}
}

public override bool Equals(PrimitiveType? other)
{
if (ReferenceEquals(this, other)) return true;
if (other is null) return false;
if (other is not Array array) return false;
return ArrayItems.SequenceEqual(array.ArrayItems);
}

public override int GetHashCode()
{
var h = new HashCode();
h.Add(Type);
h.AddBytes(Memory.Span);
return h.ToHashCode();
}

public override void Clear()
{
if (IsReadOnly) throw new NotSupportedException();
ArrayItems.Clear();
}

public void Add(PrimitiveType item)
{
if (IsReadOnly) throw new NotSupportedException();
ArrayItems.Add(item);
}

public bool Contains(PrimitiveType item) =>
ArrayItems.Contains(item);

public void CopyTo(PrimitiveType[] array, int arrayIndex) =>
ArrayItems.CopyTo(array, arrayIndex);

public bool Remove(PrimitiveType item)
{
if (IsReadOnly) throw new NotSupportedException();
return ArrayItems.Remove(item);
}

public IEnumerator<PrimitiveType> GetEnumerator() =>
ArrayItems.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() =>
GetEnumerator();

private byte[] GetMemory()
{
byte[] memory = [];
ArrayItems.ForEach(f =>
{
if (f is null) return;
memory = [.. memory, .. f.Memory.Span];
});

return memory;
}
}
44 changes: 44 additions & 0 deletions src/NeoEvents.VirtualMachine.Types/Boolean.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Licensed to the "Neo Events" under one or more agreements.
// The "Neo Events" licenses this file to you under the GPL-3.0 license.

using System;
using System.Diagnostics;
using System.Numerics;

namespace NeoEvents.VirtualMachine.Types;

[DebuggerDisplay("Type={Type}, Value={_value}")]
public class Boolean(bool value) : PrimitiveType()
{
public static readonly Boolean True = new(true);
public static readonly Boolean False = new(false);

public override StackItemType Type => StackItemType.Boolean;
public override ReadOnlyMemory<byte> Memory => _value ? (byte[])[1] : [0];
public override int Size => sizeof(bool);

private readonly bool _value = value;

public override bool Equals(PrimitiveType? other)
{
if (ReferenceEquals(this, other)) return true;
if (other is Boolean b) return _value == b._value;
return false;
}

public override int GetHashCode() =>
HashCode.Combine(Type, _value);

public override bool GetBoolean() => _value;

public override BigInteger GetInteger() =>
_value ? BigInteger.One : BigInteger.Zero;

public override string? GetString() =>
_value ? bool.TrueString : bool.FalseString;

public static implicit operator Boolean(bool value) =>
value ? True : False;


}
17 changes: 12 additions & 5 deletions src/NeoEvents.VirtualMachine.Types/ByteString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

using NeoEvents.Text;
using System;
using System.Diagnostics;
using System.Numerics;

namespace NeoEvents.VirtualMachine.Types;

[DebuggerDisplay("Type={Type}, Size={Size}")]
public class ByteString(
ReadOnlyMemory<byte> memory) : PrimitiveType
ReadOnlyMemory<byte> memory) : PrimitiveType()
{
public override StackItemType Type => StackItemType.ByteString;

Expand All @@ -21,14 +23,19 @@ public override bool Equals(PrimitiveType? other)
return GetSpan().SequenceEqual(other.GetSpan());
}

public override int GetHashCode()
{
var h = new HashCode();
h.Add(Type);
h.AddBytes(Memory.Span);
return h.ToHashCode();
}

public override bool GetBoolean()
{
if (Size > Integer.MaxSize) throw new InvalidCastException();

foreach (var b in Memory.Span)
if (b != 0) return true;

return false;
return Memory.Span.ContainsAnyExcept((byte)0);
}

public override BigInteger GetInteger()
Expand Down
21 changes: 21 additions & 0 deletions src/NeoEvents.VirtualMachine.Types/CompoundType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the "Neo Events" under one or more agreements.
// The "Neo Events" licenses this file to you under the GPL-3.0 license.

using System;
using System.Collections.Generic;

namespace NeoEvents.VirtualMachine.Types;

public abstract class CompoundType() : PrimitiveType()
{
public abstract int Count { get; }
public abstract ICollection<PrimitiveType> Items { get; }
public bool IsReadOnly { get; protected set; }

public abstract void Clear();

public sealed override bool GetBoolean() => true;

public override int GetHashCode() =>
throw new NotSupportedException();
}
5 changes: 4 additions & 1 deletion src/NeoEvents.VirtualMachine.Types/Integer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class Integer : PrimitiveType
private readonly BigInteger _value;

public Integer(
BigInteger value)
BigInteger value) : base()
{
if (value.IsZero)
Size = 0;
Expand All @@ -40,6 +40,9 @@ public override bool Equals(PrimitiveType? other)
return _value == ((Integer)other)._value;
}

public override int GetHashCode() =>
_value.GetHashCode();

public override bool GetBoolean() =>
!_value.IsZero;

Expand Down
120 changes: 120 additions & 0 deletions src/NeoEvents.VirtualMachine.Types/Map.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Licensed to the "Neo Events" under one or more agreements.
// The "Neo Events" licenses this file to you under the GPL-3.0 license.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

namespace NeoEvents.VirtualMachine.Types;

[DebuggerDisplay("Type={Type}, Count={Count}")]
public class Map() : CompoundType(), IReadOnlyDictionary<PrimitiveType, PrimitiveType>, IReadOnlyCollection<KeyValuePair<PrimitiveType, PrimitiveType>>, IDictionary<PrimitiveType, PrimitiveType>, ICollection<KeyValuePair<PrimitiveType, PrimitiveType>>
{
public const int MaxKeySize = 64;

public IEnumerable<PrimitiveType> Keys => _dictionary.Keys;
public IEnumerable<PrimitiveType> Values => _dictionary.Values;
public override int Count => _dictionary.Count;
public override ICollection<PrimitiveType> Items => [.. Keys, .. Values];
public override StackItemType Type => StackItemType.Map;
public override ReadOnlyMemory<byte> Memory => GetMemory();

ICollection<PrimitiveType> IDictionary<PrimitiveType, PrimitiveType>.Keys => _dictionary.Keys;

ICollection<PrimitiveType> IDictionary<PrimitiveType, PrimitiveType>.Values => _dictionary.Values;

private readonly Dictionary<PrimitiveType, PrimitiveType> _dictionary = new(EqualityComparer<PrimitiveType>.Default);

public PrimitiveType this[PrimitiveType key]
{
get
{
if (key.Size > MaxKeySize)
throw new ArgumentException($"Key size is too large: {key.Size} > {MaxKeySize}", nameof(key));
return _dictionary[key];
}
set
{
if (key.Size > MaxKeySize)
throw new ArgumentException($"Key size is too large: {key.Size} > {MaxKeySize}", nameof(key));
if (IsReadOnly)
throw new NotSupportedException();
_dictionary[key] = value;
}
}

public override bool Equals(PrimitiveType? other)
{
if (ReferenceEquals(this, other)) return true;
if (other is null or not Map) return false;
return _dictionary.SequenceEqual(((Map)other)._dictionary);
}

public override int GetHashCode()
{
var h = new HashCode();
h.Add(Type);
h.AddBytes(Memory.Span);
return h.ToHashCode();
}

public override void Clear()
{
if (IsReadOnly)
throw new NotSupportedException();
_dictionary.Clear();
}

public bool ContainsKey(PrimitiveType key)
{
if (key.Size > MaxKeySize)
throw new ArgumentException($"Key size is too large: {key.Size} > {MaxKeySize}", nameof(key));
return _dictionary.ContainsKey(key);
}

public bool TryGetValue(PrimitiveType key, [MaybeNullWhen(false)] out PrimitiveType value)
{
if (key.Size > MaxKeySize)
throw new ArgumentException($"Key size is too large: {key.Size} > {MaxKeySize}", nameof(key));
return _dictionary.TryGetValue(key, out value);
}

public IEnumerator<KeyValuePair<PrimitiveType, PrimitiveType>> GetEnumerator() =>
_dictionary.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() =>
GetEnumerator();

public void Add(PrimitiveType key, PrimitiveType value) =>
_dictionary.Add(key, value);

public bool Remove(PrimitiveType key) =>
_dictionary.Remove(key);

public void Add(KeyValuePair<PrimitiveType, PrimitiveType> item) =>
Add(item.Key, item.Value);

public bool Contains(KeyValuePair<PrimitiveType, PrimitiveType> item) =>
_dictionary.ToArray().Contains(item);

public void CopyTo(KeyValuePair<PrimitiveType, PrimitiveType>[] array, int arrayIndex) =>
_dictionary.ToArray().CopyTo(array, arrayIndex);

public bool Remove(KeyValuePair<PrimitiveType, PrimitiveType> item) =>
_dictionary.Remove(item.Key);

private byte[] GetMemory()
{
byte[] memory = [];
foreach (var item in Items)
{
if (item is null) continue;
memory = [.. memory, .. item.Memory.Span];
}

return memory;
}
}
2 changes: 1 addition & 1 deletion src/NeoEvents.VirtualMachine.Types/Null.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class Null : PrimitiveType

public override ReadOnlyMemory<byte> Memory => Memory<byte>.Empty;

internal Null() { }
internal Null() : base() { }

public override bool Equals(PrimitiveType? other)
{
Expand Down
Loading