Big speed boost with Go and Strings.Builder comes from not having to allocate memory all the time, but using buffer for slice and only growing it some amount when needed.
There is a handy feature on 8th, that allows associating data item with some extra data. That allows one to easily write custom string builder for ascii strings.
1000000 constant LIMIT
a:new 0 a:push var, a
26 b:new true b:writable b:clear 0 extra! var, s
LIMIT b:new true b:writable b:clear 0 extra! var, t
: write-byte \ b byte -- b
swap extra@ rot b:!
extra@ n:1+ extra! ;
: write \ b1 b2 -- b1
extra@ dup >r 0 swap b:slice >r
extra@ r> swap b:splice
extra@ r> n:+ extra! ;
: reset \ b -- b
b:clear
0 extra! ;
: len \ b -- b n
extra@ ;
: slice
extra@ 0 swap b:slice ;
: rev \ b - b
extra@ swap b:rev swap extra! ;
: iterate
s @ over n:1- 26 n:mod 65 n:+ write-byte
len 26 n:< not if
t @ swap write drop
s @ reset drop
else
drop
then
a:push ;
: app:main
a @ ' iterate 1 LIMIT loop
t @ slice rev >s s:len "r LEN: %d\n" s:strfmt .
dup 26 s:lsub "Front: %s\n" s:strfmt .
26 s:rsub "Back: %s\n" s:strfmt .
LIMIT a:@ nip "UBVal: %d\n" s:strfmt .
bye ;
General purpose version should test if there is enough room on the buffer and grow buffer, if needed.