graph_properties.hh 20.5 KB
Newer Older
Tiago Peixoto's avatar
Tiago Peixoto committed
1 2
// graph-tool -- a general graph modification and manipulation thingy
//
Tiago Peixoto's avatar
Tiago Peixoto committed
3
// Copyright (C) 2006-2015 Tiago de Paula Peixoto <tiago@skewed.de>
Tiago Peixoto's avatar
Tiago Peixoto committed
4 5 6
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
Tiago Peixoto's avatar
Tiago Peixoto committed
7
// as published by the Free Software Foundation; either version 3
Tiago Peixoto's avatar
Tiago Peixoto committed
8 9 10 11 12 13 14 15
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
16
// along with this program. If not, see <http://www.gnu.org/licenses/>.
Tiago Peixoto's avatar
Tiago Peixoto committed
17 18 19 20

#ifndef GRAPH_PROPERTIES_HH
#define GRAPH_PROPERTIES_HH

21
#include <typeinfo>
Tiago Peixoto's avatar
Tiago Peixoto committed
22
#include <string>
23
#include <vector>
Tiago Peixoto's avatar
Tiago Peixoto committed
24 25 26
#include <memory>
#include <random>
#include <functional>
27
#include <boost/functional/hash.hpp>
28
#include <boost/python/object.hpp>
29
#include <boost/python/extract.hpp>
30

31 32 33 34 35 36 37 38
#include <boost/version.hpp>
#if (BOOST_VERSION >= 104000)
#   include <boost/property_map/property_map.hpp>
#   include <boost/property_map/dynamic_property_map.hpp>
#else
#   include <boost/property_map.hpp>
#   include <boost/dynamic_property_map.hpp>
#endif
39
#include "fast_vector_property_map.hh"
40 41
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>
42 43
#include <boost/mpl/transform.hpp>
#include <boost/mpl/find.hpp>
Tiago Peixoto's avatar
Tiago Peixoto committed
44

45
#include "graph.hh"
46
#include "graph_exceptions.hh"
47
#include "hash_map_wrap.hh"
48

49
// this file provides general functions for manipulating graph properties
50 51

namespace graph_tool
Tiago Peixoto's avatar
Tiago Peixoto committed
52
{
53
using namespace std;
Tiago Peixoto's avatar
Tiago Peixoto committed
54

55 56 57 58 59
// Metaprogramming
// ===============
//
// Metafunctions and data structures to deal with property maps

60 61
// Global Property Types
// ---------------------
62
// global property types. only these types are allowed in property maps
63 64 65 66
// Note: we must avoid a vector<bool> (and bools in general) since it is quite
//       broken, and use a vector<uint8_t> instead!
//       see: http://www.gotw.ca/publications/N1211.pdf

67 68 69 70
typedef boost::mpl::vector15<uint8_t, int16_t, int32_t, int64_t, double, long double, string,
                             vector<uint8_t>, vector<int16_t>, vector<int32_t>, vector<int64_t>,
                             vector<double>, vector<long double>, vector<string>,
                             boost::python::object>
71 72
    value_types;

73 74
extern const char* type_names[]; // respective type names (defined in
                                 // graph_properties.cc)
75 76

// scalar types: types contained in value_types which are scalar
77
typedef boost::mpl::vector6<uint8_t, int16_t, int32_t, int64_t, double, long double>
78
    scalar_types;
79 80

// integer_types: scalar types which are integer
81
typedef boost::mpl::vector4<uint8_t, int16_t, int32_t, int64_t> integer_types;
82 83

// floating_types: scalar types which are floating point
84
typedef boost::mpl::vector2<double, long double> floating_types;
85 86 87 88 89 90 91

struct make_vector
{
    template <class ValueType> struct apply { typedef vector<ValueType> type; };
};

// scalar_vector_types: vector types with floating point values
Tiago Peixoto's avatar
Tiago Peixoto committed
92
typedef boost::mpl::transform<scalar_types,make_vector>::type scalar_vector_types;
93 94

// integer_vector_types: vector types with floating point values
Tiago Peixoto's avatar
Tiago Peixoto committed
95
typedef boost::mpl::transform<integer_types,make_vector>::type integer_vector_types;
96 97

// floating_vector_types: vector types with floating point values
Tiago Peixoto's avatar
Tiago Peixoto committed
98
typedef boost::mpl::transform<floating_types,make_vector>::type floating_vector_types;
99

100 101 102
//
// Property Map Types
// ------------------
103

104 105
// metafunction to generate the correct property map type given a value type and
// an index map
106 107 108 109 110
struct property_map_type
{
    template <class ValueType, class IndexMap>
    struct apply
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
111
        typedef boost::checked_vector_property_map<ValueType,IndexMap> type;
112
    };
113 114
};

