CMOVE

( c-addr1 c-addr2 u -- )

If u is greater than zero, copy u consecutive characters from the data space starting at c-addr1 to that starting at c-addr2, proceeding character-by-character from lower addresses to higher addresses.

See:

Rationale:

If c-addr2 lies within the source region (i.e., when c-addr2 is not less than c-addr1 and c-addr2 is less than the quantity c-addr1 u CHARS +), memory propagation occurs.

Assume a character string at address 100: "ABCD". Then after

100 DUP CHAR+ 3 CMOVE

the string at address 100 is "AAAA".

See A.6.1.1900 MOVE.

ContributeContributions

AntonErtlavatar of AntonErtl CMOVE implementation based on MOVESuggested reference implementation2021-09-02 10:52:45

: cmove {: afrom ato u | u1 -- :}
    ato afrom - u u< if \ pattern replication case
        ato afrom - u over + to u1 begin
            afrom afrom 2 pick + 2 pick u1 over - min move
            2* dup u u>= until
        drop
    else \ the usual non-pattern case
        ato afrom u move
    then ;

This is not as simple as copying byte by byte, but significantly more efficient (e.g., factor >10 for 32-bit VFX 4.71 with patterns of length 2) for both cases if MOVE is implemented efficiently.

PeterFalthavatar of PeterFalth

For the usual non-pattern case should it not be afrom ato u move?

AntonErtlavatar of AntonErtlNew Version

Show differences
: cmove {: afrom ato u | u1 -- :}
    ato afrom - u u< if \ pattern replication case
        ato afrom - u over + to u1 begin
            afrom afrom 2 pick + 2 pick u1 over - min move
            2* dup u u>= until
        drop
    else \ the usual non-pattern case
        afrom ato u move
    then ;

This is not as simple as copying byte by byte, but significantly more efficient (e.g., factor >10 for 32-bit VFX 4.71 with patterns of length 2) for both cases if MOVE is implemented efficiently.

MitraArdronavatar of MitraArdron

I really don't think a reference implementation in one optional set should be dependent on a word from a different set {: :} are not part of the core standard.

ruvavatar of ruv

Actually, a reference implementation may even depend on specific system implementation details (it's impossible to avoid such dependencies). Hence, the more it may depend on any standard word set. And even more, reference implementations may have recursive "dependencies" — when several words uses each other (directly or indirectly).

A reference implementation for a word is just an illustration how this word can be implemented, or what algorithm can be used for that. There is no such a purpose as mutual consistency of all reference implementations that allows to unite them all and get a ready system.

See also E.1 Introduction to Annex E. Reference Implementations and the proposal Reference implementations are not normative.

AntonErtlavatar of AntonErtl

If you prefer a version without locals, this one is based on work by dxforth <sgqdpg$1jsg$1@gioia.aioe.org>, but I have not tested it:

: cmove ( afrom ato u -- )
    >r 2dup swap - r@ u< if  \ overlapping case
        over -  r@ ( u) over +  begin ( u1) >r
        over ( afrom) dup 2 pick + 2 pick r@ over - min move
        2*  r>  over r@ ( u) u< not
      until  r> 2drop 2drop
    else  \ the usual non-pattern case
      r> ( afrom ato u) move
    then ;

AntonErtlavatar of AntonErtlNew Version

Show differences

Rewrite after a bug report from dxforth; this implementation violates 13.3.3.2 d, so it will not run on systems that rely on this restriction.

: cmove {: afrom ato u -- :}
    ato afrom - u u< if \ pattern propagation case
    ato afrom - >r ato u begin
        2dup r@ min afrom -rot move
        dup r@ u> while
        r@ /string r> 2* >r repeat
    r> drop 2drop
    else \ non-pattern case
    afrom ato u move
    then ;

This is not as simple as copying byte by byte, but significantly more efficient (e.g., factor >10 for 32-bit VFX 4.71 with patterns of length 2) for both cases if MOVE is implemented efficiently.

AntonErtlavatar of AntonErtlNew Version

Show differences

Rewrite after better testing revealed bugs appearing in corner cases:

: cmove ( afrom ato u -- )
    dup 0= ?exit
    begin {: afrom ato u :} ato afrom - {: u1 :}
    afrom ato u1 u umin move
    u1 1 u within while
        afrom ato u u1 /string repeat ;

Few systems can handle the locals usage above, so here is a no-locals version:

: cmove ( afrom ato u -- )
    dup 0= if exit then
    begin ( afrom1 ato1 u1 )
    over 3 pick - 2>r
    2dup 2r@ umin move
    2r@ 1 rot within while
        2r> /string repeat
    2r> 2drop 2drop ;

This is not as simple as copying byte by byte, but significantly more efficient (e.g., factor >10 for 32-bit VFX 4.71 with patterns of length 2) for both cases if MOVE is implemented efficiently.

Reply New Version