Array stream library written in pure Cairo
Project description
⚠️ WARNING! ⚠️
This repo contains highly experimental code. Expect rapid iteration. Use at your own risk.
Installation
If you are using Protostar
protostar install https://github.com/onlydustxyz/cairo-streams
If you are using StarkNet with a Python env or Nile
pip install onlydust-cairo-streams
Usage
To import the library in a cairo file, add this line:
from onlydust.stream.default_implementation import stream
Default implementations
foreach
The foreach() method executes a provided function once for each array element.
Signature:
func foreach(function : codeoffset, array_len : felt, array : felt*)
The provided function must have this signature exactly (including implicit params):
func whatever{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(index : felt, element : felt*)
Example
func test_foreach{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
alloc_locals
let (local array : felt*) = alloc()
assert array[0] = 1
assert array[1] = 1
assert array[2] = 1
assert array[3] = 7
stream.foreach(do_something, 4, array)
return ()
end
func do_something{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(index : felt, el : felt*):
...
return ()
end
Look here for a full working example.
foreach_struct
The foreach_struct() method executes a provided function once for each array element. Unlike foreach(), the array can be an array of structs.
Signature:
func foreach_struct(function : codeoffset, array_len : felt, array : felt*, element_size : felt)
Assuming the struct is named Foo
, the provided function must have this signature exactly (including implicit params):
func whatever{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(index : felt, el : Foo*)
Example
struct Foo:
member x : felt
member y : felt
end
func test_foreach_struct{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
alloc_locals
let (local array : Foo*) = alloc()
assert array[0] = Foo(1, 10)
assert array[1] = Foo(1, 10)
assert array[2] = Foo(2, 20)
assert array[3] = Foo(7, 70)
stream.foreach_struct(do_something, 4, array, Foo.SIZE)
return ()
end
func do_something{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(el : Foo*):
...
return ()
end
Look here for a full working example.
filter
The filter() method executes a "filtering" callback function on each element of the array and keep only the elements that match.
Signature:
func filter(function : codeoffset, array_len : felt, array : felt*) -> (filtered_array_len : felt, filtered_array : felt*)
The callback function must return 0
or 1
and must have this signature exactly (including implicit params):
func whatever{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(el : felt) -> (keep : felt)
Example
func test_filter{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
alloc_locals
let (local array : felt*) = alloc()
assert array[0] = 1
assert array[1] = 2
assert array[2] = 8
assert array[3] = 7
let (local filtered_array_len : felt, filtered_array : felt*) = stream.filter(
keep_even, 4, array
)
assert 2 = filtered_array_len
assert 2 = filtered_array[0]
assert 8 = filtered_array[1]
return ()
end
func keep_even{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(el : felt) -> (
keep : felt
):
let (_, rest) = unsigned_div_rem(el, 2)
return (1 - rest)
end
Look here for a full working example.
filter_struct
The filter_struct() method executes a "filtering" callback function on each element of the array and keep only the elements that match. Unlike filter(), the array can be an array of structs.
Signature:
func filter_struct(function : codeoffset, array_len : felt, array : felt*, element_size : felt) -> (filtered_array_len : felt, filtered_array : felt*)
Assuming the struct is named Foo
, the callback function must return 0
or 1
and must have this signature exactly (including implicit params):
func whatever{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(el : Foo*) -> (keep : felt)
Example
struct Foo:
member x : felt
member y : felt
end
func test_filter_struct{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
alloc_locals
let (local array : Foo*) = alloc()
assert array[0] = Foo(1, 1)
assert array[1] = Foo(1, 0)
assert array[2] = Foo(2, 8)
assert array[3] = Foo(7, 4)
let (local filtered_array_len : felt, filtered_array : Foo*) = stream.filter_struct(
keep_even_foo, 4, array, Foo.SIZE
)
assert 2 = filtered_array_len
assert Foo(1, 1) = filtered_array[0]
assert Foo(2, 8) = filtered_array[1]
return ()
end
func keep_even_foo{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
el : Foo*
) -> (keep : felt):
tempvar sum = el.x + el.y
let (_, rest) = unsigned_div_rem(sum, 2)
return (1 - rest)
end
Look here for a full working example.
map
The map() method executes a "mapping" callback function on each element of the array and store the returned value in-place of the processed element.
Signature:
func map(function : codeoffset, array_len : felt, array : felt*) -> (mapped_array : felt*)
The callback function must have this signature exactly (including implicit params):
func whatever{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(value : felt) -> (result : felt)
Example
func test_map{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
alloc_locals
let (local array : felt*) = alloc()
assert array[0] = 1
assert array[1] = 2
assert array[2] = 3
assert array[3] = 4
let (array) = stream.map(double, 4, array)
assert 2 = array[0]
assert 4 = array[1]
assert 6 = array[2]
assert 8 = array[3]
return ()
end
func double{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(value : felt) -> (
result : felt
):
return (result=value * 2)
end
Look here for a full working example.
map_struct
The map_struct() method executes a "mapping" callback function on each element of the array and store the returned value in-place of the processed element. Unlike map(), the array can be an array of structs.
Signature:
func map_struct(function : codeoffset, array_len : felt, array : felt*, element_size : felt) -> (mapped_array : felt*)
The callback function must have this signature exactly (including implicit params):
func whatever{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(foo : Foo*) -> (result : Foo*)
Example
struct Foo:
member x : felt
member y : felt
end
func test_map_struct{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
alloc_locals
let (local array : Foo*) = alloc()
assert array[0] = Foo(1, 10)
assert array[1] = Foo(2, 20)
assert array[2] = Foo(3, 30)
assert array[3] = Foo(4, 40)
let (local array : Foo*) = stream.map_struct(double_foo, 4, array, Foo.SIZE)
assert Foo(2, 20) = array[0]
assert Foo(4, 40) = array[1]
assert Foo(6, 60) = array[2]
assert Foo(8, 80) = array[3]
return ()
end
func double_foo{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(foo : Foo*) -> (
result : Foo*
):
return (new Foo(foo.x * 2, foo.y * 2))
end
Look here for a full working example.
reduce
The reduce() method executes a "reducer" callback function on each element of the array.
Signature:
func reduce(function : codeoffset, array_len : felt, array : felt*) -> (res : felt)
The callback function must have this signature exactly (including implicit params):
func whatever{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(initial_value : felt, el : felt) -> (res : felt)
Example
func test_reduce{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
alloc_locals
let (local array : felt*) = alloc()
assert array[0] = 1
assert array[1] = 1
assert array[2] = 1
assert array[3] = 7
let (res) = stream.reduce(sum, 4, array)
assert res = 10
# Reading a storage var will fail if builtins haven't been properly updated
let (dummy) = dumb.read()
return ()
end
func sum{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
initial_value : felt, el : felt
) -> (res : felt):
let res = initial_value + el
return (res)
end
Look here for a full working example.
reduce_struct
The reduce_struct() method executes a "reducer" callback function on each element of the array. Unlike reduce(), the array can be an array of structs.
Signature:
func reduce_struct(function : codeoffset, array_len : felt, array : felt*, element_size : felt) -> (res : felt*)
Assuming the struct is named Foo
, the callback function must have this signature exactly (including implicit params):
func whatever{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(initial_value : Foo*, element : Foo*) -> (res : Foo*)
Example
struct Foo:
member x : felt
member y : felt
end
func test_reduce_struct{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}():
alloc_locals
let (local array : Foo*) = alloc()
assert array[0] = Foo(1, 10)
assert array[1] = Foo(1, 10)
assert array[2] = Foo(2, 20)
assert array[3] = Foo(7, 70)
let (res : Foo*) = stream.reduce_struct(
function=sum_foo, array_len=4, array=array, element_size=Foo.SIZE
)
assert 11 = res.x
assert 110 = res.y
# Reading a storage var will fail if builtins haven't been properly updated
let (dummy) = dumb.read()
return ()
end
func sum_foo{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
initial_value : Foo*, element : Foo*
) -> (res : Foo*):
return (new Foo(initial_value.x + element.x, initial_value.y + element.y))
end
Look here for a full working example.
Custom implementations
You can implement your own functions, with custom implicit arguments, using the generic functions provided by the library:
from onlydust.stream.generic import generic
To see implementation examples, the best is to look at the default implementations.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file onlydust-cairo-streams-0.1.2.tar.gz
.
File metadata
- Download URL: onlydust-cairo-streams-0.1.2.tar.gz
- Upload date:
- Size: 10.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.8.13
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 50b6385ab1b9178e7d236d06dde834366169bcac61bc8c4d43f60c29b779c6fd |
|
MD5 | d1687da50ef96886018610a7b4956da1 |
|
BLAKE2b-256 | 36c2ce1ef4721734adf330a10c6fc70c405722630d5cdb8e4a3f8fc85e739f69 |
File details
Details for the file onlydust_cairo_streams-0.1.2-py3-none-any.whl
.
File metadata
- Download URL: onlydust_cairo_streams-0.1.2-py3-none-any.whl
- Upload date:
- Size: 14.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.8.13
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | d5af8902d8c21e3bdc44c45fc8aa04995a7e289c4202d0bd92d057c34bfdbc20 |
|
MD5 | b4ecbe4bde7b2ae12f8d12499483ded4 |
|
BLAKE2b-256 | 772021e814778554aab0919999019883321e570aa4b3b2743e8551f18eda81a8 |