115 116
// metafunction to get the sequence of property map types of ValueTypes and
// IndexMap
117 118 119 120 121 122 123 124 125
struct property_map_types
{
   // this wraps an unary metafunction class Bind into a unary metafunction,
   // i.e., it is an identity operation. I'm not sure why it's necessary, but
   // using pure unary bind expressions below didn't work for me, and this fixed
   // it.
    template <class Bind>
    struct bind_wrap1
    {
126
        template <class T1> struct apply
127 128 129
        { typedef typename Bind::template apply<T1>::type type; };
    };

130
    template <class ValueTypes, class IndexMap,
Tiago Peixoto's avatar
Tiago Peixoto committed
131
              class IncludeIndexMap = boost::mpl::bool_<true>>
132 133
    struct apply
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
134
        typedef typename boost::mpl::transform<
135
            ValueTypes,
Tiago Peixoto's avatar
Tiago Peixoto committed
136 137 138
            bind_wrap1<boost::mpl::bind2<property_map_type,
                                         boost::mpl::_1,
                                         IndexMap>>
139 140
            >::type scalar_properties;

141
        // put index map itself
Tiago Peixoto's avatar
Tiago Peixoto committed
142
        typedef typename boost::mpl::if_<
143
            IncludeIndexMap,
Tiago Peixoto's avatar
Tiago Peixoto committed
144
            typename boost::mpl::push_back<scalar_properties,IndexMap>::type,
145 146
            scalar_properties
            >::type type;
147
    };
148
};
149

150 151 152 153 154
// Property map manipulation
// =========================
//
// Functions which deal with several aspects of property map manipulation

155

156 157 158 159 160 161 162 163 164 165 166 167 168
// this functor tests whether or not a given boost::any object holds a type
// contained in a given type Sequence
template <class Sequence>
struct belongs
{
    struct get_type
    {
        get_type(const boost::any& val, bool& found)
            : _val(val), _found(found) {}

        template <class Type>
        void operator()(Type) const
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
169
            const Type* ptr = boost::any_cast<Type>(&_val);
170 171 172 173 174 175 176 177 178 179 180
            if (ptr != 0)
                _found = true;
        }

        const boost::any& _val;
        bool& _found;
    };

    bool operator()(const boost::any& prop)
    {
        bool found = false;
Tiago Peixoto's avatar
Tiago Peixoto committed
181
        boost::mpl::for_each<Sequence>(get_type(prop, found));
182 183 184 185 186 187 188 189 190 191 192
        return found;
    }
};

// this will return the name of a given type
template <class TypeSequence = value_types,
          class NamedSequence = value_types>
class get_type_name
{
public:
    get_type_name(const char* names[] = type_names)
193
        : _type_names(names)
194 195 196
    {
        if (_all_names.empty())
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
197
            boost::mpl::for_each<TypeSequence>
198
                (bind(get_all_names(), std::placeholders::_1,
Tiago Peixoto's avatar
Tiago Peixoto committed
199
                      ref(_type_names), ref(_all_names)));
200 201 202
        }
    }

203
    const string& operator()(const std::type_info& type) const
204
    {
205
        string const* name;
Tiago Peixoto's avatar
Tiago Peixoto committed
206
        boost::mpl::for_each<TypeSequence>
207
            (bind(find_name(), std::placeholders::_1, ref(type),
Tiago Peixoto's avatar
Tiago Peixoto committed
208
                  ref(_all_names), ref(name)));
209 210 211 212 213 214 215 216 217 218 219 220
        return *name;
    }

    const vector<string>& all_names() const
    {
        return _all_names;
    }

private:
    struct find_name
    {
        template <class Type>
221
        void operator()(Type, const std::type_info& type,
222 223
                        const vector<string>& all_names,
                        string const*& name) const
224
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
225
            size_t index = boost::mpl::find<TypeSequence,Type>::type::pos::value;
226 227 228 229 230 231 232
            if (type == typeid(Type))
                name = &all_names[index];
        }
    };

    struct get_all_names
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
233
        typedef void result_type;
234
        template <class Type>
