Конференция "KOL" » Версия 2.90 [Delphi, Windows]
 
  • Vladimir Kladov © (27.03.10 22:03) [0]
    Новости от 27 марта 2010 (KOL & MCK v2.90)
    [-]
    Для символа USE_NAMES, исправлен SetName
    Hallif, VK
    [*]
    TStrList, TStrListEx (так же частично для TWStrList, TWStrListEx) методы IndexOf, IndexOf_NoCase, Find и Sort улучшены, добавлен FindFirst
    VK, mdw
    [-]
    Восстановлена совместимость с Delphi2 и Delphi3
    VK
    [*]
    UNI
    Дополнительные изменения для улучшения UNICODE_CTRLS: RemoveSpaces, AnsiCompareText, AnsiCompareStrA, _AnsiCompareStrA, AnsiCompareStrNoCaseA, _AnsiCompareStrNoCaseA, AnsiEq, CompareLVColumns

    [-]
    Ссылка на uxtheme изменена на uxtheme.dll.
    MTsv DN
    [-]
    Исправления в декларациях (для определенного символа STREAM_COMPAT): SeekMemStream, SetSizeMemStream, ReadMemStream, WriteMemStream, WriteExMemoryStream.
    Hallif
    [-]
    Исправление в WndProcToolbarCtrl для Win98
    MTsv DN
    [+]
    TIcon.LoadFromXXXX теперь понимает иконки WinCE (16 бит на пиксель)
    mdw
    [+]
    ASM версия для WinVer
    MTsv DN, VK
    [*]
    MCK
    В mirror.pas и mckCtrls.pas, введен тип TDelphiString и все условные декларации по {$IFDEF _D2009orHigher} устранены - для правильной работы Code Completion.
    VK
    [-]
    TAction.LinkMenuItem исправлен для динамических меню
    mdw
    [*]
    В WndProc_LVCustomDraw, Canvas больше не создается.
    mdw

  • Dufa © (28.03.10 11:58) [1]
    Не понимаю, почему так уопрно не хотите юзать свн... но все же обновил его. Теперь есть пара отличий:

    - delphidef.inc удален, вся информация перенесена в KOLDEF.inc
    * про MCKAppExpert200x, MTsvDN уже писал, но напомню:

    procedure TMCKWizard.Execute;
    var
     prj: String;
     unt: String;
     dlg: TSaveDialog;
     lst: TStringList;
    begin
     dlg            := TSaveDialog.Create(nil);
     dlg.Options    := [ofOverwritePrompt, ofExtensionDifferent, ofPathMustExist];
     dlg.Title      := 'Save Project';
     dlg.Filter     := 'DPR files|*.dpr';
     dlg.DefaultExt := 'dpr';
     if dlg.Execute then begin
       prj := dlg.FileName;
       if (Pos('.', prj) = Length(prj) - 3) then
         SetLength(prj, Length(prj) - 4);
       dlg.Title := 'Save Unit';
       dlg.Filter := 'PAS files|*.pas';
    .....



    KOL.pas:
    * шрифт по умолчанию Tahoma, размер шрифта -11
    + добавлена функция Swap для Byte

    procedure Swap( var X, Y: Integer ); overload;
    {$IFDEF F_P}
    var Tmp: Integer;
    begin
     Tmp := X;
     X := Y;
     Y := Tmp;
    end;
    {$ELSE DELPHI}
    asm
     MOV  ECX, [EDX]
     XCHG ECX, [EAX]
     MOV  [EDX], ECX
    end;
    //[END Swap]
    {$ENDIF F_P/DELPHI}

    //[procedure Swap]
    procedure Swap(var X, Y: Byte); overload;
    var
     T: Byte;
    begin
     T := X;
     X := Y;
     Y := T;
    end;


    + добавлена функции _GetDIBPixelsTrueColorWithAlpha, _SetDIBPixelsTrueColorWithAlpha (для 32битных битмапов, старый код вырезает альфу)
    //[FUNCTION _GetDIBPixelsTrueColorWithAlpha]
    function _GetDIBPixelsTrueColorWithAlpha( Bmp: PBitmap; X, Y: Integer ): TColor;
    var
     Pixel: DWORD;
     RGB:   TRGBQuad;
    begin
     Pixel := PDWORD( Integer(Bmp.fScanLine0) + Y * Bmp.fScanLineDelta +
                      X * Bmp.fBytesPerPixel )^ and $FFFFFFFF;
     RGB := TRGBQuad(Pixel);
     Swap(RGB.rgbBlue, RGB.rgbRed);
     Result := TColor( RGB );
    end;
    //[END _GetDIBPixelsTrueColorWithAlpha]

    function TBitmap.GetDIBPixels(X, Y: Integer): TColor;
    begin
     if not Assigned( fGetDIBPixels ) then
     begin
       if fHandleType = bmDIB then
       begin
         fScanLine0 := ScanLine[ 0 ];
         fScanLineDelta := Integer(ScanLine[ 1 ]) - Integer(fScanLine0);
         case PixelFormat of
         pf1bit:
           begin
             fPixelMask := $01;
             fPixelsPerByteMask := 7;
             fGetDIBPixels := _GetDIBPixelsPalIdx;
           end;
         pf4bit:
           begin
             fPixelMask := $0F;
             fPixelsPerByteMask := 1;
             fGetDIBPixels := _GetDIBPixelsPalIdx;
           end;
         pf8bit:
           begin
             fPixelMask := $FF;
             fPixelsPerByteMask := 0;
             fGetDIBPixels := _GetDIBPixelsPalIdx;
           end;
         pf15bit:
           begin
             fPixelMask := 15;
             fGetDIBPixels := _GetDIBPixels16bit;
           end;
         pf16bit:
           begin
             fPixelMask := 16;
             fGetDIBPixels := _GetDIBPixels16bit;
           end;
         pf24bit:
           begin
             fPixelsPerByteMask := 0;
             fBytesPerPixel := 3;
             fGetDIBPixels := _GetDIBPixelsTrueColor;
           end;
         pf32bit:
           begin
             fPixelsPerByteMask := 1;
             fBytesPerPixel := 4;
             fGetDIBPixels := {$IFDEF FIXDIB32}_GetDIBPixelsTrueColorWithAlpha{$ELSE}_GetDIBPixelsTrueColor{$ENDIF};
           end;
         else;
         end;
       end;
       if not Assigned( fGetDIBPixels ) then
       begin
         Result := Pixels[ X, Y ];
         Exit;
       end;
     end;
     Result := fGetDIBPixels( @Self, X, Y );
    end;

    ...

    //[PROCEDURE _SetDIBPixelsTrueColorWithAlpha]
    procedure _SetDIBPixelsTrueColorWithAlpha(Bmp: PBitmap; X, Y: Integer; Value: TColor);
    var RGB: TRGBQuad;
       Pos: PDWord;
    begin
     RGB := TRGBQuad({Color2RGB}(Value));
     Swap(RGB.rgbBlue, RGB.rgbRed);

     Pos := PDWORD( Integer(Bmp.fScanLine0) + Y * Bmp.fScanLineDelta
                    + X * Bmp.fBytesPerPixel );
     Pos^ := Pos^ {and $FF000000} or DWORD(RGB);
    end;
    //[END _SetDIBPixelsTrueColorWithAlpha]

    procedure TBitmap.SetDIBPixels(X, Y: Integer; const Value: TColor);
    begin
     if not Assigned( fSetDIBPixels ) then
     begin
       if fHandleType = bmDIB then
       begin
         fScanLine0 := ScanLine[ 0 ];
         fScanLineDelta := Integer(ScanLine[ 1 ]) - Integer(fScanLine0);
         case PixelFormat of
         pf1bit:
           begin
             //fPixelMask := $01;
             //fPixelsPerByteMask := 7;
             fSetDIBPixels := _SetDIBPixels1bit;
           end;
         pf4bit:
           begin
             fPixelMask := $0F;
             fPixelsPerByteMask := 1;
             fSetDIBPixels := _SetDIBPixelsPalIdx;
           end;
         pf8bit:
           begin
             fPixelMask := $FF;
             fPixelsPerByteMask := 0;
             fSetDIBPixels := _SetDIBPixelsPalIdx;
           end;
         pf15bit:
           begin
             fPixelMask := 15;
             fSetDIBPixels := _SetDIBPixels16bit;
           end;
         pf16bit:
           begin
             fPixelMask := 16;
             fSetDIBPixels := _SetDIBPixels16bit;
           end;
         pf24bit:
           begin
             fPixelsPerByteMask := 0;
             fBytesPerPixel := 3;
             fSetDIBPixels := _SetDIBPixelsTrueColor;
           end;
         pf32bit:
           begin
             fPixelsPerByteMask := 1;
             fBytesPerPixel := 4;
             fSetDIBPixels := {$IFDEF FIXDIB32}_SetDIBPixelsTrueColorWithAlpha{$ELSE}_SetDIBPixelsTrueColor{$ENDIF};
           end;
         else;
         end;
       end;
       if not Assigned( fSetDIBPixels ) then
       begin
         Pixels[ X, Y ] := Value;
         Exit;
       end;
     end;
     fSetDIBPixels( @Self, X, Y, Value );
    end;



    KOLasm.inc:
    * изменен на использование _GetDIBPixelsTrueColorWithAlpha, _SetDIBPixelsTrueColorWithAlpha
  • Vladimir Kladov © (28.03.10 14:24) [2]
    delphidef.inc удален, вся информация перенесена в KOLDEF.inc
    Давно это произошло? Верните на место. Я сейчас попробую объяснить. koldef.inc предназначен для включения в любой файл проекта, не только в KOL.pas. Его задача - помочь бороться с тысячами ненужных предупреждений от компиляторов новых версий, в основном, ну и уже заодно - добавить символы условной компиляции _$Dxx, _$DxxorHigher и т.п., чтобы можно было в проектах тоже учитывать версию компилятора. delphidef.inc содержит определения только для kol.pas.

    MCKAppExpert200x - к этому продукту я отношения не имею. Если надо, могу поменять ссылку на странице загрузок на то место, где есть актуальный архив.

    шрифт по умолчанию Tahoma, размер шрифта -11 Сколько раз уже писал, что не надо так делать. Дефолтный фонт должен быть таким, чтобы не приходилось его устанавливать программным кодом, пусть даже его генерит автоматом MCK. Кому надо установить в MCK желаемый дефолтный фонт на проект - TKOLProject.DefaultFont + TKOLForm.fontDefault = true. По умолчанию вообще должен быть фонт System, это где-то это когда-то вызывало неприятности, уже не помню где. Против Tahoma я как бы не возражаю как против дефолтного не системного, но он появился как обязательный только начиная с win98, если не ошибаюсь. Нет, не ошибаюсь: http://itua.info/news/hardware/3726.html
    А мы вроде как и Win95 поддерживаем.

    procedure Swap( var X, Y: Integer ); overload; Не очень хорошо. Для Delphi2, 3, и кажется 4, overload - слово неизвестное. Уже лучше назовите SwapBytes. (Можно и IFDEF'ами, но тогда пользователи старых Delphi лишаются одной функции, и непонятно зачем).

    добавлена функции _GetDIBPixelsTrueColorWithAlpha, _SetDIBPixelsTrueColorWithAlpha (для 32битных битмапов, старый код вырезает альфу Не проще ли было поправить (по кондиции или сразу) Color2RGBQuad, ведь альфа именно там и отрезается в _Set, а для _Get - изменить саму _GetDIBPixelsTrueColor (там Color2RGBQuad всего лишь для обмена R и B, и вызывается просто по принципу "вылить из чайника и вызвать уже готовый код").

    SVN я не пробовал, пока на диал-апе сидел. Когда платишь за каждую лишнюю минуту онлайна, сидеть и разбираться, что к чему, некогда. Сейчас можно. Хотя новшеств я не люблю. Если они не позволяют радикально облегчить жизнь. Потому и Delphi 20хx не люблю.
  • Dufa © (28.03.10 16:50) [3]
    delphidef- только для КОЛа, а KOLDEF для всего... малость не понятно %) плюс к этому внутри delphidef.inc можно обнаружить {$I KOLDEF.INC}...
    MCKAppExpert200x- находится в вашем архиве, поэтому и стоит его исправить
    Насчет поддержки 95... Просто каждый раз начиная новый проект (в котором хотелось бы иметь "обычный виндовый шрифт"), с установленным, по умолчанию System приходится его каждый раз менять.. А так один раз поставил и забыл.. Вылез в 95ой глюк - исправил..
    Swap Это еще повезло, что inline; не успел воткнуть :D
    Конечно можно и переименовать, но имхо лучше в сторону юзабельности отказываться от старых версий.. D2 оно зачем ваще?

    GetDIBPixelsTrueColorWithAlpha, SetDIBPixelsTrueColorWithAlpha А вот тут как раз, чтоб не испортить старое, добавил совершенно отдельными функциями

    SVN Предлагаю разобраться как время будет =) я сделаю доступ Вам и сможете напрямую все обновлять. Минусов в SVN нет имхо, даже тот кто не хочет качать через svn-клиент, может сливать все через браузер (GNU tarball)

    Delphi 20хx На самом деле привыкнуть гораздо быстрее чем кажется. Ну и от задач все зависит. Сейчас сижу на Турбе, а уже хотелось бы генереки...

    USE_CONSTRUCTORS, KOLCLASSES USE_CONSTRUCTORS - давно не работает. По KOLCLASSES уже давно не хватает кода.. Реально ли восстановить функциональность? И какой будет прирост к размеру ЕХЕ, если использвать class вместо object?

    Напоминаю адрес SVN http://sourceforge.net/projects/kolmck/
  • Vladimir Kladov © (28.03.10 17:42) [4]
    Ну как же не понятно. Посмотрите, что в них есть. Я всегда включаю koldef.inc во все исходные файлы, чтобы получить удаление всех предупреждений, не имеющих смысла для низкоуровневого кода. И получить символы версии в нормальных запоминаемых буквах, тем более кумулятивные символы сам Delphi Не дает, если ver120, то она и есть 120, а 130 отдельно сравнивать надо. И зачем мне надо, чтобы в каждом исходном файле вставлялись символы из delphidef.inc.

    MCKAppExpert200x - перенаправил ссылку на kolnmck.

    Вылез в 95ой глюк - исправил. Я вот не могу даже запустить под 95, у меня ее нет. Глюк вылезет у того, кто запустит готовую программу на 95.

    имхо лучше в сторону юзабельности отказываться от старых версий.. D2 оно зачем ваще?Delphi2 поддерживает coff-формат объектных файлов,  это единственная версия Delphi, в которой можно делать драйвера. А зачем мне Delphi 5 ? Да потому что он не тормозит даже по сравнению с Delphi 7. И нет никаких особых преимуществ у новых версий по сравнению со старыми.
    Delphi 20хx На самом деле привыкнуть Поэтому дело не в том чтобы привыкнуть, а в тормозах. А привыкать чего, я же на шарпе работал, тот же дико неудобный интерфейс. Но главное - тормоза.

    До сих пор в KOL не было почти ни одного overload'а. Зачем их добавлять, тем более из-за такой функции, для которой отдельное имя никак не уменьшит юзабельности. Я же так понял, что он только для обмена каналов R и B в цвете используется. Пока не поздно, надо поменять.

    GetDIBPixelsTrueColorWithAlpha, SetDIBPixelsTrueColorWithAlpha А вот тут как раз, чтоб не испортить старое Зачем портить IFDEF, никто не отменял.

    USE_CONSTRUCTORS, KOLCLASSES USE_CONSTRUCTORS - давно не работает. Но и выбрасывать тоже как-то не вижу особой причины. По KOLCLASSES уже давно не хватает кода. Это хуже, но тоже поправимо. На все надо время. Прирост небольшой, ровно как после включения classes, килобайт 30.
  • Vladimir Kladov © (28.03.10 17:56) [5]
    Не могу SVN запустить. Я Explorer'ом обычно не пользуюсь. А тут запустил для svn - и сразу после этого и-нет стал недоступен. Отключил Web-экран в авасте, этот сайт пошел, теперь kolmck.net и Soundforge недоступен. Вроде пингуются. Ерунда какая-то. В общем, сегодня и-нет барахлит, не получится.
  • vampir_infernal (28.03.10 18:47) [6]
    Господа, всплыл неприятный глюк. Метод TMenu.RemoveSubMenu в версиях 2.89 и 2.90 оставляет утечку памяти (по fastmm4). В версии 2.88 такого не было, проверил.

    Если закомментировать строку
    M.FMenuItems.Remove( Result );

    в методе TMenu.RemoveSubMenu, то фастмм доволен, но и Count не уменьшается
  • Vladimir Kladov © (28.03.10 19:35) [7]
    А если заменить
    M.FMenuItems.Remove( Result );


    на
    if Result.FParentMenu <> nil then
    Result.FParentMenu.FMenuItems.Remove( Result );


    ?
  • Vladimir Kladov © (28.03.10 19:37) [8]
    Второй вариант - на
    Items.Remove(Result);


    уже без всяких условий.
  • vampir_infernal (28.03.10 22:41) [9]
    Items.Remove(Result);

    хочет, чтобы ему казали индекс, так как
    property Items[ Id: HMenu ]: PMenu

    . Первый вариант тоже не подходит, фастмм ругается на все то же
  • mdw (29.03.10 17:51) [10]

    > TStrList, TStrListEx (так же частично для TWStrList, TWStrListEx)
    > методы IndexOf, IndexOf_NoCase, Find и Sort улучшены...


    Владимир, нашел ошибку в Find(). Возникает, если искомая строка больше любой строки в списке. Вот простейший пример:

    var SL: PStrList;
       I: Integer;
    begin
       SL:= NewStrList;
       SL.Add('0'); SL.Add('1'); SL.Add('2'); SL.Add('3');
       SL.Sort(False);
       SL.Find('1', I); //Здесь отрабатывает нормально
       SL.Find('2', I); //Здесь отрабатывает нормально
       
       SL.Find('4, I); //Здесь валится
       SL.Free;

    Посмотрел код, причина - выхода индекса за пределы диапазона в последнем сравнивании метода Find(). Если использовать AnsiSort, по AV не возникает, но только потому, что используются другие функции сравнивания.
  • mdw (29.03.10 17:54) [11]
    Так поправил:
    ....
     if (L < FCount) and not Result then
         Result := fCompareStrListFun( PAnsiChar( fList.Items[ L ] ),
                                       PAnsiChar( S ) ) = 0;
    end;
  • Vladimir Kladov © (29.03.10 18:12) [12]
    Вытащил версию. Было так (в 2.88):

    //[function TMenu.RemoveSubMenu]
    function TMenu.RemoveSubMenu( ItemToRemove: Integer ): PMenu;
    {$IFDEF DEBUG_MENU}var OK: Boolean; {$ENDIF}
    begin
     Result := Items[ ItemToRemove ];
     if Result = nil then Exit;
     if Result.FParentMenu <> nil then
       {$IFDEF DEBUG_MENU} OK := {$ENDIF}
       RemoveMenu( Result.FParentMenu.FHandle, Result.FId, MF_BYCOMMAND )
     else
       {$IFDEF DEBUG_MENU} OK := {$ENDIF}
       RemoveMenu( FHandle, Result.FId, MF_BYCOMMAND );
     {$IFDEF DEBUG_MENU}
     if not OK then
       ShowMessage( 'Error removing menu: ' + Int2Str( GetLastError ) + ' - ' +
                    SysErrorMessage( GetLastError ) );
     {$ENDIF}
     if Count = 0 then
     begin
       Result.Free;
       Result := nil;
     end;
     RedrawFormMenuBar;
    end;



    Стало так (в 2.89-2.90):
    //[function TMenu.RemoveSubMenu]
    function TMenu.RemoveSubMenu( ItemToRemove: Integer ): PMenu;
    {$IFDEF DEBUG_MENU}var OK: Boolean; {$ENDIF}
    var M: PMenu;
    begin
     Result := Items[ ItemToRemove ];
     if Result = nil then Exit;
     M := Result.FParentMenu;
     if M = nil then M := @Self;
     {$IFDEF DEBUG_MENU} OK := {$ENDIF}
     RemoveMenu( M.FHandle, Result.FId, MF_BYCOMMAND );
     M.FMenuItems.Remove( Result );
     {$IFDEF DEBUG_MENU}
     if not OK then
       ShowMessage( 'Error removing menu: ' + Int2Str( GetLastError ) + ' - ' +
                    SysErrorMessage( GetLastError ) );
     {$ENDIF}
     if Count = 0 then
     begin
       Result.Free;
       Result := nil;
     end;
     RedrawFormMenuBar;
    end;



    Хоть тресни, никак не могу углядеть разницы, кроме формально другого кода с использованием промежуточной переменной. И добавления
    M.FMenuItems.Remove( Result );



    Наконец, просто попробуйте вернуть старый код из 2.88. Если там шло и без утечек. И тогда надо разобраться зачем я добавил (по чьей просьбе) эту строчку. У меня почему-то не помечено, кто просил.

    Ага, MTsv DN: http://pda.delphimaster.net/?id=1259909126&n=10
    Чтобы Count уменьшался типа.
  • Vladimir Kladov © (29.03.10 18:56) [13]
    2mdw:
    if (L < FCount) and not Result then



    Допускаю. На тестах ищется только случайная строка из самого списка. Но, кажется, так будет лучше:
     
     ...
     if  L >= Count then
         Dec( L );
     Index := L;
     if  not Result then
         Result := fCompareStrListFun( PAnsiChar( fList.Items[ L ] ),
                                       PAnsiChar( S ) ) = 0;


    Через параметр Index возвращается в любом случае последняя строка как ближайшая найденная, возвращаемый результат FALSE. Или неважно, лишь бы не падало в случае если больше чем любая в списке?
  • Vladimir Kladov © (29.03.10 19:03) [14]
    Чего-то у меня черепашка svn не может достучаться до nekki.ru. Пишет Cannt connect to host. A connection attempt failed because the connection party did not properly respond after a period of time or established connection failed because connected host has failed to respond. В файрволле крыжык на TortoiseProc.exe стоит. Web-экран в avast! отключен. Не знаю, чего ему еще надо. Может мой провайдер отсекает. ping идет, http://nekki.ru работает.
  • mdw (29.03.10 19:50) [15]

    > Через параметр Index возвращается в любом случае последняя
    > строка как ближайшая найденная, возвращаемый результат FALSE.
    >  Или неважно, лишь бы не падало в случае если больше чем
    > любая в списке?

    Да мне в конкретном случае пофиг, главное - найдено\не найдено. Поэтому так и поправил. Но возможно, кому-то действительно будет важно еще и ближайшая "найденая" строка, да и описанию функции будет соответствовать. :) Ваш вариант оставляем тогда.
  • mdw (29.03.10 19:57) [16]

    > > Через параметр Index возвращается в любом случае последняя
    > > строка как ближайшая найденная, возвращаемый результат
    > FALSE.>  Или неважно, лишь бы не падало в случае если больше
    > чем > любая в списке?Да мне в конкретном случае пофиг, главное
    > - найдено\не найдено. Поэтому так и поправил. Но возможно,
    >  кому-то действительно будет важно еще и ближайшая "найденая"
    > строка, да и описанию функции будет соответствовать. :)
    > Ваш вариант оставляем тогда.

    Хотя, другой стороны, то Index = FCount информирует о том, что строка именно больше последней... В общем, не знаю, на Ваше усмотрение, как правильнее...
  • Vladimir Kladov © (29.03.10 20:53) [17]
    Я предпочел Count-1, т.к. планировал Find использовать для вставки в уже отсортированный список новых строк так, чтобы список оставался отсортированным. Если возвращается false, сравниваем со строкой по индексу, если получилась новая больше, делаем Insert( Index+1, newS ), иначе Insert( Index, newS ). Оно и в случае Index==Count не страшно, но нужна еще одна дополнительная проверка, не вышел ли Index>=Count, зато строку в этом случае сравнивать не нужно. Можно и описание чуть-чуть поменять. Главное здесь - что быстрее. Но если смотреть, что быстрее, то еще быстрее не делать последнее сравнение, оно явно лишнее. А лучше вообще вот так:

    function TStrList.Find(const S: AnsiString; var Index: Integer): Boolean;
    var
     L, H, I, C: Integer;
    begin
     Result := FALSE;
     L := 0;
     H := FCount - 1;
     if  H < 0 then Exit; // === if FCount = 0 then Exit;
     if  fAnsiSort then
     begin
         if  fCaseSensitiveSort then
             fCompareStrListFun := CompareAnsiCase
         else
             fCompareStrListFun := CompareAnsiNoCase;
     end
       else
     begin
         if  fCaseSensitiveSort then
             fCompareStrListFun := StrComp
         else
             fCompareStrListFun := StrComp_NoCase;
     end;
     C := 0;
     while L <= H do
     begin
       I := (L + H) shr 1;
       C := fCompareStrListFun( PAnsiChar( fList.Items[ I ] ),
                                PAnsiChar( S ) );
       if C < 0 then L := I + 1 else
       begin
         H := I - 1;
         if C = 0 then
         begin
           Result := TRUE;
           Index := I;
           Exit;
         end;
       end;
     end;
     Index := L;
     if  C < 0 then Index := -L;
    end;



    Т.е. возвращать в случае FALSE в Index индекс ближайшей строки, но если искомая меньше этой строки, то возвращать Index с минусом. Тогда проверка еще больше упрощается:

    if Index < 0 then Insert( -Index, sNew ) else Insert( Index+1, sNew );

    И соответственно поправить описание.
  • Vladimir Kladov © (29.03.10 21:05) [18]
    Нет, немного не так. На тестах погонял, понял, что не то. Вот так лучше:

    function TStrList.Find(const S: AnsiString; var Index: Integer): Boolean;
    var
     L, H, C: Integer;
    begin
     Result := FALSE;
     Index := 0;
     L := 0;
     H := FCount - 1;
     if  H < 0 then Exit; // === if FCount = 0 then Exit;
     if  fAnsiSort then
     begin
         if  fCaseSensitiveSort then
             fCompareStrListFun := CompareAnsiCase
         else
             fCompareStrListFun := CompareAnsiNoCase;
     end
       else
     begin
         if  fCaseSensitiveSort then
             fCompareStrListFun := StrComp
         else
             fCompareStrListFun := StrComp_NoCase;
     end;
     C := 0;
     while L <= H do
     begin
       Index := (L + H) shr 1;
       C := fCompareStrListFun( PAnsiChar( fList.Items[ Index ] ),
                                PAnsiChar( S ) );
       if C < 0 then L := Index + 1 else
       begin
         H := Index - 1;
         if C = 0 then
         begin
           Result := TRUE;
           Exit;
         end;
       end;
     end;
     if  C < 0 then Index := -L;
    end;

  • Vladimir Kladov © (29.03.10 21:20) [19]
    А если немного улучшить StrComp, StrCom_NoCase, то еще быстрее. Где-то на 5%:

    function StrComp(const Str1, Str2: PAnsiChar): Integer; assembler;
    asm
     {$IFDEF F_P}
           MOV     EAX, [Str1]
           MOV     EDX, [Str2]
     {$ENDIF F_P}
     MOV CL, [EAX]
     SUB CL, [EDX]
     JZ  @@compare
     MOVSX EAX, CL
     JMP @@fin
    @@compare:

           PUSH    EDI
           PUSH    ESI
           MOV     EDI,EDX
           XCHG    ESI,EAX
           OR      ECX, -1
           XOR     EAX,EAX
           REPE    CMPSB
           MOV     AL,[ESI-1]
           MOV     DL,[EDI-1]
           SUB     EAX,EDX
           POP     ESI
           POP     EDI
    @@fin:
    end {$IFDEF F_P} [ 'EAX', 'EDX', 'ECX' ] {$ENDIF};

    function StrComp_NoCase(const Str1, Str2: PAnsiChar): Integer;
    asm
     {$IFDEF F_P}
           MOV     EAX, [Str1]
           MOV     EDX, [Str2]
     {$ENDIF F_P}
           PUSH    EDI
           PUSH    ESI
           MOV     EDI,EDX
           XCHG    ESI,EAX
           OR      ECX, -1
           
           MOV     EDI,EDX
     @@0:
           XOR     EDX,EDX
           REPE    CMPSB
           MOV     AL,[ESI-1]
           MOV     AH, AL
           SUB     AH, 'a'
           CMP     AH, 25
           JA      @@1
           SUB     AL, $20
     @@1:
           MOV     DL,[EDI-1]
           MOV     AH, DL
           SUB     AH, 'a'
           CMP     AH, 25
           JA      @@2
           SUB     DL, $20
     @@2:
           MOV     AH, 0
           SUB     EAX,EDX
           JNZ     @@exit
           CMP     DL, 0
           JNZ     @@0

     @@exit:
           POP     ESI
           POP     EDI
    end {$IFDEF F_P} [ 'EAX', 'EDX', 'ECX' ] {$ENDIF};

 
Конференция "KOL" » Версия 2.90 [Delphi, Windows]
Есть новые Нет новых   [134427   +35][b:0][p:0.01]