-
Notifications
You must be signed in to change notification settings - Fork 1k
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
[Fixes/Optimizations/Styles
] KeyBuilder, StorageKey, StorageItem, MemorySnapshot, MemoryStore, ByteArrayComparer & ByteArrayEqualityComparer
#3705
base: master
Are you sure you want to change the base?
Changes from all commits
1bf58cd
3f6811a
d3f7327
5a2e4e9
96d20d3
8037ddf
53cfb06
2058a28
e5d25b2
db7d314
abf93fb
c206715
f32faf0
6dd4bb9
de4c2df
b4e5418
f6b0c11
a8af5a6
dda49b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,10 +11,10 @@ | |
|
||
#nullable enable | ||
|
||
using Neo.Extensions; | ||
using Neo.IO; | ||
using System; | ||
using System.Buffers.Binary; | ||
using System.IO; | ||
using System.Runtime.CompilerServices; | ||
|
||
namespace Neo.SmartContract | ||
|
@@ -24,7 +24,8 @@ namespace Neo.SmartContract | |
/// </summary> | ||
public class KeyBuilder | ||
{ | ||
private readonly MemoryStream _stream; | ||
private readonly Memory<byte> _cachedData; | ||
private int _keyLen = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the same, but the true is that it will speed up the code a lot of, maybe we should check all the keyBuilds and force to be less than this length There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my opinion this 3 classes should be improved in different PR's because I'm agree with some changes and not with others |
||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="KeyBuilder"/> class. | ||
|
@@ -34,12 +35,11 @@ public class KeyBuilder | |
/// <param name="keySizeHint">The hint of the storage key size(including the id and prefix).</param> | ||
public KeyBuilder(int id, byte prefix, int keySizeHint = ApplicationEngine.MaxStorageKeySize) | ||
cschuchardt88 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
Span<byte> data = stackalloc byte[sizeof(int)]; | ||
BinaryPrimitives.WriteInt32LittleEndian(data, id); | ||
_cachedData = new byte[keySizeHint]; | ||
cschuchardt88 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
BinaryPrimitives.WriteInt32LittleEndian(_cachedData.Span, id); | ||
|
||
_stream = new(keySizeHint); | ||
_stream.Write(data); | ||
_stream.WriteByte(prefix); | ||
_keyLen = sizeof(int); | ||
_cachedData.Span[_keyLen++] = prefix; | ||
} | ||
|
||
/// <summary> | ||
|
@@ -50,7 +50,7 @@ public KeyBuilder(int id, byte prefix, int keySizeHint = ApplicationEngine.MaxSt | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public KeyBuilder Add(byte key) | ||
{ | ||
_stream.WriteByte(key); | ||
_cachedData.Span[_keyLen++] = key; | ||
return this; | ||
} | ||
|
||
|
@@ -62,7 +62,8 @@ public KeyBuilder Add(byte key) | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public KeyBuilder Add(ReadOnlySpan<byte> key) | ||
{ | ||
_stream.Write(key); | ||
key.CopyTo(_cachedData.Span[_keyLen..]); | ||
_keyLen += key.Length; | ||
return this; | ||
} | ||
|
||
|
@@ -97,11 +98,11 @@ public KeyBuilder Add(ReadOnlySpan<byte> key) | |
/// <returns>A reference to this instance after the add operation has completed.</returns> | ||
public KeyBuilder Add(ISerializable key) | ||
{ | ||
using (BinaryWriter writer = new(_stream, Utility.StrictUTF8, true)) | ||
{ | ||
key.Serialize(writer); | ||
writer.Flush(); | ||
} | ||
var raw = key.ToArray(); | ||
|
||
raw.CopyTo(_cachedData[_keyLen..]); | ||
_keyLen += raw.Length; | ||
|
||
return this; | ||
} | ||
|
||
|
@@ -167,15 +168,12 @@ public KeyBuilder AddBigEndian(ulong key) | |
/// <returns>The storage key.</returns> | ||
public byte[] ToArray() | ||
{ | ||
using (_stream) | ||
{ | ||
return _stream.ToArray(); | ||
} | ||
return _cachedData[.._keyLen].ToArray(); | ||
} | ||
|
||
public static implicit operator StorageKey(KeyBuilder builder) | ||
{ | ||
return new StorageKey(builder.ToArray()); | ||
return new StorageKey(builder._cachedData[..builder._keyLen].ToArray()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -33,7 +33,7 @@ public sealed record StorageKey | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public ReadOnlyMemory<byte> Key { get; init; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private byte[]? _cache; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private Memory<byte> _cache; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// NOTE: StorageKey is readonly, so we can cache the hash code. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private int _hashCode = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -49,9 +49,9 @@ public StorageKey() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/// <param name="cache">The cached byte array. NOTE: It must be read-only and can be modified by the caller.</param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
internal StorageKey(byte[] cache) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
_cache = cache; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Id = BinaryPrimitives.ReadInt32LittleEndian(cache); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Key = cache.AsMemory(sizeof(int)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
_cache = cache.AsMemory().ToArray(); // allocate new buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cschuchardt88 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Id = BinaryPrimitives.ReadInt32LittleEndian(_cache.Span); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Key = _cache[sizeof(int)..].ToArray(); // allocate new buffer. NOTE: DONT USE POINTERS HERE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -68,10 +68,10 @@ internal StorageKey(ReadOnlySpan<byte> cache) : this(cache.ToArray()) { } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/// <returns>The created search prefix.</returns> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static byte[] CreateSearchPrefix(int id, ReadOnlySpan<byte> prefix) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
var buffer = new byte[sizeof(int) + prefix.Length]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Span<byte> buffer = stackalloc byte[sizeof(int) + prefix.Length]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BinaryPrimitives.WriteInt32LittleEndian(buffer, id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
prefix.CopyTo(buffer.AsSpan(sizeof(int))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return buffer; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
prefix.CopyTo(buffer[sizeof(int)..]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return buffer.ToArray(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public bool Equals(StorageKey? other) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -92,22 +92,22 @@ public override int GetHashCode() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public byte[] ToArray() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (_cache is null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (_cache is { IsEmpty: true }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
_cache = new byte[sizeof(int) + Key.Length]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BinaryPrimitives.WriteInt32LittleEndian(_cache, Id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Key.CopyTo(_cache.AsMemory(sizeof(int))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
_cache = new byte[sizeof(int) + Key.Length]; // allocate new buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BinaryPrimitives.WriteInt32LittleEndian(_cache.Span, Id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Key.CopyTo(_cache[sizeof(int)..]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return _cache; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return _cache.ToArray(); // allocate new buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every time that is invoked a new buffer is created, so the "cache" is not complete, and slower There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How is it slower? No memory is moved. Its like creating a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So my way is faster NEW
OLD
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static implicit operator StorageKey(byte[] value) => new(value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static implicit operator StorageKey(ReadOnlyMemory<byte> value) => new(value.Span); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static implicit operator StorageKey(ReadOnlyMemory<byte> value) => new(value.ToArray()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static implicit operator StorageKey(ReadOnlySpan<byte> value) => new(value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static implicit operator StorageKey(ReadOnlySpan<byte> value) => new(value.ToArray()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default
should be marked as obsolete because it's public