235
        void operator()(Type, const char** t_names,
236 237
                        vector<string>& names) const
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
238
            size_t index = boost::mpl::find<NamedSequence,Type>::type::pos::value;
239
            names.push_back(t_names[index]);
240 241 242 243
        }
    };

    const char** _type_names;
244
    vector<string> _all_names;
245 246
};

247 248 249 250
//
// Extra Property Map Types
// ========================

251 252 253 254 255 256 257 258 259 260 261 262

// handle type convertions

// generic types
template <class Type1, class Type2>
struct convert
{
    Type1 operator()(const Type2& v) const
    {
        return do_convert(v, is_convertible<Type2,Type1>());
    }

Tiago Peixoto's avatar
Tiago Peixoto committed
263
    Type1 do_convert(const Type2& v, std::true_type) const
264 265 266 267
    {
        return Type1(v);
    }

Tiago Peixoto's avatar
Tiago Peixoto committed
268
    Type1 do_convert(const Type2& v, std::false_type) const
269 270 271 272 273 274 275
    {
        return specific_convert<Type1,Type2>()(v);
    }

    template <class T1, class T2>
    struct specific_convert
    {
276
        T1 operator()(const T2&) const
277
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
278
            throw boost::bad_lexical_cast(); // default action
279 280 281 282 283 284 285
        }
    };

    // specific specializations

    // python::object
    template <class T1>
Tiago Peixoto's avatar
Tiago Peixoto committed
286
    struct specific_convert<T1,boost::python::object>
287
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
288
        T1 operator()(const boost::python::object& v) const
289
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
290
            boost::python::extract<Type1> x(v);
291 292 293
            if (x.check())
                return x();
            else
Tiago Peixoto's avatar
Tiago Peixoto committed
294
                throw boost::bad_lexical_cast();
295 296 297 298 299 300 301 302 303 304 305
        }
    };

    // string
    template <class T1>
    struct specific_convert<T1,string>
    {
        T1 operator()(const string& v) const
        {
            //uint8_t is not char, it is bool!
            if (is_same<T1, uint8_t>::value)
Tiago Peixoto's avatar
Tiago Peixoto committed
306
                return convert<T1,int>()(boost::lexical_cast<int>(v));
307
            else
Tiago Peixoto's avatar
Tiago Peixoto committed
308
                return boost::lexical_cast<T1>(v);
309 310 311 312 313 314 315 316 317 318
        }
    };

    template <class T2>
    struct specific_convert<string,T2>
    {
        string operator()(const T2& v) const
        {
            //uint8_t is not char, it is bool!
            if (is_same<T2, uint8_t>::value)
Tiago Peixoto's avatar
Tiago Peixoto committed
319
                return boost::lexical_cast<string>(convert<int,T2>()(v));
320
            else
Tiago Peixoto's avatar
Tiago Peixoto committed
321
                return boost::lexical_cast<string>(v);
322 323 324 325 326
        }
    };

    // vectors
    template <class T1, class T2>
Tiago Peixoto's avatar
Tiago Peixoto committed
327
    struct specific_convert<vector<T1>, vector<T2>>
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    {
        vector<T1> operator()(const vector<T2>& v) const
        {
            vector<T1> v2(v.size());
            convert<T1,T2> c;
            for (size_t i = 0; i < v.size(); ++i)
                v2[i] = c(v[i]);
            return v2;
        }
    };

};

// python::object to string, to solve ambiguity
template<> template<>
Tiago Peixoto's avatar
Tiago Peixoto committed
343
struct convert<string,boost::python::object>::specific_convert<string,boost::python::object>
344
{
Tiago Peixoto's avatar
Tiago Peixoto committed
345
    string operator()(const boost::python::object& v) const
346
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
347
        boost::python::extract<string> x(v);
348
        if (x.check())
349
            return x();
350
        else
Tiago Peixoto's avatar
Tiago Peixoto committed
351
            throw boost::bad_lexical_cast();
352 353 354
    }
};

355 356 357 358 359 360 361 362 363 364
// No op
template <class Type1>
struct convert<Type1, Type1>
{
    const Type1& operator()(const Type1& v) const
    {
        return v;
    }
};

365 366 367 368 369
// the following class wraps a generic property map, so it can be used as a
// property with a given Key and Value type. The keys and values are converted
// to the desired Key and Value type, which may cause a performance impact,
// since virtual functions are used. Should be used only when property map
// access time is not crucial
370 371
template <class Value, class Key,
          template <class T1, class T2> class Converter = convert>
372 373 374 375 376 377
class DynamicPropertyMapWrap
{
public:
    typedef Value value_type;
    typedef Value reference;
    typedef Key key_type;
Tiago Peixoto's avatar
Tiago Peixoto committed
378
    typedef boost::read_write_property_map_tag category;
379

380 381
    template <class PropertyTypes>
    DynamicPropertyMapWrap(boost::any pmap, PropertyTypes)
382 383
    {
        ValueConverter* converter = 0;
Tiago Peixoto's avatar
Tiago Peixoto committed
384
        boost::mpl::for_each<PropertyTypes>
385
            (std::bind(choose_converter(), std::placeholders::_1, std::ref(pmap),
Tiago Peixoto's avatar
Tiago Peixoto committed
386
                       std::ref(converter)));
387
        if (converter == 0)
Tiago Peixoto's avatar
Tiago Peixoto committed
388
            throw boost::bad_lexical_cast();
389
        else
Tiago Peixoto's avatar
Tiago Peixoto committed
390
            _converter = shared_ptr<ValueConverter>(converter);
391
    }
392

393 394
    DynamicPropertyMapWrap() {}

395 396
    Value get(const Key& k) const
    {
397
        return (*_converter).get(k);
398 399 400 401
    }

    void put(const Key& k, const Value& val)
    {
402
        (*_converter).put(k, val);
403 404 405
    }

private:
406 407 408
    class ValueConverter
    {
    public:
409 410
        virtual Value get(const Key& k) = 0;
        virtual void put(const Key& k, const Value& val) = 0;
411
        virtual ~ValueConverter() {}
412 413
    };

414
    template <class PropertyMap>
415 416 417
    class ValueConverterImp: public ValueConverter
    {
    public:
418
        ValueConverterImp(PropertyMap pmap): _pmap(pmap) {}
419
        virtual ~ValueConverterImp() {}
Tiago Peixoto's avatar
Tiago Peixoto committed
420 421
        typedef typename boost::property_traits<PropertyMap>::value_type val_t;
        typedef typename boost::property_traits<PropertyMap>::key_type key_t;
422 423 424

        virtual Value get(const Key& k)
        {
425
            return get_dispatch(_pmap, k,
Tiago Peixoto's avatar
Tiago Peixoto committed
426 427
                                is_convertible<typename boost::property_traits<PropertyMap>::category,
                                               boost::readable_property_map_tag>());
428 429 430
        }

        virtual void put(const Key& k, const Value& val)
431
        {
432 433 434
            put_dispatch(_pmap, k, _c_put(val),
                         is_convertible<typename boost::property_traits<PropertyMap>::category,
                         boost::writable_property_map_tag>());
435 436 437
        }

        template <class PMap>
Tiago Peixoto's avatar
Tiago Peixoto committed
438 439
        Value get_dispatch(PMap pmap, const typename boost::property_traits<PMap>::key_type& k,
                           std::true_type)
440 441 442
        {
            return _c_get(boost::get(pmap, k));
        }
443

444
        template <class PMap>
Tiago Peixoto's avatar
Tiago Peixoto committed
445 446
        Value get_dispatch(PMap, const typename boost::property_traits<PMap>::key_type&,
                           std::false_type)
447 448
        {
            throw graph_tool::ValueException("Property map is not readable.");
449
        }
450

451
        template <class PMap>
Tiago Peixoto's avatar
Tiago Peixoto committed
452 453 454
        void put_dispatch(PMap pmap, const typename boost::property_traits<PMap>::key_type& k,
                          typename boost::property_traits<PMap>::value_type val,
                          std::true_type)
455 456 457 458 459
        {
            boost::put(pmap, k, val);
        }

        template <class PMap>
Tiago Peixoto's avatar
Tiago Peixoto committed
460 461 462
        void put_dispatch(PMap, const typename boost::property_traits<PMap>::key_type&,
                          typename boost::property_traits<PMap>::value_type,
                          std::false_type)
463 464 465
        {
            throw ValueException("Property map is not writable.");
        }
466

467 468
    private:
        PropertyMap _pmap;
469 470
        Converter<Value, val_t> _c_get;
        Converter<val_t, Value> _c_put;
471 472 473 474
    };

