Конференция "KOL" » my func StrDelDup for KOL [Delphi]
 
  • vastani (30.08.10 14:20) [0]
    Привет всем ценителям 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] //=указатель на VAR L2
       mov     ebp, [ebp]    //ebp=L2
       mov     ebx, eax
       add     eax, ecx // конец буфера BazeList
       mov     esi, edx
       add     ebp, edx // конец буфера NewList
    @00:
       dec     ebp
    @01:
       dec     ebp
       cmp     ebp, esi
        je     @Exit
       cmp     word [ebp], $0A0D
        jne    @01
       cmp     word [ebp-2], $0A0D
        je     @00
    //   в [EBP] последнее завершение строки $0A0D буфера NewList
    @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
    //  в [EDX] последнее завершение строки $0A0D буфера BazeList
       cld
       xor     eax, eax //счётчик найденных совпадений обнулить
    //  поиск начала первой строки в NewList
    @04:
       cmp     byte [esi], 33 // игнорируем начальные символы с кодом меньше чем 33
        jnc    @05
       inc     esi
       jmp     @04
    //  поиск начала первой строки в BazeList
    @05:
       cmp     byte [ebx], 33 // игнорируем начальные символы с кодом меньше чем 33
        jnc    @06
       inc     ebx
       jmp     @05
    // начало цикла поиска и удаления строк в буфере NewList (ESI адресация)
    @06:
       mov     edi, ebx // загрузить в EDI указатель на начало буфера BazeList
       mov     ecx, esi // поместим в ECX текущий указатель головы в буфере NewList (начало очередной искомой строки)
    @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 // достигли конца BazeList?
        jnc    @13
       inc     edi
       inc     edi
       jmp     @10
    @13:                 // перешагнём через текущую строку в NewList
       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 // учтём длину текущей строки + LF + CF
       inc     esi
       inc     esi
       rep movsb        // сдвинем вниз на строку весь NewList
       dec     edi
       dec     edi
       cmp     ebp, edx // это работа с одним буфером?
        jne    @16
       mov     edx, edi // да, поэтому позаботимся о равенстве "хвостов" псевдо 2-х буферов (ebp=edx!!!)
    @16:
       mov     ebp, edi
       pop     esi
       jmp     @06
    @Exit:
       inc     ebp
       inc     ebp
       mov     byte [ebp], 0
       inc     ebp
       mov     [esp+28], eax //=EAX на стеке после PUSHAD
       sub     ebp, [esp+20] //=EDX на стеке после PUSHAD
       mov     edx, [esp+40]
       mov     [edx], ebp
       popad
    end;                            

  • vastani (19.09.10 14:33) [1]
    доработано  

    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;
 
Конференция "KOL" » my func StrDelDup for KOL [Delphi]
Есть новые Нет новых   [120347   +17][b:0][p:0.003]