У меня есть двумерная матрица Олеварианта удвоений xyInput := VarArrayCreate([0, Count-1, 0, 1], varDouble);
.Самый быстрый способ конвертировать двумерный массив двустворчатого двумерного динамического двумерного массива
Я хочу преобразовать (как можно быстрее) в простой 2D динамический массив DestArray : array[0..1] of array of Double
с использованием move()
.
В этом процессе решения этого вопроса я использовал Count=5
с ожидаемыми 40 байтами на измерение. Но я обнаружил, что адрес diff между Pointer(DestArray[0])
и Pointer(DestArray[1])
составляет 56 байт.
Итак, каковы 16 байтов между ними? Я не знаю о первых 8 байтах, но последние 8 байтов - это информация о размере массива.
В результате move()
не работает за один шаг Move(VarArrayData^, Pointer(DestArray[0])^, BytesToMove);
.
Я нашел способ, используя два отдельных шага, но у меня все еще есть чувство, что это можно сделать более элегантным.
Вопросы:
- Есть ли на самом деле гораздо более простой и легкий быстрый способ?
- Есть ли какие-либо директивы компилятора или аналогичные, которые могут изменить макет памяти динамического массива, чтобы позволить
move()
работать за один шаг? - Из любопытства, каковы первые 8 байтов в промежутке между
Pointer(DestArray[0])
иPointer(DestArray[1])
?
Вот полный фрагмент кода:
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;
Спасибо за ваши материалы и мое первое знакомство с зубчатым массивом. Было бы неплохо, если бы метаданные были помещены в конец динамического массива. Но я дам ему выстрел с помощью одного длинного массива. –
Это не помогло бы. Тогда это будет в конце первого массива. Кроме того, мета-данные менеджера памяти. Плюс нет гарантии, что блоки смежны. –