Страница 2 из 5
Re: Динамический массив любого типа
Добавлено: 17.07.2013 11:36:21
zub
>>Но судя по всему это реализуемо гораздо сложнее, чем я думал и небольшое увеличение читаемости кода того не стоит.
читаемость повысить упаковкой record в variant... оригинально

Посмотри всетаки fpc-stl, всё для чего обычно пишутся велосипеды типа "массив любого типа" там есть
Re: Динамический массив любого типа
Добавлено: 17.07.2013 13:56:38
debi12345
"Массив любого (однородного ?)типа" не есть массив РАЗНОРОДНЫХ элементов - а суть вопроса именно в этом

Re: Динамический массив любого типа
Добавлено: 17.07.2013 15:52:52
zub
суть какраз в том что массив он всегда массив ОДНОРОДНЫХ элементов, даже если это variant. то что в variant можно запихать хотьчто - это особенности реализации variant, на массиве и на setlength это никак не сказывается
Re: Динамический массив любого типа
Добавлено: 17.07.2013 17:12:52
debi12345
Я имел ввиду, что STL может работать с массивами из элементов любого, но одного (в пределах массива) типа - то есть массив , в котором смешаны строки, числа и записи - STL, без выхода на VARIANT (или TOBJECT) как тип ВСЕХ элементов массива, не потянет. А раз элементы типа VARIANT - то сам массив получается типа "array of Variant". А раз VARIANT не умеет хранить нестандартные типы (записи,..) - то без обертки этих типов в понимаемый VARINAT-ом тип (строку, байтовый кусок,..) не обойдешься. Вроде так. Или c TObject-ом все можно сделать проще ?
Re: Динамический массив любого типа
Добавлено: 18.07.2013 00:08:54
zub
>>Или c TObject-ом все можно сделать проще ?
Надеюсь что автору всетаки нужны "раздельные" "однотипные" массивы для его типов данных, если нет то выделение общего "абстрактного" родительского класса гораздо красивее-надежнее-быстрее упаковки всего что влезет в variant.
про вариант вообще давно пора забыть, ИМХО нафиг ненужен
Re: Динамический массив любого типа
Добавлено: 18.07.2013 00:30:02
debi12345
если нет то выделение общего "абстрактного" родительского класса гораздо красивее-надежнее-быстрее упаковки
Ага, еще интерфейсы задействовать - и прсваивать значения по полиморфизму

