пятница, декабря 29, 2006

Инструменты, которые Free

Скорее речь даже не об инструментальных средствах разработчика, а о free-софте вообще. После выхода Turbo Delphi Explorer (которая free) у меня появилось желание если не отказаться от проприетарного софта совсем, то хотя бы свести его использование к минимуму. Как раз к этому моменту, вдоволь наэкспериментировавшись с Вистой (коею пользоваться не собираюсь, но в курсе быть нужно), решил начать с чистого листа, т.е. винта :) Вставил рекавери в свою Тошу и согласился на все, что мне предложили ;).

Итак:

  • ОС - лицензионная XP Pro SP2.
  • Браузер - Опера 9
  • Почта - Опера 9
  • Качалка - WinWGet (оболочка над консольной wget)
  • Аська - QIP
  • Блог-клиент - Windows Live Writer
  • Музычка - foobar 2000
  • Видео - Media Player Classic
  • Офис - OpenOffice (мне очень понравился)
  • CD писалка - с Тошей в комплекте идет Drag'n Drop CD+DVD (рядом поставил CDBurnerXP 3 Pro)
  • CD-виртуализатор - Алкоголь 120% (вечный триал ;) ибо мне хватает 3 дисков из 6 доступных)
  • Графика - GIMP, PhotoFiltre, XnView
  • 3D - Blender
  • Веб-дизайн - Nvu (мне показался удобнее дрима :)
  • Виртуалка - Microsoft Virtual PC 2004 (она же free!!!)
  • Архиватор - 7zip
  • Файл-менеджер - Far
  • Файрвол - Jetico Personal Firewall
  • Антивирус - Dr.Web CureIT!
  • Секурность - TrueCrypt
  • Программирование - Turbo Delphi Explorer, Ada GNAT
  • СУБД - FireBird (у него же есть embedded версия!!! ;) средство администрирования - IBExpert (для русских free!!!) (смотрел еще на Interbase Development Studio, но что-то она глючновата...)
  • Инсталь-мейкер - InnoSetup
  • Компоненты - множество бесплатных и разных ;) Условие только одно - наличие исходников. Очень нравятся: Synapse, UIB, ToolBar2000

Чему не нашел замены (может посоветует кто...):

  • Macromedia Fireworks (правда я его использовал не по назначению, а именно, как обычную рисовалку (т.е. его веб-ориентация меня мало интересовала). Может глянуть на Inscape или, как его там...)
  • AWIcons Pro - отличный редактор иконок
  • ReGet WebSynchronizer - отличный синхронизатор (я им бэкапы исходников делаю :)

вторник, декабря 19, 2006

И снова пакеты в Turbo Delphi Explorer

Ранее я уже писал о процессе подключения пакетов в Turbo Delphi Explorer, а теперь выкладываю модуль делающий это без необходимости саморегистрации подключаемых пакетов.

понедельник, ноября 13, 2006

Ловкость рук, и ни какого мошенства

Задача: дан класс имеющий приватный TThreadList (список с thread-safe доступом) и содержащий некие объекты. Нужно написать метод предоставляющий безопасный доступ к содержимому списка, без доступа пользователя к объекту-списку.

На первый взгляд задача совсем не простая т.к. для того чтоб обеспечить безопасный доступ необходимо вызывать методы блокировки/разблокировки объекта-списка, а условия нам этого не позволяют. На помощь приходят... интерфейсы (ну если быть точным, то лишь механизм подсчета их ссылок).

Решение: Определяем интерфейс IObjectProvider, который будет возвращать наш метод.

Type

IObjectProvider = Interface

Function GetObject : TObject;

Property Object : TObject Read GetObject;

End;

Затем описываем класс TObjectProvider, который реализует описанный ранее интефейс.

Type

//
TObjectProvider = Class(TInterfacedObject, IObjectProvider)

Private

FList : TThreadList;
FObject : TObject;

Public

Constructor Create(Const AList : TThreadList; AIndex : Integer);
Destructor Destroy; Override;

Function GetObject : TObject;

End;
//

// Реализация конструктора
Begin

FList := AList;
FObject := TObject(FList.LockList.Items[AIndex]);

End;
//

// Реализация деструктора
Begin

FList.UnlockList;
Inherited;

End;
//

// Реализация метода GetObject
Begin

Result := FObject;

End;
//


Теперь можно реализовать и наш метод:

Function SafeGetObject(AIndex : Integer) : IObjectProvider;
Begin

Result := TObjectProvider.Create(ThreadSafeList, AIndex);

End;

