]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
17 | Summary | |
18 | ------- | |
19 | The dynamic property map interfaces provides access to a collection of | |
20 | property maps through a dynamically-typed interface. An algorithm can | |
21 | use it to manipulate property maps without knowing their key or | |
22 | value types at compile-time. Type-safe codes can use dynamic property | |
23 | maps to interface more easily and completely with scripting languages | |
24 | and other text-based representations of key-value data. | |
25 | ||
26 | .. contents:: | |
27 | ||
28 | Introduction | |
29 | ------------ | |
30 | The Boost Property Map library specifies statically type-safe | |
31 | interfaces through which key-value pairs can be manipulated by | |
32 | generic algorithms. Typically, an algorithm that uses property maps is | |
33 | parameterized on the types of the property maps it uses, and it | |
34 | manipulates them using the interfaces specified by the | |
35 | Boost Property Map Library. | |
36 | ||
37 | The 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 | ||
64 | The function is parameterized on two property map types, ``AgeMap`` and | |
65 | ``GPAMap``, and takes a value parameter for each of those types. The | |
66 | function uses the ``property_traits`` interface to ascertain, at | |
67 | compile-time, the value and key types of the property maps. The code | |
68 | then retrieves Fred's old information, using the ``get`` function, and | |
69 | updates it using the ``put`` function. The ``get`` function is required by the | |
70 | Readable Property Map concept and both ``get`` and ``put`` are required by the | |
71 | Read/Write Property Map concept. | |
72 | ||
73 | The above function not only requires the two type parameters to model | |
74 | property map concepts, but also makes some extra assumptions. | |
75 | ``AgeMap`` and ``GPAMap`` must have the same key type, and that type must be | |
76 | constructable from a string. Furthermore, ``AgeMap``'s value type must be | |
77 | constructable from an ``int``. Although these requirements are not | |
78 | explicitly stated, they are statically checked during compilation and | |
79 | failure to meet them yields compile-time errors. | |
80 | ||
81 | Although the static typing of property map interfaces usually provides | |
82 | desirable compile-time safety, some algorithms require a more dynamic | |
83 | interface to property maps. For example, the Boost Graph Library (BGL) | |
84 | provides functions that can initialize a graph by interpreting the | |
85 | contents of a textual graph description (i.e. a GraphML file). Such | |
86 | general-purpose graph description languages can specify an arbitrary | |
87 | number of edge and vertex properties, using strings to represent the | |
88 | key-value pairs. A graph reader function should capture these | |
89 | arbitrary properties, but since function templates can only be | |
90 | parameterized on a fixed number of property maps, the traditional | |
91 | techniques for handling property maps do not suffice to implement them. | |
92 | ||
93 | Dynamic property maps specifically address the need for an interface | |
94 | to property maps whose checking is delayed to runtime. Several | |
95 | components combine to provide support for dynamic property maps. The | |
96 | ``dynamic_properties`` class collects a | |
97 | group of heterogenous objects that model concepts from | |
98 | the Boost Property Map library. Each property map is assigned a | |
99 | string-based key when it is added to the collection, and it can be | |
100 | addressed using that key. Internally, ``dynamic_properties`` adapts | |
101 | each contained property map with the dynamic property map interface, | |
102 | which provides ``get`` and ``put`` functions that | |
103 | can be called using values of any type that meets a few requirements. | |
104 | Internally, the dynamic property map converts key and value pairs to | |
105 | meet the requirements of the underlying property map or signals a | |
106 | runtime exception if it cannot. | |
107 | ||
108 | ||
109 | "Fred's Info" Revisited | |
110 | ~~~~~~~~~~~~~~~~~~~~~~~ | |
111 | Here'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 | ||
133 | The new function is not a template parameterized on the property map | |
134 | types but instead a concrete function that takes a ``dynamic_properties`` | |
135 | object. Furthermore, the code no longer makes reference to key or | |
136 | value types: keys and values are represented with strings. | |
137 | Nonetheless the function still uses non-string types where they are | |
138 | useful. For instance, Fred's old age is represented using an ``int``. | |
139 | It's value is retreived by calling ``get`` with a | |
140 | type parameter, which determines its return type. Finally, the | |
141 | ``get`` and ``put`` functions are each supplied a string-based key that | |
142 | differs depending on the property of concern. | |
143 | ||
144 | Here'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 | ||
176 | The code first creates two property maps using ``std::map`` and the | |
177 | ``associative_property_map`` adaptor. After initializing the | |
178 | property maps with key-value data, it constructs a | |
179 | ``dynamic_properties`` object and adds to it both property maps, | |
180 | keyed on the strings "age" and "gpa". Finally ``manipulate_freds_info`` | |
181 | is passed the ``dynamic_properties`` object and the results of its changes are | |
182 | displayed. | |
183 | ||
184 | As shown above, the ``dynamic_properties`` object provides, where needed, a | |
185 | dynamically-typed interface to property maps yet preserves the static | |
186 | typing of property map uses elsewhere in an application. | |
187 | ||
188 | Reference | |
189 | --------- | |
190 | :: | |
191 | ||
192 | class dynamic_properties | |
193 | ||
194 | The ``dynamic_properties`` class provides a dynamically-typed interface to | |
195 | a set of property maps. To use it, one must populate | |
196 | an object of this class with property maps using the ``property`` member | |
197 | function. | |
198 | ||
199 | Member 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 | ||
211 | A ``dynamic_properties`` object can be constructed with a function object | |
212 | that, 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. | |
214 | If an attempt is made | |
215 | to ``put`` a key-value pair to a nonexistent ``dynamic_properties`` key, | |
216 | then this function is called with the ``dynamic_properties`` key and the | |
217 | intended property key and value . If ``dynamic_properties`` is | |
218 | default-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 | ||
228 | This member function adds a property map to the set of maps contained, | |
229 | using ``name`` as its key. | |
230 | ||
231 | Requirements: ``PropertyMap`` must model Readable Property Map or | |
232 | Read/Write Property Map. | |
233 | ||
234 | :: | |
235 | ||
236 | void insert(const std::string& name, boost::shared_ptr<dynamic_property_map> pm) | |
237 | ||
238 | This member function directly adds a ``dynamic_property_map`` | |
239 | to the collection, using ``name`` as its key. | |
240 | ||
241 | :: | |
242 | ||
243 | iterator begin() | |
244 | const_iterator begin() const | |
245 | ||
246 | This member function returns an iterator over the set of property maps | |
247 | held by the ``dynamic_properties`` object. | |
248 | ||
249 | :: | |
250 | ||
251 | iterator end() | |
252 | const_iterator end() const | |
253 | ||
254 | This member function returns a terminal iterator over the set of | |
255 | dynamic property maps held by the ``dynamic_properties`` object. It is used to | |
256 | terminate traversals over the set of dynamic property maps | |
257 | ||
258 | :: | |
259 | ||
260 | iterator lower_bound(const std::string& name) | |
261 | ||
262 | This member function returns an iterator that points to the first | |
263 | property map whose ``dynamic_properties`` key is ``name``. | |
264 | Bear in mind that multiple property maps may have the same | |
265 | ``dynamic_properties`` key, so long as their property map key types differ. | |
266 | ||
267 | Invariant: The range [ lower_bound(name), end() ) contains every | |
268 | property map that has name for its ``dynamic_properties`` key. | |
269 | ||
270 | Free 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 | ||
280 | When passed to the ``dynamic_properties`` constructor, this function | |
281 | allows the ``dynamic_properties`` object to disregard attempts to put | |
282 | values 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 | ||
290 | This function adds a key-value pair to the property map with the | |
291 | matching name and key type. If no matching property map is found, | |
292 | behavior depends on the availability of a property map generator. If | |
293 | a property map generator was supplied when the ``dynamic_properties`` | |
294 | object was constructed, then that function is used to create a new | |
295 | property 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 | |
298 | has no property map generator (meaning it was default-constructed), | |
299 | then ``property_not_found`` is thrown. If a candidate property map is | |
300 | found but it does not support ``put``, ``dynamic_const_put_error`` is | |
301 | thrown. | |
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 | ||
309 | This function gets the value from the property-map whose namee is | |
310 | given and whose key type matches. If ``Value`` is ``std::string``, then the | |
311 | property map's value type must either be ``std::string`` or model | |
312 | OutputStreamable. In the latter case, the ``get`` function converts the | |
313 | value 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 | ||
323 | This class describes the interface used by ``dynamic_properties`` to | |
324 | interact with a user's property maps polymorphically. | |
325 | ||
326 | :: | |
327 | ||
328 | boost::any get(const any& key) | |
329 | ||
330 | Given a representation of a key, return the value associated with that key. | |
331 | ||
332 | Requirement: | |
333 | 1) The object passed as the key must be convertible to a value of the | |
334 | map's key type. Details of that conversion are unspecified. | |
335 | 2) For this expression to be valid, the key must be | |
336 | associated with some value, otherwise the result is undefined. | |
337 | ||
338 | :: | |
339 | ||
340 | std::string get_string(const any& key) | |
341 | ||
342 | Given a representation of a key, return the string representation | |
343 | of the value associated with that key. | |
344 | ||
345 | Requirements: | |
346 | 1) The object passed as the key must be convertible to the | |
347 | property map's key type. Details of that conversion are unspecified. | |
348 | 2) For this expression to be valid, the key must be | |
349 | associated with some value, otherwise the result is undefined. | |
350 | 3) The value type of the property map must model Output Streamable. | |
351 | ||
352 | :: | |
353 | ||
354 | void put(const any& key, const any& value) | |
355 | ||
356 | Given a representation of a key and a representation of a value, the | |
357 | key and value are associated in the property map. | |
358 | ||
359 | Requirements: | |
360 | 1) The object passed as the key must be convertible to the | |
361 | property map's key type. Details of that conversion are unspecified. | |
362 | 2) The object passed as the value must be convertible to the | |
363 | property map's value type. Details of that conversion are unspecified. | |
364 | 3) The property map need not support this member function, in which | |
365 | case an error will be signaled. This is the runtime analogue of the | |
366 | Readable Property Map concept. | |
367 | ||
368 | :: | |
369 | ||
370 | const std::type_info& key() const | |
371 | ||
372 | Returns a ``type_info`` object that represents the property map's key type. | |
373 | ||
374 | :: | |
375 | ||
376 | const std::type_info& value() const | |
377 | ||
378 | Returns a ``type_info`` object that represents the property map's value type. | |
379 | ||
380 | ||
381 | Exceptions | |
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 | ||
413 | Under certain circumstances, calls to ``dynamic_properties`` member | |
414 | functions will throw one of the above exceptions. The three concrete | |
415 | exceptions can all be caught using the general | |
416 | ``dynamic_property_exception`` moniker when greater precision is not | |
417 | needed. In addition, all of the above exceptions derive from the | |
418 | standard ``std::exception`` for even more generalized error handling. | |
419 | The specific circumstances that result in these exceptions are | |
420 | described above. |