2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-23 17:52:17 +00:00
[SVN r14219]
This commit is contained in:
Dave Abrahams
2002-06-20 21:47:26 +00:00
parent 693b21188c
commit 55dff4d512
13 changed files with 549 additions and 78 deletions

View File

@@ -21,8 +21,9 @@ class object;
namespace boost { namespace python { namespace converter {
template <class T>
class is_object_manager
struct is_object_manager
{
private:
BOOST_STATIC_CONSTANT(bool, hdl = is_handle<T>::value);
BOOST_STATIC_CONSTANT(bool, borrowed = python::detail::is_borrowed_ptr<T>::value);
public:

View File

@@ -9,6 +9,7 @@
# include <boost/python/object_core.hpp>
# include <boost/python/object_attributes.hpp>
# include <boost/python/object_items.hpp>
# include <boost/python/object_slices.hpp>
# include <boost/python/object_operators.hpp>
namespace boost { namespace python {

View File

@@ -14,12 +14,14 @@ namespace boost { namespace python { namespace api {
struct const_attribute_policies
{
static object get(object const& target, object const& key);
typedef char const* key_type;
static object get(object const& target, char const* key);
};
struct attribute_policies : const_attribute_policies
{
static object const& set(object const& target, object const& key, object const& value);
static object const& set(object const& target, char const* key, object const& value);
static void del(object const&target, char const* key);
};
//
@@ -28,55 +30,38 @@ struct attribute_policies : const_attribute_policies
template <class U>
inline object_attribute object_operators<U>::attr(char const* name)
{
object const& x = *static_cast<U*>(this);
return object_attribute(x, object(name));
object_cref x = *static_cast<U*>(this);
return object_attribute(x, name);
}
template <class U>
inline const_object_attribute object_operators<U>::attr(char const* name) const
{
object const& x = *static_cast<U const*>(this);
return const_object_attribute(x, object(name));
object_cref x = *static_cast<U const*>(this);
return const_object_attribute(x, name);
}
inline object const_attribute_policies::get(object const& target, object const& key)
inline object const_attribute_policies::get(object const& target, char const* key)
{
return python::getattr(target, key);
}
inline object const& attribute_policies::set(
object const& target
, object const& key
, char const* key
, object const& value)
{
python::setattr(target, key, value);
return value;
}
} // namespace api
namespace converter
inline void attribute_policies::del(
object const& target
, char const* key)
{
// These specializations are a lie; the proxies do not directly
// manage an object. What actually happens is that the implicit
// conversion to object takes hold and its conversion to_python is
// used. That's OK in part because the object temporary *is*
// actually managing the object during the duration of the
// conversion.
template <>
struct is_object_manager<api::object_attribute>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <>
struct is_object_manager<api::const_object_attribute>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
python::delattr(target, key);
}
}} // namespace boost::python
}}} // namespace boost::python::api
#endif // OBJECT_ATTRIBUTES_DWA2002615_HPP

View File

@@ -10,6 +10,8 @@
# include <boost/python/detail/preprocessor.hpp>
# include <boost/python/call.hpp>
# include <boost/preprocessor/max.hpp>
# include <boost/python/slice_nil.hpp>
# include <boost/type.hpp>
namespace boost { namespace python {
@@ -27,12 +29,74 @@ namespace api
struct attribute_policies;
struct const_item_policies;
struct item_policies;
struct const_slice_policies;
struct slice_policies;
typedef proxy<const_attribute_policies> const_object_attribute;
typedef proxy<attribute_policies> object_attribute;
typedef proxy<const_item_policies> const_object_item;
typedef proxy<item_policies> object_item;
typedef proxy<const_slice_policies> const_object_slice;
typedef proxy<slice_policies> object_slice;
//
// is_proxy -- proxy type detection
//
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T>
struct is_proxy
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class T>
struct is_proxy<proxy<T> >
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
# else
typedef char yes_proxy;
typedef char (&no_proxy)[2];
template <class T>
yes_proxy is_proxy_helper(boost::type<proxy<T> >*);
no_proxy is_proxy_helper(...);
template <class T>
struct is_proxy
{
BOOST_STATIC_CONSTANT(
bool, value = (sizeof(is_proxy_helper((boost::type<T>*)0))
== sizeof(yes_proxy)));
};
# endif
//
// object_handle -- get the handle to construct the object with,
// based on whether T is a proxy or not
//
template <bool = false>
struct object_handle
{
template <class T>
static handle<> get(T const& x)
{
return handle<>(
python::borrowed(
python::allow_null( // null check is already done
converter::arg_to_python<T>(x).get())
)
);
}
};
template <>
struct object_handle<true>
{
template <class Policies>
static handle<> get(proxy<Policies> const& x)
{
return x.operator object().ptr();
}
};
// A way to turn a conrete type T into a type dependent on U. This
// keeps conforming compilers from complaining about returning an
// incomplete T from a template member function (which must be
@@ -54,12 +118,19 @@ namespace api
# else
typedef object self_cref;
# endif
// there appears to be a codegen bug here. We prevent the early
// destruction of a temporary in CWPro8 by binding a named
// object instead.
# if __MWERKS__ != 0x3000
typedef object const& object_cref;
# else
typedef object const object_cref;
# endif
public:
// Attribute access via x.attr("attribute_name")
const_object_attribute attr(char const*) const;
object_attribute attr(char const*);
// function call
//
object operator()() const;
# ifndef BOOST_PYTHON_GENERATE_CODE
@@ -81,10 +152,17 @@ namespace api
, BOOST_PYTHON_OBJECT_CALL, ignored)
// truth value testing
//
operator bool_type() const;
bool operator!() const; // needed for vc6
// Attribute access
//
const_object_attribute attr(char const*) const;
object_attribute attr(char const*);
// item access
//
const_object_item operator[](self_cref) const;
object_item operator[](self_cref);
@@ -110,6 +188,47 @@ namespace api
}
# endif
// slicing
//
const_object_slice slice(self_cref, self_cref) const;
object_slice slice(self_cref, self_cref);
const_object_slice slice(slice_nil, self_cref) const;
object_slice slice(slice_nil, self_cref);
const_object_slice slice(self_cref, slice_nil) const;
object_slice slice(self_cref, slice_nil);
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
template <class T, class V>
const_object_slice
slice(T const& start, V const& end) const;
template <class T, class V>
object_slice
slice(T const& start, V const& end);
# else
template <class T, class V>
const_object_slice
slice(T const& start, V const& end) const
{
return this->slice(
slice_bound<T>::type(start)
, slice_bound<V>::type(end));
}
template <class T, class V>
object_slice
slice(T const& start, V const& end)
{
return this->slice(
slice_bound<T>::type(start)
, slice_bound<V>::type(end));
}
# endif
# if BOOST_MSVC == 1200
// For whatever reason, VC6 generates incorrect code unless we
// define this
@@ -128,12 +247,7 @@ namespace api
// explicit conversion from any C++ object to Python
template <class T>
explicit object(T const& x)
: m_ptr(
python::borrowed(
python::allow_null( // null check is already done
converter::arg_to_python<T>(x).get())
)
)
: m_ptr(object_handle<is_proxy<T>::value>::get(x))
{
}
@@ -141,12 +255,7 @@ namespace api
// literals. Otherwise, they get deduced as char[N]const& above
// and conversion fails at runtime.
explicit object(char const* x)
: m_ptr(
python::borrowed(
python::allow_null( // null check is already done
converter::arg_to_python<char const*>(x).get())
)
)
: m_ptr(object_handle<>::get(x))
{
}

View File

@@ -14,12 +14,14 @@ namespace boost { namespace python { namespace api {
struct const_item_policies
{
typedef object key_type;
static object get(object const& target, object const& key);
};
struct item_policies : const_item_policies
{
static object const& set(object const& target, object const& key, object const& value);
static void del(object const& target, object const& key);
};
//
@@ -29,7 +31,7 @@ template <class U>
inline object_item
object_operators<U>::operator[](self_cref key)
{
object const& x = *static_cast<U*>(this);
object_cref x = *static_cast<U*>(this);
return object_item(x, key);
}
@@ -37,7 +39,7 @@ template <class U>
inline const_object_item
object_operators<U>::operator[](self_cref key) const
{
object const& x = *static_cast<U const*>(this);
object_cref x = *static_cast<U const*>(this);
return const_object_item(x, key);
}
@@ -62,7 +64,7 @@ object_operators<U>::operator[](T const& key)
inline object const_item_policies::get(object const& target, object const& key)
{
return python::getitem(target, key);
return getitem(target, key);
}
inline object const& item_policies::set(
@@ -70,33 +72,17 @@ inline object const& item_policies::set(
, object const& key
, object const& value)
{
python::setitem(target, key, value);
setitem(target, key, value);
return value;
}
} // namespace api
namespace converter
inline void item_policies::del(
object const& target
, object const& key)
{
// These specializations are a lie; the proxies do not directly
// manage an object. What actually happens is that the implicit
// conversion to object takes hold and its conversion to_python is
// used. That's OK in part because the object temporary *is*
// actually managing the object during the duration of the
// conversion.
template <>
struct is_object_manager<api::object_item>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <>
struct is_object_manager<api::const_object_item>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
delitem(target, key);
}
}} // namespace boost::python
}}} // namespace boost::python::api
#endif // OBJECT_ITEMS_DWA2002615_HPP

View File

@@ -11,7 +11,7 @@
# include <boost/python/object_protocol_core.hpp>
# include <boost/python/object_core.hpp>
namespace boost { namespace python {
namespace boost { namespace python { namespace api {
template <class Target, class Key>
object getattr(Target const& target, Key const& key)
@@ -26,6 +26,12 @@ void setattr(object const& target, Key const& key, Value const& value)
return setattr(target, object(key), object(value));
}
template <class Key>
void delattr(object const& target, Key const& key)
{
delattr(target, object(key));
}
template <class Target, class Key>
object getitem(Target const& target, Key const& key)
{
@@ -39,7 +45,30 @@ void setitem(object const& target, Key const& key, Value const& value)
return setitem(target, object(key), object(value));
}
template <class Key>
void delitem(object const& target, Key const& key)
{
delitem(target, object(key));
}
}} // namespace boost::python
template <class Target, class Begin, class End>
object getslice(Target const& target, Begin const& begin, End const& end)
{
return getslice(object(target), object(begin), object(end));
}
template <class Begin, class End, class Value>
void setslice(object const& target, Begin const& begin, End const& end, Value const& value)
{
return setslice(target, object(begin), object(end), object(value));
}
template <class Begin, class End>
void delslice(object const& target, Begin const& begin, End const& end)
{
delslice(target, object(begin), object(end));
}
}}} // namespace boost::python::api
#endif // OBJECT_PROTOCOL_DWA2002615_HPP

