我有记录,有关背景信息,请参阅此问题。
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;
背景
我正在使用一个(几乎)像普通整数一样工作的 bignum 类。
因此a:= 1000000*10000000*12000000*10000000*1000000;
会产生非常有用的结果。为此,我使用带有class operators
. 这些触发自动类型转换和初始化。
除非没有转换,因为我将 a 分配TBigint
给 another TBigint
。
解决方案
使用 Ansistring 存储核心数据,它具有写时复制功能,并会在需要时自行克隆。
问题:(如果 Delphi 不知道您正在更改字符串,则 COW 不起作用)
我有一些纯汇编程序例程可以操纵dynamic array
伪装成Ansistring
.
但是,当我做这样的事情时:
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
并且LocX
在臀部关节处,无论一个发生在另一个身上。
显然 Delphi 不知道 asm 例程DivBigint
正在改变LocX
,因此 COW 是有序的。
解决方法
如果我将例程更改为:
function BigintToStr(const X: TBigint): AnsiString;
var
..
LocX:= x;
LocX.Digit[2]:= #0; <<-- inconsequential change to force COW.
repeat
D := DivBigint(LocX, 1000000000, LocX);
德尔福得到了所有的线索并且表现得很好。
LocX
并且X
没有链接,一切正常。
但是,我不想在一些空白空间的中间做出愚蠢的改变。
是否有一种体面/适当/官方*的方式来强制触发字符串中的 COW?
可能是系统调用之类的东西?
*圈出你最喜欢的选项(用手绘圆圈)