Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A `collect` mezzanine variant of improved performance and RAM footprint
Red []
; outright improvement of collect mezzanine's performance and RAM footprint
; the compiled default "collect"
collect1: :collect
; the interpreted default "collect"
collect2: func spec-of :collect body-of :collect
; the improved, compilable "collect"
; 1) doesn't allocate new functions
; 2) uses `bind` instead of parse
collect3: func [
{Collect in a new block all the values passed to KEEP function from the body block}
body [block!] "Block to evaluate"
/into {Insert into a buffer instead (returns position after insert)}
coll [series!] "The buffer series (modified)"
] bind [
unless coll [coll: make block! 16]
; `also` here works like a stack
body': also body' (
body': body
coll': also coll' (
coll': coll
shoot :keep coll
) )
either into [coll] [head coll]
] context [ ; why not move this stuff out into an anonymous context?
keep: func [v /only] [either only [append/only coll' v] [append coll' v] v]
; these two are here to satisfy the compiler, otherwise can be done by binding keep/shoot bodies to :collect3
body': coll': none
; can't bind to a context [keep: collected: none] directly, since it will also bind `self` to it
; so here comes a func: `shoot` holds the 2 words used by body: `keep` and `collected`
shoot: func [keep collected] [do bind body' 'keep]
]
;------------------ tests -------------------
; recursive invocation test
foreach e [
[collect1 [loop 4 [ keep collect1 [repeat i 4 [keep i probe collected]] probe collected ]]]
[collect2 [loop 4 [ keep collect2 [repeat i 4 [keep i probe collected]] probe collected ]]]
[collect3 [loop 4 [ keep collect3 [repeat i 4 [keep i probe collected]] probe collected ]]]
] [ print [mold e "=>" mold do e lf]]
; benchmark
clock: func [b /local t1 t2 s1 s2 b' r] [
b': copy/deep b
s1: stats
t1: now/precise/time
r: loop 10000 [do b]
t2: now/precise/time
s2: stats
print [pad (t2 - t1) 12 pad s2 - s1 8 mold/flat b' "=>" mold/flat r]
]
n: 10
print lf
clock [collect1 [repeat i n [keep i]]]
clock [collect2 [repeat i n [keep i]]]
clock [collect3 [repeat i n [keep i]]]
clock [collect1/into [repeat i n [keep i]] clear []]
clock [collect2/into [repeat i n [keep i]] clear []]
clock [collect3/into [repeat i n [keep i]] clear []]
@hiiamboris

This comment has been minimized.

Copy link
Owner Author

@hiiamboris hiiamboris commented May 19, 2018

Compiled benchmarks:

0:00:00.144  8978432  [collect1 [repeat i n [keep i]]] => [1 2 3 4 5 6 7 8 9 10]              
0:00:00.224  9142272  [collect2 [repeat i n [keep i]]] => [1 2 3 4 5 6 7 8 9 10]              
0:00:00.095  2183168  [collect3 [repeat i n [keep i]]] => [1 2 3 4 5 6 7 8 9 10]              
0:00:00.144  6795264  [collect1/into [repeat i n [keep i]] clear []] => [1 2 3 4 5 6 7 8 9 10]
0:00:00.219  6959104  [collect2/into [repeat i n [keep i]] clear []] => [1 2 3 4 5 6 7 8 9 10]
0:00:00.092  0        [collect3/into [repeat i n [keep i]] clear []] => [1 2 3 4 5 6 7 8 9 10]

Interpreted:

0:00:00.139  8978432  [collect1 [repeat i n [keep i]]] => [1 2 3 4 5 6 7 8 9 10]
0:00:00.214  11243520 [collect2 [repeat i n [keep i]]] => [1 2 3 4 5 6 7 8 9 10]
0:00:00.144  2183168  [collect3 [repeat i n [keep i]]] => [1 2 3 4 5 6 7 8 9 10]
0:00:00.138  4694016  [collect1/into [repeat i n [keep i]] clear []] => [1 2 3 4 5 6 7 8 9 10]
0:00:00.211  6959104  [collect2/into [repeat i n [keep i]] clear []] => [1 2 3 4 5 6 7 8 9 10]
0:00:00.139  0        [collect3/into [repeat i n [keep i]] clear []] => [1 2 3 4 5 6 7 8 9 10]
@dockimbel

This comment has been minimized.

Copy link

@dockimbel dockimbel commented May 19, 2018

Very interesting work, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.