Как видно из кода, метод возвращает не сам объект, а интерфейс объекта-провайдера, для обеспечения безопасности. Пользователь вызвав метод и раскрыв его оператором with, получает в эксклюзивное пользование затребованный объект, а после завершения работы с объектом сработает механизм подсчета ссылок и будет вызван деструктор объекта-провайдера, который в свою очередь разблокирует список, после чего объект-провайдер будет разрушен.


Пример:

With SafeGetObject(5) Do
Begin

Object.Method;
...
Object.Method;

End;

воскресенье, ноября 12, 2006

Выравнивание вариантной части

Сегодня столкнулся с интересной штукой: вариантные поля (описанные с использованием case) записи могут быть выровнены по разному (ну компилятору ес-но виднее). В смысле не гарантируется что начало каждого вариантного поля будет сразу после последнего описанного не вариантного (или начала записи). Об этом, по большому счету, можно и не беспокоится до тех пор пока не придется обращаться к полям по смещению ;). Но об этом нужно помнить и быть аккуратным.

p.s. На packed записях не проверял.

понедельник, октября 30, 2006

Заменитель Indy

Не так давно открыл для себя сетевую библиотеку Synapse. Ощущения самые положительные. В отличии от монстра по имени Indy, Synapse являет собой легкую и элегантную оболочку над сетевой инфраструктурой сокетов. В настоящий момент, на ее основе, мною создаются транспортные уровни клиента и сервера XML-RPC (правда реализация на Indy, тоже предусматривается ;))

Глюкобага. Очередная...

Заколебало :( Сегодня снова столкнулся с очень неприятной багой компилятора (бага старая и ранее я ее описывал на iXBT).

Объявляем вложенный тип в записи. Пытаемся объявить поле данного типа и получаем от компилятора пламенный привет. А вот свойства объявленного вложенного типа определяются на ура. Есть workaround: объявить поле с типом допускающим приведение к объявленному, объявить свойство проблемного типа и в методах доступа (read/write) производить приведение типов (поле к свойству/свойство к полю). Дабы устранить оверхэд методов, объявить их, как  inline.

среда, октября 18, 2006

Маленькая радость

Америки я не отрою, если скажу, что с появлением динамических массивов и динамических строк жить стало легче, жить стало веселей :) Распределение памяти и управление временем жизни берет на себя компилятор, а мы можем избавится от выделения буферов средствами GetMem и ей подобным, т.к. такие массивы и строки являются по сути указателями на те самые буферы. И самое приятное, что такой буфер можно передать любой части программы без (даже временного) дублирования, т.к. компилятор использует механизм подсчета ссылок. Правда использовать такой буфер придется с приведением типа, но оно того стоит ;)

Пример:

s := 'http://www.borland.com/';


Stream.Write(Pointer(s)^, Length(s));

четверг, октября 12, 2006

Борис, ты не прав!

FAQ Apache, в части о сжатии запроса/ответа XML-RPC, говорит о том, что спецификация XML-RPC запрещает использование сжатия (и где они это нашли??). Считаю необходимым прояснить ситуацию. Спецификация XML-RPC требует: чтоб тип контента (Content-Type) запроса/ответа соответствовал text/xml, имелись некоторые обязательные заголовки (User-Agent, Content-Length) и не более того. Спецификация не запрещает применения сжатия к контенту (Content-Encoding), поэтому - Apache, ты не прав!

понедельник, октября 02, 2006

Enumerators (for-in-do)

Одним из самых заметных нововведений BDS 2006 является внесение в язык конструкции расширяющей оператор цикла For. For <container_item> In <container> Do; Переписывать сюда кусок документации не считаю нужным, и поэтому буду краток :) Лучше реализовывать перечислители в виде advanced-records т.к. при работе с ними не требуется динамического распределения памяти, а значит, код будет работать быстрее. Плюс удобнее работать с перечислителем вручную (не нужно создавать, не нужно финалить и разрушать), в случае необходимости. Правда сделать это (реализовать записью) не всегда удается, т.к. компилятор начинает ругаться на возвращаемый тип от GetEnumerator (видимо очередная глюкобага). Удачный пример перечислителя - перебор элементов XML документа, учитывая его структуру (каждый элемент может являться и родителем и ребенком) можно создать эффективный инструмент для перебора дочерних элементов любого родителя (хоть корня, хоть любого ребенка) с возможностью полного/близкого перебора. Сам перечислитель может обладать при этом указателем текущей глубины и номером элемента относительно начала перебора.

суббота, сентября 23, 2006

Счастливы вместе

