Commit e84aaf3c authored by Tiago Peixoto's avatar Tiago Peixoto

Add support for array access to property maps

A property map object has now a get_array() member which returns an internally
owned array pointing to the property values.
parent e4d79af6
// Copyright (C) Vladimir Prus 2003.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// See for
// documentation.
#ifndef VECTOR_PROPERTY_MAP_HPP_VP_2003_03_04
#define VECTOR_PROPERTY_MAP_HPP_VP_2003_03_04
#include <boost/property_map.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace boost {
template<typename T, typename IndexMap = identity_property_map>
class vector_property_map
: public boost::put_get_helper<
typename std::iterator_traits<
typename std::vector<T>::iterator >::reference,
vector_property_map<T, IndexMap> >
typedef typename property_traits<IndexMap>::key_type key_type;
typedef T value_type;
typedef typename std::iterator_traits<
typename std::vector<T>::iterator >::reference reference;
typedef boost::lvalue_property_map_tag category;
vector_property_map(const IndexMap& index = IndexMap())
: store(new std::vector<T>()), index(index)
vector_property_map(unsigned initial_size,
const IndexMap& index = IndexMap())
: store(new std::vector<T>(initial_size)), index(index)
typename std::vector<T>::iterator storage_begin()
return store->begin();
typename std::vector<T>::iterator storage_end()
return store->end();
typename std::vector<T>::const_iterator storage_begin() const
return store->begin();
typename std::vector<T>::const_iterator storage_end() const
return store->end();
void reserve(size_t size)
if (store->size() < size)
std::vector<T>& get_storage() { return (*store); }
// Copy ctor absent, default semantics is OK.
// Assignment operator absent, default semantics is OK.
// CONSIDER: not sure that assignment to 'index' is correct.
reference operator[](const key_type& v) const {
typename property_traits<IndexMap>::value_type i = get(index, v);
if (static_cast<unsigned>(i) >= store->size()) {
store->resize(i + 1, T());
return (*store)[i];
// Conceptually, we have a vector of infinite size. For practical
// purposes, we start with an empty vector and grow it as needed.
// Note that we cannot store pointer to vector here -- we cannot
// store pointer to data, because if copy of property map resizes
// the vector, the pointer to data will be invalidated.
// I wonder if class 'pmap_ref' is simply needed.
shared_ptr< std::vector<T> > store;
IndexMap index;
template<typename T, typename IndexMap>
vector_property_map<T, IndexMap>
make_vector_property_map(IndexMap index)
return vector_property_map<T, IndexMap>(index);
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
// along with this program. If not, see <>. // along with this program. If not, see <>.
#include "graph.hh" #include "graph.hh"
#include "graph_python_interface.hh" #include "graph_python_interface.hh"
#include "graph_util.hh" #include "graph_util.hh"
#include "numpy_bind.hh" #include "numpy_bind.hh"
#include <boost/python.hpp> #include <boost/python.hpp>
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "graph.hh" #include "graph.hh"
#include "graph_filtering.hh" #include "graph_filtering.hh"
#include "graph_selectors.hh" #include "graph_selectors.hh"
#include "numpy_bind.hh"
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/python/type_id.hpp> #include <boost/python/type_id.hpp>
...@@ -428,6 +429,28 @@ public: ...@@ -428,6 +429,28 @@ public:
(_pmap)); (_pmap));
} }
python::object GetArray(size_t size)
typedef typename mpl::or_<
typename mpl::not_<typename mpl::has_key<numpy_types,
::type is_vector_map;
return get_array(_pmap, size, is_vector_map());
python::object get_array(PropertyMap pmap, size_t size, mpl::bool_<false>)
return wrap_vector_not_owned(_pmap.get_storage());
python::object get_array(PropertyMap pmap, size_t size, mpl::bool_<true>)
return python::object();
private: private:
PropertyMap _pmap; // hold an internal copy, since it's cheap PropertyMap _pmap; // hold an internal copy, since it's cheap
}; };
...@@ -66,7 +66,8 @@ struct export_vertex_property_map ...@@ -66,7 +66,8 @@ struct export_vertex_property_map
return_policy()) return_policy())
.def("__setitem__", &pmap_t::template SetValue<PythonVertex>) .def("__setitem__", &pmap_t::template SetValue<PythonVertex>)
.def("get_map", &pmap_t::GetMap) .def("get_map", &pmap_t::GetMap)
.def("get_dynamic_map", &pmap_t::GetDynamicMap); .def("get_dynamic_map", &pmap_t::GetDynamicMap)
.def("get_array", &pmap_t::GetArray);
} }
string _name; string _name;
...@@ -152,6 +152,26 @@ class PropertyMap(object): ...@@ -152,6 +152,26 @@ class PropertyMap(object):
"""The value type of the map""" """The value type of the map"""
return self.__map.value_type() return self.__map.value_type()
def get_array(self):
"""Get an array with property values
The returned array does not own the data, which belongs to the
property map. Therefore, the returned array cannot have a longer
lifespan than the property map itself! Futhermore, if the graph
changes, it may leave the pointer to the data in the array dangling!
Do *not* store the array if the graph is to be modified, or the
original property map deleted; *store a copy instead*!
if self.__key_type == 'v':
n = self.__g().num_vertices()
elif self.__key_type == 'e':
n = self.__g().num_edges()
n = 1
return self.__map.get_array(n)
class PropertyDict(dict): class PropertyDict(dict):
"""Wrapper for the dict of vertex, graph or edge properties, which sets the """Wrapper for the dict of vertex, graph or edge properties, which sets the
value on the property map when changed in the dict.""" value on the property map when changed in the dict."""
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment