-
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
Added CreateStruct
& Fixed CreateMap
#3494
Changes from 2 commits
49aea69
792968d
551e05f
0d08f2f
7f02725
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 |
---|---|---|
|
@@ -54,18 +54,64 @@ public static ScriptBuilder CreateArray<T>(this ScriptBuilder builder, IReadOnly | |
/// <param name="builder">The <see cref="ScriptBuilder"/> to be used.</param> | ||
/// <param name="map">The key/value pairs of the map.</param> | ||
/// <returns>The same instance as <paramref name="builder"/>.</returns> | ||
public static ScriptBuilder CreateMap<TKey, TValue>(this ScriptBuilder builder, IEnumerable<KeyValuePair<TKey, TValue>> map = null) | ||
public static ScriptBuilder CreateMap<TKey, TValue>(this ScriptBuilder builder, IEnumerable<KeyValuePair<TKey, TValue>> map) | ||
where TKey : notnull | ||
where TValue : notnull | ||
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. Value can not be null? Do we have this limitation before? 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. You can't do This just stop you from using |
||
{ | ||
builder.Emit(OpCode.NEWMAP); | ||
if (map != null) | ||
foreach (var p in map) | ||
{ | ||
builder.Emit(OpCode.DUP); | ||
builder.EmitPush(p.Key); | ||
builder.EmitPush(p.Value); | ||
builder.Emit(OpCode.SETITEM); | ||
} | ||
return builder; | ||
var count = map.Count(); | ||
|
||
if (count == 0) | ||
return builder.Emit(OpCode.NEWMAP); | ||
|
||
foreach (var (key, value) in map.Reverse()) | ||
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. Does we need the reverse? 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. yes, before tests were failing because of order. 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. But it's more optimized if we change the tests, isn't it? 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. tests are fine 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 know, but the test should be changed if fail, I think that it's faster to do it without this reverse 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 guess the expectation is that we have the same order (even though "order" doesn't make much sense for a map in general) of elements in the VM map as we have in a map passed to 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. But we need to preserve the order in a map? 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. It's hard for me to answer that coming from Go that tries hard to make iterations over map to have undeterministic order. But NeoVM does have some specific order of map elements. And IIRC C# too. So matching this order makes some sense for a C# |
||
{ | ||
builder.EmitPush(value); | ||
builder.EmitPush(key); | ||
} | ||
builder.EmitPush(count); | ||
return builder.Emit(OpCode.PACKMAP); | ||
AnnaShaleva marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// <summary> | ||
/// Emits the opcodes for creating a map. | ||
/// </summary> | ||
/// <typeparam name="TKey">The type of the key of the map.</typeparam> | ||
/// <typeparam name="TValue">The type of the value of the map.</typeparam> | ||
/// <param name="builder">The <see cref="ScriptBuilder"/> to be used.</param> | ||
/// <param name="map">The key/value pairs of the map.</param> | ||
/// <returns>The same instance as <paramref name="builder"/>.</returns> | ||
public static ScriptBuilder CreateMap<TKey, TValue>(this ScriptBuilder builder, IReadOnlyDictionary<TKey, TValue> map) | ||
where TKey : notnull | ||
where TValue : notnull | ||
{ | ||
if (map.Count == 0) | ||
return builder.Emit(OpCode.NEWMAP); | ||
|
||
foreach (var (key, value) in map.Reverse()) | ||
{ | ||
builder.EmitPush(value); | ||
builder.EmitPush(key); | ||
} | ||
builder.EmitPush(map.Count); | ||
return builder.Emit(OpCode.PACKMAP); | ||
} | ||
|
||
/// <summary> | ||
/// Emits the opcodes for creating a struct. | ||
/// </summary> | ||
/// <typeparam name="T">The type of the property.</typeparam> | ||
/// <param name="builder">The <see cref="ScriptBuilder"/> to be used.</param> | ||
/// <param name="array">The list of properties.</param> | ||
/// <returns>The same instance as <paramref name="builder"/>.</returns> | ||
public static ScriptBuilder CreateStruct<T>(this ScriptBuilder builder, IReadOnlyList<T> array) | ||
where T : notnull | ||
{ | ||
if (array.Count == 0) | ||
return builder.Emit(OpCode.NEWSTRUCT0); | ||
for (var i = array.Count - 1; i >= 0; i--) | ||
builder.EmitPush(array[i]); | ||
builder.EmitPush(array.Count); | ||
return builder.Emit(OpCode.PACKSTRUCT); | ||
} | ||
|
||
/// <summary> | ||
|
@@ -218,7 +264,7 @@ public static ScriptBuilder EmitPush(this ScriptBuilder builder, object obj) | |
builder.EmitPush(data); | ||
break; | ||
case char data: | ||
builder.EmitPush((ushort)data); | ||
builder.EmitPush(data); | ||
cschuchardt88 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
break; | ||
case ushort data: | ||
builder.EmitPush(data); | ||
|
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.
if the key and value are non-null before emitting the map structure. If previous code allowed null values, this new behavior could lead to unexpected failures where null handling was previously permissible.