3. Доработка модуля Generics.Defaults
Как видно из таблице INITFINAL,приведенной в части 2, при инициализации программы вызываются конструкторы классов следующих типов: THashService<T: THashFactory>, TExtendedHashService<T: TExtendedHashFactory> и TOrdinalComparer<T, THashFactory>.
Рассмотрим в начале зависимости для классов THashService<T: THashFactory> и TExtendedHashService<T: TExtendedHashFactory>. Родительскими классами для них являются следующие два абстрактных класса:
THashService = class(TComparerService)
public
class function LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; virtual; abstract;
end;
TExtendedHashService = class(THashService)
public
class function LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; override;
class function LookupExtendedEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; virtual; abstract;
end;
Ограничивая видимость различных разделов спецификаторами видимости strict private и strict protected, были выявлены те методы классов THashService<T: THashFactory> и TExtendedHashService<T: TExtendedHashFactory>, которые вызываются вне этих классов:
THashService<T: THashFactory> = class(THashService)
...
private
class constructor Create;
public
class function LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; override;
end;
TExtendedHashService<T: TExtendedHashFactory> = class(TExtendedHashService)
...
private
class constructor Create;
public
class function LookupExtendedEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; override;
end;
В модуле Generics.Defaults настройка классов для реализации интерфейсов IEqualityComparer<T> и IExtendedEqualityComparer<T>, которые предосталяют функции хеширования, осуществляется только в следующих публичных методах классов THashService<T: THashFactory> и TExtendedHashService<T: TExtendedHashFactory>:
class function THashService<T>.LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer;
class function TExtendedHashService<T>.LookupExtendedEqualityComparer( ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer;
Такой механизм позволяет достаточно легко заменить инициализацию класса через конструктор класса на инициализацию в методе класса. Для этого выполним следующие модификации:
1. В базовом классе THashService добавляем следующую секцию
strict protected class var
FInitiated: boolean;
2. В классах THashService<T: THashFactory> и TExtendedHashService<T: TExtendedHashFactory> заменяем конструктор
class constructor Create;
на метод
class procedure Init;
Код метода Init полностью совпадает с кодом конструктора Create, в конце добавляется строчка
FInitiated := true;
3. В самое функций LookupEqualityComparer и LookupExtendedEqualityComparer добавляем следующий фрагмент:
if not FInitiated then
Init;
Компилируем и запускаем тестовую программу с использование класса TAnsiStringComparer — все работает, получаем следующие результаты:
"абвгде" hash code = 0xD16487C4
"абвгде" hash params = -1; 2
-> list[1] = 0xD16487C4
-> list[2] = 0x00000000
-> list[3] = 0x00000000
-> list[4] = 0x00000000
-> list[5] = 0x00000000
-> list[6] = 0x00000000
Equals "ABCDEF" "ABCDEF" == TRUE
Equals "ABCDEF" "abcdef" == FALSE
Результаты полностью совпадают с полученными при использовании класса TExtendedEqualityComparer<T> — см. часть 1.
Запуск программы с выводом отладочной информации дает следующий листинг:
<<<<<< TOrdinalComparer<T, THashFactory>.Create
ClassName = TOrdinalComparer<System.AnsiString,Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> AnsiString
THashFactory type -> TDelphiQuadrupleHashFactory
<<<<<< TExtendedEqualityComparer<T>.Default
ClassName = TExtendedEqualityComparer<System.AnsiString>
T type -> AnsiString
AExtenedHashFactoryClass type -> TExtendedHashFactoryClass
<<<<<< TExtendedHashService<T>.LookupExtendedEqualityComparer
ClassName = TExtendedHashService<Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> TDelphiQuadrupleHashFactory
Self type name: TExtendedHashService<Generics.Defaults.TDelphiQuadrupleHashFactory>
<<<<<< TExtendedHashService<T>.Init
ClassName = TExtendedHashService<Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> TDelphiQuadrupleHashFactory
TExtendedHashService<T>.Init >>>>>>
Result = 0x00461C9C
TExtendedHashService<T>.LookupExtendedEqualityComparer >>>>>>
Result = 0x00461C9C
Result type -> IExtendedEqualityComparer$1$crcB76584A7
TExtendedEqualityComparer<T>.Default >>>>>>
FEqualityComparer = 0x00461C9C
FExtendedEqualityComparer = 0x00461C9C
TOrdinalComparer<T, THashFactory>.Create >>>>>>
<<<<<< TOrdinalComparer<T, THashFactory>.Create
ClassName = TOrdinalComparer<System.UnicodeString,Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> UnicodeString
THashFactory type -> TDelphiQuadrupleHashFactory
<<<<<< TExtendedEqualityComparer<T>.Default
ClassName = TExtendedEqualityComparer<System.UnicodeString>
T type -> UnicodeString
AExtenedHashFactoryClass type -> TExtendedHashFactoryClass
<<<<<< TExtendedHashService<T>.LookupExtendedEqualityComparer
ClassName = TExtendedHashService<Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> TDelphiQuadrupleHashFactory
Self type name: TExtendedHashService<Generics.Defaults.TDelphiQuadrupleHashFactory>
Result = 0x00461CA4
TExtendedHashService<T>.LookupExtendedEqualityComparer >>>>>>
Result = 0x00461CA4
Result type -> IExtendedEqualityComparer$1$crcFF9B7487
TExtendedEqualityComparer<T>.Default >>>>>>
FEqualityComparer = 0x00461CA4
FExtendedEqualityComparer = 0x00461CA4
TOrdinalComparer<T, THashFactory>.Create >>>>>>
-------------- PASCAL MAIN --------------
<<<<<< TGStringComparer<T, THashFactory>.Ordinal
ClassName = TAnsiStringComparer
T type -> AnsiString
THashFactory type -> TDelphiQuadrupleHashFactory
FEqualityComparer = 0x00461C9C
FExtendedEqualityComparer = 0x00461C9C
FOrdinal = 0x001F2AD8
FOrdinal type -> TCustomComparer$1$crcB76584A7
FOrdinal ClassName -> TGOrdinalStringComparer<System.AnsiString,Generics.Defaults.TDelphiQuadrupleHashFactory>
TGStringComparer<T, THashFactory>.Ordinal >>>>>>
<<<<<< TGOrdinalStringComparer<T, THashFactory>.GetHashCode
ClassName = TGOrdinalStringComparer<System.AnsiString,Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> AnsiString
THashFactory type -> TDelphiQuadrupleHashFactory
FEqualityComparer = 0x00461C9C
FExtendedEqualityComparer = 0x00461C9C
TGOrdinalStringComparer<T, THashFactory>.GetHashCode >>>>>>
"абвгде" hash code = 0xD16487C4
<<<<<< TGOrdinalStringComparer<T, THashFactory>.GetHashList
ClassName = TGOrdinalStringComparer<System.AnsiString,Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> AnsiString
THashFactory type -> TDelphiQuadrupleHashFactory
FEqualityComparer = 0x00461C9C
FExtendedEqualityComparer = 0x00461C9C
TGOrdinalStringComparer<T, THashFactory>.GetHashList >>>>>>
"абвгде" hash params = -1; 2
-> list[1] = 0xD16487C4
-> list[2] = 0x00000000
-> list[3] = 0x00000000
-> list[4] = 0x00000000
-> list[5] = 0x00000000
-> list[6] = 0x00000000
Equals "ABCDEF" "ABCDEF" == TRUE
Equals "ABCDEF" "abcdef" == FALSE
Видно, что на этапе инициализации программы выполняется вызов двух конструкторов класса TOrdinalComparer<T, THashFactory>, в которых выполняется специализация для типов AnsiString и UnicodeString и хешера TDelphiQuadrupleHashFactory. На этом этапе не выполняется ни одного вызова конструкторов классов THashService<T: THashFactory> и TExtendedHashService<T: TExtendedHashFactory>, которые выполнялись при инициализации программы до внесения наших изменений (см листинг в части 2). Виден лишь один вызов class procedure TExtendedHashService<T>.Init при первом обращении к методу class function TExtendedHashService<T>.LookupExtendedEqualityComparer.
В таблица INITFINAL остается лишь два вызова конструкторов класса для generic'ов модуля Generics.Defaults (выделены красным цветом), то есть внесенные изменения убрали вызовы 10-ти конструкторов по сравнению с исходной таблицей INITFINAL.
.section .data.n_INITFINAL,"d"
.balign 4
.globl INITFINAL
INITFINAL:
.long 24,0
.long INIT$_$SYSTEM
.long 0,0
.long FINALIZE$_$OBJPAS
.long INIT$_$LINEINFO
.long FINALIZE$_$LINEINFO
.long INIT$_$FPINTRES
.long 0,0
.long FINALIZE$_$WINDIRS
.long SYSUTILS$_$TENCODING_$__$$_create
.long SYSUTILS$_$TENCODING_$__$$_destroy
.long INIT$_$SYSUTILS
.long FINALIZE$_$SYSUTILS
.long INIT$_$TYPINFO
.long FINALIZE$_$TYPINFO
.long INIT$_$CLASSES
.long FINALIZE$_$CLASSES
.long INIT$_$FPCADDS
.long 0,0
.long FINALIZE$_$GETTEXT
.long INIT$_$LAZUTF8
.long FINALIZE$_$LAZUTF8
.long INIT$_$GENERICS.HASHES
.long 0
.long INIT$_$VARIANTS
.long FINALIZE$_$VARIANTS
.long INIT$_$MYDEBUG
.long FINALIZE$_$MYDEBUG
.long GENERICS.DEFAULTS$_$TORDINALCOMPARER$2$CRC09680922_$__$$_create
.long 0,0
.long GENERICS.DEFAULTS$_$TGSTRINGCOMPARER$2$CRC09680922_$__$$_destroy
.long GENERICS.DEFAULTS$_$TORDINALCOMPARER$2$CRC603AE4FA_$__$$_create
.long 0,0
.long GENERICS.DEFAULTS$_$TGSTRINGCOMPARER$2$CRC603AE4FA_$__$$_destroy
.long 0
.long GENERICS.DEFAULTS$_$TGISTRINGCOMPARER$2$CRC09680922_$__$$_destroy
.long 0
.long GENERICS.DEFAULTS$_$TGISTRINGCOMPARER$2$CRC603AE4FA_$__$$_destroy
.long 0
.long GENERICS.DEFAULTS$_$TGORDINALIUTF8STRINGCOMPARER$2$CRC09680922_$__$$_destroy
.long INIT$_$GENERICS.DEFAULTS
.long FINALIZE$_$GENERICS.DEFAULTS
.long INIT$_$P$TESTGCM
.long FINALIZE$_$P$TESTGCM
Для удаления вызовов конструкторов класса TOrdinalComparer<T, THashFactory> поступим аналогично описанному для классов THashService<T: THashFactory> и TExtendedHashService<T: TExtendedHashFactory>:
1. В базовом классе TOrdinalComparer<T, THashFactory> добавляем следующую секцию
strict protected class var
FInitiated: boolean;
2. Также заменяем конструктор
class constructor Create;
на метод
class procedure Init;
Код метода Init полностью совпадает с кодом конструктора Create, в конце добавляется строчка
FInitiated := true;
3. Во всех классах–наследниках в функциях class function Ordinal: TCustomComparer<T> добавляем следующий фрагмент:
if not FInitiated then
Init;
Листинг запуска тестовой программы с включенным выводом отладочной информации имеет следующий вид:
-------------- PASCAL MAIN --------------
<<<<<< TGStringComparer<T, THashFactory>.Ordinal
ClassName = TAnsiStringComparer
T type -> AnsiString
THashFactory type -> TDelphiQuadrupleHashFactory
FEqualityComparer = 0x00000000
FExtendedEqualityComparer = 0x00000000
<<<<<< TOrdinalComparer<T, THashFactory>.Init
ClassName = TAnsiStringComparer
T type -> AnsiString
THashFactory type -> TDelphiQuadrupleHashFactory
<<<<<< TExtendedEqualityComparer<T>.Default
ClassName = TExtendedEqualityComparer<System.AnsiString>
T type -> AnsiString
AExtenedHashFactoryClass type -> TExtendedHashFactoryClass
<<<<<< TExtendedHashService<T>.LookupExtendedEqualityComparer
ClassName = TExtendedHashService<Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> TDelphiQuadrupleHashFactory
Self type name: TExtendedHashService<Generics.Defaults.TDelphiQuadrupleHashFactory>
<<<<<< TExtendedHashService<T>.Init
ClassName = TExtendedHashService<Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> TDelphiQuadrupleHashFactory
TExtendedHashService<T>.Init >>>>>>
Result = 0x00461CA0
TExtendedHashService<T>.LookupExtendedEqualityComparer >>>>>>
Result = 0x00461CA0
Result type -> IExtendedEqualityComparer$1$crcB76584A7
TExtendedEqualityComparer<T>.Default >>>>>>
FEqualityComparer = 0x00461CA0
FExtendedEqualityComparer = 0x00461CA0
TOrdinalComparer<T, THashFactory>.Init >>>>>>
FOrdinal = 0x00082C78
FOrdinal type -> TCustomComparer$1$crcB76584A7
FOrdinal ClassName -> TGOrdinalStringComparer<System.AnsiString,Generics.Defaults.TDelphiQuadrupleHashFactory>
TGStringComparer<T, THashFactory>.Ordinal >>>>>>
<<<<<< TGOrdinalStringComparer<T, THashFactory>.GetHashCode
ClassName = TGOrdinalStringComparer<System.AnsiString,Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> AnsiString
THashFactory type -> TDelphiQuadrupleHashFactory
FEqualityComparer = 0x00461CA0
FExtendedEqualityComparer = 0x00461CA0
TGOrdinalStringComparer<T, THashFactory>.GetHashCode >>>>>>
"абвгде" hash code = 0xD16487C4
<<<<<< TGOrdinalStringComparer<T, THashFactory>.GetHashList
ClassName = TGOrdinalStringComparer<System.AnsiString,Generics.Defaults.TDelphiQuadrupleHashFactory>
T type -> AnsiString
THashFactory type -> TDelphiQuadrupleHashFactory
FEqualityComparer = 0x00461CA0
FExtendedEqualityComparer = 0x00461CA0
TGOrdinalStringComparer<T, THashFactory>.GetHashList >>>>>>
"абвгде" hash params = -1; 2
-> list[1] = 0xD16487C4
-> list[2] = 0x00000000
-> list[3] = 0x00000000
-> list[4] = 0x00000000
-> list[5] = 0x00000000
-> list[6] = 0x00000000
Equals "ABCDEF" "ABCDEF" == TRUE
Equals "ABCDEF" "abcdef" == FALSE
Таким образом удалось:
- 1. Удалить все вызовы конструкторов класса из этапа инициализации программы, где порядок их вызова был фактически неконтролируемым. Инициализацию необходимых классов перенесена на этап исполнения программы.
- 2. Удаление вызова конструкторов для неиспользуемых классов уменьшает размер программы примерно на 29 кбайт :).
К началу
|