mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
Compare commits
5 Commits
python313
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef802e1691 | ||
|
|
8ed4c145ed | ||
|
|
addbbc8210 | ||
|
|
95e7da6203 | ||
|
|
b2eb59aa0a |
@@ -27,6 +27,9 @@
|
||||
# include <boost/python/object/add_to_namespace.hpp>
|
||||
# include <boost/python/object/class_converters.hpp>
|
||||
|
||||
# include <boost/python/converter/python_type.hpp>
|
||||
|
||||
|
||||
# include <boost/python/detail/overloads_fwd.hpp>
|
||||
# include <boost/python/detail/operator_id.hpp>
|
||||
# include <boost/python/detail/def_helper.hpp>
|
||||
@@ -638,6 +641,7 @@ inline void class_<T,X1,X2,X3>::register_() const
|
||||
mpl::bool_<is_copyable>()
|
||||
, select_holder()
|
||||
);
|
||||
converter::python_class<T>::register_();
|
||||
}
|
||||
|
||||
template <class T, class X1, class X2, class X3>
|
||||
|
||||
45
include/boost/python/converter/python_type.hpp
Executable file
45
include/boost/python/converter/python_type.hpp
Executable file
@@ -0,0 +1,45 @@
|
||||
#ifndef BOOST_PYTHON_OBJECT_PYTHON_TYPE_H
|
||||
#define BOOST_PYTHON_OBJECT_PYTHON_TYPE_H
|
||||
|
||||
#include <boost/python/converter/registered.hpp>
|
||||
|
||||
namespace boost {namespace python {namespace converter{
|
||||
namespace detail{
|
||||
namespace strip_type_info{
|
||||
BOOST_PYTHON_DECL void insert(boost::python::type_info, boost::python::type_info);
|
||||
BOOST_PYTHON_DECL type_info query(boost::python::type_info);
|
||||
}
|
||||
|
||||
class python_class_base : public PyObject{
|
||||
python_class_base ();
|
||||
public:
|
||||
static void *converter (PyObject *p){return p;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}// namespace converter::detail
|
||||
|
||||
|
||||
template <class T> struct python_class : detail::python_class_base
|
||||
{
|
||||
typedef python_class<T> this_type;
|
||||
typedef T type;
|
||||
static void register_()
|
||||
{
|
||||
static bool first_time = true;
|
||||
|
||||
if ( !first_time ) return;
|
||||
first_time = false;
|
||||
converter::registry::insert(&detail::python_class_base::converter, boost::python::type_id<this_type>());
|
||||
converter::detail::strip_type_info::insert(boost::python::type_id<type>(), boost::python::type_id<type*>());
|
||||
converter::detail::strip_type_info::insert(boost::python::type_id<type>(), boost::python::type_id<type const *>());
|
||||
converter::detail::strip_type_info::insert(boost::python::type_id<type>(), boost::python::type_id<this_type*>());
|
||||
converter::detail::strip_type_info::insert(type_id<type>(), type_id<shared_ptr<type> >());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}} //namespace boost :: python :: converter
|
||||
|
||||
#endif //BOOST_PYTHON_OBJECT_PYTHON_TYPE_H
|
||||
@@ -24,8 +24,14 @@ namespace boost { namespace python { namespace detail {
|
||||
|
||||
struct signature_element
|
||||
{
|
||||
char const* basename;
|
||||
char const* basename() const{return tid.name();}
|
||||
type_info tid;
|
||||
bool lvalue;
|
||||
signature_element( type_info t, bool l)
|
||||
: tid(t)
|
||||
, lvalue(l)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned> struct signature_arity;
|
||||
@@ -70,14 +76,14 @@ struct signature_arity<N>
|
||||
static signature_element const result[N+2] = {
|
||||
|
||||
# define BOOST_PP_LOCAL_MACRO(i) \
|
||||
{ \
|
||||
type_id<BOOST_DEDUCED_TYPENAME mpl::at_c<Sig,i>::type>().name() \
|
||||
signature_element( \
|
||||
type_id<BOOST_DEDUCED_TYPENAME mpl::at_c<Sig,i>::type>() \
|
||||
, is_reference_to_non_const<BOOST_DEDUCED_TYPENAME mpl::at_c<Sig,i>::type>::value \
|
||||
},
|
||||
),
|
||||
|
||||
# define BOOST_PP_LOCAL_LIMITS (0, N)
|
||||
# include BOOST_PP_LOCAL_ITERATE()
|
||||
{0,0}
|
||||
signature_element(type_info(), 0)
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -39,10 +39,12 @@ struct BOOST_PYTHON_DECL function : PyObject
|
||||
void doc(object const& x);
|
||||
|
||||
object const& name() const;
|
||||
object pretty_signature(bool cpp_types = false, size_t n_optional_trailing_args=0)const;
|
||||
|
||||
private: // helper functions
|
||||
void argument_error(PyObject* args, PyObject* keywords) const;
|
||||
void add_overload(handle<function> const&);
|
||||
function const * overloads() const ;
|
||||
|
||||
private: // data members
|
||||
py_function m_fn;
|
||||
@@ -52,6 +54,7 @@ struct BOOST_PYTHON_DECL function : PyObject
|
||||
object m_doc;
|
||||
object m_arg_names;
|
||||
unsigned m_nkeyword_values;
|
||||
friend class function_signature_generator;
|
||||
};
|
||||
|
||||
//
|
||||
@@ -71,7 +74,7 @@ inline object const& function::name() const
|
||||
{
|
||||
return this->m_name;
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::python::objects
|
||||
|
||||
#endif // FUNCTION_DWA20011214_HPP
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
|
||||
# include <boost/python/object/instance.hpp>
|
||||
|
||||
# include <boost/python/converter/registry.hpp>
|
||||
# include <boost/python/converter/python_type.hpp>
|
||||
|
||||
# include <boost/python/object/forward.hpp>
|
||||
# include <boost/python/detail/preprocessor.hpp>
|
||||
|
||||
@@ -75,7 +78,7 @@ struct make_holder<N>
|
||||
# endif
|
||||
|
||||
static void execute(
|
||||
PyObject* p
|
||||
converter::python_class<Holder::value_type> *p
|
||||
BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, t, a))
|
||||
{
|
||||
typedef instance<Holder> instance_t;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
# include <boost/python/object/instance.hpp>
|
||||
# include <boost/python/detail/force_instantiate.hpp>
|
||||
|
||||
# include <boost/python/converter/python_type.hpp>
|
||||
|
||||
# include <boost/type.hpp>
|
||||
|
||||
# include <boost/mpl/bool.hpp>
|
||||
@@ -111,7 +113,10 @@ namespace detail
|
||||
|
||||
typedef Held held_type;
|
||||
|
||||
static inline void register_() {}
|
||||
static inline void register_()
|
||||
{
|
||||
converter::detail::strip_type_info::insert(python::type_id<T>(), python::type_id<Held>());
|
||||
}
|
||||
|
||||
static type* get() { return 0; }
|
||||
};
|
||||
@@ -143,6 +148,7 @@ namespace detail
|
||||
static inline void register_()
|
||||
{
|
||||
select_pointer_holder::register_(use_back_ref());
|
||||
converter::detail::strip_type_info::insert(python::type_id<T>(), python::type_id<Ptr>());
|
||||
}
|
||||
|
||||
static type* get() { return 0; }
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <boost/python/pointee.hpp>
|
||||
#include <boost/python/object.hpp>
|
||||
#include <boost/python/object/class_wrapper.hpp>
|
||||
#include <boost/python/converter/python_type.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
@@ -23,6 +24,7 @@ void register_ptr_to_python(BOOST_EXPLICIT_TEMPLATE_TYPE(P))
|
||||
, objects::pointer_holder<P,X>
|
||||
>
|
||||
>();
|
||||
converter::detail::strip_type_info::insert(type_id<X>(), type_id<P>());
|
||||
}
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
// (C) Copyright Joel de Guzman 2003.
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies. This
|
||||
// software is provided "as is" without express or implied warranty, and
|
||||
// with no claim as to its suitability for any purpose.
|
||||
|
||||
#ifndef PY_CONTAINER_UTILS_JDG20038_HPP
|
||||
# define PY_CONTAINER_UTILS_JDG20038_HPP
|
||||
|
||||
# include <boost/python/object.hpp>
|
||||
# include <boost/python/handle.hpp>
|
||||
# include <boost/python/extract.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace container_utils {
|
||||
|
||||
template <typename Container>
|
||||
void
|
||||
extend_container(Container& container, object l)
|
||||
{
|
||||
typedef typename Container::value_type data_type;
|
||||
|
||||
// l must be a list or some container
|
||||
|
||||
for (int i = 0; i < l.attr("__len__")(); i++)
|
||||
{
|
||||
object elem(l[i]);
|
||||
extract<data_type const&> x(elem);
|
||||
// try if elem is an exact data_type type
|
||||
if (x.check())
|
||||
{
|
||||
container.push_back(x());
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to convert elem to data_type type
|
||||
extract<data_type> x(elem);
|
||||
if (x.check())
|
||||
{
|
||||
container.push_back(x());
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Incompatible Data Type");
|
||||
throw_error_already_set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::container_utils
|
||||
|
||||
#endif
|
||||
@@ -1,743 +0,0 @@
|
||||
// (C) Copyright Joel de Guzman 2003.
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies. This
|
||||
// software is provided "as is" without express or implied warranty, and
|
||||
// with no claim as to its suitability for any purpose.
|
||||
|
||||
#ifndef INDEXING_SUITE_DETAIL_JDG20036_HPP
|
||||
# define INDEXING_SUITE_DETAIL_JDG20036_HPP
|
||||
|
||||
# include <boost/python/extract.hpp>
|
||||
# include <boost/scoped_ptr.hpp>
|
||||
# include <boost/get_pointer.hpp>
|
||||
# include <boost/detail/binary_search.hpp>
|
||||
# include <vector>
|
||||
# include <map>
|
||||
#include <iostream>
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#define BOOST_PYTHON_INDEXING_CHECK_INVARIANT
|
||||
#else
|
||||
#define BOOST_PYTHON_INDEXING_CHECK_INVARIANT check_invariant()
|
||||
#endif
|
||||
|
||||
template <class Proxy>
|
||||
struct compare_proxy_index
|
||||
{
|
||||
// This functor compares a proxy and an index.
|
||||
// This is used by proxy_group::first_proxy to
|
||||
// get first proxy with index i.
|
||||
|
||||
template <class Index>
|
||||
bool operator()(PyObject* prox, Index i) const
|
||||
{
|
||||
typedef typename Proxy::policies_type policies_type;
|
||||
Proxy& proxy = extract<Proxy&>(prox)();
|
||||
return policies_type::
|
||||
compare_index(proxy.get_container(), proxy.get_index(), i);
|
||||
}
|
||||
};
|
||||
|
||||
// The proxy_group class holds a vector of container element
|
||||
// proxies. First, what is a container element proxy? A container
|
||||
// element proxy acts like a smart pointer holding a reference to
|
||||
// a container and an index (see container_element, for details).
|
||||
//
|
||||
// The proxies are held in a vector always sorted by its index.
|
||||
// Various functions manage the addition, removal and searching
|
||||
// of proxies from the vector.
|
||||
//
|
||||
template <class Proxy>
|
||||
class proxy_group
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename std::vector<PyObject*>::const_iterator const_iterator;
|
||||
typedef typename std::vector<PyObject*>::iterator iterator;
|
||||
typedef typename Proxy::index_type index_type;
|
||||
typedef typename Proxy::policies_type policies_type;
|
||||
|
||||
iterator
|
||||
first_proxy(index_type i)
|
||||
{
|
||||
// Return the first proxy with index <= i
|
||||
return boost::detail::lower_bound(
|
||||
proxies.begin(), proxies.end(),
|
||||
i, compare_proxy_index<Proxy>());
|
||||
}
|
||||
|
||||
void
|
||||
remove(Proxy& proxy)
|
||||
{
|
||||
// Remove a proxy
|
||||
for (iterator iter = first_proxy(proxy.get_index());
|
||||
iter != proxies.end(); ++iter)
|
||||
{
|
||||
if (&extract<Proxy&>(*iter)() == &proxy)
|
||||
{
|
||||
proxies.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
}
|
||||
|
||||
void
|
||||
add(PyObject* prox)
|
||||
{
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
// Add a proxy
|
||||
proxies.insert(
|
||||
first_proxy(extract<Proxy&>(prox)().get_index()), prox);
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
}
|
||||
|
||||
void
|
||||
erase(index_type i, mpl::false_)
|
||||
{
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
// Erase the proxy with index i
|
||||
replace(i, i+1, 0);
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
}
|
||||
|
||||
void
|
||||
erase(index_type i, mpl::true_)
|
||||
{
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
// Erase the proxy with index i
|
||||
|
||||
iterator iter = first_proxy(i);
|
||||
extract<Proxy&> p(*iter);
|
||||
|
||||
if (iter != proxies.end() && p().get_index() == i)
|
||||
{
|
||||
extract<Proxy&> p(*iter);
|
||||
p().detach();
|
||||
proxies.erase(iter);
|
||||
}
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
}
|
||||
|
||||
void
|
||||
erase(index_type from, index_type to)
|
||||
{
|
||||
// note: this cannot be called when container is not sliceable
|
||||
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
// Erase all proxies with indexes from..to
|
||||
replace(from, to, 0);
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
}
|
||||
|
||||
void
|
||||
replace(
|
||||
index_type from,
|
||||
index_type to,
|
||||
typename std::vector<PyObject*>::size_type len)
|
||||
{
|
||||
// note: this cannot be called when container is not sliceable
|
||||
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
// Erase all proxies with indexes from..to.
|
||||
// Adjust the displaced indexes such that the
|
||||
// final effect is that we have inserted *len*
|
||||
// number of proxies in the vacated region. This
|
||||
// procedure involves adjusting the indexes of
|
||||
// the proxies.
|
||||
|
||||
iterator left = first_proxy(from);
|
||||
iterator right = proxies.end(); // we'll adjust this later
|
||||
|
||||
for (iterator iter = left; iter != right; ++iter)
|
||||
{
|
||||
if (extract<Proxy&>(*iter)().get_index() > to)
|
||||
{
|
||||
right = iter; // adjust right
|
||||
break;
|
||||
}
|
||||
extract<Proxy&> p(*iter);
|
||||
p().detach();
|
||||
}
|
||||
|
||||
typename std::vector<PyObject*>::size_type
|
||||
offset = left-proxies.begin();
|
||||
proxies.erase(left, right);
|
||||
right = proxies.begin()+offset;
|
||||
|
||||
while (right != proxies.end())
|
||||
{
|
||||
typedef typename Proxy::container_type::difference_type difference_type;
|
||||
extract<Proxy&> p(*right);
|
||||
p().set_index(
|
||||
extract<Proxy&>(*right)().get_index()
|
||||
- (difference_type(to) - from - len)
|
||||
);
|
||||
|
||||
++right;
|
||||
}
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
find(index_type i)
|
||||
{
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
// Find the proxy with *exact* index i.
|
||||
// Return 0 (null) if no proxy with the
|
||||
// given index is found.
|
||||
iterator iter = first_proxy(i);
|
||||
if (iter != proxies.end()
|
||||
&& extract<Proxy&>(*iter)().get_index() == i)
|
||||
{
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
return *iter;
|
||||
}
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typename std::vector<PyObject*>::size_type
|
||||
size() const
|
||||
{
|
||||
BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
|
||||
// How many proxies are there so far?
|
||||
return proxies.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
void
|
||||
check_invariant() const
|
||||
{
|
||||
for (const_iterator i = proxies.begin(); i != proxies.end(); ++i)
|
||||
{
|
||||
if ((*i)->ob_refcnt <= 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Invariant: Proxy vector in an inconsistent state");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
if (i+1 != proxies.end())
|
||||
{
|
||||
if (extract<Proxy&>(*(i+1))().get_index() ==
|
||||
extract<Proxy&>(*(i))().get_index())
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Invariant: Proxy vector in an inconsistent state (duplicate proxy)");
|
||||
throw_error_already_set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<PyObject*> proxies;
|
||||
};
|
||||
|
||||
// proxy_links holds a map of Container pointers (keys)
|
||||
// with proxy_group(s) (data). Various functions manage
|
||||
// the addition, removal and searching of proxies from
|
||||
// the map.
|
||||
//
|
||||
template <class Proxy, class Container>
|
||||
class proxy_links
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::map<Container*, proxy_group<Proxy> > links_t;
|
||||
typedef typename Proxy::index_type index_type;
|
||||
|
||||
void
|
||||
remove(Proxy& proxy)
|
||||
{
|
||||
// Remove a proxy.
|
||||
typename links_t::iterator r = links.find(&proxy.get_container());
|
||||
if (r != links.end())
|
||||
{
|
||||
r->second.remove(proxy);
|
||||
if (r->second.size() == 0)
|
||||
links.erase(r);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
add(PyObject* prox, Container& container)
|
||||
{
|
||||
// Add a proxy
|
||||
links[&container].add(prox);
|
||||
}
|
||||
|
||||
template <class NoSlice>
|
||||
void erase(Container& container, index_type i, NoSlice no_slice)
|
||||
{
|
||||
// Erase the proxy with index i
|
||||
typename links_t::iterator r = links.find(&container);
|
||||
if (r != links.end())
|
||||
{
|
||||
r->second.erase(i, no_slice);
|
||||
if (r->second.size() == 0)
|
||||
links.erase(r);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
erase(Container& container, index_type from, index_type to)
|
||||
{
|
||||
// Erase all proxies with indexes from..to
|
||||
typename links_t::iterator r = links.find(&container);
|
||||
if (r != links.end())
|
||||
{
|
||||
r->second.erase(from, to);
|
||||
if (r->second.size() == 0)
|
||||
links.erase(r);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
replace(
|
||||
Container& container,
|
||||
index_type from, index_type to, index_type len)
|
||||
{
|
||||
// Erase all proxies with indexes from..to.
|
||||
// Adjust the displaced indexes such that the
|
||||
// final effect is that we have inserted *len*
|
||||
// number of proxies in the vacated region. This
|
||||
// procedure involves adjusting the indexes of
|
||||
// the proxies.
|
||||
|
||||
typename links_t::iterator r = links.find(&container);
|
||||
if (r != links.end())
|
||||
{
|
||||
r->second.replace(from, to, len);
|
||||
if (r->second.size() == 0)
|
||||
links.erase(r);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject*
|
||||
find(Container& container, index_type i)
|
||||
{
|
||||
// Find the proxy with *exact* index i.
|
||||
// Return 0 (null) if no proxy with the given
|
||||
// index is found.
|
||||
typename links_t::iterator r = links.find(&container);
|
||||
if (r != links.end())
|
||||
return r->second.find(i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
links_t links;
|
||||
};
|
||||
|
||||
// container_element is our container proxy class.
|
||||
// This class acts like a smart pointer to a container
|
||||
// element. The class holds an index and a reference to
|
||||
// a container. Dereferencing the smart pointer will
|
||||
// retrieve the nth (index) element from the container.
|
||||
//
|
||||
// A container_element can also be detached from the
|
||||
// container. In such a detached state, the container_element
|
||||
// holds a copy of the nth (index) element, which it
|
||||
// returns when dereferenced.
|
||||
//
|
||||
template <class Container, class Index, class Policies>
|
||||
class container_element
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Index index_type;
|
||||
typedef Container container_type;
|
||||
typedef typename Policies::data_type element_type;
|
||||
typedef Policies policies_type;
|
||||
typedef container_element<Container, Index, Policies> self_t;
|
||||
typedef proxy_group<self_t> links_type;
|
||||
|
||||
container_element(object container, Index index)
|
||||
: ptr()
|
||||
, container(container)
|
||||
, index(index)
|
||||
{
|
||||
}
|
||||
|
||||
container_element(container_element const& ce)
|
||||
: ptr(ce.ptr.get() == 0 ? 0 : new element_type(*ce.ptr.get()))
|
||||
, container(ce.container)
|
||||
, index(ce.index)
|
||||
{
|
||||
}
|
||||
|
||||
~container_element()
|
||||
{
|
||||
if (!is_detached())
|
||||
get_links().remove(*this);
|
||||
}
|
||||
|
||||
element_type& operator*() const
|
||||
{
|
||||
if (is_detached())
|
||||
return *get_pointer(ptr);
|
||||
return Policies::get_item(get_container(), index);
|
||||
}
|
||||
|
||||
element_type* get() const
|
||||
{
|
||||
if (is_detached())
|
||||
return get_pointer(ptr);
|
||||
return &Policies::get_item(get_container(), index);
|
||||
}
|
||||
|
||||
void
|
||||
detach()
|
||||
{
|
||||
if (!is_detached())
|
||||
{
|
||||
ptr.reset(
|
||||
new element_type(
|
||||
Policies::get_item(get_container(), index)));
|
||||
container = object(); // free container. reset it to None
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
is_detached() const
|
||||
{
|
||||
return get_pointer(ptr) != 0;
|
||||
}
|
||||
|
||||
Container&
|
||||
get_container() const
|
||||
{
|
||||
return extract<Container&>(container)();
|
||||
}
|
||||
|
||||
Index
|
||||
get_index() const
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
void
|
||||
set_index(Index i)
|
||||
{
|
||||
index = i;
|
||||
}
|
||||
|
||||
static proxy_links<self_t, Container>&
|
||||
get_links()
|
||||
{
|
||||
// All container_element(s) maintain links to
|
||||
// its container in a global map (see proxy_links).
|
||||
// This global "links" map is a singleton.
|
||||
|
||||
static proxy_links<self_t, Container> links;
|
||||
return links; // singleton
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
container_element& operator=(container_element const& ce);
|
||||
|
||||
scoped_ptr<element_type> ptr;
|
||||
object container;
|
||||
Index index;
|
||||
};
|
||||
|
||||
template <
|
||||
class Container
|
||||
, class DerivedPolicies
|
||||
, class ContainerElement
|
||||
, class Index
|
||||
>
|
||||
struct no_proxy_helper
|
||||
{
|
||||
static void
|
||||
register_container_element()
|
||||
{
|
||||
}
|
||||
|
||||
static object
|
||||
base_get_item_(back_reference<Container&> const& container, PyObject* i)
|
||||
{
|
||||
return object(
|
||||
DerivedPolicies::get_item(
|
||||
container.get(), DerivedPolicies::
|
||||
convert_index(container.get(), i)));
|
||||
}
|
||||
|
||||
static void
|
||||
base_replace_indexes(
|
||||
Container& container, Index from,
|
||||
Index to, Index n)
|
||||
{
|
||||
}
|
||||
|
||||
template <class NoSlice>
|
||||
static void
|
||||
base_erase_index(
|
||||
Container& container, Index i, NoSlice no_slice)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
base_erase_indexes(Container& container, Index from, Index to)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
class Container
|
||||
, class DerivedPolicies
|
||||
, class ContainerElement
|
||||
, class Index
|
||||
>
|
||||
struct proxy_helper
|
||||
{
|
||||
static void
|
||||
register_container_element()
|
||||
{
|
||||
register_ptr_to_python<ContainerElement>();
|
||||
}
|
||||
|
||||
static object
|
||||
base_get_item_(back_reference<Container&> const& container, PyObject* i)
|
||||
{
|
||||
// Proxy
|
||||
Index idx = DerivedPolicies::convert_index(container.get(), i);
|
||||
|
||||
if (PyObject* shared =
|
||||
ContainerElement::get_links().find(container.get(), idx))
|
||||
{
|
||||
handle<> h(python::borrowed(shared));
|
||||
return object(h);
|
||||
}
|
||||
else
|
||||
{
|
||||
object prox(ContainerElement(container.source(), idx));
|
||||
ContainerElement::
|
||||
get_links().add(prox.ptr(), container.get());
|
||||
return prox;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
base_replace_indexes(
|
||||
Container& container, Index from,
|
||||
Index to, Index n)
|
||||
{
|
||||
ContainerElement::get_links().replace(container, from, to, n);
|
||||
}
|
||||
|
||||
template <class NoSlice>
|
||||
static void
|
||||
base_erase_index(
|
||||
Container& container, Index i, NoSlice no_slice)
|
||||
{
|
||||
ContainerElement::get_links().erase(container, i, no_slice);
|
||||
}
|
||||
|
||||
static void
|
||||
base_erase_indexes(
|
||||
Container& container, Index from, Index to)
|
||||
{
|
||||
ContainerElement::get_links().erase(container, from, to);
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
class Container
|
||||
, class DerivedPolicies
|
||||
, class ProxyHandler
|
||||
, class Data
|
||||
, class Index
|
||||
>
|
||||
struct slice_helper
|
||||
{
|
||||
static object
|
||||
base_get_slice(Container& container, PySliceObject* slice)
|
||||
{
|
||||
Index from, to;
|
||||
base_get_slice_data(container, slice, from, to);
|
||||
return DerivedPolicies::get_slice(container, from, to);
|
||||
}
|
||||
|
||||
static void
|
||||
base_get_slice_data(
|
||||
Container& container, PySliceObject* slice, Index& from, Index& to)
|
||||
{
|
||||
if (Py_None != slice->step) {
|
||||
PyErr_SetString( PyExc_IndexError, "slice step size not supported.");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
Index min_index = DerivedPolicies::get_min_index(container);
|
||||
Index max_index = DerivedPolicies::get_max_index(container);
|
||||
|
||||
|
||||
if (Py_None == slice->start) {
|
||||
from = min_index;
|
||||
}
|
||||
else {
|
||||
from = extract<long>( slice->start);
|
||||
if (from < 0) // Negative slice index
|
||||
from += max_index;
|
||||
if (from < 0) // Clip lower bounds to zero
|
||||
from = 0;
|
||||
if (from > max_index) // Clip upper bounds to max_index.
|
||||
from = max_index;
|
||||
|
||||
}
|
||||
|
||||
if (Py_None == slice->stop) {
|
||||
to = DerivedPolicies::get_max_index(container);
|
||||
}
|
||||
else {
|
||||
to = extract<long>( slice->stop);
|
||||
if (to < 0)
|
||||
to += max_index;
|
||||
if (to < 0)
|
||||
to = 0;
|
||||
if (to > max_index)
|
||||
to = max_index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
base_set_slice(Container& container, PySliceObject* slice, PyObject* v)
|
||||
{
|
||||
Index from, to;
|
||||
base_get_slice_data(container, slice, from, to);
|
||||
|
||||
extract<Data&> elem(v);
|
||||
// try if elem is an exact Data
|
||||
if (elem.check())
|
||||
{
|
||||
ProxyHandler::base_replace_indexes(container, from, to, 1);
|
||||
DerivedPolicies::set_slice(container, from, to, elem());
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to convert elem to Data
|
||||
extract<Data> elem(v);
|
||||
if (elem.check())
|
||||
{
|
||||
ProxyHandler::base_replace_indexes(container, from, to, 1);
|
||||
DerivedPolicies::set_slice(container, from, to, elem());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, it must be a list or some container
|
||||
handle<> l_(python::borrowed(v));
|
||||
object l(l_);
|
||||
|
||||
std::vector<Data> temp;
|
||||
for (int i = 0; i < l.attr("__len__")(); i++)
|
||||
{
|
||||
object elem(l[i]);
|
||||
extract<Data const&> x(elem);
|
||||
// try if elem is an exact Data type
|
||||
if (x.check())
|
||||
{
|
||||
temp.push_back(x());
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to convert elem to Data type
|
||||
extract<Data> x(elem);
|
||||
if (x.check())
|
||||
{
|
||||
temp.push_back(x());
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Invalid sequence element");
|
||||
throw_error_already_set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProxyHandler::base_replace_indexes(container, from, to,
|
||||
temp.end()-temp.begin());
|
||||
DerivedPolicies::set_slice(container, from, to,
|
||||
temp.begin(), temp.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
base_delete_slice(Container& container, PySliceObject* slice)
|
||||
{
|
||||
Index from, to;
|
||||
base_get_slice_data(container, slice, from, to);
|
||||
ProxyHandler::base_erase_indexes(container, from, to);
|
||||
DerivedPolicies::delete_slice(container, from, to);
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
class Container
|
||||
, class DerivedPolicies
|
||||
, class ProxyHandler
|
||||
, class Data
|
||||
, class Index
|
||||
>
|
||||
struct no_slice_helper
|
||||
{
|
||||
static void
|
||||
slicing_not_suported()
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "Slicing not supported");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
static object
|
||||
base_get_slice(Container& container, PySliceObject* slice)
|
||||
{
|
||||
slicing_not_suported();
|
||||
return object();
|
||||
}
|
||||
|
||||
static void
|
||||
base_set_slice(Container& container, PySliceObject* slice, PyObject* v)
|
||||
{
|
||||
slicing_not_suported();
|
||||
}
|
||||
|
||||
static void
|
||||
base_delete_slice(Container& container, PySliceObject* slice)
|
||||
{
|
||||
slicing_not_suported();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
|
||||
}} // namespace python::detail
|
||||
#endif
|
||||
|
||||
template <class Container, class Index, class Policies>
|
||||
inline typename Policies::data_type*
|
||||
get_pointer(
|
||||
python::detail::container_element<Container, Index, Policies> const& p)
|
||||
{
|
||||
// Get the pointer of a container_element smart pointer
|
||||
return p.get();
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
|
||||
// Don't hide these other get_pointer overloads
|
||||
using boost::python::get_pointer;
|
||||
using boost::get_pointer;
|
||||
}} // namespace python::detail
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // INDEXING_SUITE_DETAIL_JDG20036_HPP
|
||||
@@ -1,294 +0,0 @@
|
||||
// (C) Copyright Joel de Guzman 2003.
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies. This
|
||||
// software is provided "as is" without express or implied warranty, and
|
||||
// with no claim as to its suitability for any purpose.
|
||||
|
||||
#ifndef INDEXING_SUITE_JDG20036_HPP
|
||||
# define INDEXING_SUITE_JDG20036_HPP
|
||||
|
||||
# include <boost/python/class.hpp>
|
||||
# include <boost/python/def_visitor.hpp>
|
||||
# include <boost/python/register_ptr_to_python.hpp>
|
||||
# include <boost/python/suite/indexing/detail/indexing_suite_detail.hpp>
|
||||
# include <boost/python/return_internal_reference.hpp>
|
||||
# include <boost/python/iterator.hpp>
|
||||
# include <boost/mpl/or.hpp>
|
||||
# include <boost/mpl/not.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
// indexing_suite class. This class is the protocol class for
|
||||
// the management of C++ containers intended to be integrated
|
||||
// to Python. The objective is make a C++ container look and
|
||||
// feel and behave exactly as we'd expect a Python container.
|
||||
// By default indexed elements are returned by proxy. This can be
|
||||
// disabled by supplying *true* in the NoProxy template parameter.
|
||||
//
|
||||
// Derived classes provide the hooks needed by the indexing_suite
|
||||
// to do its job:
|
||||
//
|
||||
// static data_type&
|
||||
// get_item(Container& container, index_type i);
|
||||
//
|
||||
// static object
|
||||
// get_slice(Container& container, index_type from, index_type to);
|
||||
//
|
||||
// static void
|
||||
// set_item(Container& container, index_type i, data_type const& v);
|
||||
//
|
||||
// static void
|
||||
// set_slice(
|
||||
// Container& container, index_type from,
|
||||
// index_type to, data_type const& v
|
||||
// );
|
||||
//
|
||||
// template <class Iter>
|
||||
// static void
|
||||
// set_slice(Container& container, index_type from,
|
||||
// index_type to, Iter first, Iter last
|
||||
// );
|
||||
//
|
||||
// static void
|
||||
// delete_item(Container& container, index_type i);
|
||||
//
|
||||
// static void
|
||||
// delete_slice(Container& container, index_type from, index_type to);
|
||||
//
|
||||
// static size_t
|
||||
// size(Container& container);
|
||||
//
|
||||
// template <class T>
|
||||
// static bool
|
||||
// contains(Container& container, T const& val);
|
||||
//
|
||||
// static index_type
|
||||
// convert_index(Container& container, PyObject* i);
|
||||
//
|
||||
// static index_type
|
||||
// adjust_index(index_type current, index_type from,
|
||||
// index_type to, size_type len
|
||||
// );
|
||||
//
|
||||
// Most of these policies are self explanatory. convert_index and
|
||||
// adjust_index, however, deserves some explanation.
|
||||
//
|
||||
// convert_index converts an Python index into a C++ index that the
|
||||
// container can handle. For instance, negative indexes in Python, by
|
||||
// convention, indexes from the right (e.g. C[-1] indexes the rightmost
|
||||
// element in C). convert_index should handle the necessary conversion
|
||||
// for the C++ container (e.g. convert -1 to C.size()-1). convert_index
|
||||
// should also be able to convert the type of the index (A dynamic Python
|
||||
// type) to the actual type that the C++ container expects.
|
||||
//
|
||||
// When a container expands or contracts, held indexes to its elements
|
||||
// must be adjusted to follow the movement of data. For instance, if
|
||||
// we erase 3 elements, starting from index 0 from a 5 element vector,
|
||||
// what used to be at index 4 will now be at index 1:
|
||||
//
|
||||
// [a][b][c][d][e] ---> [d][e]
|
||||
// ^ ^
|
||||
// 4 1
|
||||
//
|
||||
// adjust_index takes care of the adjustment. Given a current index,
|
||||
// the function should return the adjusted index when data in the
|
||||
// container at index from..to is replaced by *len* elements.
|
||||
//
|
||||
|
||||
template <
|
||||
class Container
|
||||
, class DerivedPolicies
|
||||
, bool NoProxy = false
|
||||
, bool NoSlice = false
|
||||
, class Data = typename Container::value_type
|
||||
, class Index = typename Container::size_type
|
||||
, class Key = typename Container::value_type
|
||||
>
|
||||
class indexing_suite
|
||||
: public def_visitor<
|
||||
indexing_suite<
|
||||
Container
|
||||
, DerivedPolicies
|
||||
, NoProxy
|
||||
, NoSlice
|
||||
, Data
|
||||
, Index
|
||||
, Key
|
||||
> >
|
||||
{
|
||||
private:
|
||||
|
||||
typedef mpl::or_<
|
||||
mpl::bool_<NoProxy>
|
||||
, mpl::not_<is_class<Data> > >
|
||||
no_proxy;
|
||||
|
||||
typedef detail::container_element<Container, Index, DerivedPolicies>
|
||||
container_element_t;
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
|
||||
struct return_policy : return_internal_reference<> {};
|
||||
#else
|
||||
typedef return_internal_reference<> return_policy;
|
||||
#endif
|
||||
|
||||
typedef typename mpl::if_<
|
||||
no_proxy
|
||||
, iterator<Container>
|
||||
, iterator<Container, return_policy> >::type
|
||||
def_iterator;
|
||||
|
||||
typedef typename mpl::if_<
|
||||
no_proxy
|
||||
, detail::no_proxy_helper<
|
||||
Container
|
||||
, DerivedPolicies
|
||||
, container_element_t
|
||||
, Index>
|
||||
, detail::proxy_helper<
|
||||
Container
|
||||
, DerivedPolicies
|
||||
, container_element_t
|
||||
, Index> >::type
|
||||
proxy_handler;
|
||||
|
||||
typedef typename mpl::if_<
|
||||
mpl::bool_<NoSlice>
|
||||
, detail::no_slice_helper<
|
||||
Container
|
||||
, DerivedPolicies
|
||||
, proxy_handler
|
||||
, Data
|
||||
, Index>
|
||||
, detail::slice_helper<
|
||||
Container
|
||||
, DerivedPolicies
|
||||
, proxy_handler
|
||||
, Data
|
||||
, Index> >::type
|
||||
slice_handler;
|
||||
|
||||
public:
|
||||
|
||||
template <class Class>
|
||||
void visit(Class& cl) const
|
||||
{
|
||||
// Hook into the class_ generic visitation .def function
|
||||
proxy_handler::register_container_element();
|
||||
|
||||
cl
|
||||
.def("__len__", base_size)
|
||||
.def("__setitem__", &base_set_item)
|
||||
.def("__delitem__", &base_delete_item)
|
||||
.def("__getitem__", &base_get_item)
|
||||
.def("__contains__", &base_contains)
|
||||
.def("__iter__", def_iterator())
|
||||
;
|
||||
|
||||
DerivedPolicies::extension_def(cl);
|
||||
}
|
||||
|
||||
template <class Class>
|
||||
static void
|
||||
extension_def(Class& cl)
|
||||
{
|
||||
// default.
|
||||
// no more extensions
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static object
|
||||
base_get_item(back_reference<Container&> container, PyObject* i)
|
||||
{
|
||||
if (PySlice_Check(i))
|
||||
return slice_handler::base_get_slice(
|
||||
container.get(), reinterpret_cast<PySliceObject*>(i));
|
||||
|
||||
return proxy_handler::base_get_item_(container, i);
|
||||
}
|
||||
|
||||
static void
|
||||
base_set_item(Container& container, PyObject* i, PyObject* v)
|
||||
{
|
||||
if (PySlice_Check(i))
|
||||
{
|
||||
slice_handler::base_set_slice(container,
|
||||
reinterpret_cast<PySliceObject*>(i), v);
|
||||
}
|
||||
else
|
||||
{
|
||||
extract<Data&> elem(v);
|
||||
// try if elem is an exact Data
|
||||
if (elem.check())
|
||||
{
|
||||
DerivedPolicies::
|
||||
set_item(container,
|
||||
DerivedPolicies::
|
||||
convert_index(container, i), elem());
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to convert elem to Data
|
||||
extract<Data> elem(v);
|
||||
if (elem.check())
|
||||
{
|
||||
DerivedPolicies::
|
||||
set_item(container,
|
||||
DerivedPolicies::
|
||||
convert_index(container, i), elem());
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid assignment");
|
||||
throw_error_already_set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
base_delete_item(Container& container, PyObject* i)
|
||||
{
|
||||
if (PySlice_Check(i))
|
||||
{
|
||||
slice_handler::base_delete_slice(
|
||||
container, reinterpret_cast<PySliceObject*>(i));
|
||||
return;
|
||||
}
|
||||
|
||||
Index index = DerivedPolicies::convert_index(container, i);
|
||||
proxy_handler::base_erase_index(container, index, mpl::bool_<NoSlice>());
|
||||
DerivedPolicies::delete_item(container, index);
|
||||
}
|
||||
|
||||
static size_t
|
||||
base_size(Container& container)
|
||||
{
|
||||
return DerivedPolicies::size(container);
|
||||
}
|
||||
|
||||
static bool
|
||||
base_contains(Container& container, PyObject* key)
|
||||
{
|
||||
extract<Key const&> x(key);
|
||||
// try if key is an exact Key type
|
||||
if (x.check())
|
||||
{
|
||||
return DerivedPolicies::contains(container, x());
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to convert key to Key type
|
||||
extract<Key> x(key);
|
||||
if (x.check())
|
||||
return DerivedPolicies::contains(container, x());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // INDEXING_SUITE_JDG20036_HPP
|
||||
@@ -1,180 +0,0 @@
|
||||
// (C) Copyright Joel de Guzman 2003.
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies. This
|
||||
// software is provided "as is" without express or implied warranty, and
|
||||
// with no claim as to its suitability for any purpose.
|
||||
|
||||
#ifndef MAP_INDEXING_SUITE_JDG20038_HPP
|
||||
# define MAP_INDEXING_SUITE_JDG20038_HPP
|
||||
|
||||
# include <boost/python/suite/indexing/indexing_suite.hpp>
|
||||
# include <boost/python/iterator.hpp>
|
||||
# include <boost/python/call_method.hpp>
|
||||
# include <boost/python/tuple.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
// Forward declaration
|
||||
template <class Container, bool NoProxy, class DerivedPolicies>
|
||||
class map_indexing_suite;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class Container, bool NoProxy>
|
||||
class final_map_derived_policies
|
||||
: public map_indexing_suite<Container,
|
||||
NoProxy, final_map_derived_policies<Container, NoProxy> > {};
|
||||
}
|
||||
|
||||
// The map_indexing_suite class is a predefined indexing_suite derived
|
||||
// class for wrapping std::vector (and std::vector like) classes. It provides
|
||||
// all the policies required by the indexing_suite (see indexing_suite).
|
||||
// Example usage:
|
||||
//
|
||||
// class X {...};
|
||||
//
|
||||
// ...
|
||||
//
|
||||
// class_<std::map<std::string, X> >("XMap")
|
||||
// .def(map_indexing_suite<std::map<std::string, X> >())
|
||||
// ;
|
||||
//
|
||||
// By default indexed elements are returned by proxy. This can be
|
||||
// disabled by supplying *true* in the NoProxy template parameter.
|
||||
//
|
||||
template <
|
||||
class Container,
|
||||
bool NoProxy = false,
|
||||
class DerivedPolicies
|
||||
= detail::final_map_derived_policies<Container, NoProxy> >
|
||||
class map_indexing_suite
|
||||
: public indexing_suite<
|
||||
Container
|
||||
, DerivedPolicies
|
||||
, NoProxy
|
||||
, true
|
||||
, typename Container::value_type::second_type
|
||||
, typename Container::key_type
|
||||
, typename Container::key_type
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename Container::value_type value_type;
|
||||
typedef typename Container::value_type::second_type data_type;
|
||||
typedef typename Container::key_type key_type;
|
||||
typedef typename Container::key_type index_type;
|
||||
typedef typename Container::size_type size_type;
|
||||
typedef typename Container::difference_type difference_type;
|
||||
|
||||
template <class Class>
|
||||
static void
|
||||
extension_def(Class& cl)
|
||||
{
|
||||
// Wrap the map's element (value_type)
|
||||
std::string elem_name = "map_indexing_suite_";
|
||||
elem_name += cl.ptr()->ob_type->tp_name; // the class name
|
||||
elem_name += "_entry";
|
||||
|
||||
typedef typename mpl::if_<
|
||||
is_class<data_type>
|
||||
, return_internal_reference<>
|
||||
, default_call_policies
|
||||
>::type get_data_return_policy;
|
||||
|
||||
class_<value_type>(elem_name.c_str())
|
||||
.def("__repr__", &DerivedPolicies::print_elem)
|
||||
.def("data", &DerivedPolicies::get_data, get_data_return_policy())
|
||||
.def("key", &DerivedPolicies::get_key)
|
||||
;
|
||||
}
|
||||
|
||||
static object
|
||||
print_elem(typename Container::value_type const& e)
|
||||
{
|
||||
return "(%s, %s)" % make_tuple(e.first, e.second);
|
||||
}
|
||||
|
||||
static
|
||||
typename mpl::if_<
|
||||
is_class<data_type>
|
||||
, data_type&
|
||||
, data_type
|
||||
>::type
|
||||
get_data(typename Container::value_type& e)
|
||||
{
|
||||
return e.second;
|
||||
}
|
||||
|
||||
static typename Container::key_type
|
||||
get_key(typename Container::value_type& e)
|
||||
{
|
||||
return e.first;
|
||||
}
|
||||
|
||||
static data_type&
|
||||
get_item(Container& container, index_type i_)
|
||||
{
|
||||
typename Container::iterator i = container.find(i_);
|
||||
if (i == container.end())
|
||||
{
|
||||
PyErr_SetString(PyExc_KeyError, "Invalid key");
|
||||
throw_error_already_set();
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
static void
|
||||
set_item(Container& container, index_type i, data_type const& v)
|
||||
{
|
||||
container[i] = v;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_item(Container& container, index_type i)
|
||||
{
|
||||
container.erase(i);
|
||||
}
|
||||
|
||||
static size_t
|
||||
size(Container& container)
|
||||
{
|
||||
return container.size();
|
||||
}
|
||||
|
||||
static bool
|
||||
contains(Container& container, key_type const& key)
|
||||
{
|
||||
return container.find(key) != container.end();
|
||||
}
|
||||
|
||||
static bool
|
||||
compare_index(Container& container, index_type a, index_type b)
|
||||
{
|
||||
return container.key_comp()(a, b);
|
||||
}
|
||||
|
||||
static index_type
|
||||
convert_index(Container& container, PyObject* i_)
|
||||
{
|
||||
extract<key_type const&> i(i_);
|
||||
if (i.check())
|
||||
{
|
||||
return i();
|
||||
}
|
||||
else
|
||||
{
|
||||
extract<key_type> i(i_);
|
||||
if (i.check())
|
||||
return i();
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid index type");
|
||||
throw_error_already_set();
|
||||
return index_type();
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // MAP_INDEXING_SUITE_JDG20038_HPP
|
||||
@@ -1,243 +0,0 @@
|
||||
// (C) Copyright Joel de Guzman 2003.
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies. This
|
||||
// software is provided "as is" without express or implied warranty, and
|
||||
// with no claim as to its suitability for any purpose.
|
||||
|
||||
#ifndef VECTOR_INDEXING_SUITE_JDG20036_HPP
|
||||
# define VECTOR_INDEXING_SUITE_JDG20036_HPP
|
||||
|
||||
# include <boost/python/suite/indexing/indexing_suite.hpp>
|
||||
# include <boost/python/suite/indexing/container_utils.hpp>
|
||||
# include <boost/python/iterator.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
// Forward declaration
|
||||
template <class Container, bool NoProxy, class DerivedPolicies>
|
||||
class vector_indexing_suite;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class Container, bool NoProxy>
|
||||
class final_vector_derived_policies
|
||||
: public vector_indexing_suite<Container,
|
||||
NoProxy, final_vector_derived_policies<Container, NoProxy> > {};
|
||||
}
|
||||
|
||||
// The vector_indexing_suite class is a predefined indexing_suite derived
|
||||
// class for wrapping std::vector (and std::vector like) classes. It provides
|
||||
// all the policies required by the indexing_suite (see indexing_suite).
|
||||
// Example usage:
|
||||
//
|
||||
// class X {...};
|
||||
//
|
||||
// ...
|
||||
//
|
||||
// class_<std::vector<X> >("XVec")
|
||||
// .def(vector_indexing_suite<std::vector<X> >())
|
||||
// ;
|
||||
//
|
||||
// By default indexed elements are returned by proxy. This can be
|
||||
// disabled by supplying *true* in the NoProxy template parameter.
|
||||
//
|
||||
template <
|
||||
class Container,
|
||||
bool NoProxy = false,
|
||||
class DerivedPolicies
|
||||
= detail::final_vector_derived_policies<Container, NoProxy> >
|
||||
class vector_indexing_suite
|
||||
: public indexing_suite<Container, DerivedPolicies, NoProxy>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename Container::value_type data_type;
|
||||
typedef typename Container::value_type key_type;
|
||||
typedef typename Container::size_type index_type;
|
||||
typedef typename Container::size_type size_type;
|
||||
typedef typename Container::difference_type difference_type;
|
||||
|
||||
template <class Class>
|
||||
static void
|
||||
extension_def(Class& cl)
|
||||
{
|
||||
cl
|
||||
.def("append", &base_append)
|
||||
.def("extend", &base_extend)
|
||||
;
|
||||
}
|
||||
|
||||
static
|
||||
typename mpl::if_<
|
||||
is_class<data_type>
|
||||
, data_type&
|
||||
, data_type
|
||||
>::type
|
||||
get_item(Container& container, index_type i)
|
||||
{
|
||||
return container[i];
|
||||
}
|
||||
|
||||
static object
|
||||
get_slice(Container& container, index_type from, index_type to)
|
||||
{
|
||||
if (from > to)
|
||||
return object(Container());
|
||||
return object(Container(container.begin()+from, container.begin()+to));
|
||||
}
|
||||
|
||||
static void
|
||||
set_item(Container& container, index_type i, data_type const& v)
|
||||
{
|
||||
container[i] = v;
|
||||
}
|
||||
|
||||
static void
|
||||
set_slice(Container& container, index_type from,
|
||||
index_type to, data_type const& v)
|
||||
{
|
||||
if (from > to) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
container.erase(container.begin()+from, container.begin()+to);
|
||||
container.insert(container.begin()+from, v);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
static void
|
||||
set_slice(Container& container, index_type from,
|
||||
index_type to, Iter first, Iter last)
|
||||
{
|
||||
if (from > to) {
|
||||
container.insert(container.begin()+from, first, last);
|
||||
}
|
||||
else {
|
||||
container.erase(container.begin()+from, container.begin()+to);
|
||||
container.insert(container.begin()+from, first, last);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
delete_item(Container& container, index_type i)
|
||||
{
|
||||
container.erase(container.begin()+i);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_slice(Container& container, index_type from, index_type to)
|
||||
{
|
||||
if (from > to) {
|
||||
// A null-op.
|
||||
return;
|
||||
}
|
||||
container.erase(container.begin()+from, container.begin()+to);
|
||||
}
|
||||
|
||||
static size_t
|
||||
size(Container& container)
|
||||
{
|
||||
return container.size();
|
||||
}
|
||||
|
||||
static bool
|
||||
contains(Container& container, key_type const& key)
|
||||
{
|
||||
return std::find(container.begin(), container.end(), key)
|
||||
!= container.end();
|
||||
}
|
||||
|
||||
static index_type
|
||||
get_min_index(Container& container)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static index_type
|
||||
get_max_index(Container& container)
|
||||
{
|
||||
return container.size();
|
||||
}
|
||||
|
||||
static bool
|
||||
compare_index(Container& container, index_type a, index_type b)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
|
||||
static index_type
|
||||
convert_index(Container& container, PyObject* i_)
|
||||
{
|
||||
extract<long> i(i_);
|
||||
if (i.check())
|
||||
{
|
||||
long index = i();
|
||||
if (index < 0)
|
||||
index += DerivedPolicies::size(container);
|
||||
if (index >= long(container.size()) || index < 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_IndexError, "Index out of range");
|
||||
throw_error_already_set();
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid index type");
|
||||
throw_error_already_set();
|
||||
return index_type();
|
||||
}
|
||||
|
||||
static void
|
||||
append(Container& container, data_type const& v)
|
||||
{
|
||||
container.push_back(v);
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
static void
|
||||
extend(Container& container, Iter first, Iter last)
|
||||
{
|
||||
container.insert(container.end(), first, last);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void
|
||||
base_append(Container& container, object v)
|
||||
{
|
||||
extract<data_type&> elem(v);
|
||||
// try if elem is an exact Data
|
||||
if (elem.check())
|
||||
{
|
||||
DerivedPolicies::append(container, elem());
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to convert elem to data_type
|
||||
extract<data_type> elem(v);
|
||||
if (elem.check())
|
||||
{
|
||||
DerivedPolicies::append(container, elem());
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Attempting to append an invalid type");
|
||||
throw_error_already_set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
base_extend(Container& container, object v)
|
||||
{
|
||||
std::vector<data_type> temp;
|
||||
container_utils::extend_container(temp, v);
|
||||
DerivedPolicies::extend(container, temp.begin(), temp.end());
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // VECTOR_INDEXING_SUITE_JDG20036_HPP
|
||||
@@ -58,6 +58,7 @@ namespace
|
||||
, &slot_rvalue_from_python<T,SlotPolicy>::construct
|
||||
, type_id<T>()
|
||||
);
|
||||
const_cast<registration*>(registry::query(type_id<T>()))->m_class_object = SlotPolicy::get_class_object();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -94,6 +95,7 @@ namespace
|
||||
return (PyInt_Check(obj) || PyLong_Check(obj))
|
||||
? &number_methods->nb_int : 0;
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -129,6 +131,7 @@ namespace
|
||||
return (PyInt_Check(obj) || PyLong_Check(obj))
|
||||
? &py_object_identity : 0;
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -167,6 +170,7 @@ namespace
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
struct long_long_rvalue_from_python : long_long_rvalue_from_python_base
|
||||
@@ -222,6 +226,7 @@ namespace
|
||||
{
|
||||
return PyObject_IsTrue(intermediate);
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyInt_Type;}
|
||||
};
|
||||
|
||||
// A SlotPolicy for extracting floating types from Python objects.
|
||||
@@ -253,6 +258,7 @@ namespace
|
||||
return PyFloat_AS_DOUBLE(intermediate);
|
||||
}
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyFloat_Type;}
|
||||
};
|
||||
|
||||
// A SlotPolicy for extracting C++ strings from Python objects.
|
||||
@@ -270,6 +276,7 @@ namespace
|
||||
{
|
||||
return std::string(PyString_AsString(intermediate),PyString_Size(intermediate));
|
||||
}
|
||||
static PyTypeObject * get_class_object() { return &PyString_Type;}
|
||||
};
|
||||
|
||||
// encode_string_unaryfunc/py_encode_string -- manufacture a unaryfunc
|
||||
@@ -308,6 +315,8 @@ namespace
|
||||
throw_error_already_set();
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyTypeObject * get_class_object() { return &PyUnicode_Type;}
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -404,6 +413,7 @@ void initialize_builtin_converters()
|
||||
|
||||
// Add an lvalue converter for char which gets us char const*
|
||||
registry::insert(convert_to_cstring,type_id<char>());
|
||||
const_cast<registration&>(registry::lookup(type_id<char const*>())).m_class_object = &PyString_Type;
|
||||
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
// Register by-value converters to std::string, std::wstring
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
#include <boost/python/converter/registry.hpp>
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
#include <boost/python/converter/builtin_converters.hpp>
|
||||
#include <boost/python/converter/python_type.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
@@ -243,4 +245,74 @@ namespace registry
|
||||
}
|
||||
} // namespace registry
|
||||
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace strip_type_info{
|
||||
struct type_info_map : std::map<boost::python::type_info, boost::python::type_info>
|
||||
{
|
||||
type_info_map(){
|
||||
(*this)[boost::python::type_id<bool*>()] = boost::python::type_id<bool>();
|
||||
(*this)[boost::python::type_id<bool const*>()] = boost::python::type_id<bool>();
|
||||
|
||||
(*this)[boost::python::type_id<char*>()] = boost::python::type_id<char>();
|
||||
(*this)[boost::python::type_id<unsigned char*>()] = boost::python::type_id<unsigned char>();
|
||||
|
||||
(*this)[boost::python::type_id<short*>()] = boost::python::type_id<short>();
|
||||
(*this)[boost::python::type_id<short const*>()] = boost::python::type_id<short>();
|
||||
(*this)[boost::python::type_id<unsigned short*>()] = boost::python::type_id<unsigned short>();
|
||||
(*this)[boost::python::type_id<unsigned short const*>()] = boost::python::type_id<unsigned short>();
|
||||
|
||||
(*this)[boost::python::type_id<int*>()] = boost::python::type_id<int>();
|
||||
(*this)[boost::python::type_id<int const*>()] = boost::python::type_id<int>();
|
||||
(*this)[boost::python::type_id<unsigned int*>()] = boost::python::type_id<unsigned int>();
|
||||
(*this)[boost::python::type_id<unsigned int const*>()] = boost::python::type_id<unsigned int>();
|
||||
|
||||
(*this)[boost::python::type_id<long*>()] = boost::python::type_id<long>();
|
||||
(*this)[boost::python::type_id<long const*>()] = boost::python::type_id<long>();
|
||||
(*this)[boost::python::type_id<unsigned long*>()] = boost::python::type_id<unsigned long>();
|
||||
(*this)[boost::python::type_id<unsigned long const*>()] = boost::python::type_id<unsigned long>();
|
||||
|
||||
(*this)[boost::python::type_id<long double*>()] = boost::python::type_id<long double>();
|
||||
(*this)[boost::python::type_id<long double const*>()] = boost::python::type_id<long double>();
|
||||
|
||||
(*this)[boost::python::type_id<double*>()] = boost::python::type_id<double>();
|
||||
(*this)[boost::python::type_id<double const*>()] = boost::python::type_id<double>();
|
||||
|
||||
(*this)[boost::python::type_id<float*>()] = boost::python::type_id<float>();
|
||||
(*this)[boost::python::type_id<float const*>()] = boost::python::type_id<float>();
|
||||
|
||||
(*this)[boost::python::type_id<std::string*>()] = boost::python::type_id<std::string>();
|
||||
(*this)[boost::python::type_id<std::string const*>()] = boost::python::type_id<std::string>();
|
||||
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
(*this)[boost::python::type_id<std::wstring*>()] = boost::python::type_id<std::wstring>();
|
||||
(*this)[boost::python::type_id<std::wstring const*>()] = boost::python::type_id<std::wstring>();
|
||||
# endif
|
||||
}
|
||||
};
|
||||
|
||||
static std::map<boost::python::type_info, boost::python::type_info> &type_info_remap_registry()
|
||||
{
|
||||
static type_info_map res;
|
||||
return res;
|
||||
}
|
||||
BOOST_PYTHON_DECL void insert(boost::python::type_info t, boost::python::type_info pt)
|
||||
{
|
||||
if(t==pt)
|
||||
return;
|
||||
type_info_remap_registry()[pt] = t;
|
||||
}
|
||||
|
||||
BOOST_PYTHON_DECL type_info query(boost::python::type_info pt)
|
||||
{
|
||||
std::map<boost::python::type_info, boost::python::type_info> :: iterator i
|
||||
= type_info_remap_registry().find(pt);
|
||||
return i == type_info_remap_registry().end()? pt : (*i).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::python::converter
|
||||
|
||||
@@ -167,5 +167,14 @@ list dict_base::values() const
|
||||
return assume_list(this->attr("values")());
|
||||
}
|
||||
}
|
||||
static struct register_dict_pytype_ptr
|
||||
{
|
||||
register_dict_pytype_ptr()
|
||||
{
|
||||
const_cast<converter::registration &>(
|
||||
converter::registry::lookup(boost::python::type_id<boost::python::dict>())
|
||||
).m_class_object = &PyDict_Type;
|
||||
}
|
||||
}register_dict_pytype_ptr_;
|
||||
|
||||
}}} // namespace boost::python
|
||||
|
||||
12
src/list.cpp
12
src/list.cpp
@@ -4,6 +4,8 @@
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
#include <boost/python/list.hpp>
|
||||
#include <boost/python/converter/registry.hpp>
|
||||
#include <boost/python/converter/registrations.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
|
||||
@@ -136,5 +138,13 @@ long list_base::count(object_cref value) const
|
||||
throw_error_already_set();
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct register_list_pytype_ptr
|
||||
{
|
||||
register_list_pytype_ptr()
|
||||
{
|
||||
const_cast<converter::registration &>(
|
||||
converter::registry::lookup(boost::python::type_id<boost::python::list>())
|
||||
).m_class_object = &PyList_Type;
|
||||
}
|
||||
}register_list_pytype_ptr_;
|
||||
}}} // namespace boost::python
|
||||
|
||||
@@ -613,14 +613,15 @@ namespace objects
|
||||
|
||||
namespace
|
||||
{
|
||||
PyObject* callable_check(PyObject* callable)
|
||||
PyObject* callable_check(PyObject* callable, const char *name)
|
||||
{
|
||||
if (PyCallable_Check(expect_non_null(callable)))
|
||||
return callable;
|
||||
|
||||
::PyErr_Format(
|
||||
PyExc_TypeError
|
||||
, "staticmethod expects callable object; got an object of type %s, which is not callable"
|
||||
, "staticmethod expects callable object; got an object \"%s\" of type %s, which is not callable"
|
||||
, name
|
||||
, callable->ob_type->tp_name
|
||||
);
|
||||
|
||||
@@ -638,7 +639,7 @@ namespace objects
|
||||
|
||||
this->attr(method_name) = object(
|
||||
handle<>(
|
||||
PyStaticMethod_New((callable_check)(method.ptr()) )
|
||||
PyStaticMethod_New((callable_check)(method.ptr(), method_name) )
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <boost/python/tuple.hpp>
|
||||
#include <boost/python/list.hpp>
|
||||
|
||||
#include <boost/python/converter/python_type.hpp>
|
||||
|
||||
#include <boost/python/detail/api_placeholder.hpp>
|
||||
#include <boost/python/detail/signature.hpp>
|
||||
#include <boost/mpl/vector/vector10.hpp>
|
||||
@@ -24,6 +26,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES
|
||||
# include <cstdio>
|
||||
@@ -226,6 +229,269 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline function const * function::overloads() const
|
||||
{
|
||||
return this->m_overloads.get();
|
||||
}
|
||||
|
||||
|
||||
class function_signature_generator{
|
||||
public:
|
||||
static bool arity_cmp( function const *f1, function const *f2 )
|
||||
{
|
||||
return f1->m_fn.max_arity() < f2->m_fn.max_arity();
|
||||
}
|
||||
|
||||
static bool are_seq_overloads( function const *f1, function const *f2 , bool check_docs)
|
||||
{
|
||||
py_function const & impl1 = f1->m_fn;
|
||||
py_function const & impl2 = f2->m_fn;
|
||||
|
||||
//the number of parameters differs by 1
|
||||
if (impl2.max_arity()-impl1.max_arity() != 1)
|
||||
return false;
|
||||
|
||||
// if check docs then f1 shold not have docstring or have the same docstring as f2
|
||||
if (check_docs && f2->doc() != f1->doc() && f1->doc())
|
||||
return false;
|
||||
|
||||
python::detail::signature_element const* s1 = impl1.signature();
|
||||
python::detail::signature_element const* s2 = impl2.signature();
|
||||
|
||||
size_t size = impl1.max_arity();
|
||||
|
||||
for (size_t i = 0; i != size; ++i)
|
||||
{
|
||||
//check if the argument types are the same
|
||||
if (s1[i].basename() != s2[i].basename())
|
||||
return false;
|
||||
|
||||
//return type
|
||||
if (!i) continue;
|
||||
|
||||
//check if the argument default values are the same
|
||||
if (f1->m_arg_names && f2->m_arg_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1]
|
||||
|| bool( f1->m_arg_names ) != bool( f2->m_arg_names
|
||||
))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<function const*> flatten(function const *f)
|
||||
{
|
||||
object name = f->name();
|
||||
|
||||
std::vector<function const*> res;
|
||||
|
||||
while (f) {
|
||||
|
||||
//this if takes out the not_implemented_function
|
||||
if (f->name() == name)
|
||||
res.push_back(f);
|
||||
|
||||
f=f->overloads();
|
||||
}
|
||||
|
||||
std::sort(res.begin(),res.end(), &arity_cmp);
|
||||
|
||||
return res;
|
||||
}
|
||||
static std::vector<function const*> split_seq_overloads( const std::vector<function const *> &funcs, bool split_on_doc_change)
|
||||
{
|
||||
std::vector<function const*> res;
|
||||
|
||||
std::vector<function const*>::const_iterator fi = funcs.begin();
|
||||
|
||||
function const * last = *fi;
|
||||
|
||||
while (++fi != funcs.end()){
|
||||
|
||||
//check if fi starts a new chain of overloads
|
||||
if (!are_seq_overloads( last, *fi, split_on_doc_change ))
|
||||
res.push_back(last);
|
||||
|
||||
last = *fi;
|
||||
}
|
||||
|
||||
if (last)
|
||||
res.push_back(last);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static object raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types = false)
|
||||
{
|
||||
str res("object");
|
||||
|
||||
res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char * py_type_str(const python::detail::signature_element &s)
|
||||
{
|
||||
if (s.basename()==std::string("void")){
|
||||
static const char * none = "None";
|
||||
return none;
|
||||
}
|
||||
const converter::registration *r=0;
|
||||
|
||||
if ( (r = converter::registry::query(s.tid) ) && r->m_class_object)
|
||||
return r->m_class_object->tp_name;
|
||||
else if ( (r = converter::registry::query(converter::detail::strip_type_info::query(s.tid) ) ) && r->m_class_object )
|
||||
return r->m_class_object->tp_name;
|
||||
else{
|
||||
static const char * object = "object";
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
static object parameter_string(const python::detail::signature_element *s, size_t n, object arg_names, bool cpp_types)
|
||||
{
|
||||
str param;
|
||||
|
||||
if (cpp_types)
|
||||
{
|
||||
if (s[n].basename() == 0)
|
||||
{
|
||||
return str("...");
|
||||
}
|
||||
|
||||
param = str(s[n].tid.name());
|
||||
|
||||
if (s[n].lvalue)
|
||||
param += " {lvalue}";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n) //we are processing an argument and trying to come up with a name for it
|
||||
{
|
||||
object kv;
|
||||
if ( arg_names && (kv = arg_names[n-1]) )
|
||||
param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) );
|
||||
else
|
||||
param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) );
|
||||
}
|
||||
else //we are processing the return type - how should we handle it???
|
||||
param = py_type_str(s[n]);
|
||||
}
|
||||
|
||||
//an argument - check for default value and append it
|
||||
if(n && arg_names)
|
||||
{
|
||||
object kv(arg_names[n-1]);
|
||||
if (kv && len(kv) == 2)
|
||||
{
|
||||
param = str("%s=%r" % make_tuple(param, kv[1]));
|
||||
}
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
static object pretty_signature(function const *f, size_t n_overloads, bool cpp_types = false)
|
||||
{
|
||||
py_function
|
||||
const& impl = f->m_fn;
|
||||
;
|
||||
|
||||
python::detail::signature_element
|
||||
const* s = impl.signature()
|
||||
;
|
||||
|
||||
size_t arity = impl.max_arity();
|
||||
|
||||
if(arity == size_t(-1))// is this the proper raw function test?
|
||||
{
|
||||
return raw_function_pretty_signature(f,n_overloads,cpp_types);
|
||||
}
|
||||
|
||||
list formal_params;
|
||||
|
||||
size_t n_extra_default_args=0;
|
||||
|
||||
for (unsigned n = 0; n <= arity; ++n)
|
||||
{
|
||||
str param;
|
||||
|
||||
formal_params.append(
|
||||
parameter_string(s, n, f->m_arg_names, cpp_types)
|
||||
);
|
||||
|
||||
// find all the arguments with default values preceeding the arity-n_overloads
|
||||
if (n && f->m_arg_names)
|
||||
{
|
||||
object kv(f->m_arg_names[n-1]);
|
||||
|
||||
if (kv && len(kv) == 2)
|
||||
{
|
||||
//default argument preceeding the arity-n_overloads
|
||||
if( n <= arity-n_overloads)
|
||||
++n_extra_default_args;
|
||||
}
|
||||
else
|
||||
//argument without default, preceeding the arity-n_overloads
|
||||
if( n <= arity-n_overloads)
|
||||
n_extra_default_args = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arity && cpp_types)
|
||||
formal_params.append("void");
|
||||
|
||||
str ret_type (formal_params.pop(0));
|
||||
if ( !cpp_types )
|
||||
ret_type = str("-> "+ret_type);
|
||||
|
||||
n_overloads+=n_extra_default_args;
|
||||
|
||||
return str(
|
||||
"%s %s(%s%s%s%s) %s"
|
||||
% make_tuple
|
||||
( cpp_types?ret_type:str("")
|
||||
, f->m_name
|
||||
, str(",").join(formal_params.slice(0,arity-n_overloads))
|
||||
, n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str()
|
||||
, str(" [,").join(formal_params.slice(arity-n_overloads,arity))
|
||||
, std::string(n_overloads,']')
|
||||
, cpp_types?str(""):ret_type
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
static list function_signatures( function const * f, bool cpp_types, bool docs)
|
||||
{
|
||||
list signatures;
|
||||
std::vector<function const*> funcs = function_signature_generator::flatten( f);
|
||||
std::vector<function const*> split_funcs = function_signature_generator::split_seq_overloads( funcs, docs);
|
||||
std::vector<function const*>::const_iterator sfi=split_funcs.begin(), fi;
|
||||
size_t n_overloads=0;
|
||||
for (fi=funcs.begin(); fi!=funcs.end(); ++fi)
|
||||
{
|
||||
if(*sfi == *fi){
|
||||
signatures.append(
|
||||
(*fi)->doc() && docs
|
||||
? function_signature_generator::pretty_signature(*fi, n_overloads,cpp_types)+ " : " +(*fi)->doc()
|
||||
: function_signature_generator::pretty_signature(*fi, n_overloads,cpp_types)
|
||||
);
|
||||
++sfi;
|
||||
n_overloads = 0;
|
||||
}else
|
||||
++n_overloads ;
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
object function::pretty_signature(bool cpp_types, size_t n_optional_trailing_args )const
|
||||
{
|
||||
function const *f = this;
|
||||
return function_signature_generator::pretty_signature(this, n_optional_trailing_args, cpp_types);
|
||||
|
||||
}
|
||||
|
||||
void function::argument_error(PyObject* args, PyObject* keywords) const
|
||||
{
|
||||
static handle<> exception(
|
||||
@@ -243,47 +509,7 @@ void function::argument_error(PyObject* args, PyObject* keywords) const
|
||||
message += str(", ").join(actual_args);
|
||||
message += ")\ndid not match C++ signature:\n ";
|
||||
|
||||
list signatures;
|
||||
for (function const* f = this; f; f = f->m_overloads.get())
|
||||
{
|
||||
py_function const& impl = f->m_fn;
|
||||
|
||||
python::detail::signature_element const* s
|
||||
= impl.signature() + 1; // skip over return type
|
||||
|
||||
list formal_params;
|
||||
if (impl.max_arity() == 0)
|
||||
formal_params.append("void");
|
||||
|
||||
for (unsigned n = 0; n < impl.max_arity(); ++n)
|
||||
{
|
||||
if (s[n].basename == 0)
|
||||
{
|
||||
formal_params.append("...");
|
||||
break;
|
||||
}
|
||||
|
||||
str param(s[n].basename);
|
||||
if (s[n].lvalue)
|
||||
param += " {lvalue}";
|
||||
|
||||
if (f->m_arg_names) // None or empty tuple will test false
|
||||
{
|
||||
object kv(f->m_arg_names[n]);
|
||||
if (kv)
|
||||
{
|
||||
char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s";
|
||||
param += fmt % kv;
|
||||
}
|
||||
}
|
||||
|
||||
formal_params.append(param);
|
||||
}
|
||||
|
||||
signatures.append(
|
||||
"%s(%s)" % make_tuple(f->m_name, str(", ").join(formal_params))
|
||||
);
|
||||
}
|
||||
list signatures = function_signature_generator::function_signatures(this, true/*cpp types*/, false/*no docs*/);
|
||||
|
||||
message += str("\n ").join(signatures);
|
||||
|
||||
@@ -302,10 +528,6 @@ void function::add_overload(handle<function> const& overload_)
|
||||
parent = parent->m_overloads.get();
|
||||
|
||||
parent->m_overloads = overload_;
|
||||
|
||||
// If we have no documentation, get the docs from the overload
|
||||
if (!m_doc)
|
||||
m_doc = overload_->m_doc;
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -545,8 +767,11 @@ extern "C"
|
||||
//
|
||||
static PyObject* function_get_doc(PyObject* op, void*)
|
||||
{
|
||||
function* f = downcast<function>(op);
|
||||
return python::incref(f->doc().ptr());
|
||||
function const * f = downcast<function >(op);
|
||||
|
||||
list signatures = function_signature_generator::function_signatures(f, false/*pythonic args*/, true/*+docs*/);
|
||||
|
||||
return python::incref( str("\n ").join(signatures).ptr());
|
||||
}
|
||||
|
||||
static int function_set_doc(PyObject* op, PyObject* doc, void*)
|
||||
@@ -640,6 +865,7 @@ handle<> function_handle_impl(py_function const& f)
|
||||
new function(f, 0, 0)));
|
||||
}
|
||||
|
||||
|
||||
} // namespace objects
|
||||
|
||||
namespace detail
|
||||
|
||||
10
src/str.cpp
10
src/str.cpp
@@ -328,5 +328,15 @@ BOOST_PYTHON_DEFINE_STR_METHOD(title, 0)
|
||||
BOOST_PYTHON_DEFINE_STR_METHOD(translate, 1)
|
||||
BOOST_PYTHON_DEFINE_STR_METHOD(translate, 2)
|
||||
BOOST_PYTHON_DEFINE_STR_METHOD(upper, 0)
|
||||
|
||||
static struct register_str_pytype_ptr
|
||||
{
|
||||
register_str_pytype_ptr()
|
||||
{
|
||||
const_cast<converter::registration &>(
|
||||
converter::registry::lookup(boost::python::type_id<boost::python::str>())
|
||||
).m_class_object = &PyString_Type;
|
||||
}
|
||||
}register_str_pytype_ptr_;
|
||||
|
||||
}}} // namespace boost::python
|
||||
|
||||
@@ -17,4 +17,15 @@ tuple_base::tuple_base(object_cref sequence)
|
||||
: object(call(sequence))
|
||||
{}
|
||||
|
||||
static struct register_tuple_pytype_ptr
|
||||
{
|
||||
register_tuple_pytype_ptr()
|
||||
{
|
||||
const_cast<converter::registration &>(
|
||||
converter::registry::lookup(boost::python::type_id<boost::python::tuple>())
|
||||
).m_class_object = &PyTuple_Type;
|
||||
}
|
||||
}register_tuple_pytype_ptr_;
|
||||
|
||||
|
||||
}}} // namespace boost::python
|
||||
|
||||
Reference in New Issue
Block a user