Autor Téma: Návrh typu pro regex - problém s vnořením do sebe sama  (Přečteno 1485 krát)

Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 754
  • Karma: 42
    • Verze Delphi: 10.3
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #15 kdy: 11-06-2019, 21:36:18 »
Možná jsem to přehlídnul, ale jak je vlastně deklarovaný Assertions? :-)
Jinak "len" možná ani nepotřebuješ ukládat, pokud teda ve Tvé verzi Delphi taky už funguje length(Assertions.secs);

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #16 kdy: 12-06-2019, 08:20:37 »
Assertions to celé zabaluje a je členem třídy.

type TRegex_assertions = record
  on: boolean;
  isBefore: boolean;
  isAfter:  boolean;
  len: byte;  // length of the sections
  secs: Array of TRegex_sec;
end;


Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 754
  • Karma: 42
    • Verze Delphi: 10.3
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #17 kdy: 12-06-2019, 08:41:17 »
Excellent
Rated 1 time
Jo, tady máš secs: Array of TRegex_sec; tj. stačí opravdu setlength, protože prvky pole jsou přímo ty záznamy a ne ukazatele.

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #18 kdy: 12-06-2019, 10:17:53 »
Ještě bych potřeboval poradit. Teď jsem si uvědomil, že budu potřebovat pracovat s pointerama, abych se k sekcím dostal dynamicky. Takže potřebuju napsat funkci, která vrátí pointer.

Jak ale takovou funkci nadeklarovat?

Co chci použít je:
var pSection: ^pTRegex_sec;
pSection := getCurrentSectionPointer();
incSection(false, pSection); // zavedení první sekce

A teď vysím u té deklarace:
Kód: Delphi [Vybrat]
  1. function getCurrentSectionPointer(): ???;

Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 754
  • Karma: 42
    • Verze Delphi: 10.3
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #19 kdy: 12-06-2019, 10:22:47 »
Ještě bych potřeboval poradit. Teď jsem si uvědomil, že budu potřebovat pracovat s pointerama, abych se k sekcím dostal dynamicky. Takže potřebuju napsat funkci, která vrátí pointer.

Jak ale takovou funkci nadeklarovat?

Co chci použít je:
var pSection: ^pTRegex_sec;
pSection := getCurrentSectionPointer();
incSection(false, pSection); // zavedení první sekce

A teď vysím u té deklarace:
Kód: Delphi [Vybrat]
  1. function getCurrentSectionPointer(): ???;

var pSection: ^pTRegex_sec je asi špatně;
TRegex_sec je záznam
pTRegex_sec je ukazatel na ten záznam
^pTRegex_sec je ukazatel na ukazatel na záznam, to pravděpodobně nepotřebuješ

function getCurrentSectionPointer(): pTRegex_sec  ? (vrací ukazatel na záznam)

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #20 kdy: 12-06-2019, 10:44:28 »
EDIT 1

Co jsem zatím vymyslel (ale ještě nefunkční):

Kód: Delphi [Vybrat]
  1. procedure TTrackerRegex.incSection(newLevel: boolean; pSec: PTRegex_sec; pPrevLevSec: PTRegex_sec = nil);
  2. begin
  3.   if (false) then
  4.     begin
  5.       info.sec := Assertions.len;
  6.       setlength(Assertions.secs, Assertions.len+1);
  7.       Inc(Assertions.len);
  8.     end
  9.   else
  10.     begin // CREATE NEW LEVEL INTO CURRENT SECTION
  11.       setlength(pSec.secs, pPrevLevSec.len+1);
  12.       Inc(pPrevLevSec.len);
  13.       Inc(info.sec_level);
  14.     end;
  15. //  info.sec_levels[] // zápis úrovní pøístupu k aktuálnì zpracovávané sekci
  16. end;
  17.  

Kód: Delphi [Vybrat]
  1. function TTrackerRegex.getCurrentSectionPointer(): pTRegex_sec;
  2. begin
  3. end;
  4.  
Iniciace:
Kód: Delphi [Vybrat]
  1. pSection := getCurrentSectionPointer();
  2. incSection(false, pSection);
  3.  
« Poslední změna: 12-06-2019, 10:49:26 od vangog »

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #21 kdy: 12-06-2019, 11:24:42 »
Jak napsat toto (tučná část), abych získal pointer?

