• No se han encontrado resultados

C. Descripci´ on detallada del proceso de desarrollo 51

C.3. Dise˜ no de la aplicaci´ on

In order to understand the components of the high level interface of the static data-flow dispatcher, some details of the implementation have to be discussed first. Therefore, the library developer’s view will be explained first and the view of the algorithm developer is shown afterwards.

The data-flow dispatcher must be configurable at compile-time. To enable compile-time configuration, the following C++type definitions model the static data-flow dispatcher.

The definition of the data-flow dispatcher requires two sets:

 the first set encompasses the data-events and

 the second set encompasses the callable event handlers.

These sets are defined by using enumerations. Listing 3.14 shows an abstract example using three data-events and four event-handlers. These definitions are the basis for creating the data-flow dispatcher.

As mentioned in the definition, the event handlers need to be executable. This functionality is done with a helper class called CallableImpl. Listing 3.15 shows

an example of this helper class. The class has a template parameter from the set of event handlers. To provide the callable feature of an event handler, the class

Listing 3.16:Definition of the EventListener Type

1 template <DataEventSet RegisteredEvent, EventHandlerSet... EventHandlers>

2 class EventListener {

3 // ...

4 };

5

6 // Example

7 using EventListener1 = EventListener<DataEvent2, TaskC>;

8 using EventListener2 = EventListener<DataEvent1, TaskA, TaskB>;

Listing 3.17:EventListenerContainer for collecting EventListeners

1 template <typename... EventListeners>

2 class EventListenerContainer {

3 // ...

4 }

needs to be specialized and a static Call method needs to be provided. This is

done at line 4 for the event handler TaskA. With this class, the event handlers become callable.

Until now, it is only possible to define a set of data-events and a set of callable event handlers. For the definition of a data-flow dispatcher the composition of data-events and event handlers into the event listeners is required. Listing 3.16 shows the definition of the event listener type. The classEventListener has two

template parameters. The first is the registered event and the second is an arbitrary number of event handlers. Listing 3.16 also shows two examples of concrete event listeners. The first uses the data-eventDataEvent2 and the event handler TaskC.

The second example combines the data-event DataEvent1and the event handler

TaskA andTaskB.

The last feature missing for the static data-flow dispatcher is the possibility to collect event listeners. This is done using the event listener container shown in Listing 3.17. The EventListenerContainer uses a variadic template parameter for arbitrary many event listeners.

The Dispatch Flow

Using the data structures shown before the structure of the static data-flow dis- patcher can be defined. The only thing missing is the actual dispatch functionality. This will be introduced now.

The desired dispatch workflow can be seen in Figure 3.15. TheEventListener- Container and the EventListener are extended with a static dispatch method. The top level dispatch method is the method called by the algorithm developer and implemented in theEventListenerContainer. This method will iterate over

all registeredEventListeners and call their dispatch method. The event listeners will filter if the triggered event is equal to the registered event. If the events are the same, the event listener will call the callable helper class for all event handlers. If the events are not the same, the event listener will immediately return. Since the data-flow structure is defined as template parameters, the iteration as well as

EventListeners left?

[no]

triggered event = registered event?

call event handlers [yes] [no]

activity EventListener::dispatch

[yes]

activity EventListenerContainer::dispatch

Figure 3.15: The flow of the dispatch method of the EventListenerContainer. The

EventListenerContaineriterates over all availableEventListenerand calls their dispatch methods. TheEventListener calls the event handlers if the events match.

Listing 3.18:EventListener template

1 template <DataEventSet triggered_event, typename... Args>

2 static typename std::enable_if<triggered_event == registered_event, void>::type

3 dispatch(Args &&... args) {

4 // Events are the same.

5 // Call all event handlers

6 }

7

8 template <DataEventSet triggered_event, typename... Args>

9 static typename std::enable_if<triggered_event != registered_event, void>::type

10 dispatch(Args &&...) {

11 // Events are different

12 // NO-OP

13 }

the filtering must be done using compile-time programming.

Filtering Events

The dispatch process needs to filter the event listeners at some point. This is done by the event listeners itself. Each event listener will distinguish between two cases. Either the triggered event and the registered event are the same or not. If this filtering can be done at compile-time, the resolving of the dispatch method can be done at compile-time as well.

Listing 3.18 shows the dispatch method of the event listener. The interface of this method and the template parameters are the same as for the dispatch method of theEventListenerContainer. The event listener uses SFINAE to filter the events (at line 2 and line 9). The first implementation of the dispatch method is valid for the case, that the triggered event is the same as the registered event. In this cases, the dispatch method will call all event handlers belonging to this event listener. The second method implementation is valid for the case, that the events are different. This means, the event listener is not registered for the triggered event. Thus it results in an empty method. These empty methods will be removed by the compiler.

Documento similar