    struct choose_converter
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
475
        typedef void return_type;
476 477
        template <class PropertyMap>
        void operator()(PropertyMap, boost::any& dmap,
478 479
                        ValueConverter*& converter) const
        {
480 481
            if (typeid(PropertyMap) == dmap.type())
                converter = new ValueConverterImp<PropertyMap>
Tiago Peixoto's avatar
Tiago Peixoto committed
482
                    (boost::any_cast<PropertyMap>(dmap));
483 484 485
        }
    };

Tiago Peixoto's avatar
Tiago Peixoto committed
486
    shared_ptr<ValueConverter> _converter;
487 488
};

489
template <class Value, class Key, class ConvKey>
490
Value get(const graph_tool::DynamicPropertyMapWrap<Value,Key>& pmap,
491
          ConvKey k)
492
{
493 494
    Key key = k;
    return pmap.get(key);
495 496 497
}

template <class Value, class Key>
498 499
void put(graph_tool::DynamicPropertyMapWrap<Value,Key>& pmap,
         Key k, const Value& val)
500
{
501
    pmap.put(k, val);
502 503
}

504 505
// the following is hash functor which, will hash a vertex or edge descriptor
// based on its index
506
template <class IndexMap>
507
class DescriptorHash
508
    : public unary_function<typename IndexMap::key_type, size_t>
509 510 511 512
{
public:
    DescriptorHash() {}
    DescriptorHash(IndexMap index_map): _index_map(index_map) {}
513
    size_t operator()(typename IndexMap::key_type const& d) const
514
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
515 516
        std::hash<typename IndexMap::value_type> hash;
        return hash(_index_map[d]);
517
    }
518 519 520 521
private:
    IndexMap _index_map;
};

522 523
// the following is a property map based on a hashed container, which uses the
// above hash function for vertex or edge descriptors
524 525
template <class IndexMap, class Value>
class HashedDescriptorMap
Tiago Peixoto's avatar
Tiago Peixoto committed
526
    : public boost::put_get_helper<Value&, HashedDescriptorMap<IndexMap,Value>>
527 528 529
{
public:
    typedef DescriptorHash<IndexMap> hashfc_t;
530
    typedef unordered_map<typename IndexMap::key_type,Value,hashfc_t>
531
        map_t;
Tiago Peixoto's avatar
Tiago Peixoto committed
532
    typedef boost::associative_property_map<map_t> prop_map_t;
533

Tiago Peixoto's avatar
Tiago Peixoto committed
534 535 536 537
    typedef typename boost::property_traits<prop_map_t>::value_type value_type;
    typedef typename boost::property_traits<prop_map_t>::reference reference;
    typedef typename boost::property_traits<prop_map_t>::key_type key_type;
    typedef typename boost::property_traits<prop_map_t>::category category;
538

539
    HashedDescriptorMap(IndexMap index_map)
540 541
        : _base_map(std::make_shared<map_t>(0, hashfc_t(index_map))),
        _prop_map(*_base_map) {}
542
    HashedDescriptorMap(){}
543

544 545 546 547
    reference operator[](const key_type& k) { return _prop_map[k]; }
    const reference operator[](const key_type& k) const { return _prop_map[k]; }

private:
548
    shared_ptr<map_t> _base_map;
549 550 551 552 553 554 555 556
    prop_map_t _prop_map;
};


// this wraps a container as a property map which is automatically initialized
// with a given default value
template <class Container>
class InitializedPropertyMap
Tiago Peixoto's avatar
Tiago Peixoto committed
557 558
    : public boost::put_get_helper<typename Container::value_type::second_type&,
                                   InitializedPropertyMap<Container>>
559 560 561 562 563
{
public:
    typedef typename Container::value_type::second_type value_type;
    typedef value_type& reference;
    typedef typename Container::key_type key_type;
Tiago Peixoto's avatar
Tiago Peixoto committed
564
    typedef boost::read_write_property_map_tag category;
565 566

    InitializedPropertyMap(Container& base_map, value_type def)
567
        : _base_map(&base_map), _default(def) {}
568 569 570 571
    InitializedPropertyMap(){}

    reference operator[](const key_type& k)
    {
572
        return get(k);
573 574
    }

575
    reference operator[](const key_type& k) const
576
    {
577
        return get(k);
578 579
    }

580
    reference get(const key_type& k) const
581
    {
582 583 584 585 586
        typename Container::iterator val;
        val = _base_map->find(k);
        if (val == _base_map->end())
            val = _base_map->insert(make_pair(k, _default)).first;
        return val->second;
587 588 589 590 591 592 593
    }

private:
    Container* _base_map;
    value_type _default;
};

594
// the following is a property map which always returns a constant value
595 596
template <class Value, class Key>
class ConstantPropertyMap
Tiago Peixoto's avatar
Tiago Peixoto committed
597
    : public boost::put_get_helper<Value, ConstantPropertyMap<Value,Key>>
598 599 600 601 602
{
public:
    typedef Value value_type;
    typedef value_type& reference;
    typedef Key key_type;
Tiago Peixoto's avatar
Tiago Peixoto committed
603
    typedef boost::readable_property_map_tag category;
604

605 606
    ConstantPropertyMap(const value_type& c): c(c) {}
    ConstantPropertyMap(): c() {}
607

608
    const value_type& operator[](const key_type&) const { return c; }
609

610 611 612 613 614 615 616
    ConstantPropertyMap& operator=(const ConstantPropertyMap& other)
    {
        const_cast<value_type&>(c) = other.c;
        return *this;
    }

    const value_type c;
617 618
};

Tiago Peixoto's avatar
Tiago Peixoto committed
619
// the following is a property map which always returns one
620
template <class Value, class Key>
Tiago Peixoto's avatar
Tiago Peixoto committed
621
class UnityPropertyMap
622
    : public boost::put_get_helper<Value, UnityPropertyMap<Value, Key>>
Tiago Peixoto's avatar
Tiago Peixoto committed
623 624
{
public:
625
    typedef Value value_type;
Tiago Peixoto's avatar
Tiago Peixoto committed
626 627 628 629 630
    typedef value_type reference;
    typedef Key key_type;
    typedef boost::readable_property_map_tag category;

    template <class K>
631
    value_type operator[](const K&) const { return value_type(1); }
Tiago Peixoto's avatar
Tiago Peixoto committed
632 633 634 635 636 637 638 639 640 641
};


template <class Property>
struct is_constant_property
{
    typedef typename boost::property_traits<Property>::key_type key_type;
    typedef typename boost::property_traits<Property>::value_type value_type;
    typedef typename std::conditional<std::is_same<Property, ConstantPropertyMap<value_type, key_type>>::value,
                                      std::true_type,
642
                                      typename std::is_same<Property, UnityPropertyMap<value_type, key_type>>::type>::type type;
Tiago Peixoto's avatar
Tiago Peixoto committed
643 644
};

645

646 647
// this wraps an existing property map, but always converts its values to a
// given type
648 649
template <class PropertyMap, class Type,
          template <class T1, class T2> class Converter = convert>
650 651 652 653
class ConvertedPropertyMap
{
public:
    typedef Type value_type;
Tiago Peixoto's avatar
Tiago Peixoto committed
654
    typedef typename boost::property_traits<PropertyMap>::value_type orig_type;
655
    typedef value_type reference;
Tiago Peixoto's avatar
Tiago Peixoto committed
656 657
    typedef typename boost::property_traits<PropertyMap>::key_type key_type;
    typedef boost::read_write_property_map_tag category;
658

659 660 661 662
    ConvertedPropertyMap(PropertyMap base_map)
        : _base_map(base_map) {}
    ConvertedPropertyMap(){}

663
    value_type do_get(const key_type& k) const
664
    {
665
        return _convert_to(get(_base_map, k));
666 667
    }

668
    void do_put(const key_type& k, const value_type& v)
669
    {
670
        put(_base_map, k, _convert_from(v));
671 672 673
    }
private:
    PropertyMap _base_map;
674 675
    Converter<value_type, orig_type> _convert_to;
    Converter<orig_type, value_type> _convert_from;
676
};
677

678
template <class PropertyMap, class Type>
679 680
Type get(ConvertedPropertyMap<PropertyMap,Type> pmap,
         typename ConvertedPropertyMap<PropertyMap,Type>::key_type k)
681
{
682
    return pmap.do_get(k);
683 684 685
}

template <class PropertyMap, class Type>
686
void put(ConvertedPropertyMap<PropertyMap,Type> pmap,
Tiago Peixoto's avatar
Tiago Peixoto committed
687
         typename boost::property_traits<PropertyMap>::key_type k,
688
         const typename ConvertedPropertyMap<PropertyMap,Type>::value_type& val)
689
{
690
    pmap.do_put(k, val);
691 692 693
}

} // graph_tool namespace
694

Tiago Peixoto's avatar
Tiago Peixoto committed
695
#endif