I've got a record, see this question for background info.
TDigits = AnsiString; //Should be `= array of NativeUInt`, but string has COW
TBigint = record
Digit: TDigits; // Unsigned number, LSB stored in D[0], MSB in D[size-1]
Size: Byte; // Mininum = 4, maximum 127.
MSI: Byte; // Most significant (native)integer minimum=1, maximum=127
Sign: Shortint;
class operator Implicit(a: Integer): TBigint;
Background
I'm using a bignum class that (almost) works like normal integers.
So a:= 1000000*10000000*12000000*10000000*1000000;
yields perfectly useful results.
For this purpose I use a record with class operators
.
These trigger automatic type conversion and initialisation.
Except when there is no conversion, because I'm assigning a TBigint
to another TBigint
.
The solution
Use an Ansistring to store the core data, it's got copy-on-write and will clone itself when needed.
The problem: (COW does not work if Delphi does not know you're altering the string)
I've got a few pure assembler routines that manipulate the Digit dynamic array
disguised as Ansistring
.
However when I do something like this:
Label1.Caption:= BigintToStr(b);
..... this fires:
function BigintToStr(const X: TBigint): AnsiString;
var
..
LocX:= x; <<-- assignment, locX and X are joined at the hip.
repeat
D := DivBigint(LocX, 1000000000, LocX); <<-- this routine changes LocX
^^+-- but assembler routines bypass COW
X
and LocX
are joint at the hip, whatever happens to one happens to the other.
Clearly Delphi does not know that the asm routine DivBigint
is changing LocX
and therefore a COW is in order.
The workaround
If I change the routine to:
function BigintToStr(const X: TBigint): AnsiString;
var
..
LocX:= x;
LocX.Digit[2]:= #0; <<-- inconsequential change to force COW.
repeat
D := DivBigint(LocX, 1000000000, LocX);
Delphi gets all clued up and performs just fine.
LocX
and X
are unlinked and everything works fine.
However I don't want to be making silly changes in the middle of some empty space.
Is there a decent/proper/offical* way to force trigger COW in strings?
Something like a system call perhaps?
*circle your favourite option (with a handdrawn circle)