View File

@@ -6,6 +6,8 @@
#ifndef OBJECT_PROTOCOL_CORE_DWA2002615_HPP
# define OBJECT_PROTOCOL_CORE_DWA2002615_HPP
# include <boost/python/handle_fwd.hpp>
namespace boost { namespace python {
namespace api
@@ -14,14 +16,34 @@ namespace api
BOOST_PYTHON_DECL object getattr(object const& target, object const& key);
BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object const& value);
BOOST_PYTHON_DECL void delattr(object const& target, object const& key);
// These are defined for efficiency, since attributes are commonly
// accessed through literal strings.
BOOST_PYTHON_DECL object getattr(object const& target, char const* key);
BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value);
BOOST_PYTHON_DECL void delattr(object const& target, char const* key);
BOOST_PYTHON_DECL object getitem(object const& target, object const& key);
BOOST_PYTHON_DECL void setitem(object const& target, object const& key, object const& value);
BOOST_PYTHON_DECL void delitem(object const& target, object const& key);
BOOST_PYTHON_DECL object getslice(object const& target, handle<> const& begin, handle<> const& end);
BOOST_PYTHON_DECL void setslice(object const& target, handle<> const& begin, handle<> const& end, object const& value);
BOOST_PYTHON_DECL void delslice(object const& target, handle<> const& begin, handle<> const& end);
}
using api::getattr;
using api::setattr;
using api::delattr;
using api::getitem;
using api::setitem;
using api::delitem;
using api::getslice;
using api::setslice;
using api::delslice;
}} // namespace boost::python