Речь снова о TurboDelphi. Описаный ранее трюк с подключением пакетов перестает работать после установки вышедшего не так давно патча. Установка в среду пакета dclusr становится невозможной, а если он был ранее установлен то последующая его пересборка приведет к тому, что пакет из среды будет удален. Но есть решение: установить данный пакет до установки патча, код загрузки с прямым указанием загружаемых пакетов заменить на чтение списка пакетов из файла. После чего установить патч и не изменять dclusr.

четверг, сентября 21, 2006

Кодировки в XML-RPC

Неоднократно встречал в сети недовольные высказывания относительно того, что спецификация XML-RPC никак не регламентирует использование различных кодировок, в частности Unicode (и это, якобы, является минусом протокола). Но я считаю, что авторы этих высказываний (как и авторы библиотек включивших поддержку Unicode) не до конца понимают сути XML-RPC. Дело в том, что пакеты XML-RPC это лишь транспорт для данных приложения/сервиса и в каком виде данные должны предоставляться дело именно взаимодействующих сущностей, но ни как не протокола. На самом деле проблемы нет, как таковой. Ни что не мешает сервису предъявлять требования к передаче строк в кодировке, скажем UTF-8, если в том есть необходимость, а клиенту останется только "соответствовать". Такое требование затрагивает лишь данные, но не формат самого пакета. Таким образом и цель достигается, и происходит все в рамках спецификации. Выходит, что эта проблема "не в клозетах, а в головах" (c) Почти Булгаков :)

 

P.S.

Ну, а если вспомнить, что спецификация XML говорит об использовании UTF-8 во всяком случае, когда кодировка не может быть определена (не указаны Encoding и ByteOrder), то все становится просто и понятно, ведь пакеты XML-RPC не содержат ни того ни другого ;)

100 лет вместе с Turbo!

Позавчера получил CD c TurboDelphi 2006 Explorer! Спасибо Borland'у за бесплатную лицензию на 100 лет :) Правда в версии Explorer есть ограничение, а именно невозможность установки в среду сторонних компонентов. Но "ничего нет невозможного, для врача, для неотложного" (c) Розенбаум :), поэтому рецепт в студию: открываем пакет dclusr.dpk (это стандартный пакет пользовательских компонент и его установка допустима) и добавляем в него новый модуль инициализационная часть которого содержит код для загрузки необходимых пакетов:

Initialization

  LoadPackage('package_1.bpl');

  LoadPackage('package_1.bpl');

  LoadPackage('package_1.bpl');

Но это еще не все! Для успешности данной операции необходимо, чтоб загружаемые пакеты могли саморегистрироваться (в отличие от обычного способа, когда регистрацией занимается среда) т.е. в инициализационной части модуля/модулей необходимо вызвать процедуру Register. Теперь все :) При запуске среды будет загружен dclusr.bpl, который, в свою очередь, загрузит нужные нам пакеты.

пятница, сентября 15, 2006

Багафича, даже две...

На оператор класса Implicit (другие не пробовал) не действует директива Inline. Все условия для Inline соблюдены, но тело оператора не разворачивается в код :( И еще об Implicit: не удается добиться работоспособности данного оператора при декларировании с типами Double и TDateTime. Типы по описанию не идентичные, но компилятор, так, видимо, не считает... Поэтому, если описать неявное преобразование в Double, будет допустимо присваивание значения типа TDateTime, но при этом, разумеется, будет вызван метод Implicit для типа Double. Если же описать неявное преобразование для них обоих, будет потеряна всякая возможность присваивания значений данных типов. Такое вот, хреновое лето...

среда, сентября 06, 2006

Advanced Records ("class-like")

Замечательная возможность BDS 2006! Работа с записями превращается в сказку, в смысле элегантности использования при грамотном проектировании. Использование свойств, методов и модификаторов видимости позволяет абстрагироваться от внутренней структуры записи, а применение директивы inline уменьшает/сводит на нет, какие бы то нибыло накладные расходы. В результате получаем работу с абстракцией и имеем при этом "чистый код"! Наличие конструкторов (пусть и параметризированных) облегчает использование advanced records в коде т.к. избавляет от необходимости объявлять переменные. Огромным плюсом является и тот факт, что даже при "конструировании" запись остается статической переменной, что в свою очередь снижает (опять же) накладные расходы и стимулирует к использованию advanced records в качестве перечислителей (enumerators). О перечислителях немного позже ;)

Небольшой пример:

    // Структура для хранения данных о регионе
TData = Record

Public

{$REGION ' Определение вложенных членов '}

Type

// Массив прямоугольников и указатель на него
TRects = Array [0 .. MaxInt Div SizeOf(TRect) - 1] Of TRect;
PRects = ^TRects;

{$ENDREGION}

Strict Private

FBuffer : TByteDynArray;

Function GetPRect(AIndex : Cardinal) : PRect; Inline;

{$REGION ' Методы доступа к значениям свойств '}

Function GetBuffer : Pointer; Inline;
Function GetBufferSize : Integer; Inline;
Function GetHeader : PRgnDataHeader; Inline;
Function GetRects : PRects; Inline;
Function GetRectCount : Integer; Inline;
Procedure SetRectCount(Const Value : Integer); Inline;

{$ENDREGION}

Public

{$REGION ' Поддержка оператора for-in-do '}

Function GetEnumerator : TRectEnumerator; Inline;

{$ENDREGION}

Constructor Create(ARegion : HRGN); Overload;
Constructor Create(ARegion : TRegion); Overload;

Procedure UpdateHeader(ARecalculateBounds : Boolean = False);
Procedure RecalculateBounds;

Function TakeFrom(ARegion : TRegion{$IFDEF LASTERROR_SUPPORT}; Out ALastError : Longword{$ENDIF}) : Boolean; Overload;

{$IFDEF LASTERROR_SUPPORT}

Function TakeFrom(ARegion : TRegion) : Boolean; Overload; Inline;

{$ENDIF}

Function TakeFrom(ARegion : HRGN{$IFDEF LASTERROR_SUPPORT}; Out ALastError : Longword{$ENDIF}) : Boolean; Overload;

{$IFDEF LASTERROR_SUPPORT}

Function TakeFrom(ARegion : HRGN) : Boolean; Overload; Inline;

{$ENDIF}

Function TakeFrom(Const ARects : Array Of TRect) : Boolean; Overload;
Function TakeFrom(Const ABuffer : TByteDynArray) : Boolean; Overload;

Property Buffer : Pointer Read GetBuffer;
Property BufferSize : Integer Read GetBufferSize;
Property Header : PRgnDataHeader Read GetHeader;
Property Rects : PRects Read GetRects;
Property RectCount : Integer Read GetRectCount Write SetRectCount;

End;

Turbo возвращается!

Сегодня стала доступна для скачивания TurboDelphi! Ура, товарищи! Уже заказал CD, поглядим через пару неделек :)

пятница, августа 25, 2006

Class Helpers

Еще один способ облегчить себе жизнь воспользовавшись прелестями BDS 2006, а именно прелестью вынесенной в заголовок. Об этом я тоже уже упоминал но повторить (да еще и самого себя) не помешает. Итак:

Type

// Класс-хелпер для класса TObject
TObjectClassHelper = Class Helper For TObject

Private

{$REGION ' Методы доступа к значениям свойств '}

Function GetThis : TObject; Inline;
Function GetThisAssigned : Boolean; Inline;

{$ENDREGION}

Public

Property This : TObject Read GetThis;
Property ThisAssigned : Boolean Read GetThisAssigned;

End;

Implementation

{ TObjectClassHelper }

//
Function TObjectClassHelper.GetThis : TObject;
Begin

Result := Self;

End;
//

//
Function TObjectClassHelper.GetThisAssigned : Boolean;
Begin

Result := Assigned(Self);

End;
//


Удобно использовать в коде требующем ссылку на объект раскрытый оператором With. В зависимости от стиля программирования такое может случаться довольно часто ;) Примеры:


  With TRegion.CreateAssigned(ARegion, amSharing) Do
Try

Result := TakeFrom(TRegion(This), ALastError);

Finally

Free;

End;
 With FindControl(0) Do
If ThisAssigned Then
Caption := Caption + 'OK';

четверг, августа 24, 2006

Record Helpers

С чего-то нужно было начинать, поэтому я начну с того о чем уже упоминал. Несмотря на то, что в документации BDS 2006 не сказано о наличии record helper'ов для платформы Win32 (я во всяком случае не нашел) эта изумительная вещица работает! Простейший пример иллюстрирует всю прелесть данной конструкции:

 Type
  TRectHelper = Record Helper For TRect

Function GetWidth : Integer; Inline;
Function Getheight : Integer; Inline;

Property Width : Integer Read GetWidth;
Property Height : Integer Read GetHeight;

End;

...

//
Function TRectHelper.GetWidth : Integer;
Begin

With Self Do
Result := Right - Left;

End;
//

//
Function TRectHelper.GetHeight : Integer;
Begin

With Self Do
Result := Bottom - Top;

End;
//

После чего все переменные типа TRect получают свойства Width и Height.