Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 [ 97 ] 98 99 100 101 102 103 104 105

canbacks .push back(Row()); idxLhs = callbacks..sizeQ - 1;

else if (callbacks .size() <= idxLhs) {

callbacks..resizeCidxLhs +1);

ROW& thisRow = callbacks [idxLhs];

int idxRhs = SomeRhs::GetClasslndexStaticC);

if (idxRhs < 0)

thisRow.resizeC++columns ); idxRhs = thisRow.sizeC) - 1;

else if (thisRow.sizeC) <= idxRhs) {

thisRow.resize(idxRhs + 1);

thisRow[idxRhs] = pFun;

Матрица обратных вызовов реализуется в виде вектора, состоящего из векторов типа MappedType. Функция BasicFastDispatcher: :Add выполняет следующую последовательность действий.

• Извлекает идентификационный номер каждого класса, вызывая функцию Get-С1assindexStati с.

• Выполняет инициализацию и настройку, если один или оба индекса не были проинициализированы. Для неинициализированных индексов функция Add расширяет матрицу, добавляя в нее дополнительный элемент.

• Вставляет обратный вызов в соответствующую позицию матрицы.

Переменная-член columns подсчитывает количество столбцов, добавленных к данному моменту. Строго говоря, эта переменная излищня. Вычисление максимальной длины строки в матрице приведет к тому же результату. Однако переменная col -umns добавлена для удобства.

Теперь легко реализовать функцию BasicFastDispatcher: :Go. Основное отличие от предыдущей реализации заключается в том, что теперь функция Go использует виртуальную функцию GetClassindex.

template <.. .>

class BasicFastDispatcher

... как и раньше ...

ResultType GoCBaseLhs& Ihs, BaseRhs& rhs) {

int& idxLhs = Ihs.GetClassindexC); int& idRhs = rhs.GetClasslndexC); if (idxLhs < 0 M idxRhs < 0

idxLhs >= ca1lbacks .sizeC)

idxRhs >= callbacs [idxLhs].sizeC) II

callbacks [idxLhs][idxRhs] == 0)

... обработка ошибок ...



return canbacks [idxLhs] [idxRhs] .canback Clhs, rhs);

Подведем итоги. Мы определили диспетчер, используюший матрицу. Он позволяет выполнить обратный вызов на постоянное время с помошью доступа к целочисленному индексу каждого класса. Кроме того, он выполняет автоматическую инициализацию данных (индексов, соответствуюших классам). Пользователи класса BasicFastDispatcher должны добавить в каждый класс, используюший диспетчер, одну строку макроса IMPLEMENT INDEXABLE CLASS(класс).

11.11. Классы BasicDispatcher и BasicFastDispatcher как стратегии

Класс BasicFastDispatcher (основанный на матрице) предпочтительнее класса BasicDispatcher (основанного на карте) с точки зрения быстродействия. Однако на основе класса BasicDispatcher были разработаны прекрасные классы FnDispatcher и FunctorDispatcher. Можно ли создать два новых класса- FnFastDispatcher и FunctorFastDispatcher, которые использовали бы класс BasicFastDispatcher?

Лучше попытаться адаптировать классы FnDispatcher и FunctorDispatcher так, чтобы они могли использовать класс BasicDispatcher или BasicFastDispatcher в зависимости от шаблонного параметра. Таким образом, диспетчер следует реализовать в виде стратегии для классов FnDispatcher и FunctorDispatcher, как это мы делали для приведения типов.

Задача преобразования диспетчера в стратегию облегчается, поскольку классы BasicDispatcher и BasicDispatcher имеют одинаковый интерфейс вызова. Таким образом, их легко менять местами, изменяя шаблонный аргумент.

Ниже приводится модифицированное объявление класса FnDispatcher (класс FunctorDispatcher объявляется аналогично).

template

<

class BaseLhs, class BaseRhs = BaseLhs, typename ResultType = void, template <class, class>

class CastingPolicy = DynamicCaster, template <class, class, class, class>

class DispatcherBackend = BasicDispatcher

>

class FnDispatcher; Аналогично классу FunctorDispatcher

Сами классы практически не изменяются.

Уточним требования, предъявляемые к стратегии DispatcherBackend. Прежде всего, очевидно, что эта стратегия должна быть шаблонным классом с четырьмя параметрами. Семантика этих параметров такова.

• Тип левого операнда.

• Тип правого операнда.

• Тип значения, возвращаемого обратным вызовом.

• Тип обратного вызова.



в табл. 11.1 класс BackendType представляет собой конкретизацию диспетчера, а объект backEnd - переменную этого типа. Таблица содержит функции, о которых мы не упоминали, - не беспокойтесь. Полное описание диспетчера должно содержать функции удаления обратных вызовов и "пассивного" просмотра без обращения к обратным вызовам. Они реализуются тривиальным образом. Их описание приведено в библиотеке Loki в файле Mul timethods. h.

Таблица 11.1. Требования, предъявляемые к стратегии DispatcherBackend

Выражение

Тип возвращаемого значения

Примечания

сору, assign, swap, destroy

backEnd.Add<SomeLhs, SomeRhs>Ccanback)

backEnd.GoCBaseLhsA, BaseRhsA)

backEnd.Remove<SomeLhs, SomeRhs>C)

backEnd.HandlerExi sts <SomeLhs, SomeRhs>C)

Семантика значений

void Добавляет обратный вызов в

объект backEnd для типов SomeLhs и SomeRhs

ResultType Выполняет просмотр и

диспетчеризацию для двух объектов. Если обработчик не найден, генерирует исключительную ситуацию std::runtume error

bool Удаляет обратный вызов для

типов SomeLhs и SomeRhs. Если обратный вызов существовал, возвращает значение true

bool Если обратный вызов для типов

SomeLhs и SomeRhs зарегистрирован, возвращает значение true. Новый обратный вызов не добавляется

11.12. Перспективы

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

На самом деле это довольно просто. Мы определили три типа диспетчеров.

• Статический диспетчер, управляемый двумя списками типов.

• Диспетчер, управляемый ассоциативным массивом, содержащим пары объектов типа std: :type info в качестве ключей.

• Диспетчер, управляемый матрицей, индексированной уникальными идентификационными номерами классов.

Эти диспетчеры можно легко обобщить. Статический диспетчер, управляемый двумя списками типов, можно преобразовать в диспетчер, управляемый одним спи-

Эти объекты скрыты под оболочкой класса OrderedTypeinfo, облегчающего сравнение и копирование.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 [ 97 ] 98 99 100 101 102 103 104 105