View File

@@ -0,0 +1,124 @@
// Copyright David Abrahams 2002. 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 OBJECT_SLICES_DWA2002615_HPP
# define OBJECT_SLICES_DWA2002615_HPP
# include <boost/python/proxy.hpp>
# include <boost/python/object_core.hpp>
# include <boost/python/object_protocol.hpp>
# include <utility>
namespace boost { namespace python { namespace api {
struct const_slice_policies
{
typedef std::pair<handle<>, handle<> > key_type;
static object get(object const& target, key_type const& key);
};
struct slice_policies : const_slice_policies
{
static object const& set(object const& target, key_type const& key, object const& value);
static void del(object const& target, key_type const& key);
};
//
// implementation
//
template <class U>
object_slice
object_operators<U>::slice(self_cref start, self_cref finish)
{
object_cref x = *static_cast<U*>(this);
return object_slice(x, std::make_pair(start.ptr(), finish.ptr()));
}
template <class U>
const_object_slice
object_operators<U>::slice(self_cref start, self_cref finish) const
{
object_cref x = *static_cast<U const*>(this);
return const_object_slice(x, std::make_pair(start.ptr(), finish.ptr()));
}
template <class U>
object_slice
object_operators<U>::slice(slice_nil, self_cref finish)
{
object_cref x = *static_cast<U*>(this);
return object_slice(x, std::make_pair(handle<>(), finish.ptr()));
}
template <class U>
const_object_slice
object_operators<U>::slice(slice_nil, self_cref finish) const
{
object_cref x = *static_cast<U const*>(this);
return const_object_slice(x, std::make_pair(handle<>(), finish.ptr()));
}
template <class U>
object_slice
object_operators<U>::slice(self_cref start, slice_nil)
{
object_cref x = *static_cast<U*>(this);
return object_slice(x, std::make_pair(start.ptr(), handle<>()));
}
template <class U>
const_object_slice
object_operators<U>::slice(self_cref start, slice_nil) const
{
object_cref x = *static_cast<U const*>(this);
return const_object_slice(x, std::make_pair(start.ptr(), handle<>()));
}
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
template <class U>
template <class T, class V>
inline const_object_slice
object_operators<U>::slice(T const& start, V const& end) const
{
return this->slice(
typename slice_bound<T>::type(start)
, typename slice_bound<V>::type(end));
}
template <class U>
template <class T, class V>
inline object_slice
object_operators<U>::slice(T const& start, V const& end)
{
return this->slice(
typename slice_bound<T>::type(start)
, typename slice_bound<V>::type(end));
}
# endif
inline object const_slice_policies::get(object const& target, key_type const& key)
{
return getslice(target, key.first, key.second);
}
inline object const& slice_policies::set(
object const& target
, key_type const& key
, object const& value)
{
setslice(target, key.first, key.second, value);
return value;
}
inline void slice_policies::del(
object const& target
, key_type const& key)
{
delslice(target, key.first, key.second);
}
}}} // namespace boost::python::api
#endif // OBJECT_SLICES_DWA2002615_HPP

