Skip to content

Instantly share code, notes, and snippets.

@hiiamboris
Created May 19, 2018 16:46
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hiiamboris/a624c3d767dfe4e4ed20f23bc96433ff to your computer and use it in GitHub Desktop.
Save hiiamboris/a624c3d767dfe4e4ed20f23bc96433ff to your computer and use it in GitHub Desktop.
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
Copy link
Author

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
Copy link

Very interesting work, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment