2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-20 16:52:15 +00:00

Remove slice to separate file, out of line function bodies, working set_slice

[SVN r1528]
This commit is contained in:
Raoul Gough
2003-09-10 15:40:38 +00:00
parent a8eb3979ee
commit 2c8f4753e2

View File

@@ -26,81 +26,29 @@
#include <boost/python/object.hpp>
#include <boost/python/list.hpp>
#include <boost/python/converter/pytype_object_mgr_traits.hpp>
#include <boost/python/extract.hpp>
#include <boost/mpl/apply.hpp>
#include <algorithm>
// #include <boost/python/extract.hpp>
#include "slice.hpp"
#include "python_iterator.hpp"
namespace indexing
{
class slice : public boost::python::object
{
int mStart;
int mStep;
int mStop;
bool mLengthSet;
void validate () const {
if (!mLengthSet)
{
PyErr_SetString (PyExc_RuntimeError
, "slice access attempted before setLength called");
boost::python::throw_error_already_set();
}
}
public:
slice (boost::python::detail::borrowed_reference ref)
: boost::python::object (ref)
, mStart (0)
, mStep (0)
, mStop (0)
, mLengthSet (false)
{
if (!PySlice_Check (this->ptr()))
{
PyErr_SetString (PyExc_TypeError
, "slice constructor: passed a non-slice object");
boost::python::throw_error_already_set();
}
//
// *** WARNING ***
//
// The slice object is useless until setLength is called
//
}
void setLength (int sequenceLength)
{
PySlice_GetIndices ((PySliceObject *) this->ptr()
, sequenceLength
, &mStart
, &mStop
, &mStep);
mStart = std::max (0, std::min (sequenceLength, mStart));
mStop = std::max (0, std::min (sequenceLength, mStop));
mLengthSet = true;
}
int start() const { validate(); return mStart; }
int step() const { validate(); return mStep; }
int stop() const { validate(); return mStop; }
};
template<class Algorithms, class Policy>
struct slice_handler
{
static boost::python::object make_getitem (Policy const &);
static boost::python::object make_setitem (Policy const &);
private:
typedef typename Algorithms::container container;
typedef typename Algorithms::index_param index_param;
typedef typename Algorithms::value_type value_type;
typedef typename Algorithms::reference reference;
class postcall_override
static boost::python::list get_slice (container &, slice);
static void set_slice (container &, slice, boost::python::object);
struct postcall_override
{
// This class overrides our Policy's postcall function and
// result_conveter to handle the list returned from get_slice.
@@ -109,69 +57,240 @@ namespace indexing
// original postcall to each element of the Python list returned
// from get_slice.
Policy mBase;
public:
postcall_override (Policy const &p) : mBase (p) {
}
bool precall (PyObject *args) {
return mBase.precall (args);
}
PyObject* postcall (PyObject *args, PyObject *result) {
int size = PyList_Size (result);
for (int count = 0; count < size; ++count)
{
mBase.postcall (args, PyList_GetItem (result, count));
}
return result;
}
typedef boost::python::default_result_converter result_converter;
postcall_override (Policy const &p);
bool precall (PyObject *args);
PyObject* postcall (PyObject *args, PyObject *result);
private:
Policy mBase;
};
};
static boost::python::list get_slice (container &c, slice sl)
template<bool doit> struct maybe_insert {
template<class Algorithms>
static void apply (typename Algorithms::container &
, typename Algorithms::index_param
, typename Algorithms::value_param)
{
typedef typename Policy::result_converter converter_type;
typedef typename Algorithms::reference reference;
typename boost::mpl::apply1<converter_type, reference>::type converter;
PyErr_SetString (PyExc_TypeError
, "container does not support item insertion");
boost::python::list result;
sl.setLength (Algorithms::size(c));
int direction = (sl.step() > 0) ? 1 : ((sl.step() == 0) ? 0 : -1);
for (int index = sl.start()
; ((sl.stop() - index) * direction) > 0
; index += sl.step())
{
result.append
(boost::python::handle<>
(converter (Algorithms::get (c, index))));
}
return result;
boost::python::throw_error_already_set ();
}
};
static boost::python::object make_getitem (Policy const &policy)
template<> struct maybe_insert<true> {
template<class Algorithms>
static void apply (typename Algorithms::container &c
, typename Algorithms::index_param i
, typename Algorithms::value_param v)
{
return boost::python::make_function
(get_slice, postcall_override (policy));
Algorithms::insert (c, i, v);
}
};
template<bool doit> struct maybe_erase {
template<class Algorithms>
static void apply (typename Algorithms::container &
, typename Algorithms::index_param
, typename Algorithms::index_param)
{
PyErr_SetString (PyExc_TypeError
, "container does not support item deletion");
boost::python::throw_error_already_set ();
}
};
template<> struct maybe_erase<true> {
template<class Algorithms>
static void apply (typename Algorithms::container &c
, typename Algorithms::index_param from
, typename Algorithms::index_param to)
{
Algorithms::erase (c, from, to);
}
};
}
namespace boost { namespace python { namespace converter {
// Specialized converter to handle PySlice_Type objects
template<>
struct object_manager_traits<indexing::slice>
: pytype_object_manager_traits<&PySlice_Type, ::indexing::slice>
{
};
}}}
/////////////////////////////////////////////////////////////////////////////
// postcall_override constructor
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
indexing::slice_handler<Algorithms, Policy>
::postcall_override::postcall_override (Policy const &p)
: mBase (p)
{
}
/////////////////////////////////////////////////////////////////////////////
// precall forwarder
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
bool
indexing::slice_handler<Algorithms, Policy>
::postcall_override::precall (PyObject *args)
{
return mBase.precall (args);
}
/////////////////////////////////////////////////////////////////////////////
// Apply base postcall to each element of the list returend by get_slice
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
PyObject *
indexing::slice_handler<Algorithms, Policy>
::postcall_override::postcall (PyObject *args, PyObject *result)
{
int size = PyList_Size (result);
for (int count = 0; count < size; ++count)
{
mBase.postcall (args, PyList_GetItem (result, count));
}
return result;
}
/////////////////////////////////////////////////////////////////////////////
// Return a function object that implements the slice version of __getitem__
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
boost::python::object
indexing::slice_handler<Algorithms, Policy>
::make_getitem (Policy const &policy)
{
return boost::python::make_function (get_slice, postcall_override (policy));
}
/////////////////////////////////////////////////////////////////////////////
// Return a function object that implements the slice version of __setitem__
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
boost::python::object
indexing::slice_handler<Algorithms, Policy>
::make_setitem (Policy const &policy)
{
// should we try to get funky with policy::precall?
return boost::python::make_function (set_slice, policy);
}
/////////////////////////////////////////////////////////////////////////////
// Implementation for the slice version of __getitem__
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
boost::python::list
indexing::slice_handler<Algorithms, Policy>
::get_slice (container &c, slice sl)
{
typedef typename Policy::result_converter converter_type;
typedef typename Algorithms::reference reference;
typename boost::mpl::apply1<converter_type, reference>::type converter;
boost::python::list result;
sl.setLength (Algorithms::size(c));
for (int index = sl.start(); sl.inRange (index); index += sl.step())
{
// Apply the result converter (only) to each element before
// appending. postcall is done in postcall_override
result.append
(boost::python::handle<>
(converter (Algorithms::get (c, index))));
}
return result;
}
/////////////////////////////////////////////////////////////////////////////
// Implementation for the slice version of __setitem__
/////////////////////////////////////////////////////////////////////////////
template<class Algorithms, class Policy>
void
indexing::slice_handler<Algorithms, Policy>
::set_slice (container &c, slice sl, boost::python::object values)
{
std::auto_ptr<python_iterator> iterPtr (make_iterator (values));
if (!iterPtr.get())
{
PyErr_SetString (PyExc_TypeError
, "Type assigned to slice must be a sequence");
boost::python::throw_error_already_set();
}
typedef typename Algorithms::container_traits traits;
typedef boost::python::extract<typename Algorithms::value_param> extractor;
// Note: any error during this operation will probably leave the
// container partially updated. This can occur (for example) if the
// replacement sequence is of a different length to the original
// slice and the container does not support insertion/deletion.
// This could be prevented if the length of the replacement sequence
// is known in advance (via __len__, for example) but not otherwise.
sl.setLength (Algorithms::size (c)); // Current length of our container
int index = sl.start(); // Index in our container for update
// Overwrite and/or insert elements
while (iterPtr->next())
{
if (sl.inRange (index))
{
Algorithms::assign (c, index, extractor (iterPtr->current()));
}
else if (sl.step() != 1)
{
PyErr_SetString (PyExc_ValueError
, "attempt to insert via extended slice");
boost::python::throw_error_already_set ();
}
else
{
// Could optimize this in some cases (i.e. if the length of
// the replacement sequence is known)
maybe_insert<traits::has_insert>
::template apply<Algorithms> (c, index
, extractor (iterPtr->current()));
}
index += sl.step();
}
// Erase any remaining elements in the slice
if (sl.inRange(index))
{
if (sl.step() != 1)
{
PyErr_SetString (PyExc_ValueError
, "attempt to erase via extended slice");
boost::python::throw_error_already_set ();
}
else
{
maybe_erase<traits::has_erase>
::template apply<Algorithms> (c, index, sl.stop());
}
}
}
#endif // slice_handler_rmg_20030909_included