Но лично уменя рука не поднимется выделять тяжеловесный класс для хранения напримет только одного челочисленного значения. И классы в массив не засунешь, а пойдут туда их указатели - а раз так, то лучше срауз работать с указателями (на оригинальные типы)
про вариант вообще давно пора забыть, ИМХО нафиг ненужен
Он компактен, но, из-за двустороннего маршаллинга - чуток медленный. Для целочисленого типа (сам тестирвал) - пример в 5 раз медленнее на чтении, и в 15 раз медленнее на записи.
Re: Динамический массив любого типа
Добавлено: 18.07.2013 00:52:22
zub
>> Но лично уменя рука не поднимется выделять тяжеловесный класс для хранения напримет только одного челочисленного значения. И классы в массив не засунешь, а пойдут туда их указатели - а раз так, то лучше срауз работать с указателями (на оригинальные типы)
пожалуйста - object`ы и в массив пойдут не указатели. Ничем не хуже VARIANTа: PVMT заменит VarType (или как он там в варианте называется?) Data:pointer будет самим данным если оно туда влезет и указателем на него если нет. Только типы придется руками приводить иногда))
Re: Динамический массив любого типа
Добавлено: 18.07.2013 12:45:55
debi12345
Data:pointer будет самим данным если оно туда влезет и указателем на него если нет.
TOject - динамический бессылочный объект, его нужно ручками создавать и удалять - то есть ничем не оличается от работы с указателями, кроме громоздкости. Причем вариант с указателями не страдает от "если..то иначе..".
Re: Динамический массив любого типа
Добавлено: 18.07.2013 13:18:23
zub
Я собственно не понимаю о чем мы спорим.
>>Причем вариант с указателями не страдает от "если..то иначе.."
А как тип узнавать будем? какраз этим не страдает вариант с object`ами если доступ к разнотипным данным можно хоть както унифицировать виртуальными методами
>>его нужно ручками создавать и удалять - то есть ничем не оличается от работы с указателями
как и он работы с классами. незнаю как в случае variant`ов, наверно там присутствует compilermagic напрдобити стринговской, но упаковка в него record`а - это жесть))
Re: Динамический массив любого типа
Добавлено: 18.07.2013 17:04:32
debi12345
А как тип узнавать будем?
Не проблема - см. ниже :
Код: Выделить всё
program test;
{$mode objfpc}{$h+}
uses
sysutils,strings;
type
chmorec = packed record
int_val: integer;
str_val: pchar;
end;
pchmorec = ^chmorec;
ANYTYPE = (INT_T,TEXT_T,REAL_T,CHMO_T);
anydatarecty = packed record
case data_type:ANYTYPE of
INT_T: (ival: integer);
TEXT_T: (tval: pchar);
REAL_T: (rval: double);
CHMO_T: (chmoval: chmorec);
end;
anydatarecarty = array of anydatarecty;
procedure addelem(var arr: anydatarecarty; atype:ANYTYPE; adataptr: pointer);
begin
setlength(arr,length(arr)+1);
arr[high(arr)].data_type:= atype;
case integer(atype) of
integer(INT_T): arr[high(arr)].ival:= integer(adataptr^);
integer(TEXT_T): arr[high(arr)].tval:= strnew(pchar(adataptr));
integer(REAL_T): arr[high(arr)].rval:= double(adataptr^);
integer(CHMO_T): begin
with arr[high(arr)].chmoval do begin
int_val:= (chmorec(adataptr^)).int_val;
str_val:= strnew((chmorec(adataptr^)).str_val);
end;
end;
end;
end;
var
arr1: anydatarecarty;
i1: integer;
pch1: pchar;
r1: double;
chmo1: chmorec;
i: integer;
begin
i1:= 1;
addelem(arr1,INT_T,@i1);
r1:= 1.234;
addelem(arr1,REAL_T,@r1);
pch1:= 'one';
addelem(arr1,TEXT_T,pch1);
chmo1.int_val:= 100;
chmo1.str_val:= 'hundred';
addelem(arr1,CHMO_T,@chmo1);
for i:= high(arr1) downto low(arr1) do begin
case integer(arr1[i].data_type) of
integer(INT_T): writeln('int val = ', arr1[i].ival);
integer(TEXT_T): begin
writeln('text val = ', arr1[i].tval);
dispose(arr1[i].tval);
end;
integer(REAL_T): writeln('real val = ', arr1[i].rval);
integer(CHMO_T): begin
writeln('chmo rec = {', arr1[i].chmoval.int_val,',',arr1[i].chmoval.str_val, '}');
dispose(arr1[i].chmoval.str_val);
end;
end;
end;
end.
Виду актульности данной задачи, не могли бы накать аналогичное решение с TObject ?
(я с ними работал о-о-очень давно - уже многое забыл)
Добавлено спустя 1 час 52 минуты 1 секунду:Хочу спросить у знатоков - бага или фича ?
Суть :
ENUM-тип не принимается как ключ "CASE OF" если не привести его явно к типу INTEGER - и в "шапке", и в "ветках".
(см. в примере в предыдущем посте).
Re: Динамический массив любого типа
Добавлено: 18.07.2013 17:06:19
zub
Код: Выделить всё
program project1;
{$mode objfpc}{$h+}
uses
sysutils,strings;
const
TEST_CNT = 300000;
type
chmorec = packed record
int_val: integer;
str_val: pchar;
end;
pchmorec = ^chmorec;
baseObj = packed object
data:pointer;
procedure WriteDataWithType;virtual;abstract;
destructor done;virtual;
end;
INTObj = packed object(baseObj)
procedure WriteDataWithType;virtual;
constructor init(adataptr: pointer);
end;
TEXTObj = packed object(baseObj)
procedure WriteDataWithType;virtual;
constructor init(adataptr: pointer);
destructor done;virtual;
end;
REALObj = packed object(baseObj)
procedure WriteDataWithType;virtual;
constructor init(adataptr: pointer);
destructor done;virtual;
end;
CHMOObj = packed object(baseObj)
procedure WriteDataWithType;virtual;
constructor init(adataptr: pointer);
destructor done;virtual;
end;
anyObjarty = array of baseObj;
ANYTYPE = (INT_T,TEXT_T,REAL_T,CHMO_T);
destructor baseObj.done;
begin
end;
procedure INTObj.WriteDataWithType;
begin
writeln('int val = ', integer(data));
end;
constructor INTObj.init(adataptr: pointer);
begin
integer(data):=pinteger(adataptr)^;
end;
procedure TEXTObj.WriteDataWithType;
begin
writeln('text val = ', pchar(data));
end;
constructor TEXTObj.init(adataptr: pointer);
begin
pchar(data):=strnew(pchar(adataptr));
end;
destructor TEXTObj.done;
begin
strdispose(pchar(data));
end;
procedure REALObj.WriteDataWithType;
begin
writeln('real val = ', pdouble(data)^);
end;
constructor REALObj.init(adataptr: pointer);
begin
new(pdouble(data));
pdouble(data)^:=pdouble(adataptr)^;
end;
destructor REALObj.done;
begin
dispose(pdouble(data));
end;
procedure CHMOObj.WriteDataWithType;
begin
writeln('chmo rec = {', inttostr(pchmorec(data)^.int_val)+',',pchmorec(data)^.str_val,'}');
end;
constructor CHMOObj.init(adataptr: pointer);
begin
new(pchmorec(data));
pchmorec(data)^.int_val:=pchmorec(adataptr)^.int_val;
pchmorec(data)^.str_val:=strnew(pchmorec(adataptr)^.str_val);
end;
destructor CHMOObj.done;
begin
strdispose(pchmorec(data)^.str_val);
dispose(pchmorec(data));
end;
procedure addelem(var arr: anyObjarty; atype:ANYTYPE; adataptr: pointer);
begin
setlength(arr,length(arr)+1);
case atype of
INT_T: INTObj(arr[high(arr)]).init(adataptr);
TEXT_T:TEXTObj(arr[high(arr)]).init(adataptr);
REAL_T:REALObj(arr[high(arr)]).init(adataptr);
CHMO_T:CHMOObj(arr[high(arr)]).init(adataptr);
end;
end;
var
arr1: anyObjarty;
i1: integer;
pch1: pchar;
r1: double;
chmo1: chmorec;
i: integer;
begin
for i:= 0 to TEST_CNT do begin
i1:= 1;
addelem(arr1,INT_T,@i1);
r1:= 1.234;
addelem(arr1,REAL_T,@r1);
pch1:= 'one';
addelem(arr1,TEXT_T,pch1);
chmo1.int_val:= 100;
chmo1.str_val:= 'hundred';
addelem(arr1,CHMO_T,@chmo1);
end;
for i:= high(arr1) downto low(arr1) do
begin
arr1[i].WriteDataWithType;
arr1[i].done;
end;
end.
В данном примере baseObj.data я сделал pointer соответственно доступ не через указатель есть только к интегеру, если объявить data чемнибудь "пошире" - в него можно будет пихнуть и double. Что выбрать зависит от данных которых будет большинство в массиве. Большой недостаток objecta в данном случае - data_type в вашем примере размером в байт, а у меня в его роли указатель на VMT. но зато плюсы ООП налицо:
Код: Выделить всё
for i:= high(arr1) downto low(arr1) do
arr1[i].WriteDataWithType;
вместо громоздкого case.
[s]Уничтожение данных не сделал - но его нет и в примере выше))[/s]
Re: Динамический массив любого типа
Добавлено: 18.07.2013 18:36:04
debi12345
Давайте проведем тест (сколько времени выполняется и сколько памяти кушает - опция "-gh" ) для 300 тыс элементов, с освобождеием памяти. Вариант для указателей прилагается :
Код: Выделить всё
program test;
{$mode objfpc}{$h+}
uses
sysutils,strings;
const
TEST_CNT = 300000;
type
chmorec = packed record
int_val: integer;
str_val: pchar;
end;
pchmorec = ^chmorec;
ANYTYPE = (INT_T,TEXT_T,REAL_T,CHMO_T);
anydatarecty = packed record
case data_type:ANYTYPE of
INT_T: (ival: integer);
TEXT_T: (tval: pchar);
REAL_T: (rval: double);
CHMO_T: (chmoval: chmorec);
end;
anydatarecarty = array of anydatarecty;
procedure addelem(var arr: anydatarecarty; atype:ANYTYPE; adataptr: pointer);
begin
setlength(arr,length(arr)+1);
arr[high(arr)].data_type:= atype;
case integer(atype) of
integer(INT_T): arr[high(arr)].ival:= integer(adataptr^);
integer(TEXT_T): arr[high(arr)].tval:= strnew(pchar(adataptr));
integer(REAL_T): arr[high(arr)].rval:= double(adataptr^);
integer(CHMO_T): begin
with arr[high(arr)].chmoval do begin
int_val:= (chmorec(adataptr^)).int_val;
str_val:= strnew((chmorec(adataptr^)).str_val);
end;
end;
end;
end;
var
arr1: anydatarecarty;
i1: integer;
pch1: pchar;
r1: double;
chmo1: chmorec;
i: integer;
begin
for i:= 0 to TEST_CNT do begin
i1:= i;
addelem(arr1,INT_T,@i1);
r1:= double(i);
addelem(arr1,REAL_T,@r1);
pch1:= pchar(inttostr(i) + ' as text');
addelem(arr1,TEXT_T,pch1);
chmo1.int_val:= i;
chmo1.str_val:= pchar(inttostr(i) +' as text in CHMOREC');
addelem(arr1,CHMO_T,@chmo1);
end;
for i:= high(arr1) downto low(arr1) do begin
case integer(arr1[i].data_type) of
integer(INT_T): writeln('int val = ', arr1[i].ival);
integer(TEXT_T): begin
writeln('text val = ', arr1[i].tval);
dispose(arr1[i].tval);
end;
integer(REAL_T): writeln('real val = ', arr1[i].rval);
integer(CHMO_T): begin
writeln('chmo rec = {', arr1[i].chmoval.int_val,',',arr1[i].chmoval.str_val, '}');
dispose(arr1[i].chmoval.str_val);
end;
end;
end;
end.
Без осбождения памяти, вариант с объектами в 1.5 раза быстрее, хотя "кушает" на 10% больше памяти.
Добавлено спустя 13 минут 55 секунд:DISPOSE = особождение памяти.
Re: Динамический массив любого типа
Добавлено: 18.07.2013 18:37:23
Sergei I. Gorelkin
debi12345 писал(а):Хочу спросить у знатоков - бага или фича ?Суть : ENUM-тип не принимается как ключ "CASE OF" если не привести его явно к типу INTEGER - и в "шапке", и в "ветках". (см. в примере в предыдущем посте).
FPC 2.7.1, i386-win32 - все нормально принимается...
Re: Динамический массив любого типа
Добавлено: 18.07.2013 19:00:06
debi12345
все нормально принимается...
То есть это был баг, который в транке пофиксили ?
Re: Динамический массив любого типа
Добавлено: 18.07.2013 19:51:00
zub
>>Без осбождения памяти, вариант с объектами в 1.5 раза быстрее, хотя "кушает" на 10% больше памяти.
Т.е. тест уже проведен?
Примеры написаны на коленке скорость можно сыграть убрав выделения памяти - размещая данные в заранее выделенной области памяти - это преимущество вариантного рекорда сведется на нет, размер памяти можно оптимизировать под реальные данные - на какихто выиграет обжект, на какихто вариантный рекорд.
>>То есть это был баг, который в транке пофиксили ?
Никогда с таким не сталкивался, всегда пользую транк.
Добавлено спустя 18 минут 18 секунд:
добавил в пост выше освобождение памяти