//ion are dword aligned, so moving bytes avoids the cycle penalty of reading/w
//riting dwords across physical boundaries.
procedure mymove(
const source; var dest; count : integer);
asm
// note: when this function is called,
// delphi passes the parameters as follows:
// ecx = count
// eax = const source
// edx = var dest
// if there are no bytes to copy, just quit
// altogether; there's no point pushing registers.
cmp ecx,0
je @justquit
// preserve the critical delphi registers.
push esi
push edi
// move source into esi (generally the
// source register).
// move dest into edi (generally the dest
// register for string commands).
// this might not actually be necessary,
// as i'm not using movsb etc.
// i might be able to just use eax and edx;
// there could be a penalty for not using
// esi, edi, but i doubt it.
// this is another thing worth trying!
mov esi, eax
mov edi, edx
// the following loop is the same as repnz
// movsb, but oddly quicker!
@loop:
// get the source byte.
mov al, [esi]
// point to next byte.
inc esi
// put it into the dest.
mov [edi], al
// point dest to next position.
inc edi
// dec ecx to note how many we have left to copy.
dec ecx
// if ecx <> 0, then loop.
jnz @loop
// another optimization note.
// many people like to do this.
// mov al, [esi]
// mov [edi], al
// inc esi
// inc esi
//there’s a hidden problem here. i won’t go into too much detail, but the pe
//ntium can continue processing instructions while it’s still working out the
// result of inc esi or inc edi. if, however, you use them while they’re stil
//l being calculated, the processor will stop until they’re calculated (a pen
//alty). therefore, i alter esi and edi as far in advance as possible of using
// them.
// pop the critical delphi registers
// that we've altered.
pop edi
pop esi
@justquit:
end;
//point 1: i pass var asourcestring rather than just asourcestring. this is be
//cause i’ll just be passed a pointer to the data rather than a 10m copy of t
//he data itself, which is much quicker!
function fastreplace(
var asourcestring : string;
const afindstring, areplacestring : string;
casesensitive : boolean = false) : string;
var
// size already passed to setlength,
// the real size of result.
actualresultlen,
// position of afindstring is asourcestring.
currentpos,
// last position the afindstring was found at.
lastpos,
// bytes to copy (that is, lastpos to this pos).
bytestocopy,
// the "running" result length, not the actual one.
resultlen,
// length of afindstring, to save
// calling length repetitively.
findlen,
// length of areplacestring, for the same reason.
replacelen,
sourcelen : integer;
// this is where i explain the
// type tfastposproc from earlier!
fastposproc : tfastposproc;
begin
//as this function has the option of being case-insensitive, i’d need to call
// either fastpos or fastposnocase. the problem is that you’d have to do this
// within a loop. this is a bad idea, since the result never changes throughou
//t the whole operation–in which case we can determine it in advance, like so
//:
if casesensitive then
fastposproc := fastpos
else
fastposproc := fastposnocase;
// i don't think i actually need
// this, but i don't really mind!
result := '';
// get the lengths of the strings.
findlen := length(afindstring);
replacelen := length(areplacestring);
sourcelen := length(asourcestring);
// if we already have room for the replacements,
// then set the length of the result to
// the length of the sourcestring.
if replacelen <= findlen then
actualresultlen := sourcelen
else
// if not, we need to calculate the
// worst-case scenario.