function TTrackerRegex.getCurrentSectionPointer(pCurrentLevSec: PTRegex_sec = nil): pTRegex_sec;
begin
  if ( pCurrentLevSec = nil) then
    Result := Assertions.secs[info.sec]
  else
    Result := Assertions.secs[info.sec]
end;

Chyba:
Incompatible types: 'TRegex_sec' and 'pTRegex_sec'

Offline vandrovnik

  • Guru
  • *****
  • Příspěvků: 754
  • Karma: 42
    • Verze Delphi: 10.3
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #22 kdy: 12-06-2019, 11:26:06 »
Result := @Assertions.secs[info.sec]

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #23 kdy: 12-06-2019, 11:37:37 »
Díky

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #24 kdy: 14-06-2019, 18:28:06 »
Co dělám špatně?

Kód: Delphi [Vybrat]
  1.    TTrackerRegex = Class
  2.     private
  3.     Sections: pTRegex_sec; // wrapper
  4. ...
  5.  

Přidělení paměti:
Kód: Delphi [Vybrat]
  1. Sections := new(pTRegex_sec);
  2.  
V této části když to prohlédnu v kukátku ^Sections
vidím toto: #19
Co to znamená? Očekával jsem že uvidím tu výše nadeklarovanou strukturu pTRegex_sec.

destructor:
Kód: Delphi [Vybrat]
  1. Dispose(sections);
  2.  

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #25 kdy: 14-06-2019, 19:25:44 »
Dík, tak tohle se mi ještě plete.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2586
  • Karma: 133
    • Verze Delphi: D2007, XE3, DX10
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #26 kdy: 14-06-2019, 22:29:34 »
Excellent
Rated 1 time

V této části když to prohlédnu v kukátku ^Sections
vidím toto: #19
Co to znamená?
Zajimave. To vypada, ze Delphi na urovni bubaku rozumi caret notation a ty jsi napsal ^S = Ctrl-S = #19

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #27 kdy: 15-06-2019, 07:29:47 »
Nerozumím vám, musíte na mě polopaticky.

Každopádně ještě potřebuju poradit. Takže když používám setlength rekurzivně, musím to potom zase rekurzivně uvolnit z paměti, nebo se to uvolňuje samo?

Ptal jsem se předtím na stackoverflow na to jak mám nastavovat ten typ sekce a bylo mi řečeno, že první úroveň (wrapper) mmám nastavit tím setlength. A ty vnořené, že jim musím předělit paměť pomocí New. A teď když to realizuju a ladím tak se to asi potvrzuje, že to jinak nejde (ale sám nevím proč):

Kód: Delphi [Vybrat]
  1. procedure TTrackerRegex.incSection(newLevel: boolean; pSec: pTRegex_sec = nil);
  2. begin
  3.   if (pSec = nil ) then
  4.     begin
  5.       // A WRAPPER secs[0]
  6.       Sections := new(pTRegex_sec);
  7.       // The root section parent is self
  8.       Sections.parent := Sections;
  9.       Sections.len := 0;
  10.       Sections.hasSections := false;
  11.       Sections.hasUnits    := false;
  12.       exit;
  13.     end;
  14.   if (not newLevel) then
  15.     begin // EXPAND SECTION
  16.       setlength(psec.secs, psec.len+1);
  17.       psec.secs[psec.len].parent := psec.secs[psec.len];
  18.       Inc(psec.len);
  19.     end
  20.   else
  21.     begin // CREATE NEW LEVEL INTO CURRENT SECTION
  22.           pSec.hasSections := true;
  23.           setlength(psec.secs, psec.len+1);
  24.           Inc(psec.len);
  25.     end;
  26. end;

V té části, kde je // CREATE NEW LEVEL INTO CURRENT SECTION
Kód: Delphi [Vybrat]
  1. pSec.hasSections := true;
  2. setlength(psec.secs, psec.len+1);
  3.  
kukátko psec.secs ukazuje nil.

Takže sice nevím proč se nepřidělí paměť automaticky, ale rozumím, že musím přidělit paměť pomocí New. A při destruktoru rekurzivně zase deallokovat pomocí Dispose().

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #28 kdy: 15-06-2019, 18:39:39 »
I found the clue

