Created
May 19, 2018 16:46
-
-
Save hiiamboris/a624c3d767dfe4e4ed20f23bc96433ff to your computer and use it in GitHub Desktop.
A `collect` mezzanine variant of improved performance and RAM footprint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 []] | |
Very interesting work, thanks!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Compiled benchmarks:
Interpreted: