Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.10.24;
Скачать: [xml.tar.bz2];

Вниз

Поиск в бинарном файле   Найти похожие ветки 

 
Defunct ©   (2004-09-26 17:55) [40]

Const MaxBufferSize = 1000000;

Type TBuffer = Array[0..MaxBufferSize-1] of byte;
    PBuffer = ^TBuffer;

Function CharPos(AChar:Char; Buffer:Pointer; Size:Integer):Integer;Assembler;
Asm
Xchg  EDx, EDi
Push  ECx
Repne ScasB
Pop   EAx
Jnz   @@NotMatch
Sub   EAx, ECx
Xchg  EDx, Edi
Ret
@@NotMatch:
Xor   EAx, EAx
Dec   EAx
Xchg  EDx, Edi
End;

Function CompareStrings(Constant, Buffer:Pointer; BufSize:Integer):Boolean;Assembler;
Asm
 Push EDi
 Push ESi
 Xchg EAx, ESi
 Mov  EDi, EDx
 Xchg EDx, EBx
 Mov  EBx, [ESi-4]
 Dec  EBx

@@Scan:
 Mov  Al, [ESi]
 Xchg EDx, EDi
 Push ECx
 Call CharPos
 Pop  ECx
 Xchg EDx, EDi
 Sub  ECx,EAx
 Cmp  ECx,EBx
 Jb   @@Exit_False

 Cmp  EAx, 0FFFFFFFFh
 Jnz  @@CompareNextChars
@@Exit_False:
 Pop  ESi
 Pop  EDi
 Xchg EDx, Ebx
 Xor  EAx,EAx
 Ret

@@CompareNextChars:
 Push ECx
 Mov  ECx,EBx
 Push ESi
 Inc  ESi
 Push EDi    //Здесь можно предусмотреть пропуск просмотренных символов
 Repe CmpsB
 Pop  EDi    //будет работать немножко быстрее
 Pop  ESi
 Pop  ECx
 Jnz  @@Scan

 Pop  ESi
 Pop  EDi
 Xchg EDx, Ebx
 Xor  EAx,EAx
 Dec  EAx
End;

Function LoadBuffer(var Buffer; var F:File; var SeekPos:Int64):Integer;
Begin
 Seek(F, SeekPos);
 BlockRead(F, Buffer, MaxBufferSize, Result);
 SeekPos := FilePos(F);
End;

Function ConstantExists(FileName, Constant: String):Boolean;
Var Buffer  : PBuffer;
   SeekPos : Int64;
   F       : File;
   BufSize : Integer;
Begin
 Result := False;

 If FileExists(FileName) Then
 Begin
   SeekPos := 0;
   New(Buffer);
   Assign(F, FileName);
   Reset(F,1);

   Repeat
     BufSize := LoadBuffer(Buffer^, F, SeekPos);
     Result := CompareStrings(@Constant[1], Buffer, BufSize);
     SeekPos := SeekPos - Length(Constant);
   Until Result Or (BufSize<MaxBufferSize);

   Close(F);
   Dispose(Buffer);
 End;
End;


Вот до чего мне удалось оптимизировать код[15], здесь учтен выход строки за границу буфера.

GuAV ©   (26.09.04 16:59) [38]
Вместо "наездов" на код, за то же время могли бы его оптимизировать сами, или написать свой.

>И код применим как элемент "защиты", где смысл в том что одни и те же бинарные даммые соответствуют разным инструкциям, что может вызвать затруднения при дизасеблировании?

почти правильно, за исключением того, что у этого кода есть строго определенное назначение (попросту его больше не для чего применять кроме как ....). Я хотел от вас услышать именно это назначение.


 
GuAV ©   (2004-09-26 18:54) [41]

лучше.

я ещё могу немного оптимизировать, самую малость...

CompareStrings(const Constant: string; Buffer ...и при вызове соотв
CompareStrings(Constant, ...
это уберет немного лишнего кода в месте вызова.

Const MaxBufferSize = 1048576 // привязывайсь к физ размеру кластера и страницы памяти...

да и не надо FileExists(FileName), всё равно он может существовать и не открыться.

потом так ещё не мешало бы
  New(Buffer);
  try
    Assign(F, FileName);
    Reset(F,1);
    try
     
    finally
      Close(F);
  finally
      Dispose(Buffer);
  end;

так оно корректнее а на произв-ть не влияет, т.к. только один раз делается.
> Вместо "наездов" на код, за то же время могли бы его оптимизировать
> сами, или написать свой.

понимаете счас у меня нет дельфи...


> почти правильно, за исключением того, что у этого кода есть
> строго определенное назначение (попросту его больше не для
> чего применять кроме как ....). Я хотел от вас услышать
> именно это назначение.

ну не знаю. сказал же, что в Вашей области не разбираюсь...
этот код в прочем не относится к сабжу.
в яндексе искать в падлу, обзаву его "ДизАсмНаёмка" :)


 
GuAV ©   (2004-09-26 18:58) [42]

 finally
     Close(F);
  end;
 finally


 
Defunct ©   (2004-09-26 19:18) [43]

GuAV ©   (26.09.04 18:54) [41, 42]

Поправки принимаются все кроме:

> Const MaxBufferSize = 1048576 // привязывайсь к физ размеру кластера и страницы памяти...

Лучше уже привязываться к объему L2 кеша процессора, а если нет тогда все равно кратно двум или нет. К кластеру привязываться смысла нет - в ОС есть механизм упреждающего чтения.

> да и не надо FileExists(FileName), всё равно он может существовать и не открыться.

Файл может и не существовать, проверка будет нелишней.


 
GuAV ©   (2004-09-26 19:52) [44]


> Лучше уже привязываться к объему L2 кеша процессора, а если
> нет тогда все равно кратно двум или нет. К кластеру привязываться
> смысла нет - в ОС есть механизм упреждающего чтения.

ок принято.

> Файл может и не существовать, проверка будет нелишней.

Если процедура написана по правильному, т.е. чтение в блоке try то в ситуации когда файл не существует, исключение подумется при первом чтении.

Возможна ситуация когда файл существует но почему-то не читается.

Код же имхо должен работать быстро в случае нормальной ситуации, следует оптимизировать этот случай даже за счет увеличения времени обработки ненормальной.

по части оскорблений - мне не понравился код из за использование сег. регистров, также бросилось в глаза Mov  Result, EAx. N.к. я знаю что это всё ни нужно, я усомнился в качесте кода, Вы сослались на доку [22], я тоже [23], после чего в [24] - первое оскорбление в мой адрес (необоснованный "наезд"). в [26] же я усомнившись в Вашем опыте привел свой аргумент который Вы не опровергли.
ну то есть что я хочу сказать: требуй вежливости - будь вежлив сам.


 
GuAV ©   (2004-09-26 19:59) [45]


> Если процедура написана по правильному, т.е. чтение в блоке
> try то в ситуации когда файл не существует, исключение подумется
> при первом чтении.

разумеется, оно подымется в любом случае.
просто оно будет правильно обработано,
> Если процедура написана по правильному
.

И потом, подпрограмма не должна оставлять факт остсутсвия файла без внимания, она должна возбудить исключение по этому делу.


 
Defunct ©   (2004-09-26 20:12) [46]

> Если процедура написана по правильному, т.е. чтение в блоке try то в ситуации когда файл не существует, исключение подумется при первом чтении.

Кто-то, конечно же это были не вы, а ваш двойник, в смежной ветке с заголовком New() сказал золотую фразу:

GuAV ©   (26.09.04 02:01) [50]
> т.е. способ try..except - пример неправильного написания программы.

Вы сами себе противоречите.

PS: пора заканчивать, уже над нами наверно весь форум смеется "hot china guys", ICQ у меня указан в анкете.


 
Sergey_Masloff   (2004-09-26 20:18) [47]

>уже над нами наверно весь форум смеется
Если вы когда меряетесь еще и код будете продолжать приводить то лучше здесь продолжайте. Неожиданно интересная ветка оказалась...
В любом случае спасибо. Интерес конечно чисто академический но читать (не ругань а код и комментарии) мне например было очень интересно. Так что в любом случае спасибо ;-)


 
GuAV ©   (2004-09-26 21:38) [48]


> Неожиданно интересная ветка оказалась...


поэтому продолжаю здесь

Defunct ©   (26.09.04 20:12) [46]

Я имел ввиду там способ проверки валидности указателя через try... except, который неправильный. тут я предлагаю использовать конструкцию try..finally и хранить исключения для вызавашего кода. Это вещи разные, имхо даже противоположные. Вызывающая подпрограмма не должна также использовать try..except в том виде в каком Вы предложили её в той ветке.


>  (не ругань а код и комментарии) мне например было очень
> интересно.

:) мне тоже особенно
Mov  Result, EAx  // This is odd when optimization is on
т.к. любая функция Delphi, возвращающая Integer возвращает его в EAX. (кроме D1, где в AX)
<off>имхо неверный коментарий более грубая ошибка чем неверный код</off>

по поводу развития мысли кода:

DWORD вариант я пока не отмёл, т.к. можно не сдвигать строку, а пройти буфер 4 раза с разными младшими битами ESi и EDi.

Даже не было опровержение метода предолженного default (c)

Сейчас поставил Delphi, попробую этот код в работе...


> уже над нами наверно весь форум смеется

я кажется не говорю ничего смешного.
моё упорство может показаться кому-то смешным, ну вот такой я есть.


 
GuAV ©   (2004-09-26 21:41) [49]


> ESi и EDi.

только EDi точнее.


 
Dimaxx   (2004-09-26 22:13) [50]

Только отлучился, а тут уже темку раздули... :-)


 
Defunct ©   (2004-09-26 22:22) [51]

> Я имел ввиду там способ проверки валидности указателя через try... except, который неправильный.

Так то были вы? :)
Извините, но мне так понравилась эта фраза, что я ее еще раз повторю.

GuAV ©   (26.09.04 02:01) [50]
> т.е. способ try..except - пример неправильного написания программы.


> DWORD вариант я пока не отмёл, т.к. можно не сдвигать строку, а пройти буфер 4 раза с разными младшими битами ESi и EDi.

Удачи. потестируем ваше решение, смотрится хорошо но существенного выиграша в скрости не даст, см [32] пункты "что мы проиграем? - 1,3" плюс добавляется еще чаcтный случай сброса поиска.

Mov  Result, EAx  // This is odd when optimization is on
т.к. любая функция Delphi, возвращающая Integer возвращает его в EAX. (кроме D1, где в AX)
<off>имхо неверный коментарий более грубая ошибка чем неверный код</off>


Вы кстатити как поняли коментарий?
Там написано "при оптимизации - это лишнее"
далее смотрите пост [16], где я отмечаю, что код требует оптимизации, жаль автору такая интересная задачка недосталась.

Function ...;assembler;safecall;
Function ...;assembler;pascal;
Мало ли что, может захочется в DLLку вставить этот код и использоваться safecall. Кстати, вполне актуальное место для приведенного [15] кода.

> Даже не было опровержение метода предолженного default (c)
Какого метода? Ссылку давайте, сыт погорло голословными утверждениями.

> Сейчас поставил Delphi, попробую этот код в работе...
аж дух затаил, жду с нетерпением что скажет Guru AV.


 
GuAV ©   (2004-09-26 23:06) [52]

Defunct ©   (26.09.04 22:22) [51]

Про safecall может и так, но это было бы не правильное её применение.

т.к. любая функция Delphi, возвращающая Integer возвращает его в EAX

{$O-}
{$OPTIMIZATION OFF}
function Return555: Integer; stdcall; assembler; // или pascal анаолгично
asm
 MOV  EAX, 555;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Caption:=IntToStr(Return555);
end;



>  Guru AV

:) Это идея.


 
Anatoly Podgoretsky ©   (2004-09-26 23:21) [53]

GuAV ©   (26.09.04 23:06) [52]
Guru AV

Вопрос в толковании


 
GuAV ©   (2004-09-26 23:25) [54]

<off>

> Вопрос в толковании

да, я про 216 :)
</off>


 
GuAV ©   (2004-09-26 23:26) [55]

любителям стрёмного асм-кода посвящается...
Function CharPos:Integer;Assembler;
 { in: AL: Char
       EDI: Pointer to buffer
       ECX: Size of buffer
   out: EAX: Result
       ECX: Size of buffer
   }
Asm
//  Xchg  EDx, EDi
 Push  ECx
 Repne ScasB
 MOV EAX, [ESP] // Pop   EAx
 Jnz   @@NotMatch
 Sub   EAx, ECx
//  Xchg  EDx, Edi
 POP   ECX
 Ret
 @@NotMatch:
 Xor   EAx, EAx
 Dec   EAx
//  Xchg  EDx, Edi
 POP   ECX
End;

Function CompareStrings(Constant: string; Buffer:Pointer; BufSize:Integer):Boolean;Assembler;
Asm
Push EDi
Push ESi
Xchg EAx, ESi
Mov  EDi, EDx
Xchg EDx, EBx
Mov  EBx, [ESi-4]
Dec  EBx

@@Scan:
Mov  Al, [ESi]
// Xchg EDx, EDi
// Push ECx
Call CharPos
// Pop  ECx
// Xchg EDx, EDi


 
Defunct ©   (2004-09-26 23:33) [56]

> И потом, подпрограмма не должна оставлять факт остсутсвия файла без внимания, она должна возбудить исключение по этому делу.

С моей точки зрения, фукция должна игнорировать сей факт, ее назначение поиск строки в файле. А раз нет файла, то нет и строки, все четко. Не надо никаких исключений, от них только программа захламляется.

PS: Как код?
сравните оба по скорости, [15] и [40] разницы практически нет.

PPS: to GuruAV, прочитайте [10] сверьте время [10] и [15] сколько ушло на реализацию алгоритма (писал с нуля), посмотрите цель написания кода[10] и прочитайте [16]. теперь скажите, как бы на моем месте вы среагировали на [21].

Согласитесь, задача, хоть и сравнительно простая, но имеет ой как много неприятных моментов.


 
Defunct ©   (2004-09-26 23:41) [57]

GuAV ©   (26.09.04 23:26) [55]

Вот, давно пора было.
Это из серии анекдотов про Илью Муромца, "Как трезвый так золотой человек, как выпьет ну просто хавайся"

Любителям стремного кода надо еще добавить флаг C вместо проверки EAX на -1

Asm
//  Xchg  EDx, EDi
Push  ECx
Repne ScasB
MOV EAX, [ESP] // Pop   EAx
Jnz   @@NotMatch
Sub   EAx, ECx
//  Xchg  EDx, Edi
POP   ECX
CLC
Ret
@@NotMatch:
// Xor   EAx, EAx
// Dec   EAx
STC
//  Xchg  EDx, Edi
POP   ECX
End;

Call CharPos
// Pop  ECx
// Xchg EDx, EDi
Jnc  @@CompareNextChars
Sub  ECx,EAx
Cmp  ECx,EBx
Jb   @@Exit_False

// Cmp  EAx, 0FFFFFFFFh
// Jnz  @@CompareNextChars


Естессно оптимизировать мона и дальше


 
GuAV ©   (2004-09-26 23:47) [58]


> С моей точки зрения, фукция должна игнорировать сей факт,
> ее назначение поиск строки в файле. А раз нет файла, то
> нет и строки, все четко. Не надо никаких исключений, от
> них только программа захламляется.

Не согласен. Исключения полезны, особенно если умеешь с ними обращася.

> Естессно оптимизировать мона и дальше

Да.

Вопросы по коду (что я не понял):

1. Как обрабатывается буфер нулевой длины ?
2. (самое интересное) как обрабатывается ситуация когда часть строки в одном буфере, часть в другом ?
3. Зачем танцы с SeekPos учитывая что строка одна ?


 
GuAV ©   (2004-09-26 23:48) [59]


> Согласитесь, задача, хоть и сравнительно простая, но имеет
> ой как много неприятных моментов.

Вот тут безоговорочно согласен!


 
GuAV ©   (2004-09-26 23:59) [60]


> PPS: to GuruAV, прочитайте [10] сверьте время [10] и [15]
> сколько ушло на реализацию алгоритма (писал с нуля), посмотрите
> цель написания кода[10] и прочитайте [16]. теперь скажите,
> как бы на моем месте вы среагировали на [21].

Ок. Я Вас понял. Поймите и меня: мне код в [15] показался стрёмным именно из-за [21] [26] и особенно [27] в начале. Из-за этго показалось, что писал чайник. Я высказал свои опасения в [21].

зы: перерегистрироваться не хочу, лучше воспользуюсь полем реальное имя.


 
Defunct ©   (2004-09-27 00:02) [61]

GuAV ©   (26.09.04 23:47) [58]

Ха, наконец-то интересный разговор.

2. (самое интересное) как обрабатывается ситуация когда часть строки в одном буфере, часть в другом ?

вот ответ:
..
Sub  ECx,EAx
Cmp  ECx,EBx
Jb   @@Exit_False
..

..
SeekPos := SeekPos - Length(Constant);
..


3. Зачем танцы с SeekPos учитывая что строка одна ?
Думаю это отпадает после ответа на 2.

1. Как обрабатывается буфер нулевой длины ?
Не учтено. проверка должна быть в CharPos.
В измененном варинте добавляю проверку:

Asm
//  Xchg  EDx, EDi

 Push  ECx
 Test  ECx,ECx
 Jz    @@NotMatch

 Repne ScasB
 MOV EAX, [ESP] // Pop   EAx
 Jnz   @@NotMatch
 Sub   EAx, ECx
//  Xchg  EDx, Edi
 POP   ECX
 CLC
 Ret
@@NotMatch:
// Xor   EAx, EAx
// Dec   EAx
 STC
//  Xchg  EDx, Edi
 POP   ECX
End;


Это было действительно дельное замечание. спасибо.


 
Defunct ©   (2004-09-27 00:07) [62]

>Не учтено. проверка должна быть в CharPos.
>В измененном варинте добавляю проверку:


Test  ECx,ECx
Jz    @@NotMatch


хотя по большому счету, буфер нулевой длинны не должен допускаться к проверке. Ведь нам не нужно тормозить поиск, только для того чтобы установить частный случай. так что этот нововведенный код выбросить, а проверку поставить в основной процедуре:

If BufSize> Length(Constant) Then
Result := CompareStrings(@Constant[1], Buffer, BufSize);


 
Defunct ©   (2004-09-27 00:23) [63]

Вот и закончились выходные...

2 Dimaxx спасибо за вопрос


 
GuAV ©   (2004-09-27 00:30) [64]

Defunct ©   (27.09.04 00:02) [61]

понял.
а попробуйте не выносить LoadBuffer, окажется всё проще:
  Repeat
    BlockRead(F, Buffer^, MaxBufferSize, BufSize);

    Result := CompareStrings(Constant, Buffer, BufSize);

    Seek(F, FilePos(F) - Length(Constant));
  Until Result Or (BufSize<MaxBufferSize);


в своём подобном коде на pascal я просто запоминал позицию в искомой строке.
дело в том что он был не на асм. а в этом я искал того же.


> Вот и закончились выходные...

а у нас ещё полчаса выходных.


 
GuAV ©   (2004-09-27 00:40) [65]

:)
4. как обрабатывается строка длинее MaxBufferSize ?


 
Defunct ©   (2004-09-27 01:51) [66]

GuAV ©   (27.09.04 00:30) [64]

Дык, все неточности, что вы видите - исправьте. Полную версию вашего оптимизированного кода выложете.

В чужем глазу соринку видим, в своем не заметим и бревна(С) народная мудрость. Так что я нисколько не сомневаюсь, что вы в состоянии значительно улучшить код [40]

> а попробуйте не выносить LoadBuffer, окажется всё проще
Это тому яркое подтверждение, я туда и не посмотрел бы.

> 4. как обрабатывается строка длинее MaxBufferSize ?
с помощью Norton FileCompare или как оно там называется ;)

Зы, а код этот думаю для многих пригодится, так как тема быстрого поиска весьма актуальна. может стоит в кладовку выложить?


 
Defunct ©   (2004-09-27 02:53) [67]

Тут после всего залез в модуль System функция _Pos (для ShortString) работает по алгоритму [1] (если отбросить часть которая относится к файлам).


 
GuAV ©   (2004-09-27 13:01) [68]

изучил код.
счас выложу оптимизированный.
сначала кометарий об ошибке
>  Xor  EAx,EAx
>  Dec  EAx
> End;

Xor  EAx,EAx
INC  EAX
end;

дело в том, что ord(True) равно 1. Даже есть код, например в Dialogs.pas который использует конструкцию
const C: array[Boolean] of DWORD = (A, B);
естественно он не будет готов обработать -1.


 
GuAV ©   (2004-09-27 13:03) [69]

Const MaxBufferSize = 1024*1024;

Type TBuffer = Array[0..MaxBufferSize-1] of byte;
   PBuffer = ^TBuffer;

Function CompareStrings(const Constant: string;
  Buffer: Pointer; BufSize: Integer): Boolean; Assembler;
Asm
 Push EDi
 Push ESi
 {Xchg EAx, ESi}  MOV  ESI, EAX  // Eax is not preserved anyway
 Mov  EDi, EDx
 {  EDx is not used to pass buffer pointer anymore
    Hehce we can use EDx here and keep EBx unused
 }

 {Xchg EDx, EBx}
 {Mov  EBx, [ESi-4]} MOV EDX, [ESI-4]
 {Dec  EBx} DEC EDX

@@Scan:
 Mov  Al, [ESi]
 {Xchg EDx, EDi}
 {Push ECx}

 {Xchg  EDx, EDi}
 Push  ECx
 Repne ScasB
 JNE   @@NotMatch
 {
   as we"ve moved CharPos here we can now
   jump almost right to Exit_False
 }

 {Pop   EAx}
 {Jnz   @@NotMatch}
 MOV   EAX, [ESP]
 Sub   EAx, ECx
 {Xchg  EDx, Edi}
 {Ret} {JMP @@ScanDone

 @@NotMatch:
 Xor   EAx, EAx
 Dec   EAx       }
 {Xchg  EDx, Edi}
@@ScanDone:

 Pop  ECx
 {Xchg EDx, EDi}

 Sub  ECx,EAx
 Cmp  ECx, EDX
 Jb   @@Exit_False

{ Cmp  EAx, 0FFFFFFFFh
 Jnz  @@CompareNextChars }
@@NotMatch:
 POP   ECX
@@Exit_False:
 Pop  ESi
 Pop  EDi
 {Xchg EDx, Ebx}
 Xor  EAx,EAx
 Ret

@@CompareNextChars:
 Push ECx
 Mov  ECx, EDX
 Push ESi
 Inc  ESi
 Push EDi    //Здесь можно предусмотреть пропуск просмотренных символов
 Repe CmpsB
 Pop  EDi    //будет работать немножко быстрее
 Pop  ESi
 Pop  ECx
 Jnz  @@Scan

 Pop  ESi
 Pop  EDi
 {Xchg EDx, Ebx}
 Xor  EAx,EAx
 INC  EAx
End;

Function ConstantExists(FileName, Constant: String):Boolean;
Var
 Buffer  : PBuffer;
 F       : File;
 BufSize : Integer;
Begin
 Result := False;
 New(Buffer);
 try
   Assign(F, FileName);
   Reset(F,1);
   try
     Repeat
       BlockRead(F, Buffer^, MaxBufferSize, BufSize);
       Result := CompareStrings(Constant, Buffer, BufSize);
       Seek(F, FilePos(F) - Length(Constant));
     Until Result Or (BufSize<MaxBufferSize);
   finally
     Close(F);
   end;
 finally
   Dispose(Buffer);
 end;
End;


 
GuAV ©   (2004-09-27 13:13) [70]


> { Cmp  EAx, 0FFFFFFFFh
>  Jnz  @@CompareNextChars }

случайно закоментировал, не надо кометировать это
 Cmp  EAx, 0FFFFFFFFh
 Jnz  @@CompareNextChars

и ещё

     Repeat
       BlockRead(F, Buffer^, MaxBufferSize, BufSize);
       if Bufsize=0 then Exit;
       Result := CompareStrings(Constant, Buffer, BufSize);
       Seek(F, FilePos(F) - Length(Constant));
     Until Result Or (BufSize<MaxBufferSize);


 
Defunct ©   (2004-09-27 16:39) [71]

Код [69] не рабочий.

Project .... failed with message "privileged instruction at address ..." process stopped use RUN to continue

Вашу идею с объединением функций подхватил, сейчас попробую сделать рабочим.


 
Defunct ©   (2004-09-27 17:19) [72]

Function CompareStrings(const Constant: string;
 Buffer: Pointer; BufSize: Integer): Boolean; Assembler;
Asm
 Push EDi
 Push ESi
 Push EBx
 MOV  ESI, EAX       // ESi pointer to constant
 Mov  EDi, EDx       // EDi pointer to buffer
 Mov  EBX, [ESI-4]
 Dec  EBX
 Dec  EBx            // EBx - length of the constant w/o 1st and last chars
 Mov  Al, [ESi]      // Store first char of the constant in AL
 Mov  Ah, [ESi+EBx+1]// Store last char of the constant in AH
 Mov  EDx,ECx        // EDx - Stored residual buffer size

@@Scan:
 Repne ScasB
 JNE   @@Exit_False  // no 1st char of the constant found = exit_false
 Mov   EDx, ECx      // store new residual buffer size
 Cmp   EDx, EBx      // constant still can be settled in buffer
 Ja    @@CheckLastChar  // no - exit with false result

@@Exit_False:
 Pop  EBx
 Pop  ESi
 Pop  EDi
{Xchg EDx, Ebx}
 Xor  EAx,EAx        // False = (0), check delphi help for more info
 Ret

@@CheckLastChar:      // as proposed in Boyer-Mur alhorithm

 Cmp   Ah, [EDi+EBx] // check found substring with last char of the constant
 Jnz   @@Scan        // not match - continue searching

@@CompareWholeString:
  Mov  ECx, Ebx  // ECx - constant chars amount
  Push ESi       // store pointer to constant
  Inc  ESi
  Push EDi       //&#199;&#228;&#229;&#241;&#252; &#236;&#238;&#230;&#237;&#238; &#239;&#240;&#229;&#228;&#243;&#241;&#236;&#238;&#242;&#240;&#229;&#242;&#252; &#239;&#240;&#238;&#239;&#243;&#241;&#234; &#239;&#240;&#238;&#241;&#236;&#238;&#242;&#240;&#229;&#237;&#237;&#251;&#245; &#241;&#232;&#236;&#226;&#238;&#235;&#238;&#226;
  Repe CmpsB
  Pop  EDi       //&#225;&#243;&#228;&#229;&#242; &#240;&#224;&#225;&#238;&#242;&#224;&#242;&#252; &#237;&#229;&#236;&#237;&#238;&#230;&#234;&#238; &#225;&#251;&#241;&#242;&#240;&#229;&#229;
  Pop  ESi
  Mov  ECx, EDx  // restore residual buffer size to ECx
  Jnz  @@Scan

  Pop  EBx
  Pop  ESi
  Pop  EDi

  Xor  EAx,EAx
  Dec  EAx       // True = (-1) check delphi help for more info
End;

Function ConstantExists(FileName, Constant: String):Boolean;
Var
Buffer  : PBuffer;
F       : File;
BufSize : Integer;
Begin
Result := False;
New(Buffer);
try
  Assign(F, FileName);
  Reset(F,1);
  try
    Repeat
      BlockRead(F, Buffer^, MaxBufferSize, BufSize);
      If BufSize< Length(Constant) Then Exit;
      Result := CompareStrings(Constant, Buffer, BufSize);
      Seek(F, FilePos(F) - Length(Constant));
    Until Result Or (BufSize<MaxBufferSize);
  finally
    Close(F);
  end;
finally
  Dispose(Buffer);
end;
End;


Немножко модифицировал алгоритм поиска взял проверку последнего символа из алгоритма Бойера-Мура, работает быстрее кода [40] если в буфере встречается много одинаковых "обрезков" искомой строки.


 
Defunct ©   (2004-09-27 18:03) [73]

Function CompareStrings(const Constant: string;
Buffer: Pointer; BufSize: Integer): Boolean; Assembler;
Asm
Push EDi
Push ESi
Push EBx
MOV  ESI, EAX       // ESi pointer to constant
Mov  EDi, EDx       // EDi pointer to buffer
Mov  EBX, [ESI-4]
Dec  EBX
Mov  Ah, [EBx+ESi]  // Store last char of the constant in AH
Dec  EBx            // EBx - length of the constant w/o 1st and last chars
Mov  Al, [ESi]      // Store first char of the constant in AL
Mov  EDx,ECx        // EDx - Stored residual buffer size

@@Scan:
Repne ScasB
JNE   @@Exit_False  // no 1st char of the constant found = exit_false
Mov   EDx, ECx      // store new residual buffer size
Cmp   EDx, EBx      // constant still can be settled in buffer
Ja    @@CheckLastChar  // no - exit with false result

@@Exit_False:
Pop  EBx
Pop  ESi
Pop  EDi
Xor  EAx,EAx        // False = (0), check delphi help for more info
Ret

@@CheckLastChar:      // as proposed in Boyer-Mur alhorithm

Cmp   Ah, [EDi+EBx] // check found substring with last char of the constant
Jnz   @@Scan        // not match - continue searching

@@CompareWholeString:
 Mov  ECx, Ebx  // ECx - constant chars amount
 Push ESi       // store pointer to constant
 Inc  ESi
 Push EDi      //
 Repe CmpsB
 Pop  EDi       //
 Pop  ESi
 Mov  ECx, EDx  // restore residual buffer size to ECx
 Jnz  @@Scan

 Pop  EBx
 Pop  ESi
 Pop  EDi

 Xor  EAx,EAx
 Dec  EAx       // True = (-1) check delphi help for more info
End;


Вот, теперь вроде бы ничего лишнего нет, кроме пары Push/Pop, которая четно говоря мне там не нравится..


 
Defunct ©   (2004-09-27 19:25) [74]

Эта функция работает почти в два раза быстрее чем стандартная функция Pos из модуля SYSTEM Delphi. За счет того, что в основном цикле поиска нет ни одного обращения к стеку, и минимизированы обращения к памяти.

Function ConstantPos(const Constant: string;
 Buffer: Pointer; BufSize: Integer): Integer; Assembler;
Asm
  Push EDi
  Push ESi
  Push EBx
  Push EBp
  Push ECx            // store total buffer size for later calculation pos
  MOV  ESI, EAX       // ESi pointer to constant
  Mov  EDi, EDx       // EDi pointer to buffer
  Mov  EBX, [ESI-4]
  Dec  EBX
  Mov  Ah, [ESi+EBx]  // Store last char of the constant in AH
  Dec  EBx            // EBx - length of the constant w/o 1st and last chars
  Mov  Al, [ESi]      // Store first char of the constant in AL
  Mov  EDx,ECx        // EDx - Stored residual buffer size
  Inc  ESi
  Mov  EBp, ESi       // EBp - stored pointer to 2nd char of constant

@@Scan:
  Repne ScasB
  JNE   @@Exit_False  // no 1st char of the constant found = exit_false
  Mov   EDx, ECx      // store new residual buffer size
  Cmp   EDx, EBx      // constant still can be settled in buffer
  Ja    @@CheckLastChar  // no - exit with false result

@@Exit_False:
  Pop  EAx
  Xor  EAx,EAx        // False = (0), check delphi help for more info
  Dec  EAx
  Jmp  @@Leave_Proc

@@CheckLastChar:      // as proposed in Boyer-Mur alhorithm

  Cmp   Ah, [EDi+EBx] // check found substring with last char of the constant
  Jnz   @@Scan        // not match - continue searching

@@CompareWholeString:
  Mov  ECx, Ebx       // ECx - constant chars amount
  Repe CmpsB
  Jz   @@Constant_Exists
  Mov  ESi, EBp       // restore pointer to 2nd char of constant
  Add  EDx, ECx
  Sub  EDx, EBx       // correct residual buffer size
  Mov  ECx, EDx       // restore residual buffer size to ECx

  Jnz  @@Scan

