File indexing completed on 2025-02-22 10:26:16
0001
0002
0003
0004
0005
0006 #ifndef INDEXING_SUITE_DETAIL_JDG20036_HPP
0007 # define INDEXING_SUITE_DETAIL_JDG20036_HPP
0008
0009 # include <boost/python/extract.hpp>
0010 # include <boost/scoped_ptr.hpp>
0011 # include <boost/get_pointer.hpp>
0012 # include <boost/detail/binary_search.hpp>
0013 # include <boost/numeric/conversion/cast.hpp>
0014 # include <boost/python/detail/type_traits.hpp>
0015 # include <vector>
0016 # include <map>
0017 #include <iostream>
0018
0019 namespace boost { namespace python { namespace detail {
0020
0021 #if defined(NDEBUG)
0022 #define BOOST_PYTHON_INDEXING_CHECK_INVARIANT
0023 #else
0024 #define BOOST_PYTHON_INDEXING_CHECK_INVARIANT check_invariant()
0025 #endif
0026
0027 template <class Proxy>
0028 struct compare_proxy_index
0029 {
0030
0031
0032
0033
0034 template <class Index>
0035 bool operator()(PyObject* prox, Index i) const
0036 {
0037 typedef typename Proxy::policies_type policies_type;
0038 Proxy& proxy = extract<Proxy&>(prox)();
0039 return policies_type::
0040 compare_index(proxy.get_container(), proxy.get_index(), i);
0041 }
0042 };
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 template <class Proxy>
0054 class proxy_group
0055 {
0056 public:
0057
0058 typedef typename std::vector<PyObject*>::const_iterator const_iterator;
0059 typedef typename std::vector<PyObject*>::iterator iterator;
0060 typedef typename Proxy::index_type index_type;
0061 typedef typename Proxy::policies_type policies_type;
0062
0063 iterator
0064 first_proxy(index_type i)
0065 {
0066
0067 return boost::detail::lower_bound(
0068 proxies.begin(), proxies.end(),
0069 i, compare_proxy_index<Proxy>());
0070 }
0071
0072 void
0073 remove(Proxy& proxy)
0074 {
0075
0076 for (iterator iter = first_proxy(proxy.get_index());
0077 iter != proxies.end(); ++iter)
0078 {
0079 if (&extract<Proxy&>(*iter)() == &proxy)
0080 {
0081 proxies.erase(iter);
0082 break;
0083 }
0084 }
0085 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0086 }
0087
0088 void
0089 add(PyObject* prox)
0090 {
0091 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0092
0093 proxies.insert(
0094 first_proxy(extract<Proxy&>(prox)().get_index()), prox);
0095 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0096 }
0097
0098 void
0099 erase(index_type i, mpl::false_)
0100 {
0101 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0102
0103 replace(i, i+1, 0);
0104 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0105 }
0106
0107 void
0108 erase(index_type i, mpl::true_)
0109 {
0110 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0111
0112
0113 iterator iter = first_proxy(i);
0114 extract<Proxy&> p(*iter);
0115
0116 if (iter != proxies.end() && p().get_index() == i)
0117 {
0118 extract<Proxy&> p(*iter);
0119 p().detach();
0120 proxies.erase(iter);
0121 }
0122 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0123 }
0124
0125 void
0126 erase(index_type from, index_type to)
0127 {
0128
0129
0130 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0131
0132 replace(from, to, 0);
0133 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0134 }
0135
0136 void
0137 replace(
0138 index_type from,
0139 index_type to,
0140 typename std::vector<PyObject*>::size_type len)
0141 {
0142
0143
0144 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0145
0146
0147
0148
0149
0150
0151
0152 iterator left = first_proxy(from);
0153 iterator right = proxies.end();
0154
0155 for (iterator iter = left; iter != right; ++iter)
0156 {
0157 if (extract<Proxy&>(*iter)().get_index() > to)
0158 {
0159 right = iter;
0160 break;
0161 }
0162 extract<Proxy&> p(*iter);
0163 p().detach();
0164 }
0165
0166 typename std::vector<PyObject*>::size_type
0167 offset = left-proxies.begin();
0168 proxies.erase(left, right);
0169 right = proxies.begin()+offset;
0170
0171 while (right != proxies.end())
0172 {
0173 typedef typename Proxy::container_type::difference_type difference_type;
0174 extract<Proxy&> p(*right);
0175 p().set_index(
0176 extract<Proxy&>(*right)().get_index()
0177 - (difference_type(to) - from - len)
0178 );
0179
0180 ++right;
0181 }
0182 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0183 }
0184
0185 PyObject*
0186 find(index_type i)
0187 {
0188 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0189
0190
0191
0192 iterator iter = first_proxy(i);
0193 if (iter != proxies.end()
0194 && extract<Proxy&>(*iter)().get_index() == i)
0195 {
0196 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0197 return *iter;
0198 }
0199 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0200 return 0;
0201 }
0202
0203 typename std::vector<PyObject*>::size_type
0204 size() const
0205 {
0206 BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
0207
0208 return proxies.size();
0209 }
0210
0211 private:
0212
0213 #if !defined(NDEBUG)
0214 void
0215 check_invariant() const
0216 {
0217 for (const_iterator i = proxies.begin(); i != proxies.end(); ++i)
0218 {
0219 if ((*i)->ob_refcnt <= 0)
0220 {
0221 PyErr_SetString(PyExc_RuntimeError,
0222 "Invariant: Proxy vector in an inconsistent state");
0223 throw_error_already_set();
0224 }
0225
0226 if (i+1 != proxies.end())
0227 {
0228 if (extract<Proxy&>(*(i+1))().get_index() ==
0229 extract<Proxy&>(*(i))().get_index())
0230 {
0231 PyErr_SetString(PyExc_RuntimeError,
0232 "Invariant: Proxy vector in an inconsistent state (duplicate proxy)");
0233 throw_error_already_set();
0234 }
0235 }
0236 }
0237 }
0238 #endif
0239
0240 std::vector<PyObject*> proxies;
0241 };
0242
0243
0244
0245
0246
0247
0248 template <class Proxy, class Container>
0249 class proxy_links
0250 {
0251 public:
0252
0253 typedef std::map<Container*, proxy_group<Proxy> > links_t;
0254 typedef typename Proxy::index_type index_type;
0255
0256 void
0257 remove(Proxy& proxy)
0258 {
0259
0260 typename links_t::iterator r = links.find(&proxy.get_container());
0261 if (r != links.end())
0262 {
0263 r->second.remove(proxy);
0264 if (r->second.size() == 0)
0265 links.erase(r);
0266 }
0267 }
0268
0269 void
0270 add(PyObject* prox, Container& container)
0271 {
0272
0273 links[&container].add(prox);
0274 }
0275
0276 template <class NoSlice>
0277 void erase(Container& container, index_type i, NoSlice no_slice)
0278 {
0279
0280 typename links_t::iterator r = links.find(&container);
0281 if (r != links.end())
0282 {
0283 r->second.erase(i, no_slice);
0284 if (r->second.size() == 0)
0285 links.erase(r);
0286 }
0287 }
0288
0289 void
0290 erase(Container& container, index_type from, index_type to)
0291 {
0292
0293 typename links_t::iterator r = links.find(&container);
0294 if (r != links.end())
0295 {
0296 r->second.erase(from, to);
0297 if (r->second.size() == 0)
0298 links.erase(r);
0299 }
0300 }
0301
0302 void
0303 replace(
0304 Container& container,
0305 index_type from, index_type to, index_type len)
0306 {
0307
0308
0309
0310
0311
0312
0313
0314 typename links_t::iterator r = links.find(&container);
0315 if (r != links.end())
0316 {
0317 r->second.replace(from, to, len);
0318 if (r->second.size() == 0)
0319 links.erase(r);
0320 }
0321 }
0322
0323 PyObject*
0324 find(Container& container, index_type i)
0325 {
0326
0327
0328
0329 typename links_t::iterator r = links.find(&container);
0330 if (r != links.end())
0331 return r->second.find(i);
0332 return 0;
0333 }
0334
0335 private:
0336
0337 links_t links;
0338 };
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351 template <class Container, class Index, class Policies>
0352 class container_element
0353 {
0354 public:
0355
0356 typedef Index index_type;
0357 typedef Container container_type;
0358 typedef typename Policies::data_type element_type;
0359 typedef Policies policies_type;
0360 typedef container_element<Container, Index, Policies> self_t;
0361 typedef proxy_group<self_t> links_type;
0362
0363 container_element(object container, Index index)
0364 : ptr()
0365 , container(container)
0366 , index(index)
0367 {
0368 }
0369
0370 container_element(container_element const& ce)
0371 : ptr(ce.ptr.get() == 0 ? 0 : new element_type(*ce.ptr.get()))
0372 , container(ce.container)
0373 , index(ce.index)
0374 {
0375 }
0376
0377 ~container_element()
0378 {
0379 if (!is_detached())
0380 get_links().remove(*this);
0381 }
0382
0383 element_type& operator*() const
0384 {
0385 if (is_detached())
0386 return *get_pointer(ptr);
0387 return Policies::get_item(get_container(), index);
0388 }
0389
0390 element_type* get() const
0391 {
0392 if (is_detached())
0393 return get_pointer(ptr);
0394 return &Policies::get_item(get_container(), index);
0395 }
0396
0397 void
0398 detach()
0399 {
0400 if (!is_detached())
0401 {
0402 ptr.reset(
0403 new element_type(
0404 Policies::get_item(get_container(), index)));
0405 container = object();
0406 }
0407 }
0408
0409 bool
0410 is_detached() const
0411 {
0412 return get_pointer(ptr) != 0;
0413 }
0414
0415 Container&
0416 get_container() const
0417 {
0418 return extract<Container&>(container)();
0419 }
0420
0421 Index
0422 get_index() const
0423 {
0424 return index;
0425 }
0426
0427 void
0428 set_index(Index i)
0429 {
0430 index = i;
0431 }
0432
0433 static proxy_links<self_t, Container>&
0434 get_links()
0435 {
0436
0437
0438
0439
0440 static proxy_links<self_t, Container> links;
0441 return links;
0442 }
0443
0444 private:
0445
0446 container_element& operator=(container_element const& ce);
0447
0448 scoped_ptr<element_type> ptr;
0449 object container;
0450 Index index;
0451 };
0452
0453 template <
0454 class Container
0455 , class DerivedPolicies
0456 , class ContainerElement
0457 , class Index
0458 >
0459 struct no_proxy_helper
0460 {
0461 static void
0462 register_container_element()
0463 {
0464 }
0465
0466 template <class DataType>
0467 static object
0468 base_get_item_helper(DataType const& p, detail::true_)
0469 {
0470 return object(ptr(p));
0471 }
0472
0473 template <class DataType>
0474 static object
0475 base_get_item_helper(DataType const& x, detail::false_)
0476 {
0477 return object(x);
0478 }
0479
0480 static object
0481 base_get_item_(back_reference<Container&> const& container, PyObject* i)
0482 {
0483 return base_get_item_helper(
0484 DerivedPolicies::get_item(
0485 container.get(), DerivedPolicies::
0486 convert_index(container.get(), i))
0487 , is_pointer<BOOST_DEDUCED_TYPENAME Container::value_type>()
0488 );
0489 }
0490
0491 static void
0492 base_replace_indexes(
0493 Container& , Index ,
0494 Index , Index )
0495 {
0496 }
0497
0498 template <class NoSlice>
0499 static void
0500 base_erase_index(
0501 Container& , Index , NoSlice )
0502 {
0503 }
0504
0505 static void
0506 base_erase_indexes(Container& , Index , Index )
0507 {
0508 }
0509 };
0510
0511 template <
0512 class Container
0513 , class DerivedPolicies
0514 , class ContainerElement
0515 , class Index
0516 >
0517 struct proxy_helper
0518 {
0519 static void
0520 register_container_element()
0521 {
0522 register_ptr_to_python<ContainerElement>();
0523 }
0524
0525 static object
0526 base_get_item_(back_reference<Container&> const& container, PyObject* i)
0527 {
0528
0529 Index idx = DerivedPolicies::convert_index(container.get(), i);
0530
0531 if (PyObject* shared =
0532 ContainerElement::get_links().find(container.get(), idx))
0533 {
0534 handle<> h(python::borrowed(shared));
0535 return object(h);
0536 }
0537 else
0538 {
0539 object prox(ContainerElement(container.source(), idx));
0540 ContainerElement::
0541 get_links().add(prox.ptr(), container.get());
0542 return prox;
0543 }
0544 }
0545
0546 static void
0547 base_replace_indexes(
0548 Container& container, Index from,
0549 Index to, Index n)
0550 {
0551 ContainerElement::get_links().replace(container, from, to, n);
0552 }
0553
0554 template <class NoSlice>
0555 static void
0556 base_erase_index(
0557 Container& container, Index i, NoSlice no_slice)
0558 {
0559 ContainerElement::get_links().erase(container, i, no_slice);
0560 }
0561
0562 static void
0563 base_erase_indexes(
0564 Container& container, Index from, Index to)
0565 {
0566 ContainerElement::get_links().erase(container, from, to);
0567 }
0568 };
0569
0570 template <
0571 class Container
0572 , class DerivedPolicies
0573 , class ProxyHandler
0574 , class Data
0575 , class Index
0576 >
0577 struct slice_helper
0578 {
0579 static object
0580 base_get_slice(Container& container, PySliceObject* slice)
0581 {
0582 Index from, to;
0583 base_get_slice_data(container, slice, from, to);
0584 return DerivedPolicies::get_slice(container, from, to);
0585 }
0586
0587 static void
0588 base_get_slice_data(
0589 Container& container, PySliceObject* slice, Index& from_, Index& to_)
0590 {
0591 if (Py_None != slice->step) {
0592 PyErr_SetString( PyExc_IndexError, "slice step size not supported.");
0593 throw_error_already_set();
0594 }
0595
0596 Index min_index = DerivedPolicies::get_min_index(container);
0597 Index max_index = DerivedPolicies::get_max_index(container);
0598
0599 if (Py_None == slice->start) {
0600 from_ = min_index;
0601 }
0602 else {
0603 long from = extract<long>( slice->start);
0604 if (from < 0)
0605 from += max_index;
0606 if (from < 0)
0607 from = 0;
0608 from_ = boost::numeric_cast<Index>(from);
0609 if (from_ > max_index)
0610 from_ = max_index;
0611 }
0612
0613 if (Py_None == slice->stop) {
0614 to_ = max_index;
0615 }
0616 else {
0617 long to = extract<long>( slice->stop);
0618 if (to < 0)
0619 to += max_index;
0620 if (to < 0)
0621 to = 0;
0622 to_ = boost::numeric_cast<Index>(to);
0623 if (to_ > max_index)
0624 to_ = max_index;
0625 }
0626 }
0627
0628 static void
0629 base_set_slice(Container& container, PySliceObject* slice, PyObject* v)
0630 {
0631 Index from, to;
0632 base_get_slice_data(container, slice, from, to);
0633
0634 extract<Data&> elem(v);
0635
0636 if (elem.check())
0637 {
0638 ProxyHandler::base_replace_indexes(container, from, to, 1);
0639 DerivedPolicies::set_slice(container, from, to, elem());
0640 }
0641 else
0642 {
0643
0644 extract<Data> elem(v);
0645 if (elem.check())
0646 {
0647 ProxyHandler::base_replace_indexes(container, from, to, 1);
0648 DerivedPolicies::set_slice(container, from, to, elem());
0649 }
0650 else
0651 {
0652
0653 handle<> l_(python::borrowed(v));
0654 object l(l_);
0655
0656 std::vector<Data> temp;
0657 for (int i = 0; i < l.attr("__len__")(); i++)
0658 {
0659 object elem(l[i]);
0660 extract<Data const&> x(elem);
0661
0662 if (x.check())
0663 {
0664 temp.push_back(x());
0665 }
0666 else
0667 {
0668
0669 extract<Data> x(elem);
0670 if (x.check())
0671 {
0672 temp.push_back(x());
0673 }
0674 else
0675 {
0676 PyErr_SetString(PyExc_TypeError,
0677 "Invalid sequence element");
0678 throw_error_already_set();
0679 }
0680 }
0681 }
0682
0683 ProxyHandler::base_replace_indexes(container, from, to,
0684 temp.end()-temp.begin());
0685 DerivedPolicies::set_slice(container, from, to,
0686 temp.begin(), temp.end());
0687 }
0688 }
0689 }
0690
0691 static void
0692 base_delete_slice(Container& container, PySliceObject* slice)
0693 {
0694 Index from, to;
0695 base_get_slice_data(container, slice, from, to);
0696 ProxyHandler::base_erase_indexes(container, from, to);
0697 DerivedPolicies::delete_slice(container, from, to);
0698 }
0699 };
0700
0701 template <
0702 class Container
0703 , class DerivedPolicies
0704 , class ProxyHandler
0705 , class Data
0706 , class Index
0707 >
0708 struct no_slice_helper
0709 {
0710 static void
0711 slicing_not_suported()
0712 {
0713 PyErr_SetString(PyExc_RuntimeError, "Slicing not supported");
0714 throw_error_already_set();
0715 }
0716
0717 static object
0718 base_get_slice(Container& , PySliceObject* )
0719 {
0720 slicing_not_suported();
0721 return object();
0722 }
0723
0724 static void
0725 base_set_slice(Container& , PySliceObject* , PyObject* )
0726 {
0727 slicing_not_suported();
0728 }
0729
0730 static void
0731 base_delete_slice(Container& , PySliceObject* )
0732 {
0733 slicing_not_suported();
0734 }
0735 };
0736
0737 #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
0738 }}
0739 #endif
0740
0741 template <class Container, class Index, class Policies>
0742 inline typename Policies::data_type*
0743 get_pointer(
0744 python::detail::container_element<Container, Index, Policies> const& p)
0745 {
0746
0747 return p.get();
0748 }
0749
0750 #ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
0751
0752 using boost::python::get_pointer;
0753 using boost::get_pointer;
0754 }}
0755 #endif
0756
0757 }
0758
0759 #endif