View File

@@ -13,13 +13,15 @@ namespace boost { namespace python { namespace api {
template <class Policies>
class proxy : public object_operators<proxy<Policies> >
{
typedef typename Policies::key_type key_type;
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1200
typedef proxy const& copy_ctor_self;
# else
typedef proxy copy_ctor_self;
# endif
public:
proxy(object const& target, object const& key);
proxy(object const& target, key_type const& key);
operator object() const;
// to support a[b] = c[d]
@@ -31,18 +33,28 @@ class proxy : public object_operators<proxy<Policies> >
Policies::set(m_target, m_key, object(rhs));
return *this;
}
public: // implementation detail
void del() const;
private:
object m_target;
object m_key;
key_type m_key;
};
template <class T>
inline void del(proxy<T> const& x)
{
x.del();
}
//
// implementation
//
template <class Policies>
inline proxy<Policies>::proxy(object const& target, object const& key)
inline proxy<Policies>::proxy(object const& target, key_type const& key)
: m_target(target), m_key(key)
{}
@@ -78,6 +90,12 @@ BOOST_PYTHON_PROXY_INPLACE(^=)
BOOST_PYTHON_PROXY_INPLACE(|=)
# undef BOOST_PYTHON_PROXY_INPLACE
template <class Policies>
inline void proxy<Policies>::del() const
{
Policies::del(m_target, m_key);
}
}}} // namespace boost::python::api
#endif // PROXY_DWA2002615_HPP

View File

@@ -0,0 +1,41 @@
// Copyright David Abrahams 2002. 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 SLICE_NIL_DWA2002620_HPP
# define SLICE_NIL_DWA2002620_HPP
namespace boost { namespace python { namespace api {
class object;
enum slice_nil
{
# ifndef _ // Watch out for GNU gettext users, who #define _(x)
_
# endif
};
template <class T>
struct slice_bound
{
typedef object type;
};
template <>
struct slice_bound<slice_nil>
{
typedef slice_nil type;
};
}
using api::slice_nil;
# ifndef _ // Watch out for GNU gettext users, who #define _(x)
using api::_;
# endif
}} // namespace boost::python
#endif // SLICE_NIL_DWA2002620_HPP

View File

