• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1================================
2|(logo)|__ Dynamic Property Maps
3================================
4
5.. Copyright 2004-5 The Trustees of Indiana University.
6
7   Use, modification and distribution is subject to the Boost Software
8   License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9   http://www.boost.org/LICENSE_1_0.txt)
10
11.. |(logo)| image:: ../../../boost.png
12   :align: middle
13   :alt: Boost
14
15__ ../../../index.htm
16
17Summary
18-------
19The dynamic property map interfaces provides access to a collection of
20property maps through a dynamically-typed interface. An algorithm can
21use it to manipulate property maps without knowing their key or
22value types at compile-time. Type-safe codes can use dynamic property
23maps to interface more easily and completely with scripting languages
24and other text-based representations of key-value data.
25
26.. contents::
27
28Introduction
29------------
30The Boost Property Map library specifies statically type-safe
31interfaces through which key-value pairs can be manipulated by
32generic algorithms. Typically, an algorithm that uses property maps is
33parameterized on the types of the property maps it uses, and it
34manipulates them using the interfaces specified by the
35Boost Property Map Library.
36
37The following generic function illustrates property map basics.
38
39
40::
41
42  template <typename AgeMap, typename GPAMap>
43  void
44  manipulate_freds_info(AgeMap ages, GPAMap gpas) {
45
46    typedef typename boost::property_traits<AgeMap>::key_type name_type;
47    typedef typename boost::property_traits<AgeMap>::value_type age_type;
48    typedef typename boost::property_traits<GPAMap>::value_type gpa_type;
49
50    name_type fred = "Fred";
51
52    age_type old_age = get(ages, fred);
53    gpa_type old_gpa = get(gpas, fred);
54
55    std::cout << "Fred's old age: " << old_age << "\n"
56	      << "Fred's old gpa: " << old_gpa << "\n";
57
58    age_type new_age = 18;
59    gpa_type new_gpa = 3.9;
60    put(ages, fred, new_age);
61    put(gpas, fred, new_gpa);
62  }
63
64The function is parameterized on two property map types, ``AgeMap`` and
65``GPAMap``, and takes a value parameter for each of those types.  The
66function uses the ``property_traits`` interface to ascertain, at
67compile-time, the value and key types of the property maps.  The code
68then retrieves Fred's old information, using the ``get`` function, and
69updates it using the ``put`` function. The ``get`` function is required by the
70Readable Property Map concept and both ``get`` and ``put`` are required by the
71Read/Write Property Map concept.
72
73The above function not only requires the two type parameters to model
74property map concepts, but also makes some extra assumptions.
75``AgeMap`` and ``GPAMap`` must have the same key type, and that type must be
76constructable from a string.  Furthermore, ``AgeMap``'s value type must be
77constructable from an ``int``.  Although these requirements are not
78explicitly stated, they are statically checked during compilation and
79failure to meet them yields compile-time errors.
80
81Although the static typing of property map interfaces usually provides
82desirable compile-time safety, some algorithms require a more dynamic
83interface to property maps. For example, the Boost Graph Library (BGL)
84provides functions that can initialize a graph by interpreting the
85contents of a textual graph description (i.e. a GraphML file).  Such
86general-purpose graph description languages can specify an arbitrary
87number of edge and vertex properties, using strings to represent the
88key-value pairs.  A graph reader function should capture these
89arbitrary properties, but since function templates can only be
90parameterized on a fixed number of property maps, the traditional
91techniques for handling property maps do not suffice to implement them.
92
93Dynamic property maps specifically address the need for an interface
94to property maps whose checking is delayed to runtime.  Several
95components combine to provide support for dynamic property maps. The
96``dynamic_properties`` class collects a
97group of heterogenous objects that model concepts from
98the Boost Property Map library. Each property map is assigned a
99string-based key when it is added to the collection, and it can be
100addressed using that key.  Internally, ``dynamic_properties`` adapts
101each contained property map with the dynamic property map interface,
102which provides ``get`` and ``put`` functions that
103can be called using values of any type that meets a few requirements.
104Internally, the dynamic property map converts key and value pairs to
105meet the requirements of the underlying property map or signals a
106runtime exception if it cannot.
107
108
109"Fred's Info" Revisited
110~~~~~~~~~~~~~~~~~~~~~~~
111Here's what the example above looks like using the
112``dynamic_properties`` interface:
113
114::
115
116  void manipulate_freds_info(boost::dynamic_properties& properties)
117  {
118    using boost::get;
119    std::string fred = "Fred";
120
121    int old_age = get<int>("age", properties, fred);
122    std::string old_gpa = get("gpa", properties, fred);
123
124    std::cout << "Fred's old age: " << old_age << "\n"
125	      << "Fred's old gpa: " << old_gpa << "\n";
126
127    std::string new_age = "18";
128    double new_gpa = 3.9;
129    put("age",properties,fred,new_age);
130    put("gpa",properties,fred,new_gpa);
131  }
132
133The new function is not a template parameterized on the property map
134types but instead a concrete function that takes a ``dynamic_properties``
135object.  Furthermore, the code no longer makes reference to key or
136value types: keys and values are represented with strings.
137Nonetheless the function still uses non-string types where they are
138useful.  For instance, Fred's old age is represented using an ``int``.
139It's value is retreived by calling ``get`` with a
140type parameter, which determines its return type.  Finally, the
141``get`` and ``put`` functions are each supplied a string-based key that
142differs depending on the property of concern.
143
144Here's an example of how the above function might be called.
145
146::
147
148  int main()
149  {
150    using boost::get;
151
152    // build property maps using associative_property_map
153    std::map<std::string, int> name2age;
154    std::map<std::string, double> name2gpa;
155    boost::associative_property_map< std::map<std::string, int> >
156      age_map(name2age);
157    boost::associative_property_map< std::map<std::string, double> >
158      gpa_map(name2gpa);
159
160    std::string fred("Fred");
161    // add key-value information
162    name2age.insert(make_pair(fred,17));
163    name2gpa.insert(make_pair(fred,2.7));
164
165    // build and populate dynamic interface
166    boost::dynamic_properties properties;
167    properties.property("age",age_map);
168    properties.property("gpa",gpa_map);
169
170    manipulate_freds_info(properties);
171
172    std::cout << "Fred's age: " << get(age_map,fred) << "\n"
173	      << "Fred's gpa: " << get(gpa_map,fred) << "\n";
174  }
175
176The code first creates two property maps using ``std::map`` and the
177``associative_property_map`` adaptor.  After initializing the
178property maps with key-value data, it constructs a
179``dynamic_properties`` object and adds to it both property maps,
180keyed on the strings "age" and "gpa".  Finally ``manipulate_freds_info``
181is passed the ``dynamic_properties`` object and the results of its changes are
182displayed.
183
184As shown above, the ``dynamic_properties`` object provides, where needed, a
185dynamically-typed interface to property maps yet preserves the static
186typing of property map uses elsewhere in an application.
187
188Reference
189---------
190::
191
192  class dynamic_properties
193
194The ``dynamic_properties`` class provides a dynamically-typed interface to
195a set of property maps. To use it, one must populate
196an object of this class with property maps using the ``property`` member
197function.
198
199Member Functions
200~~~~~~~~~~~~~~~~
201
202::
203
204  dynamic_properties()
205  dynamic_properties(
206    const boost::function<
207      boost::shared_ptr<dynamic_property_map> (
208	const std::string&, const boost::any&, const boost::any&)
209      >& fn)
210
211A ``dynamic_properties`` object can be constructed with a function object
212that, when called, creates a new property map.  The library provides the
213``ignore_other_properties`` function object, which lets the ``dynamic_properties`` object ignore any properties that it hasn't been prepared to record.
214If an attempt is made
215to ``put`` a key-value pair to a nonexistent ``dynamic_properties`` key,
216then this function is called with the ``dynamic_properties`` key and the
217intended property key and value .  If ``dynamic_properties`` is
218default-constructed, such a ``put`` attempt throws
219``property_not_found``.
220
221
222::
223
224  template<typename PropertyMap>
225  dynamic_properties&
226  property(const std::string& name, PropertyMap property_map)
227
228This member function adds a property map to the set of maps contained,
229using ``name`` as its key.
230
231Requirements: ``PropertyMap`` must model Readable Property Map or
232Read/Write Property Map.
233
234::
235
236  void insert(const std::string& name, boost::shared_ptr<dynamic_property_map> pm)
237
238This member function directly adds a ``dynamic_property_map``
239to the collection, using ``name`` as its key.
240
241::
242
243  iterator begin()
244  const_iterator begin() const
245
246This member function returns an iterator over the set of property maps
247held by the ``dynamic_properties`` object.
248
249::
250
251  iterator end()
252  const_iterator end() const
253
254This member function returns a terminal iterator over the set of
255dynamic property maps held by the ``dynamic_properties`` object.  It is used to
256terminate traversals over the set of dynamic property maps
257
258::
259
260  iterator lower_bound(const std::string& name)
261
262This member function returns an iterator that points to the first
263property map whose ``dynamic_properties`` key is ``name``.
264Bear in mind that multiple property maps may have the same
265``dynamic_properties`` key, so long as their property map key types differ.
266
267Invariant: The range [ lower_bound(name), end() ) contains every
268property map that has name for its ``dynamic_properties`` key.
269
270Free functions
271~~~~~~~~~~~~~~
272
273::
274
275  boost::shared_ptr<boost::dynamic_property_map>
276  ignore_other_properties(const std::string&,
277                          const boost::any&,
278                          const boost::any&)
279
280When passed to the ``dynamic_properties`` constructor, this function
281allows the ``dynamic_properties`` object to disregard attempts to put
282values to unknown keys without signaling an error.
283
284::
285
286  template<typename Key, typename Value>
287  bool put(const std::string& name, dynamic_properties& dp, const Key& key,
288           const Value& value)
289
290This function adds a key-value pair to the property map with the
291matching name and key type. If no matching property map is found,
292behavior depends on the availability of a property map generator.  If
293a property map generator was supplied when the ``dynamic_properties``
294object was constructed, then that function is used to create a new
295property map.  If the generator fails to generate a property map
296(returns a null ``shared_ptr``), then the ``put`` function returns
297``false``.  If, on the other hand, the ``dynamic_properties`` object
298has no property map generator (meaning it was default-constructed),
299then ``property_not_found`` is thrown. If a candidate property map is
300found but it does not support ``put``, ``dynamic_const_put_error`` is
301thrown.
302
303::
304
305  template<typename Value, typename Key>
306  Value get(const std::string& name, const dynamic_properties& dp,
307            const Key& key)
308
309This function gets the value from the property-map whose namee is
310given and whose key type matches. If ``Value`` is ``std::string``, then the
311property map's value type must either be ``std::string`` or model
312OutputStreamable.  In the latter case, the ``get`` function converts the
313value to a string.  If no matching property map is found,
314``dynamic_get_failure`` is thrown.
315
316
317=============================================================================
318
319::
320
321  class dynamic_property_map
322
323This class describes the interface used by ``dynamic_properties`` to
324interact with a user's property maps polymorphically.
325
326::
327
328  boost::any get(const any& key)
329
330Given a representation of a key, return the value associated with that key.
331
332Requirement:
3331) The object passed as the key must be convertible to a value of the
334map's key type. Details of that conversion are unspecified.
3352) For this expression to be valid, the key must be
336associated with some value, otherwise the result is undefined.
337
338::
339
340  std::string get_string(const any& key)
341
342Given a representation of a key, return the string representation
343of the value associated with that key.
344
345Requirements:
3461) The object passed as the key must be convertible to the
347property map's key type. Details of that conversion are unspecified.
3482) For this expression to be valid, the key must be
349associated with some value, otherwise the result is undefined.
3503) The value type of the property map must model Output Streamable.
351
352::
353
354  void put(const any& key, const any& value)
355
356Given a representation of a key and a representation of a value, the
357key and value are associated in the property map.
358
359Requirements:
3601) The object passed as the key must be convertible to the
361property map's key type. Details of that conversion are unspecified.
3622) The object passed as the value must be convertible to the
363property map's value type. Details of that conversion are unspecified.
3643) The property map need not support this member function, in which
365case an error will be signaled.  This is the runtime analogue of the
366Readable Property Map concept.
367
368::
369
370  const std::type_info& key() const
371
372Returns a ``type_info`` object that represents the property map's key type.
373
374::
375
376  const std::type_info& value() const
377
378Returns a ``type_info`` object that represents the property map's value type.
379
380
381Exceptions
382~~~~~~~~~~
383
384::
385
386  struct dynamic_property_exception : public std::exception {
387    virtual ~dynamic_property_exception() throw() {}
388  };
389
390  struct property_not_found : public std::exception {
391    std::string property;
392    property_not_found(const std::string& property);
393    virtual ~property_not_found() throw();
394
395    const char* what() const throw();
396  };
397
398  struct dynamic_get_failure : public std::exception {
399    std::string property;
400    dynamic_get_failure(const std::string& property);
401    virtual ~dynamic_get_failure() throw();
402
403    const char* what() const throw();
404  };
405
406  struct dynamic_const_put_error  : public std::exception {
407    virtual ~dynamic_const_put_error() throw();
408
409    const char* what() const throw();
410  };
411
412
413Under certain circumstances, calls to ``dynamic_properties`` member
414functions will throw one of the above exceptions.  The three concrete
415exceptions can all be caught using the general
416``dynamic_property_exception`` moniker when greater precision is not
417needed.  In addition, all of the above exceptions derive from the
418standard ``std::exception`` for even more generalized error handling.
419The specific circumstances that result in these exceptions are
420described above.
421