Skip to content

Commit 57888f3

Browse files
committed
DynamicArray: support reverse feature with optional indexed forEach function
1 parent b2c1745 commit 57888f3

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-4
lines changed

src/lib/provable/dynamic-array.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,18 +270,40 @@ class DynamicArrayBase<ProvableValue = any, Value = any> {
270270
return newArray;
271271
}
272272

273+
forEach(f: (t: ProvableValue, isDummy: Bool) => void): void;
274+
forEach(f: (t: ProvableValue, isDummy: Bool, i: number) => void): void;
273275
/**
274276
* Iterate over all elements of the array.
275277
*
276278
* The callback will be passed an element and a boolean `isDummy` indicating
277-
* whether the value is part of the actual array.
279+
* whether the value is part of the actual array. Optionally, an index can be
280+
* passed as a third argument (used in `forEachReversed`)
278281
*/
279-
forEach(f: (t: ProvableValue, isDummy: Bool) => void) {
280-
zip(this.array, this.#dummyMask()).forEach(([t, isDummy]) => {
281-
f(t, isDummy);
282+
forEach(f: (...args: any[]) => void): void {
283+
zip(this.array, this.#dummyMask()).forEach(([t, isDummy], i) => {
284+
if (f.length === 2) {
285+
f(t, isDummy);
286+
} else {
287+
f(t, isDummy, i);
288+
}
282289
});
283290
}
284291

292+
/**
293+
* Iterate over all elements of the array, in reverse order.
294+
*
295+
* The callback will be passed an element and a boolean `isDummy` indicating whether the value is part of the actual array.
296+
*
297+
* Note: the indices are also passed in reverse order, i.e. we always have `t = this.array[i]`.
298+
*/
299+
forEachReverse(f: (t: ProvableValue, isDummy: Bool, i: number) => void) {
300+
zip(this.array, this.#dummyMask())
301+
.reverse()
302+
.forEach(([t, isDummy], i) => {
303+
f(t, isDummy, this.capacity - 1 - i);
304+
});
305+
}
306+
285307
/**
286308
* Return a version of the same array with a larger capacity.
287309
*
@@ -519,6 +541,21 @@ class DynamicArrayBase<ProvableValue = any, Value = any> {
519541
return sliced;
520542
}
521543

544+
/**
545+
* Returns a new array with the elements reversed.
546+
*/
547+
reverse(): DynamicArray<ProvableValue, Value> {
548+
let Array = DynamicArray(this.innerType, { capacity: this.capacity });
549+
// first, copy the inner array of length capacity and reverse it
550+
let array = this.array.slice().reverse();
551+
552+
// now, slice off the padding that is now at the beginning of the array
553+
let capacity = new Field(this.capacity);
554+
return new Array(array, capacity).slice(
555+
capacity.sub(this.length).seal()
556+
);
557+
}
558+
522559
/**
523560
* Concatenates the current array with another dynamic array, returning a new
524561
* dynamic array with the values of both arrays. The capacity of the new array

src/lib/provable/test/dynamic-array.unit-test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,14 @@ import { Provable } from '../provable.js';
581581
// Checking inclusion of elements
582582
assert(bytes.includes(new UInt8(1)));
583583
assert(bytes.includes(new UInt8(20)).not());
584+
585+
// Reverse the array
586+
let reversed = bytes.reverse();
587+
for (let i = 0; i < 8; i++) {
588+
assert(reversed.get(new Field(i)).value.equals(new Field(8 - i)));
589+
// the original array is not modified
590+
assert(bytes.get(new Field(i)).value.equals(new Field(i + 1)));
591+
}
584592
},
585593
},
586594
},

0 commit comments

Comments
 (0)