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
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/graph/vector_property_map.html 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> >
{
public:
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)
store->resize(size);
}
std::vector<T>& get_storage() { return (*store); }
public:
// 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];
}
private:
// 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);
}
}
#endif
......@@ -16,9 +16,9 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graph.hh"
#define NUMPY_EXPORT
#include "graph_python_interface.hh"
#include "graph_util.hh"
#define NUMPY_EXPORT
#include "numpy_bind.hh"
#include <boost/python.hpp>
......
......@@ -27,6 +27,7 @@
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_selectors.hh"
#include "numpy_bind.hh"
#include <boost/python.hpp>
#include <boost/python/type_id.hpp>
......@@ -428,6 +429,28 @@ public:
(_pmap));
}
python::object GetArray(size_t size)
{
typedef typename mpl::or_<
is_same<PropertyMap,
GraphInterface::vertex_index_map_t>,
typename mpl::not_<typename mpl::has_key<numpy_types,
value_type>::type>::type>
::type is_vector_map;
return get_array(_pmap, size, is_vector_map());
}
python::object get_array(PropertyMap pmap, size_t size, mpl::bool_<false>)
{
_pmap.reserve(size);
return wrap_vector_not_owned(_pmap.get_storage());
}
python::object get_array(PropertyMap pmap, size_t size, mpl::bool_<true>)
{
return python::object();
}
private:
PropertyMap _pmap; // hold an internal copy, since it's cheap
};
......
......@@ -66,7 +66,8 @@ struct export_vertex_property_map
return_policy())
.def("__setitem__", &pmap_t::template SetValue<PythonVertex>)
.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;
......
......@@ -152,6 +152,26 @@ class PropertyMap(object):
"""The value type of the map"""
return self.__map.value_type()
def get_array(self):
"""Get an array with property values
.. WARNING::
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()
else:
n = 1
return self.__map.get_array(n)
class PropertyDict(dict):
"""Wrapper for the dict of vertex, graph or edge properties, which sets the
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