-
Notifications
You must be signed in to change notification settings - Fork 145
Introduce reverseInPlace in Variable/Fixed size Array
#2626
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
base: master
Are you sure you want to change the base?
Changes from 2 commits
74ca799
db38baf
78bab43
e68bcf4
64bf9c1
6cff2d2
5056603
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 |
|---|---|---|
|
|
@@ -10395,6 +10395,67 @@ func TestInterpretArrayFirstIndexDoesNotExist(t *testing.T) { | |
| ) | ||
| } | ||
|
|
||
| func TestInterpretArrayReverse(t *testing.T) { | ||
|
Member
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. Could you please also add test cases where the elements are structs and resources?
Contributor
Author
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. Hmm, thanks for pointing it out. When I added the test case for struct, it doesn't work. pub struct TestStruct {
pub var test: Int
init(_ t: Int) {
self.test = t
}
}
fun reverseStructArray(): [Int] {
let sa = [TestStruct(1), TestStruct(2), TestStruct(3)]
sa.reverse()
let res: [Int] = [];
for s in sa {
res.append(s.test)
}
return res
}I get
Contributor
Author
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. By adding transfer call, I was able to get it to work for struct. leftValue := v.Get(interpreter, locationRange, leftIndex)
rightValue := v.Get(interpreter, locationRange, rightIndex)
leftValue = leftValue.Transfer(
interpreter,
locationRange,
v.array.Address(),
true,
nil,
)
rightValue = rightValue.Transfer(
interpreter,
locationRange,
v.array.Address(),
true,
nil,
)
v.Set(interpreter, locationRange, leftIndex, rightValue)
v.Set(interpreter, locationRange, rightIndex, leftValue)It doesn't work for resource because after the first I'll look further into how we swap resources atomically. Another option might be to just not support reverse for resource typed arrays. Most of the array functions do that already.
Member
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 the problem is, structs and resources behave differently when "Transferred". Structs are copied, whereas references are just 'moved'. Here what you would want to do is, instead of Now one thing to note is that, because the remaining values are shifted by one index by removing, if you try to remove the first element (leftValue) first, and then try to remove the last element (rightElement), it will mess-up the indexing for the second/right value removal. (could get an array-out-of-bound error / or could end up removing the wrong value) because after the first removal, the size of the array is (n-1). // Remove the right index (from the rear end) first, because removing the left index (from the front of the array) first could mess up the indexes of the rest of the elements.
rightValue := v.Remove(interpreter, locationRange, rightIndex)
leftValue := v.Remove(interpreter, locationRange, leftIndex)
// Similarly, insert the left index first, before the right index.
v.Insert(interpreter, locationRange, leftIndex, rightValue)
v.Insert(interpreter, locationRange, rightIndex, leftValue)
Member
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. Also no need for an additional "Transfer" because
Contributor
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. This feels too expensive to me; transfers here are not necessary, Why move stuff to stack and then move again to strange with totally new storageID and slab tree? We are 100% sure that storage address will not change in this operation. Why not add
Contributor
Author
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 thought so as well and asked Bastian about adding support for We can also think about adding it using
Member
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. Alternatively, as it has been briefly discussed in issue #2605, maybe we could start with the function that returns a new array with entries reversed, which should be easy to implement. And then later add this as the "optimized" version which does the same in-place. So the functionality is there, if someone needs it.
Contributor
Author
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.
Member
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.
Good point 👍 . I opened onflow/atree#326 to add |
||
|
|
||
| t.Parallel() | ||
|
|
||
| inter := parseCheckAndInterpret(t, ` | ||
| let xs = [1, 2, 3, 100, 200] | ||
| let ys = [100, 467, 297, 23] | ||
|
|
||
| fun reversexs() { | ||
| return xs.reverse() | ||
| } | ||
|
|
||
| fun reverseys() { | ||
| return ys.reverse() | ||
| } | ||
| `) | ||
|
|
||
| _, err := inter.Invoke("reversexs") | ||
| require.NoError(t, err) | ||
|
|
||
| AssertValuesEqual( | ||
| t, | ||
| inter, | ||
| interpreter.NewArrayValue( | ||
| inter, | ||
| interpreter.EmptyLocationRange, | ||
| interpreter.VariableSizedStaticType{ | ||
| Type: interpreter.PrimitiveStaticTypeInt, | ||
| }, | ||
| common.ZeroAddress, | ||
| interpreter.NewUnmeteredIntValueFromInt64(200), | ||
| interpreter.NewUnmeteredIntValueFromInt64(100), | ||
| interpreter.NewUnmeteredIntValueFromInt64(3), | ||
| interpreter.NewUnmeteredIntValueFromInt64(2), | ||
| interpreter.NewUnmeteredIntValueFromInt64(1), | ||
| ), | ||
| inter.Globals.Get("xs").GetValue(), | ||
| ) | ||
|
|
||
| _, err = inter.Invoke("reverseys") | ||
| require.NoError(t, err) | ||
|
|
||
| AssertValuesEqual( | ||
| t, | ||
| inter, | ||
| interpreter.NewArrayValue( | ||
| inter, | ||
| interpreter.EmptyLocationRange, | ||
| interpreter.VariableSizedStaticType{ | ||
| Type: interpreter.PrimitiveStaticTypeInt, | ||
| }, | ||
| common.ZeroAddress, | ||
| interpreter.NewUnmeteredIntValueFromInt64(23), | ||
| interpreter.NewUnmeteredIntValueFromInt64(297), | ||
| interpreter.NewUnmeteredIntValueFromInt64(467), | ||
| interpreter.NewUnmeteredIntValueFromInt64(100), | ||
| ), | ||
| inter.Globals.Get("ys").GetValue(), | ||
| ) | ||
| } | ||
|
|
||
| func TestInterpretOptionalReference(t *testing.T) { | ||
|
|
||
| t.Parallel() | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.