Rogue Wave banner
Previous fileTop of DocumentContentsIndex pageNext file
Threads Module User's Guide
Rogue Wave web site:  Home Page  |  Main Documentation Page

8.7 The Functor Map Subpackage

A functor map is both a container that holds functors and a functor itself. The container is a map, or registration, of functors and associated keys through which they are accessed. The map itself is a part of the functor hierarchy, and it implements the entire functor API, so it can be passed where a functor is expected.

In fact, the code to which the functor map is passed need not know that it is not a basic functor. The caller code invokes what it believes to be a simple functor, using the simple functor's API, and the map handles the complexity of finding the correct functor within the map and invoking it.

As an example, imagine an application that draws various shapes on the screen, depending on some input from the user. A functor is set up to create each shape. Each functor is added to a functor map with its key, in this case, a string containing the name of the shape. When an application user requests a certain shape be drawn, the application invokes the functor map with the name of the shape (which serves as the key). Within the functor map, the lookup is performed, and the correct functor is invoked, creating the shape and drawing it on the screen.

As the above example hints, functor maps provide a way to implement the factory pattern. You can encapsulate creator functions in functors and add them to a functor map with a string representing the name of the object to be created, thus producing a factory. An invocation of the map with the name of a class creates an object of that type. Functor maps can even handle a request to create an object that isn't in the map, by creating some default object such as a parent class object.

8.7.1 How Do They Work?

Like basic functors, functor maps are implemented by a number of template classes. Depending on the number of arguments passed at invocation time, different functor maps are required.

The map itself is a collection of unique keys and their associated functors. The key is a templatized parameter, so it can be of any type, as long as it has an appropriate hash function. The functor can be any one of the handle classes provided in the Functor package, or any class derived from these classes, such as a functor list or even a functor map.

Because the invocation of the map could invoke any of its functors, all of the functors in a given map must have the same invocation signature and either share the same functor handle type or be derived from the same functor handle type.

Because one of the arguments to the functor map invocation must be the key used for look-up, the functors stored in a functor map have one less argument than the map itself. For example, an RWTFunctorMap2 is invoked with two arguments, a key and another argument that is passed to the RWTFunctor1 associated with the key.

Like functors, functor maps use the handle body idiom. Because each functor map handle can point to exactly one type of functor map, however, the body is created automatically as a part of the handle's construction. Copying functor maps follows the general rules discussed in Section 7.3.1.4, "Handle-Body Mechanics." With this technique, the copy constructor and assignment operators reference the old object and, as a result, are very fast.


After the assignment, changes to either FunctorMap object affect the other one.

8.7.2 Functor Map Class Hierarchy

The Functor Map subpackage is made up of a number of template classes designed to accommodate functor arguments of different numbers and types. Functor map classes are an extension to the functor class hierarchy, as shown in Figure 53.

Figure 53: Hierarchy of functor map classes and the functor classes from which they derive

Class names are constructed from the base name RWTFunctorMap by adding 1 or 2 for the number of caller arguments and an optional R if the map returns a value. Because every functor map invocation requires a key, there is no RWTFunctorMap0.

The formal template parameters (shown in the hierarchy) include:

SR — The type of the functor map's return value

Key — The type of the functor map's key

S1 — The type of the encapsulated functor's first argument (which is the functor map's second argument)

8.7.3 Using Functor Maps

The specific type of functor map that you need depends on the type of functors to be held within the map. All functors in a map must be of the same handle type or be derived from the same handle type. The functors must take one less argument at invocation than the map itself.

If you are starting with a function that you wish to wrap, see Section 8.4.1, "Analyzing Functor Requirements," to select a functor type. This choice determines the type of map that you need.

8.7.3.1 Constructing Functor Maps

To construct a functor map, you need to know:

The following steps show how to create a functor map.

  1. Choose the function you want to wrap, for example:

      int setFlag(short s) { 
        flag = s;
        cout << "flag was set to " << s << endl; 
        return s;}
      
  2. Create the corresponding functor:

      RWTFunctorR1<int,short> setFlagFunctor = 
        rwtMakeFunctorR1( (int(*)(short))NULL, setFlag);
      
  3. Create the map. If you choose RWCString as the key type, the map construction would look like this:

