Анимация
JavaScript
|
Главная Библионтека 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 |