@@ -21,6 +21,40 @@ BOOST_PYTHON_DECL void setattr(object const& target, object const& key, object c
throw_error_already_set();
}
BOOST_PYTHON_DECL void delattr(object const& target, object const& key)
{
if (PyObject_DelAttr(target.ptr().get(), key.ptr().get()) == -1)
throw_error_already_set();
}
BOOST_PYTHON_DECL object getattr(object const& target, char const* key)
{
return object(
(object::new_pyobject_reference*)
PyObject_GetAttrString(target.ptr().get(), const_cast<char*>(key))
);
}
BOOST_PYTHON_DECL void setattr(object const& target, char const* key, object const& value)
{
if (PyObject_SetAttrString(
target.ptr().get(), const_cast<char*>(key), value.ptr().get()) == -1
)
{
throw_error_already_set();
}
}
BOOST_PYTHON_DECL void delattr(object const& target, char const* key)
{
if (PyObject_DelAttrString(
target.ptr().get(), const_cast<char*>(key)) == -1
)
{
throw_error_already_set();
}
}
BOOST_PYTHON_DECL object getitem(object const& target, object const& key)
{
return object((object::new_pyobject_reference*)PyObject_GetItem(target.ptr().get(), key.ptr().get()));
@@ -31,5 +65,104 @@ BOOST_PYTHON_DECL void setitem(object const& target, object const& key, object c
if (PyObject_SetItem(target.ptr().get(), key.ptr().get(), value.ptr().get()) == -1)
throw_error_already_set();
}
BOOST_PYTHON_DECL void delitem(object const& target, object const& key)
{
if (PyObject_DelItem(target.ptr().get(), key.ptr().get()) == -1)
throw_error_already_set();
}
namespace // slicing code copied directly out of the Python implementation
{
#undef ISINT
#define ISINT(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x))
static PyObject *
apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */
{
PyTypeObject *tp = u->ob_type;
PySequenceMethods *sq = tp->tp_as_sequence;
if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) {
int ilow = 0, ihigh = INT_MAX;
if (!_PyEval_SliceIndex(v, &ilow))
return NULL;
if (!_PyEval_SliceIndex(w, &ihigh))
return NULL;
return PySequence_GetSlice(u, ilow, ihigh);
}
else {
PyObject *slice = PySlice_New(v, w, NULL);
if (slice != NULL) {
PyObject *res = PyObject_GetItem(u, slice);
Py_DECREF(slice);
return res;
}
else
return NULL;
}
}
static int
assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x)
/* u[v:w] = x */
{
PyTypeObject *tp = u->ob_type;
PySequenceMethods *sq = tp->tp_as_sequence;
if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) {
int ilow = 0, ihigh = INT_MAX;
if (!_PyEval_SliceIndex(v, &ilow))
return -1;
if (!_PyEval_SliceIndex(w, &ihigh))
return -1;
if (x == NULL)
return PySequence_DelSlice(u, ilow, ihigh);
else
return PySequence_SetSlice(u, ilow, ihigh, x);
}
else {
PyObject *slice = PySlice_New(v, w, NULL);
if (slice != NULL) {
int res;
if (x != NULL)
res = PyObject_SetItem(u, slice, x);
else
res = PyObject_DelItem(u, slice);
Py_DECREF(slice);
return res;
}
else
return -1;
}
}
}
BOOST_PYTHON_DECL object getslice(object const& target, handle<> const& begin, handle<> const& end)
{
return object(
(object::new_pyobject_reference*)
apply_slice(target.ptr().get(), begin.get(), end.get()));
}
BOOST_PYTHON_DECL void setslice(object const& target, handle<> const& begin, handle<> const& end, object const& value)
{
if (assign_slice(
target.ptr().get(), begin.get(), end.get(), value.ptr().get()) == -1
)
{
throw_error_already_set();
}
}
BOOST_PYTHON_DECL void delslice(object const& target, handle<> const& begin, handle<> const& end)
{
if (assign_slice(
target.ptr().get(), begin.get(), end.get(), 0) == -1
)
{
throw_error_already_set();
}
}
}}} // namespace boost::python::api

View File

@@ -113,6 +113,22 @@ bool test_not_item(object y, object key)
return !y[key];
}
bool check_string_slice()
{
object s("hello, world");
if (s.slice(_,-3) != "hello, wo")
return false;
if (s.slice(-3,_) != "rld")
return false;
if (", " != s.slice(5,7))
return false;
return s.slice(2,-1).slice(1,-1) == "lo, wor";
}
bool check_binary_operators()
{
int y;
@@ -295,6 +311,7 @@ BOOST_PYTHON_MODULE_INIT(object_ext)
.def("check_binary_operators", check_binary_operators)
.def("check_inplace", check_inplace)
.def("check_string_slice", check_string_slice)
;
}

View File

@@ -80,10 +80,15 @@
>>> test_not_item(d, 'foo')
1
Slices
>>> assert check_string_slice()
Operators
>>> assert check_binary_operators()
>>> class X: pass
...
>>> assert check_inplace(range(3), X())