8.7.3.2 Adding Functors to the Map

At this point, you have a complete but empty functor map instance. Next, you add functors to the map.

The map now has one entry, whose key is the RWCString "setFlag" and whose functor is the setFlagFunctor created earlier.

8.7.3.3 Invoking Functor Maps

Once the map contains an entry, you can invoke it. Invocation consists of finding the entry in the map with the matching key and invoking that functor.

This instruction selects the functor setFlagFunctor from the map and invokes the functor with the caller argument 32. The variable return_value is set to 32. The functor invocation produces this output:

8.7.3.4 Defining a Default Functor for the Map

If you call the map with a key that has not been registered

it throws an RWLogicError exception. This may or may not be what the application needs. To handle this case more gracefully, functor maps have the notion of a default functor.

Such a functor is used when a user attempts to invoke or query the map with an invalid key. The default functor can be a more specific error reporting mechanism, such as a pop-up window telling the application user that the input was invalid, or it might cause a less specific but still useful action, such as creating a parent object instead of a more derived type.

Returning to the example, suppose that when the user passes an invalid key, you want to set the flag to 0 and issue a warning that a matching key was not found. To create this behavior, follow these steps:

  1. Create a function with appropriate parameters. (Remember that all of a functor map's entries must be the same functor handle type).

      int reportError(short s){ 
        flag = 0;
        cout << "Flag set to 0, key not found." << endl; 
        return 0;}
      
  2. Create a functor from the function.

      RWTFunctorR1<int,short> errorFunctor = 
        rwtMakeFunctorR1( (int(*)(short))NULL, reportError);
      
  3. Set that functor as the map's default functor.

      fmap.setDefault( errorFunctor );
      

From this point on, if the user invokes the map with an invalid key, the errorFunctor is invoked.

In this case, the return_value is set to 0, producing this output:

Later, you can check what the default functor has been set to, using getDefault(). This function returns the default functor, if a default is set, or else throws an RWLogicError exception.

Example 76: Checking for a functor map's default functor

8.7.3.5 Removing Functors from the Map

The contents of a functor map can be dynamic, perhaps corresponding to the set of currently available actions, which change over time. When you need to remove entries from the map, use the remove() function:

Now setFlagFunctor is removed from the map and removed_successfully is set to true.

To remove all entries in the map at once, use the clear() function:

8.7.4 Querying the Map

An application encountering a functor map might need some information about it, such as the number of entries or whether a certain key has been added. Below are examples of such queries, which use member functions supplied by the functor map classes. These examples assume that the setFlagFunctor entry is back in the functor map.

8.7.4.1 Checking for a Key

To check for a particular key in a map, use the contains() function.

The above code sets the contains_setFlag variable to true, while the following sets the contains_bogusKey variable to false.

8.7.4.2 Checking for a Key and its Functor

To check the map for a particular key and also see the matching functor, use the find() function. Because you are asking for two pieces of information, two mechanisms are needed for returning information. The success of the search is returned as the return value, and the matching functor is returned in the reference argument.

Here found is set to true, because there is a functor in the map with the associated key "setFlag", and matching_functor is set to the setFlagFunctor.

If you ask for a key that is not in the map, the return value is false. However, if the map has a default functor (remember, they are not required), then the default functor is returned in the reference argument matching_functor. This is what happens in the case below.

If the map does not have a default functor, calling the find function with an invalid key throws an RWLogicError exception.

8.7.4.3 Checking for the Number of Entries

To find the total number of entries in the map, use the entries() function. The default functor is not considered an entry in the map. Thus, in the example, this call sets current_size to 1.

8.7.5 Functor Map Example

This example demonstrates the use of a functor map. The complete example is available in buildspace\examples\threads\functor_map\accounts.cpp

Example 77: Using a functor map



Previous fileTop of DocumentContentsNo linkNext file

Copyright © Rogue Wave Software, Inc. All Rights Reserved.

The Rogue Wave name and logo, and SourcePro, are registered trademarks of Rogue Wave Software. All other trademarks are the property of their respective owners.
Provide feedback to Rogue Wave about its documentation.