-
Привет всем ценителям KOL и Asm+Delphi! Решил поделиться с общественностью своей ассемблерной фунцикляшкой по удалению дупликатов строк в массивах. Поскольку код минимизирован, немного asm оптимизен, прост в использовании и не сильно отяготит чудесную библиотеку KOL по поводу работы со строками, просил бы добавить сие, ибо пользительна. Если же нет или недостойна, скажем, то пусть StrDelDup станет исходником страждущим и ищущим подобное, выбирать Вам, я своего достиг. Лично я ничего подобного не найдя решил не тратить время зря и написать самому то, что мне надо + поразмять мозги в ассемблере дабы не терять квалификацию :) Итак, исходно имеем: var BF1, BF2 : array of Byte; BF1 - базовый буфер в неск тыс. строк BF2 - некий новый и как кандидат на добавочку в BF1. Задача - весьма шустро очистить кандидата BF2 от строк уже имеющихся в BF1 и желательно уметь чистить самого себя тем же кодом (т.е. источник и приёмник один и тот же буфер, например BF2)... Для зачистки кандидата BF2 по базовому BF1 вызов выглядит так: n := StrDelDup( @BF1 [0], @BF2 [0], LF1, LF2 ); здесь LF1, LF1 длины BF1, BF2 соответственно, n - полученное количество "ампутированных строк" из BF2 :) для зачистки самого себя BF2 от дубликатов, поступаем и логично и аналогично, т.е. n := StrDelDup( @BF2 [0], @BF2 [0], LF2, LF2 ); Собственно, помимо возвращаемого n, она корректирует VAR значение LF2 в обоих случаях заменяя на фактическую НОВУЮ длину данных BF2 с обязательным наличествованием байта "0" в конце. Короче говоря вот код с некими характерными по крайней мере для меня коментами ;) прошу любить и жаловать:
function StrDelDup(BazeLst,NewLst:PChar; L1:Cardinal; VAR L2:Cardinal):Cardinal;
asm
pushad
mov ebp, [esp+40] mov ebp, [ebp] mov ebx, eax
add eax, ecx mov esi, edx
add ebp, edx @00:
dec ebp
@01:
dec ebp
cmp ebp, esi
je @Exit
cmp word [ebp], $0A0D
jne @01
cmp word [ebp-2], $0A0D
je @00
@02:
dec eax
@03:
dec eax
cmp eax, ebx
je @Exit
cmp word [eax], $0A0D
jne @03
cmp word [eax-2], $0A0D
je @02
mov edx, eax
cld
xor eax, eax
@04:
cmp byte [esi], 33 jnc @05
inc esi
jmp @04
@05:
cmp byte [ebx], 33 jnc @06
inc ebx
jmp @05
@06:
mov edi, ebx mov ecx, esi @07:
cmp word [esi], $0A0D je @08
inc esi
jmp @07
@08:
cmp esi, ebp jnc @Exit
cmp ebp, edx
jne @09
mov edi, esi
inc edi
inc edi
@09:
xchg ecx, esi sub ecx, esi @10:
push esi push ecx repe cmpsb
pop ecx
pop esi
je @strFound
@11:
cmp word [edi], $0A0D
je @12
inc edi
jmp @11
@12:
cmp edi, edx jnc @13
inc edi
inc edi
jmp @10
@13: add esi, ecx
inc esi
inc esi
jmp @06
@strFound:
push esi
inc eax cmp ebp, edx je @14
mov edi, esi
add esi, ecx
jmp @15
@14:
mov esi, edi
sub edi, ecx
@15:
mov ecx, ebp
sub ecx, esi inc esi
inc esi
rep movsb dec edi
dec edi
cmp ebp, edx jne @16
mov edx, edi @16:
mov ebp, edi
pop esi
jmp @06
@Exit:
inc ebp
inc ebp
mov byte [ebp], 0
inc ebp
mov [esp+28], eax sub ebp, [esp+20] mov edx, [esp+40]
mov [edx], ebp
popad
end;
-
доработано
function StrDelDup(BazeLst,NewLst:PChar; L1:Cardinal; VAR L2:Cardinal):Cardinal; asm pushad mov ebp, [esp+40] //=указатель на VAR L2 mov ebp, [ebp] //ebp=L2 mov ebx, eax mov esi, edx add eax, ecx // конец буфера BazeList add ebp, edx // конец буфера NewList mov edx, eax xor eax, eax //счётчик совпадений обнулить cld // начало цикла поиска и удаления строк в буфере NewList (ESI адресация) @Loop: cmp byte [esi],32 // поиск начала искомой строки в NewList jnc @2 // игнорируем начальные символы с кодом меньше чем 32 inc esi jmp @Loop
@2: mov ecx, esi // поместим в ECX текущий указатель головы буфера NewList (начало очередной искомой строки) @3: inc esi cmp esi, ebp // указатель ESI не выходит за верхнюю границу? jnc @ExitLoop cmp word [esi], $0A0D // это окончание искомой строки? jne @3 inc esi inc esi mov edi, ebx // загрузить в EDI указатель на начало буфера BazeList cmp ebp, edx jne @4 mov edi, esi @4: sub esi, ecx // в ESI определим длину искомой строки push esi push ecx pop esi pop ecx @5: push esi push ecx repe cmpsb pop ecx pop esi je @StrFound @a: cmp byte [edi],32 // поиск конца строки в BazeList jc @6 // игнорируем символы с кодом больше чем 31 inc edi cmp edi, edx // достигли конца BazeList? jc @a jmp @c @6: cmp byte [edi],32 // поиск начала строки в BazeList jnc @5 // игнорируем начальные символы с кодом меньше чем 33 inc edi cmp edi, edx // достигли конца BazeList? jc @6 @c: add esi, ecx // перешагнём через текущую строку NewList jmp @Loop @StrFound: push esi inc eax // увеличим счётчик найденных совпадений строк cmp ebp, edx // это работа с одним буфером? je @7 mov edi, esi add esi, ecx jmp @8 @7: mov esi, edi sub edi, ecx @8: mov ecx, ebp sub ecx, esi // учтём длину текущей строки rep movsb // сдвинем вниз на строку весь NewList cmp ebp, edx // это работа с одним буфером? jne @9 mov edx, edi // да, позаботимся о равенстве "хвостов" псевдо 2-х буферов (ebp=edx!!!) @9: mov ebp, edi pop esi jmp @Loop @ExitLoop: inc ebp inc ebp mov byte [ebp], 0 inc ebp mov [esp+28], eax //=EAX на стеке sub ebp, [esp+20] //=EDX на стеке mov edx, [esp+40] mov [edx], ebp popad end;
|