@@Constant_Exists:
  Pop  EAx
  Sub  EAx, EDx

@@Leave_Proc:

  Pop  EBp
  Pop  EBx
  Pop  ESi
  Pop  EDi
End;


Использовать приминительно к сабжу можно так:

Function ConstantExists(FileName, Constant: String):Integer;
Var
Buffer  : PBuffer;
F       : File;
BufSize : Integer;
Begin
Result := -1;
New(Buffer);
try
  POs
  Assign(F, FileName);
  Reset(F,1);
  try
    Repeat
      BlockRead(F, Buffer^, MaxBufferSize, BufSize);
      If BufSize< Length(Constant) Then Exit;
//       Result := CompareStrings(Constant, Buffer, BufSize);
      Result := ConstantPos(Constant, Buffer, BufSize);
      Seek(F, FilePos(F) - Length(Constant));
    Until (Result>0) Or (BufSize<MaxBufferSize);
  finally
    Close(F);
  end;
finally
  Dispose(Buffer);
end;
End;


 
Defunct ©   (2004-09-27 19:41) [75]

Забыл добавить описание:

Function ConstantPos(const Constant: string;
Buffer: Pointer; BufSize: Integer): Integer; Assembler;
{  -> EAx - указатель на строку поиска (константа)
     EDx - указатель на буфер, в котором требуется найти строку поиска
     ECx - длина буфера

  <- EAx - Позиция строки поиска в буфере
           (-1) если строки в буфере нет
}


 
Defunct ©   (2004-09-27 20:52) [76]

результат поиска строки "01wbcb" в файле gladiator.avi (726Mb) с учетом что такой строки в файле нет, а есть множество строк "01wb" составил - 22.34 сек, при повторном запуске - 13.71 сек. проверял на компе с 512Mb памяти (т.е. файл не мог полностью разместиться в кеше).


 
GuAV ©   (2004-09-27 21:38) [77]


>  Xor  EAx,EAx
>  Dec  EAx       // True = (-1) check delphi help for more
> info

заблуждаетесь.
F1 - Boolean types


>   Repe CmpsB

Repe CmpsD, а CmpsD - остаток


 
GuAV ©   (2004-09-27 21:38) [78]

из справки:
Boolean ByteBool, WordBool, LongBool
False < True False <> True
Ord(False) = 0 Ord(False) = 0
Ord(True) = 1 Ord(True) <> 0
Succ(False) = True Succ(False) = True
Pred(True) = False Pred(False) = True


 
GuAV ©   (2004-09-27 22:08) [79]


> Код [69] не рабочий.
>
И после [70] ?


 
Defunct ©   (2004-09-27 22:19) [80]

GuAV ©   (27.09.04 21:38) [77]
> Repe CmpsD, а CmpsB - остаток

Уже рассматривал, этот вариант. Мне не хватает одного РОНа, чтобы сделать с CmpsD. Приходится юзать стек, значительно проиграем на коротких строках. либо придется использовать регисты MM0-MMX, тада возможен, как тут любят выражаться, "гимор" если в программе была арифметика с плавающей точкой.

> заблуждаетесь.
Возможно, а возможно и нет, читал совсем недавно 1-2 месяца назад, в справке по Delphi тока не помню где именно (удивлялся). Там еще были примеры с приведением типов Integer -> Boolean, Boolean -> Integer, Boolean -> Byte, Byte -> Boolean, и вот осело в памяти $FFFFFFFF = True. Так или иначе, это не имеет значения, т.к. проверка на True все равно делается командой Test(будь там -1 или +1 результат не изменится, а по скорости Dec и Inc идентичны)

Test Reg,Reg
Jnz  @@True

PS: могу попробовать сделать поиск с использованием MMX если найду время.



Страницы: 1 2 3 4 5 6 7 вся ветка

Форум: "Основная";
Текущий архив: 2004.10.24;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.7 MB
Время: 0.043 c
9-1087322906
Dextor
2004-06-15 22:08
2004.10.24
Стратегия. Движение объекта.


1-1097473180
Dr. Genius
2004-10-11 09:39
2004.10.24
Какой сегодня день недели?


3-1096443366
NewDelpher
2004-09-29 11:36
2004.10.24
Апострофы в MS SQL


14-1097061052
Comp
2004-10-06 15:10
2004.10.24
Где можно скачать учебник по WinAPI с применением Delphi(не VC++)


14-1096704951
VID
2004-10-02 12:15
2004.10.24
Почему система тормозит при копировании с CD ?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский