Skip to content

Commit 9989527

Browse files
committed
FEAT: Pass indexes to ARRAY/initial function
When calling ARRAY/initial with a function used to generate the values, pass the current index at the position the function is being called for, with each index in a block of sizes provided to create a multidimensional array being provided as a separate parameter to the function in the order specified in the sizes block. Uses APPLY so the function can optionally not take the parameters. Uses an internal function option for efficiency. See metaeducation/rebol-issues#2193 for details. (cherry picked from commit c082953)
1 parent 6531fbb commit 9989527

File tree

1 file changed

+30
-15
lines changed

1 file changed

+30
-15
lines changed

src/mezz/mezz-series.r

+30-15
Original file line numberDiff line numberDiff line change
@@ -85,24 +85,39 @@ array: func [
8585
size [integer! block!] "Size or block of sizes for each dimension"
8686
/initial "Specify an initial value for all elements"
8787
value "Initial value (will be called each time if a function)"
88-
/local block rest
88+
/local block rest word
89+
/with tag indexes ; Token to ensure internal use, and block of index expressions
8990
][
91+
unless same? :tag 'tag [with: tag: indexes: none] ; Enforced internal option
9092
if block? size [
93+
if all [not with any-function? :value] [ ; Make indexes to pass to function
94+
indexes: append/dup make block! 2 * length? size [index? block] length? size
95+
]
9196
if tail? rest: next size [rest: none]
9297
unless integer? set/any 'size first size [
9398
cause-error 'script 'expect-arg reduce ['array 'size type? :size]
9499
]
95100
]
96101
block: make block! size
97102
case [
98-
block? rest [
99-
loop size [block: insert/only block array/initial rest :value]
103+
block? :rest [
104+
either any-function? :value [ ; Must construct params to pass to function
105+
word: in make object! copy [x: block] 'x ; Make a persistent word for this level
106+
indexes: change next indexes word ; Put that word in the params block
107+
loop size [ ; Pass indexes block to recursive call, at that level's position
108+
set word insert/only get word array/initial/with rest :value 'tag indexes
109+
]
110+
block: get word
111+
] [ ; Regular value, no parameter handling needed
112+
loop size [block: insert/only block array/initial rest :value]
113+
]
100114
]
101115
series? :value [
102116
loop size [block: insert/only block copy/deep value]
103117
]
104-
any-function? :value [ ; So value can be a thunk :)
105-
loop size [block: insert/only block value] ; Called every time
118+
any-function? :value [
119+
unless indexes [indexes: [index? block]] ; Single dimension, single index
120+
loop size [block: insert/only block apply :value head indexes]
106121
]
107122
insert/dup block value size
108123
]
@@ -423,8 +438,8 @@ printf: func [
423438
split: func [
424439
"Split a series into pieces; fixed or variable size, fixed number, or at delimiters"
425440
series [series!] "The series to split"
426-
dlm [block! integer! char! bitset! any-string!] "Split size, delimiter(s), or rule(s)."
427-
/pieces "If dlm is an integer, split into n pieces, rather than pieces of length n."
441+
dlm [block! integer! char! bitset! any-string!] "Split size, delimiter(s), or rule(s)."
442+
/into "If dlm is an integer, split into n pieces, rather than pieces of length n."
428443
/local size piece-size count mk1 mk2 res fill-val add-fill-val
429444
][
430445
either all [block? dlm parse dlm [some integer!]] [
@@ -441,7 +456,7 @@ split: func [
441456
size: dlm ; alias for readability
442457
res: collect [
443458
parse/all series case [
444-
all [integer? size pieces] [
459+
all [integer? size into] [
445460
if size < 1 [cause-error 'Script 'invalid-arg size]
446461
count: size - 1
447462
piece-size: to integer! round/down divide length? series size
@@ -460,14 +475,14 @@ split: func [
460475
]
461476
]
462477
]
463-
; Special processing, to handle cases where the spec'd more items in
464-
; /pieces than the series contains (so we want to append empty items),
465-
; or where the dlm was a char/string/charset and it was the last char
466-
; (so we want to append an empty field that the above rule misses).
478+
;-- Special processing, to handle cases where the spec'd more items in
479+
; /into than the series contains (so we want to append empty items),
480+
; or where the dlm was a char/string/charset and it was the last char
481+
; (so we want to append an empty field that the above rule misses).
467482
fill-val: does [copy either any-block? series [[]] [""]]
468483
add-fill-val: does [append/only res fill-val]
469484
case [
470-
all [integer? size pieces] [
485+
all [integer? size into] [
471486
; If the result is too short, i.e., less items than 'size, add
472487
; empty items to fill it to 'size.
473488
; We loop here, because insert/dup doesn't copy the value inserted.
@@ -482,7 +497,7 @@ split: func [
482497
; implied empty field after it, which we add here.
483498
case [
484499
bitset? dlm [
485-
; ATTEMPT is here because LAST will return NONE for an
500+
; ATTEMPT is here because LAST will return NONE for an
486501
; empty series, and finding none in a bitest is not allowed.
487502
if attempt [find dlm last series] [add-fill-val]
488503
]
@@ -498,7 +513,7 @@ split: func [
498513
]
499514
]
500515
]
501-
516+
502517
res
503518
]
504519
]

0 commit comments

Comments
 (0)