Динамический массив любого типа

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Re: Динамический массив любого типа

Сообщение zub » 17.07.2013 11:36:21

>>Но судя по всему это реализуемо гораздо сложнее, чем я думал и небольшое увеличение читаемости кода того не стоит.
читаемость повысить упаковкой record в variant... оригинально :shock:
Посмотри всетаки fpc-stl, всё для чего обычно пишутся велосипеды типа "массив любого типа" там есть
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Динамический массив любого типа

Сообщение debi12345 » 17.07.2013 13:56:38

"Массив любого (однородного ?)типа" не есть массив РАЗНОРОДНЫХ элементов - а суть вопроса именно в этом :)
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5759
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Динамический массив любого типа

Сообщение zub » 17.07.2013 15:52:52

суть какраз в том что массив он всегда массив ОДНОРОДНЫХ элементов, даже если это variant. то что в variant можно запихать хотьчто - это особенности реализации variant, на массиве и на setlength это никак не сказывается
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Динамический массив любого типа

Сообщение debi12345 » 17.07.2013 17:12:52

Я имел ввиду, что STL может работать с массивами из элементов любого, но одного (в пределах массива) типа - то есть массив , в котором смешаны строки, числа и записи - STL, без выхода на VARIANT (или TOBJECT) как тип ВСЕХ элементов массива, не потянет. А раз элементы типа VARIANT - то сам массив получается типа "array of Variant". А раз VARIANT не умеет хранить нестандартные типы (записи,..) - то без обертки этих типов в понимаемый VARINAT-ом тип (строку, байтовый кусок,..) не обойдешься. Вроде так. Или c TObject-ом все можно сделать проще ?
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5759
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Динамический массив любого типа

Сообщение zub » 18.07.2013 00:08:54

>>Или c TObject-ом все можно сделать проще ?
Надеюсь что автору всетаки нужны "раздельные" "однотипные" массивы для его типов данных, если нет то выделение общего "абстрактного" родительского класса гораздо красивее-надежнее-быстрее упаковки всего что влезет в variant.
про вариант вообще давно пора забыть, ИМХО нафиг ненужен
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Динамический массив любого типа

Сообщение debi12345 » 18.07.2013 00:30:02

если нет то выделение общего "абстрактного" родительского класса гораздо красивее-надежнее-быстрее упаковки

Ага, еще интерфейсы задействовать - и прсваивать значения по полиморфизму :) Но лично уменя рука не поднимется выделять тяжеловесный класс для хранения напримет только одного челочисленного значения. И классы в массив не засунешь, а пойдут туда их указатели - а раз так, то лучше срауз работать с указателями (на оригинальные типы)

про вариант вообще давно пора забыть, ИМХО нафиг ненужен

Он компактен, но, из-за двустороннего маршаллинга - чуток медленный. Для целочисленого типа (сам тестирвал) - пример в 5 раз медленнее на чтении, и в 15 раз медленнее на записи.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5759
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Динамический массив любого типа

Сообщение zub » 18.07.2013 00:52:22

>> Но лично уменя рука не поднимется выделять тяжеловесный класс для хранения напримет только одного челочисленного значения. И классы в массив не засунешь, а пойдут туда их указатели - а раз так, то лучше срауз работать с указателями (на оригинальные типы)
пожалуйста - object`ы и в массив пойдут не указатели. Ничем не хуже VARIANTа: PVMT заменит VarType (или как он там в варианте называется?) Data:pointer будет самим данным если оно туда влезет и указателем на него если нет. Только типы придется руками приводить иногда))
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Динамический массив любого типа

Сообщение debi12345 » 18.07.2013 12:45:55

Data:pointer будет самим данным если оно туда влезет и указателем на него если нет.

TOject - динамический бессылочный объект, его нужно ручками создавать и удалять - то есть ничем не оличается от работы с указателями, кроме громоздкости. Причем вариант с указателями не страдает от "если..то иначе..".
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5759
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Динамический массив любого типа

Сообщение zub » 18.07.2013 13:18:23

Я собственно не понимаю о чем мы спорим.
>>Причем вариант с указателями не страдает от "если..то иначе.."
А как тип узнавать будем? какраз этим не страдает вариант с object`ами если доступ к разнотипным данным можно хоть както унифицировать виртуальными методами

>>его нужно ручками создавать и удалять - то есть ничем не оличается от работы с указателями
как и он работы с классами. незнаю как в случае variant`ов, наверно там присутствует compilermagic напрдобити стринговской, но упаковка в него record`а - это жесть))
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Динамический массив любого типа

Сообщение debi12345 » 18.07.2013 15:12:31

А как тип узнавать будем?

Не проблема - см. ниже :
Код: Выделить всё
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 - и в "шапке", и в "ветках".
(см. в примере в предыдущем посте).
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5759
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Динамический массив любого типа

Сообщение zub » 18.07.2013 17:06:19

Код: Выделить всё
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]
Последний раз редактировалось zub 18.07.2013 20:07:26, всего редактировалось 3 раз(а).
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Динамический массив любого типа

Сообщение debi12345 » 18.07.2013 18:22:09

Давайте проведем тест (сколько времени выполняется и сколько памяти кушает - опция "-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 = особождение памяти.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5759
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Динамический массив любого типа

Сообщение Sergei I. Gorelkin » 18.07.2013 18:37:23

debi12345 писал(а):Хочу спросить у знатоков - бага или фича ?Суть : ENUM-тип не принимается как ключ "CASE OF" если не привести его явно к типу INTEGER - и в "шапке", и в "ветках". (см. в примере в предыдущем посте).


FPC 2.7.1, i386-win32 - все нормально принимается...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Динамический массив любого типа

Сообщение debi12345 » 18.07.2013 19:00:06

все нормально принимается...

То есть это был баг, который в транке пофиксили ?
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5759
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Динамический массив любого типа

Сообщение zub » 18.07.2013 19:32:42

>>Без осбождения памяти, вариант с объектами в 1.5 раза быстрее, хотя "кушает" на 10% больше памяти.
Т.е. тест уже проведен?
Примеры написаны на коленке скорость можно сыграть убрав выделения памяти - размещая данные в заранее выделенной области памяти - это преимущество вариантного рекорда сведется на нет, размер памяти можно оптимизировать под реальные данные - на какихто выиграет обжект, на какихто вариантный рекорд.

>>То есть это был баг, который в транке пофиксили ?
Никогда с таким не сталкивался, всегда пользую транк.

Добавлено спустя 18 минут 18 секунд:
добавил в пост выше освобождение памяти
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Пред.След.

Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 14

Рейтинг@Mail.ru
cron