Property Map Library

# Boost Property Map Library

The Boost Property Map Library consists mainly of interface specifications in the form of concepts (similar to the iterator concepts in the STL [2]). These interface specifications are intended for use by implementors of generic libraries in communicating requirements on template parameters to their users. In particular, the Boost Property Map concepts define a general purpose interface for mapping key objects to corresponding value objects, thereby hiding the details of how the mapping is implemented from algorithms. The implementation of types fulfilling the property map interface is up to the client of the algorithm to provide. The property map requirements are purposefully vague on the type of the key and value objects to allow for the utmost genericity in the function templates of the generic library.

The need for the property map interface came from the Boost Graph Library (BGL), which contains many examples of algorithms that use the property map concepts to specify their interface. For an example, note the `ColorMap` template parameter of the `breadth_first_search`. In addition, the BGL contains many examples of concrete types that implement the property map interface. The `adjacency_list` class implements property maps for accessing objects (properties) that are attached to vertices and edges of the graph.

The Boost Property Map Library also contains a few adaptors that convert commonly used data-structures that implement a mapping operation, such as builtin arrays (pointers), iterators, and `std::map`, to have the property map interface. These adaptors are not meant to fulfill all mapping needs, but are to serve as an example of how to implement the interface as well as covering a few common cases. See the header files for details.

## Property Map Concepts

The property map interface consists of a set of concepts (see definition of "concept" in [1] and [2]) that define a syntax for mapping key objects to corresponding value objects. Since the property map operations are global functions (actually they don't have to be global, but they are always called unqualified and may be found via argument dependent lookup), it is possible to overload the map functions such that nearly arbitrary property map types and key types can be used. The interface for property maps consists of three functions: `get()`, `put()`, and `operator[]`. The following concrete example from example1.cpp shows how the three functions could be used to access the addresses associated with various people. We use a separate function template here to highlight the parts of the program that use the property map concept interface. In the `main()` function we use `std::map` and `boost::associative_property_map`, but it would have been OK to use any type (including a custom type that you create) that fulfills the property map requirements.

    #include <iostream>
    #include <map>
    #include <string>
    #include <boost/property_map.hpp>

    template <typename AddressMap>
    void foo(AddressMap address)
    {
      typedef typename boost::property_traits<AddressMap>::value_type value_type;
      typedef typename boost::property_traits<AddressMap>::key_type key_type;

      value_type old_address, new_address;
      key_type fred = "Fred";
      old_address = get(address, fred);
      new_address = "384 Fitzpatrick Street";
      put(address, fred, new_address);

      key_type joe = "Joe";
      value_type& joes_address = address[joe];
      joes_address = "325 Cushing Avenue";
    }

    int
    main()
    {
      std::map<std::string, std::string> name2address;
      boost::associative_property_map< std::map<std::string, std::string> >
        address_map(name2address);

      name2address.insert(make_pair(std::string("Fred"),
    				std::string("710 West 13th Street")));
      name2address.insert(make_pair(std::string("Joe"),
    				std::string("710 West 13th Street")));

      foo(address_map);

      for (std::map<std::string, std::string>::iterator i = name2address.begin();
           i != name2address.end(); ++i)
        std::cout << i->first << ": " << i->second << "\n";

      return EXIT_SUCCESS;
    }

For each property map object there is a set of valid keys for which the mapping to value objects is defined. Invoking a property map function on an invalid key results in undefined behavior. The property map concepts do not specify how this set of valid keys is created or modified. A function that uses a property map must specify the expected set of valid keys in its preconditions.

The need for property maps came out of the design of the Boost Graph Library, whose algorithms needed an interface for accessing properties attached to vertices and edges in a graph. In this context the vertex and edge descriptors are the key type of the property maps.

Several categories of property maps provide different access capabilities:

readable
  The associated property data can only be read. The data is returned by-value. Many property maps defining the problem input (such as edge weight) can be defined as readable property maps.

writeable
  The associated property can only be written to. The parent array used to record the paths in a bread-first search tree is an example of a property map that would be defined writeable.

read/write
  The associated property can both be written and read. The distance property use in Dijkstra's shortest paths algorithm would need to provide both read and write capabilities.

lvalue
  The associated property is actually represented in memory and it is possible to get a reference to it. The property maps in the lvalue category also support the requirements for read/write property maps.

There is a separate concept defined for each of the four property map categories. These property map concepts are listed below, with links to the documentation for each of them.

- ReadablePropertyMap
- WritablePropertyMap
- ReadWritePropertyMap
- LvaluePropertyMap

## Property Map Category Tags

There is a tag struct for each of the categories of property maps, which is defined in the header `<boost/property_map.hpp>`.

    namespace boost {

      struct readable_property_map_tag { };

      struct writable_property_map_tag { };

      struct read_write_property_map_tag :
        public readable_property_map_tag,
        public writable_property_map_tag { };

      struct lvalue_property_map_tag :
        public read_write_property_map_tag { };

    }

## Property Map Traits

Similar to the `std::iterator_traits` class of the STL, there is a `boost::property_traits` class that can be used to deduce the types associated with a property map type: the key and value types, and the property map category. There is a specialization of `boost::property_traits` so that pointers can be used as property map objects. In addition, the property map functions are overloaded for pointers. These traits classes and functions are defined in `<boost/property_map.hpp>`.

    namespace boost {

      template <typename PropertyMap>
      struct property_traits {
         typedef typename PropertyMap::key_type key_type;
         typedef typename PropertyMap::value_type value_type;
         typedef typename PropertyMap::category category;
      };

    }

## Property Map Types

- Builtin C++ pointer types.
  The following specialization of the `property_traits` class and the overloads of `put()` and `get()` make it possible to use builtin C++ pointer types as property maps. These are defined in `boost/property_map.hpp`. More specifically, it means that `T*` is a model of LvaluePropertyMap, given a key type that is at least convertible `std::ptrdiff_t`.

      namespace boost {
        // specialization for using pointers as property maps
        template <typename T>
        struct property_traits<T*> {
          typedef T value_type;
          typedef std::ptrdiff_t key_type;
          typedef random_access_iterator_pa_tag category;
        };

        // overloads of the property map functions for pointers
        template<>
        void put(T* pmap, std::ptrdiff_t k, const T& val) { pmap[k] = val;  }

        template<>
        const T& get(const T* pmap, std::ptrdiff_t k) { return pmap[k]; }

      }

- identity_property_map
- iterator_property_map
- associative_property_map
- const_associative_property_map
- vector_property_map

### History

The property map interface originated as data accessors in Dietmar Kühl's Masters Thesis on generic graph algorithms. The property map idea also appeared under the guise of decorators in early versions of the Generic Graph Component Library (GGCL), which is now the Boost Graph Library (BGL). The main motivation for the property map interface was to support the access of data associated with vertices and edges in a graph, though the applicability of property maps goes beyond this.

### Acknowledgments

Thanks go to Dietmar Kühl for coming up with this mechanism, and thanks go to the Boost members who helped refine and improve the property map interface. Thanks to Dave Abrahams for managing the formal review of the BGL which included the property map library.

### Notes to Implementors

Copying a property map should be inexpensive since they are often passed by value.

Copyright © 2000-2002 | Jeremy Siek, Indiana University (jsiek@osl.iu.edu)