Warning, file /include/boost/python/slice.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 #ifndef BOOST_PYTHON_SLICE_JDB20040105_HPP
0002 #define BOOST_PYTHON_SLICE_JDB20040105_HPP
0003
0004
0005
0006
0007
0008
0009 #include <boost/python/detail/prefix.hpp>
0010 #include <boost/config.hpp>
0011 #include <boost/python/object.hpp>
0012 #include <boost/python/extract.hpp>
0013 #include <boost/python/converter/pytype_object_mgr_traits.hpp>
0014
0015 #include <boost/iterator/iterator_traits.hpp>
0016
0017 #include <iterator>
0018 #include <algorithm>
0019
0020 namespace boost { namespace python {
0021
0022 namespace detail
0023 {
0024 class BOOST_PYTHON_DECL slice_base : public object
0025 {
0026 public:
0027
0028
0029
0030
0031
0032
0033
0034 object start() const;
0035 object stop() const;
0036 object step() const;
0037
0038 protected:
0039 explicit slice_base(PyObject*, PyObject*, PyObject*);
0040
0041 BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice_base, object)
0042 };
0043 }
0044
0045 class slice : public detail::slice_base
0046 {
0047 typedef detail::slice_base base;
0048 public:
0049
0050 slice() : base(0,0,0) {}
0051
0052
0053
0054 template<typename Integer1, typename Integer2>
0055 slice( Integer1 start, Integer2 stop)
0056 : base( object(start).ptr(), object(stop).ptr(), 0 )
0057 {}
0058
0059 template<typename Integer1, typename Integer2, typename Integer3>
0060 slice( Integer1 start, Integer2 stop, Integer3 stride)
0061 : base( object(start).ptr(), object(stop).ptr(), object(stride).ptr() )
0062 {}
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 template<typename RandomAccessIterator>
0104 struct range
0105 {
0106 RandomAccessIterator start;
0107 RandomAccessIterator stop;
0108 typename iterator_difference<RandomAccessIterator>::type step;
0109 };
0110
0111 template<typename RandomAccessIterator>
0112 slice::range<RandomAccessIterator>
0113 get_indices( const RandomAccessIterator& begin,
0114 const RandomAccessIterator& end) const
0115 {
0116
0117
0118
0119 slice::range<RandomAccessIterator> ret;
0120
0121 typedef typename iterator_difference<RandomAccessIterator>::type difference_type;
0122 difference_type max_dist = std::distance(begin, end);
0123
0124 object slice_start = this->start();
0125 object slice_stop = this->stop();
0126 object slice_step = this->step();
0127
0128
0129 if (slice_step == object()) {
0130 ret.step = 1;
0131 }
0132 else {
0133 ret.step = extract<long>( slice_step);
0134 if (ret.step == 0) {
0135 PyErr_SetString( PyExc_IndexError, "step size cannot be zero.");
0136 throw_error_already_set();
0137 }
0138 }
0139
0140
0141 if (slice_start == object()) {
0142 if (ret.step < 0) {
0143 ret.start = end;
0144 --ret.start;
0145 }
0146 else
0147 ret.start = begin;
0148 }
0149 else {
0150 difference_type i = extract<long>( slice_start);
0151 if (i >= max_dist && ret.step > 0)
0152 throw std::invalid_argument( "Zero-length slice");
0153 if (i >= 0) {
0154 ret.start = begin;
0155 BOOST_USING_STD_MIN();
0156 std::advance( ret.start, min BOOST_PREVENT_MACRO_SUBSTITUTION(i, max_dist-1));
0157 }
0158 else {
0159 if (i < -max_dist && ret.step < 0)
0160 throw std::invalid_argument( "Zero-length slice");
0161 ret.start = end;
0162
0163 std::advance( ret.start, (-i < max_dist) ? i : -max_dist );
0164 }
0165 }
0166
0167
0168
0169 if (slice_stop == object()) {
0170 if (ret.step < 0) {
0171 ret.stop = begin;
0172 }
0173 else {
0174 ret.stop = end;
0175 std::advance( ret.stop, -1);
0176 }
0177 }
0178 else {
0179 difference_type i = extract<long>(slice_stop);
0180
0181 if (ret.step < 0) {
0182 if (i+1 >= max_dist || i == -1)
0183 throw std::invalid_argument( "Zero-length slice");
0184
0185 if (i >= 0) {
0186 ret.stop = begin;
0187 std::advance( ret.stop, i+1);
0188 }
0189 else {
0190 ret.stop = end;
0191 std::advance( ret.stop, (-i < max_dist) ? i : -max_dist);
0192 }
0193 }
0194 else {
0195 if (i == 0 || -i >= max_dist)
0196 throw std::invalid_argument( "Zero-length slice");
0197
0198 if (i > 0) {
0199 ret.stop = begin;
0200 std::advance( ret.stop, (std::min)( i-1, max_dist-1));
0201 }
0202 else {
0203 ret.stop = end;
0204 std::advance( ret.stop, i-1);
0205 }
0206 }
0207 }
0208
0209
0210
0211
0212
0213
0214 typename iterator_difference<RandomAccessIterator>::type final_dist =
0215 std::distance( ret.start, ret.stop);
0216
0217
0218
0219 if (final_dist == 0)
0220 return ret;
0221
0222
0223
0224
0225 if ((final_dist > 0) != (ret.step > 0))
0226 throw std::invalid_argument( "Zero-length slice.");
0227
0228
0229
0230
0231
0232 if (final_dist < 0) {
0233 difference_type remainder = -final_dist % -ret.step;
0234 std::advance( ret.stop, remainder);
0235 }
0236 else {
0237 difference_type remainder = final_dist % ret.step;
0238 std::advance( ret.stop, -remainder);
0239 }
0240
0241 return ret;
0242 }
0243
0244
0245
0246 template<typename RandomAccessIterator>
0247 slice::range<RandomAccessIterator>
0248 get_indicies( const RandomAccessIterator& begin,
0249 const RandomAccessIterator& end) const
0250 {
0251 return get_indices(begin, end);
0252 }
0253
0254 public:
0255
0256
0257
0258
0259 BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice, detail::slice_base)
0260 };
0261
0262
0263 namespace converter {
0264
0265 template<>
0266 struct object_manager_traits<slice>
0267 : pytype_object_manager_traits<&PySlice_Type, slice>
0268 {
0269 };
0270
0271 }
0272
0273 } }
0274
0275
0276 #endif