Arrays 将二维双精度阵列转换为动态二维双精度阵列的最快方法
我有一个由doubleArrays 将二维双精度阵列转换为动态二维双精度阵列的最快方法,arrays,delphi,pointers,dynamic-arrays,variant,Arrays,Delphi,Pointers,Dynamic Arrays,Variant,我有一个由doublexyinport:=varrarycreate([0,Count-1,0,1],varDouble)组成的二维OLEVANT矩阵 我希望使用move()将(尽可能快的)转换为普通2D动态数组DestArray:Double数组的数组[0..1] 在解决这个问题的过程中,我使用了Count=5给出了每个维度预期的40字节。但是我发现指针(DestArray[0])和指针(DestArray[1])之间的地址差是56字节 那么中间的16个字节是什么呢?我不知道前8个字节,但最后
xyinport:=varrarycreate([0,Count-1,0,1],varDouble)组成的二维OLEVANT矩阵代码>
我希望使用move()
将(尽可能快的)转换为普通2D动态数组DestArray:Double数组的数组[0..1]
在解决这个问题的过程中,我使用了Count=5
给出了每个维度预期的40字节。但是我发现指针(DestArray[0])
和指针(DestArray[1])
之间的地址差是56字节
那么中间的16个字节是什么呢?我不知道前8个字节,但最后8个字节是关于数组维度的信息
因此,move()
无法在一个步骤中工作move(VarArrayData^,指针(destary[0])^,BytesToMove)代码>
我已经找到了一种方法,使用两个单独的动作,但我仍然有一种感觉,它可以做得更优雅
问题:
事实上,有没有更简单、更快捷的方法
是否有任何编译器指令或类似指令可以更改动态数组的内存布局,以允许move()
在一个步骤中工作
出于好奇,在指针(DestArray[0])
和指针(DestArray[1])
之间的内存间隙的前8个字节是多少
以下是完整的代码片段:
procedure TForm1.FormCreate(Sender: TObject);
procedure PrintEqualityVerdictLine( value1 : Double; value2 : Double );
const
cEqualVerdict : array[Boolean] of String = ( '!!!Not Equal!!!', 'Equal' );
begin
Memo1.Lines.Add(FloatToStr(value1) + ' =? ' + FloatToStr(value2) + ' ' + cEqualVerdict[ SameValue( value1, value2, 0.001 ) ] );
end;
procedure VariantArrayOfDoubleToDynamicDoubleArray;
var
xyInput : OleVariant;
Count: Integer;
n: Integer;
DestArray : packed array[0..1] of packed array of Double;
V_Ptr: PVarData;
VarArrayData: PVarData;
BytesToMove: Integer;
SourceBytePtr : PByte;
BytesToMovePerColumn: Integer;
DestBytePtr: PByte;
begin
// create 2 column OleVariant array:
Count := 5;
xyInput := VarArrayCreate([0, Count-1, 0, 1], varDouble );
// fill test data:
for n := 0 to Count-1 do
begin
xyInput[n, 0] := 1.0 * n;
xyInput[n, 1] := 2.0 * Count + n;
end;
SetLength(DestArray[0], Count);
SetLength(DestArray[1], Count);
V_Ptr := PVarData(@xyInput);
if ((V_Ptr^.VType and $F000 ) = varArray) and
((V_Ptr^.VType and varTypeMask ) = varDouble)
then
begin
VarArrayData := PVarData(V_Ptr^.VArray^.Data);
BytesToMovePerColumn := Count * V_Ptr^.VArray^.ElementSize;
BytesToMove := BytesToMovePerColumn*V_Ptr^.VArray^.DimCount;
// print 16 discovered intermediate bytes of the DestArray:
DestBytePtr := Pointer(DestArray[0]);
Inc(DestBytePtr, BytesToMovePerColumn);
for n := 1 to 16 do
begin
Memo1.Lines.Add('byte['+IntToStr(n) + ']: ' + IntToStr( DestBytePtr^ ) );
Inc(DestBytePtr);
end;
// This does NOT work: col 1 of arr gets offset due to 16 discovered intermediate bytes:
// Move(VarArrayData^, Pointer(DestArray[0])^, BytesToMove );
// This works:
SourceBytePtr := PByte(VarArrayData);
Move(SourceBytePtr^, Pointer(DestArray[0])^, BytesToMovePerColumn );
Inc(SourceBytePtr, BytesToMovePerColumn);
Move(SourceBytePtr^, Pointer(DestArray[1])^, BytesToMovePerColumn );
end;
// print:
Memo1.Lines.Add('VariantArrayOfDoubleToDoubleArray:');
Memo1.Lines.Add('col 0:');
for n := 0 to Count - 1 do
PrintEqualityVerdictLine( xyInput[n, 0], DestArray[0, n] );
Memo1.Lines.Add('');
Memo1.Lines.Add('col 1:');
for n := 0 to Count - 1 do
PrintEqualityVerdictLine( xyInput[n, 1], DestArray[1, n] );
end;
begin
Memo1.Lines.Clear;
VariantArrayOfDoubleToDynamicDoubleArray;
end;
但是我发现指针(DestArray[0])
和指针(DestArray[1])
之间的地址差是56字节
这是非常值得期待的。好的,更清楚地说,没有理由期望DestArray[0]
和DestArray[1]
将指向相邻的内存块
你的类型是
array[0..1] of array of Double;
请注意,我删除了packed
关键字,该关键字在应用于数组时被忽略。这里有一个包含两个指针的数组。这两个指针是独立的。看看如何分配动态数组
SetLength(DestArray[0], Count);
SetLength(DestArray[1], Count);
每次调用SetLength
都会导致单独的堆分配。没有任何理由使内存相邻。这是在讨论一个问题之前,动态数组在数组有效负载之前存储了一个额外的元数据块,每个内存块都有自己的元数据供内存管理器使用。因此,即使内存管理器碰巧提供了相邻的内存块,元数据也会位于两个数组之间。顺便说一句,这个内存管理器元数据就是问题3的答案
从技术角度讲,您在DestArray
中看到的是一个。另一方面,您似乎在寻找多维数组。Delphi实际上不支持动态多维数组。您所拥有的只是锯齿阵列。如果您想要一个连续的内存块,那么您需要分配一个一维内存块并自己执行索引计算
因此,就目前情况而言,如果继续使用锯齿阵列,则需要为每个内部阵列执行一个副本。如果您切换到线性阵列,那么您可以只复制一个副本,但您必须执行自己的索引。当然,索引是非常容易做的,这可能是有效的。最后,您可以提前在Delphi中分配一个线性数组,并将指向该数组的指针放入变体中,从而完全避免复制
但是我发现指针(DestArray[0])
和指针(DestArray[1])
之间的地址差是56字节
这是非常值得期待的。好的,更清楚地说,没有理由期望DestArray[0]
和DestArray[1]
将指向相邻的内存块
你的类型是
array[0..1] of array of Double;
请注意,我删除了packed
关键字,该关键字在应用于数组时被忽略。这里有一个包含两个指针的数组。这两个指针是独立的。看看如何分配动态数组
SetLength(DestArray[0], Count);
SetLength(DestArray[1], Count);
每次调用SetLength
都会导致单独的堆分配。没有任何理由使内存相邻。这是在讨论一个问题之前,动态数组在数组有效负载之前存储了一个额外的元数据块,每个内存块都有自己的元数据供内存管理器使用。因此,即使内存管理器碰巧提供了相邻的内存块,元数据也会位于两个数组之间。顺便说一句,这个内存管理器元数据就是问题3的答案
从技术角度讲,您在DestArray
中看到的是一个。另一方面,您似乎在寻找多维数组。Delphi实际上不支持动态多维数组。您所拥有的只是锯齿阵列。如果您想要一个连续的内存块,那么您需要分配一个一维内存块并自己执行索引计算
因此,就目前情况而言,如果继续使用锯齿阵列,则需要为每个内部阵列执行一个副本。如果您切换到线性阵列,那么您可以只复制一个副本,但您必须执行自己的索引。当然,索引是非常容易做的,这可能是有效的。最后,您可以提前在Delphi中分配一个线性数组,并将指向该数组的指针放入变体中,从而完全避免复制。谢谢您的输入和我对锯齿数组的首次介绍。如果元数据放在动态数组的末尾,那就太好了。但我会用一个长阵列的方法来尝试一下,这不会有帮助的。然后它将位于第一个数组的末尾。加上内存管理器元数据。另外,不保证块是相邻的。感谢您的输入和m