http://ru.wikipedia.org/wiki/%D0%90%D0%BD%D0%BE%D0%BD%D0%B8%D0%BC%D0%BD%D0%B0%D1%8F_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F
http://www.delphimaster.ru/cgi-bin/faq.pl?look=1&id=19-988623694
Зравствуете Акжан.
У вас в разделе есть следующий ворос и несколько ответов на него:
Вот всю жизнь в TVision в итераторах нужно было (параметром) передавать указатель на локальную процедуру, а тут задумал сделать свой итератор для обхода некоей древовидной структуры и на тебе - компилятор ругается. Да еще и в хелпе носом тыкают, что так мол в принципе нельзя делать... Гм. И как быть?
- могу предложить собственное решение данной проблемы. Тем более, что мой способ работает с рекурсивными вызовами любого уровня сложности:
- забавно, что метод Iterate можно вызывать как для глобального, так и для локального метода (естественно с предшествующим вызовом l3L2IA).
в секции finalization модуля где живет l3L2IA надо не забыть вызвать метод: l3FreeStubs.
- это схематично идеи, просто выдирать все целиком из своей библиотеки - тяжело да и некогда.
-- Прислал: Alex W. Lulin lulin@garant.ru http://lulinalex.chat.ru --
http://www.delphimaster.ru/cgi-bin/faq.pl?look=1&id=19-988623694
Зравствуете Акжан.
У вас в разделе есть следующий ворос и несколько ответов на него:
Вот всю жизнь в TVision в итераторах нужно было (параметром) передавать указатель на локальную процедуру, а тут задумал сделать свой итератор для обхода некоей древовидной структуры и на тебе - компилятор ругается. Да еще и в хелпе носом тыкают, что так мол в принципе нельзя делать... Гм. И как быть?
- могу предложить собственное решение данной проблемы. Тем более, что мой способ работает с рекурсивными вызовами любого уровня сложности:
type Long = LongInt; Bool = Boolean; // - так уж у меня в библиотеке сложилось Tl3IteratorAction = function(Data: Pointer; Index: Long): Bool; {$IfDef Win32} register; {$EndIf Win32} var l3StubHead : THandle = 0; function l3AllocStub: THandle; {-} (* register; asm mov ecx, l3StubHead jecxz @Alloc mov eax, ecx mov ecx, [ecx] mov l3StubHead, ecx ret @Alloc: xor eax, eax push 16 { SizeOf(TCode) -> stack } push eax { GMem_Fixed -> stack } call GlobalAlloc @ret: end;{asm}*) begin if (l3StubHead = 0) then Result := Windows{l3System}.GlobalAlloc(GMem_Fixed, 16) else begin Result := l3StubHead; l3StubHead := PHandle(Result)^; end; end; procedure l3FreeLocalStub(Stub: Pointer); {-} begin PHandle(Stub)^ := l3StubHead; l3StubHead := THandle(Stub); end; (*procedure l3FreeLocalStub(Stub: Pointer); {eax} register; {-} asm push eax { Handle -> stack } call GlobalFree end;{asm}*) procedure l3FreeStubs; var Prev : THandle; Next : THandle; begin Prev := l3StubHead; while (Prev <> 0) do begin Next := PHandle(Prev)^; Windows{l3System}.GlobalFree(Prev); Prev := Next; end;{Prev <> 0} l3StubHead := 0; end; (*type TCode = array [0..11] of Byte; const Code : TCode = ( $66, $58, { pop eax } $68, $FF, $FF, { push $FFFF } { OldBP } $66, $50, { push eax } $EA, $EE, $EE, $FF, $FF { jmp $FFFF:$EEEE } { Action } );*) function l3LocalStub(Action: Pointer): Pointer; {eax} register; {-} asm push edi { Save edi } push eax { Save Action } call l3AllocStub {! --- !} {xor eax, eax { 0 -> eax } {push 16 { SizeOf(TCode) -> stack } {push eax { GMem_Fixed -> stack } {call GlobalAlloc} {! --- !} { Создаем новый код: } mov edi, eax { Handle -> edi } mov edx, eax { Handle -> edx } cld { Move forward } mov eax, $68 stosb mov eax, ebp { предыдущий ebp -> eax } stosd { "push OldBP" -> [edi] } mov eax, $B9 stosb pop eax { Action -> eax } stosd { "mov ecx, Action" -> [edi] } mov eax, $D1FF stosw { "call ecx" -> [edi] } mov eax, $59 stosb { "pop ecx" -> es:[di] } mov eax, $C3 stosb { "ret" -> [edi] } mov eax, edx { Handle -> eax } pop edi { Restore edi } end;{asm} function l3L2IA(Action: Pointer): Tl3IteratorAction; {eax} register; {-} asm jmp l3LocalStub end;{asm} procedure l3FreeIA(Stub: Tl3IteratorAction); {eax} register; {-} asm jmp l3FreeLocalStub end;{asm} теперь простейшая реализация итератора: procedure Tl3VList.Iterate(aLo, aHi: Tl3Index; Action: Tl3IteratorAction); {virtual;{!v19} {edx, ecx} register; {-} (*asm push ebx mov ebx, eax mov eax, [eax].Tl3VList.f_Count or eax, eax jle @@ret // список пуст dec eax cmp ecx, eax jle @@aHiLECount mov ecx, eax @@aHiLECount: mov eax, [ebx].Tl3VList.f_List or eax, eax jz @@ret // список пуст or edx, edx jge @@aLoGE0 xor edx, edx @@aLoGE0: sub ecx, edx jl @@ret // верхний индекс меньше нижнего mov ebx, edx shl ebx, 2 add eax, ebx pop ebx inc ecx @@loop: push eax push edx push ecx call Action pop ecx pop edx or al, al jz @@loopend pop eax add eax, 4 inc edx loop @@loop jmp @@ex @@loopend: pop eax jmp @@ex @@ret: pop ebx @@ex: end;//asm*) var i, j, k : Long; l_TmpItem : Pointer; begin if (f_List <> nil) then begin j := Max(0, aLo); k := Min(Pred(Count), aHi); if IsMultiThread then for i := j to k do begin l_TmpItem := Items[i]; if not Action(@l_TmpItem, i) then break; end else for i := j to k do if not Action(PChar(f_List) + i * SizeOf(Pointer), i) then break; end;{f_List <> nil} end; procedure Tl3VStorage.IterateF(I1, I2: Tl3Index; Action: Tl3IteratorAction); {-} begin try Iterate(I1, I2, Action); finally l3FreeIA(Action); end;{try..finally} end; и его вызов: function Tl3VList.IndexOf(Item: Pointer): LongInt; function FindItem(P: PPointer; Index: Long): Bool; far; begin if (P^ = Item) then begin IndexOf := Index; Result := false; end else Result := true; end; begin Result := -1; IterateAllF(l3L2IA(@FindItem)); end;
- забавно, что метод Iterate можно вызывать как для глобального, так и для локального метода (естественно с предшествующим вызовом l3L2IA).
в секции finalization модуля где живет l3L2IA надо не забыть вызвать метод: l3FreeStubs.
- это схематично идеи, просто выдирать все целиком из своей библиотеки - тяжело да и некогда.
-- Прислал: Alex W. Lulin lulin@garant.ru http://lulinalex.chat.ru --
Комментариев нет:
Отправить комментарий