Kód: Delphi [Vybrat]
  1. pSec.hasSections := true;
  2. setlength(psec.secs, psec.len+1);
  3. psec.secs[psec.len] := New(PTRegex_sec);
  4. psec.secs[psec.len].parent := psec;
  5. Inc(psec.len);
  6.  
« Poslední změna: 15-06-2019, 18:42:32 od vangog »

Offline vangog

  • Hrdina
  • ****
  • Příspěvků: 370
  • Karma: 0
    • Verze Delphi: 7
Re:Návrh typu pro regex - problém s vnořením do sebe sama
« Odpověď #29 kdy: 15-06-2019, 19:58:19 »
Já jsem dlouze přemýšlel v čem dělám chybu. Furt jsem myslel na to nil (element pole, jak se tam dostal). Pak mi to najednou došlo. Že to přižazování se tam děje ve dvou úrovních. První úroveň je nastavení délky pole pointerů... Tím se tam dostane to nil. A druhá úroveň je pak to, že ten pointer musí někam směřovat, tedy tomu objektu přidělím paměť... Takže jsem z toho konečně moudřejší.

Navíc jsem řešil jak si pohlídat dealokování všech těch elementů, abych to nedělal rekurzivně. Tak jsem vymyslel toto

Kód: Delphi [Vybrat]
  1. destructor TTrackerRegex.Destroy();
  2. var i: integer;
  3. begin
  4. { Despose all objects from the last one
  5.   to the first one }
  6.   for i := info.AllSecPointers_currentIndex downto 0 do
  7.      Dispose(AllSecPointers[i]);
  8.    inherited;
  9. end;
  10.  

info.AllSecPointers_currentIndex se nastaví vždycky když allokuju paměť pro vnořenou sekci, čili nastavuju ukazatel pro element pole pointerů. A každý ukazatel si zazálohuju do pole, kde všechno sbírám. Toto pole je jednorozměrné, takže se vše dá snadno dealokovat.

Procedura pro alokování paměti vnořených objektů:

Kód: Delphi [Vybrat]
  1. procedure TTrackerRegex.incSection(newLevel: boolean; pSec: pTRegex_sec = nil);
  2. begin
  3.   if (pSec = nil ) then
  4.     begin
  5.       Sections := New(pTRegex_sec);
  6.       // Backup pointer
  7.       AllSecPointers[0] := Pointer(Sections);
  8.       info.AllSecPointers_currentIndex := 1;
  9.       // The root section parent is self
  10.       Sections.parent := Sections;
  11.       Sections.len := 0;
  12.       Sections.hasSections := false;
  13.       Sections.hasUnits    := false;
  14.       exit;
  15.     end;
  16.   if (not newLevel) then
  17.     begin // EXPAND SECTION
  18.       setlength(psec.secs, psec.len+1);
  19.       psec.secs[psec.len] := New(PTRegex_sec);
  20.       // Backup pointer
  21.       AllSecPointers[info.AllSecPointers_currentIndex] := Pointer(Sections);
  22.       Inc(info.AllSecPointers_currentIndex);
  23.       if (info.AllSecPointers_currentIndex>length(AllSecPointers)) then
  24.         setLength(AllSecPointers,length(AllSecPointers)+10);
  25.       psec.secs[psec.len].parent := psec.secs[psec.len];
  26.       Inc(psec.len);
  27.     end
  28.   else
  29.     begin // CREATE NEW LEVEL INTO CURRENT SECTION
  30.       pSec.hasSections := true;
  31.       setlength(psec.secs, psec.len+1);
  32.       psec.secs[psec.len] := New(PTRegex_sec);
  33.       // Backup pointer
  34.       AllSecPointers[info.AllSecPointers_currentIndex] := Pointer(psec.secs[psec.len]);
  35.       Inc(info.AllSecPointers_currentIndex);
  36.       if (info.AllSecPointers_currentIndex>length(AllSecPointers)) then
  37.         setLength(AllSecPointers,length(AllSecPointers)+10);
  38.       psec.secs[psec.len].parent := psec;
  39.       Inc(psec.len);
  40.     end;
  41. end;
  42.  
  43.  

Zítra bych tam mohl přidat try block. Já to normálně nepoužívám, ale tu by to nejspíš chtělo.

Dotaz:
Když to ladím stylem, že dám zarážku, alokuju paměť, zastavím na zarážce a pak restartuju debugger, tak dojde k "memory leak"? Protože debugger mi opakovaně padá.