indexing_suite_detail.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. // (C) Copyright Joel de Guzman 2003.
  2. // Distributed under the Boost Software License, Version 1.0. (See
  3. // accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef INDEXING_SUITE_DETAIL_JDG20036_HPP
  6. # define INDEXING_SUITE_DETAIL_JDG20036_HPP
  7. # include <boost/python/extract.hpp>
  8. # include <boost/scoped_ptr.hpp>
  9. # include <boost/get_pointer.hpp>
  10. # include <boost/detail/binary_search.hpp>
  11. # include <boost/numeric/conversion/cast.hpp>
  12. # include <boost/python/detail/type_traits.hpp>
  13. # include <vector>
  14. # include <map>
  15. #include <iostream>
  16. namespace boost { namespace python { namespace detail {
  17. #if defined(NDEBUG)
  18. #define BOOST_PYTHON_INDEXING_CHECK_INVARIANT
  19. #else
  20. #define BOOST_PYTHON_INDEXING_CHECK_INVARIANT check_invariant()
  21. #endif
  22. template <class Proxy>
  23. struct compare_proxy_index
  24. {
  25. // This functor compares a proxy and an index.
  26. // This is used by proxy_group::first_proxy to
  27. // get first proxy with index i.
  28. template <class Index>
  29. bool operator()(PyObject* prox, Index i) const
  30. {
  31. typedef typename Proxy::policies_type policies_type;
  32. Proxy& proxy = extract<Proxy&>(prox)();
  33. return policies_type::
  34. compare_index(proxy.get_container(), proxy.get_index(), i);
  35. }
  36. };
  37. // The proxy_group class holds a vector of container element
  38. // proxies. First, what is a container element proxy? A container
  39. // element proxy acts like a smart pointer holding a reference to
  40. // a container and an index (see container_element, for details).
  41. //
  42. // The proxies are held in a vector always sorted by its index.
  43. // Various functions manage the addition, removal and searching
  44. // of proxies from the vector.
  45. //
  46. template <class Proxy>
  47. class proxy_group
  48. {
  49. public:
  50. typedef typename std::vector<PyObject*>::const_iterator const_iterator;
  51. typedef typename std::vector<PyObject*>::iterator iterator;
  52. typedef typename Proxy::index_type index_type;
  53. typedef typename Proxy::policies_type policies_type;
  54. iterator
  55. first_proxy(index_type i)
  56. {
  57. // Return the first proxy with index <= i
  58. return boost::detail::lower_bound(
  59. proxies.begin(), proxies.end(),
  60. i, compare_proxy_index<Proxy>());
  61. }
  62. void
  63. remove(Proxy& proxy)
  64. {
  65. // Remove a proxy
  66. for (iterator iter = first_proxy(proxy.get_index());
  67. iter != proxies.end(); ++iter)
  68. {
  69. if (&extract<Proxy&>(*iter)() == &proxy)
  70. {
  71. proxies.erase(iter);
  72. break;
  73. }
  74. }
  75. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  76. }
  77. void
  78. add(PyObject* prox)
  79. {
  80. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  81. // Add a proxy
  82. proxies.insert(
  83. first_proxy(extract<Proxy&>(prox)().get_index()), prox);
  84. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  85. }
  86. void
  87. erase(index_type i, mpl::false_)
  88. {
  89. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  90. // Erase the proxy with index i
  91. replace(i, i+1, 0);
  92. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  93. }
  94. void
  95. erase(index_type i, mpl::true_)
  96. {
  97. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  98. // Erase the proxy with index i
  99. iterator iter = first_proxy(i);
  100. extract<Proxy&> p(*iter);
  101. if (iter != proxies.end() && p().get_index() == i)
  102. {
  103. extract<Proxy&> p(*iter);
  104. p().detach();
  105. proxies.erase(iter);
  106. }
  107. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  108. }
  109. void
  110. erase(index_type from, index_type to)
  111. {
  112. // note: this cannot be called when container is not sliceable
  113. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  114. // Erase all proxies with indexes from..to
  115. replace(from, to, 0);
  116. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  117. }
  118. void
  119. replace(
  120. index_type from,
  121. index_type to,
  122. typename std::vector<PyObject*>::size_type len)
  123. {
  124. // note: this cannot be called when container is not sliceable
  125. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  126. // Erase all proxies with indexes from..to.
  127. // Adjust the displaced indexes such that the
  128. // final effect is that we have inserted *len*
  129. // number of proxies in the vacated region. This
  130. // procedure involves adjusting the indexes of
  131. // the proxies.
  132. iterator left = first_proxy(from);
  133. iterator right = proxies.end(); // we'll adjust this later
  134. for (iterator iter = left; iter != right; ++iter)
  135. {
  136. if (extract<Proxy&>(*iter)().get_index() > to)
  137. {
  138. right = iter; // adjust right
  139. break;
  140. }
  141. extract<Proxy&> p(*iter);
  142. p().detach();
  143. }
  144. typename std::vector<PyObject*>::size_type
  145. offset = left-proxies.begin();
  146. proxies.erase(left, right);
  147. right = proxies.begin()+offset;
  148. while (right != proxies.end())
  149. {
  150. typedef typename Proxy::container_type::difference_type difference_type;
  151. extract<Proxy&> p(*right);
  152. p().set_index(
  153. extract<Proxy&>(*right)().get_index()
  154. - (difference_type(to) - from - len)
  155. );
  156. ++right;
  157. }
  158. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  159. }
  160. PyObject*
  161. find(index_type i)
  162. {
  163. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  164. // Find the proxy with *exact* index i.
  165. // Return 0 (null) if no proxy with the
  166. // given index is found.
  167. iterator iter = first_proxy(i);
  168. if (iter != proxies.end()
  169. && extract<Proxy&>(*iter)().get_index() == i)
  170. {
  171. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  172. return *iter;
  173. }
  174. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  175. return 0;
  176. }
  177. typename std::vector<PyObject*>::size_type
  178. size() const
  179. {
  180. BOOST_PYTHON_INDEXING_CHECK_INVARIANT;
  181. // How many proxies are there so far?
  182. return proxies.size();
  183. }
  184. private:
  185. #if !defined(NDEBUG)
  186. void
  187. check_invariant() const
  188. {
  189. for (const_iterator i = proxies.begin(); i != proxies.end(); ++i)
  190. {
  191. if ((*i)->ob_refcnt <= 0)
  192. {
  193. PyErr_SetString(PyExc_RuntimeError,
  194. "Invariant: Proxy vector in an inconsistent state");
  195. throw_error_already_set();
  196. }
  197. if (i+1 != proxies.end())
  198. {
  199. if (extract<Proxy&>(*(i+1))().get_index() ==
  200. extract<Proxy&>(*(i))().get_index())
  201. {
  202. PyErr_SetString(PyExc_RuntimeError,
  203. "Invariant: Proxy vector in an inconsistent state (duplicate proxy)");
  204. throw_error_already_set();
  205. }
  206. }
  207. }
  208. }
  209. #endif
  210. std::vector<PyObject*> proxies;
  211. };
  212. // proxy_links holds a map of Container pointers (keys)
  213. // with proxy_group(s) (data). Various functions manage
  214. // the addition, removal and searching of proxies from
  215. // the map.
  216. //
  217. template <class Proxy, class Container>
  218. class proxy_links
  219. {
  220. public:
  221. typedef std::map<Container*, proxy_group<Proxy> > links_t;
  222. typedef typename Proxy::index_type index_type;
  223. void
  224. remove(Proxy& proxy)
  225. {
  226. // Remove a proxy.
  227. typename links_t::iterator r = links.find(&proxy.get_container());
  228. if (r != links.end())
  229. {
  230. r->second.remove(proxy);
  231. if (r->second.size() == 0)
  232. links.erase(r);
  233. }
  234. }
  235. void
  236. add(PyObject* prox, Container& container)
  237. {
  238. // Add a proxy
  239. links[&container].add(prox);
  240. }
  241. template <class NoSlice>
  242. void erase(Container& container, index_type i, NoSlice no_slice)
  243. {
  244. // Erase the proxy with index i
  245. typename links_t::iterator r = links.find(&container);
  246. if (r != links.end())
  247. {
  248. r->second.erase(i, no_slice);
  249. if (r->second.size() == 0)
  250. links.erase(r);
  251. }
  252. }
  253. void
  254. erase(Container& container, index_type from, index_type to)
  255. {
  256. // Erase all proxies with indexes from..to
  257. typename links_t::iterator r = links.find(&container);
  258. if (r != links.end())
  259. {
  260. r->second.erase(from, to);
  261. if (r->second.size() == 0)
  262. links.erase(r);
  263. }
  264. }
  265. void
  266. replace(
  267. Container& container,
  268. index_type from, index_type to, index_type len)
  269. {
  270. // Erase all proxies with indexes from..to.
  271. // Adjust the displaced indexes such that the
  272. // final effect is that we have inserted *len*
  273. // number of proxies in the vacated region. This
  274. // procedure involves adjusting the indexes of
  275. // the proxies.
  276. typename links_t::iterator r = links.find(&container);
  277. if (r != links.end())
  278. {
  279. r->second.replace(from, to, len);
  280. if (r->second.size() == 0)
  281. links.erase(r);
  282. }
  283. }
  284. PyObject*
  285. find(Container& container, index_type i)
  286. {
  287. // Find the proxy with *exact* index i.
  288. // Return 0 (null) if no proxy with the given
  289. // index is found.
  290. typename links_t::iterator r = links.find(&container);
  291. if (r != links.end())
  292. return r->second.find(i);
  293. return 0;
  294. }
  295. private:
  296. links_t links;
  297. };
  298. // container_element is our container proxy class.
  299. // This class acts like a smart pointer to a container
  300. // element. The class holds an index and a reference to
  301. // a container. Dereferencing the smart pointer will
  302. // retrieve the nth (index) element from the container.
  303. //
  304. // A container_element can also be detached from the
  305. // container. In such a detached state, the container_element
  306. // holds a copy of the nth (index) element, which it
  307. // returns when dereferenced.
  308. //
  309. template <class Container, class Index, class Policies>
  310. class container_element
  311. {
  312. public:
  313. typedef Index index_type;
  314. typedef Container container_type;
  315. typedef typename Policies::data_type element_type;
  316. typedef Policies policies_type;
  317. typedef container_element<Container, Index, Policies> self_t;
  318. typedef proxy_group<self_t> links_type;
  319. container_element(object container, Index index)
  320. : ptr()
  321. , container(container)
  322. , index(index)
  323. {
  324. }
  325. container_element(container_element const& ce)
  326. : ptr(ce.ptr.get() == 0 ? 0 : new element_type(*ce.ptr.get()))
  327. , container(ce.container)
  328. , index(ce.index)
  329. {
  330. }
  331. ~container_element()
  332. {
  333. if (!is_detached())
  334. get_links().remove(*this);
  335. }
  336. element_type& operator*() const
  337. {
  338. if (is_detached())
  339. return *get_pointer(ptr);
  340. return Policies::get_item(get_container(), index);
  341. }
  342. element_type* get() const
  343. {
  344. if (is_detached())
  345. return get_pointer(ptr);
  346. return &Policies::get_item(get_container(), index);
  347. }
  348. void
  349. detach()
  350. {
  351. if (!is_detached())
  352. {
  353. ptr.reset(
  354. new element_type(
  355. Policies::get_item(get_container(), index)));
  356. container = object(); // free container. reset it to None
  357. }
  358. }
  359. bool
  360. is_detached() const
  361. {
  362. return get_pointer(ptr) != 0;
  363. }
  364. Container&
  365. get_container() const
  366. {
  367. return extract<Container&>(container)();
  368. }
  369. Index
  370. get_index() const
  371. {
  372. return index;
  373. }
  374. void
  375. set_index(Index i)
  376. {
  377. index = i;
  378. }
  379. static proxy_links<self_t, Container>&
  380. get_links()
  381. {
  382. // All container_element(s) maintain links to
  383. // its container in a global map (see proxy_links).
  384. // This global "links" map is a singleton.
  385. static proxy_links<self_t, Container> links;
  386. return links; // singleton
  387. }
  388. private:
  389. container_element& operator=(container_element const& ce);
  390. scoped_ptr<element_type> ptr;
  391. object container;
  392. Index index;
  393. };
  394. template <
  395. class Container
  396. , class DerivedPolicies
  397. , class ContainerElement
  398. , class Index
  399. >
  400. struct no_proxy_helper
  401. {
  402. static void
  403. register_container_element()
  404. {
  405. }
  406. template <class DataType>
  407. static object
  408. base_get_item_helper(DataType const& p, detail::true_)
  409. {
  410. return object(ptr(p));
  411. }
  412. template <class DataType>
  413. static object
  414. base_get_item_helper(DataType const& x, detail::false_)
  415. {
  416. return object(x);
  417. }
  418. static object
  419. base_get_item_(back_reference<Container&> const& container, PyObject* i)
  420. {
  421. return base_get_item_helper(
  422. DerivedPolicies::get_item(
  423. container.get(), DerivedPolicies::
  424. convert_index(container.get(), i))
  425. , is_pointer<BOOST_DEDUCED_TYPENAME Container::value_type>()
  426. );
  427. }
  428. static void
  429. base_replace_indexes(
  430. Container& /*container*/, Index /*from*/,
  431. Index /*to*/, Index /*n*/)
  432. {
  433. }
  434. template <class NoSlice>
  435. static void
  436. base_erase_index(
  437. Container& /*container*/, Index /*i*/, NoSlice /*no_slice*/)
  438. {
  439. }
  440. static void
  441. base_erase_indexes(Container& /*container*/, Index /*from*/, Index /*to*/)
  442. {
  443. }
  444. };
  445. template <
  446. class Container
  447. , class DerivedPolicies
  448. , class ContainerElement
  449. , class Index
  450. >
  451. struct proxy_helper
  452. {
  453. static void
  454. register_container_element()
  455. {
  456. register_ptr_to_python<ContainerElement>();
  457. }
  458. static object
  459. base_get_item_(back_reference<Container&> const& container, PyObject* i)
  460. {
  461. // Proxy
  462. Index idx = DerivedPolicies::convert_index(container.get(), i);
  463. if (PyObject* shared =
  464. ContainerElement::get_links().find(container.get(), idx))
  465. {
  466. handle<> h(python::borrowed(shared));
  467. return object(h);
  468. }
  469. else
  470. {
  471. object prox(ContainerElement(container.source(), idx));
  472. ContainerElement::
  473. get_links().add(prox.ptr(), container.get());
  474. return prox;
  475. }
  476. }
  477. static void
  478. base_replace_indexes(
  479. Container& container, Index from,
  480. Index to, Index n)
  481. {
  482. ContainerElement::get_links().replace(container, from, to, n);
  483. }
  484. template <class NoSlice>
  485. static void
  486. base_erase_index(
  487. Container& container, Index i, NoSlice no_slice)
  488. {
  489. ContainerElement::get_links().erase(container, i, no_slice);
  490. }
  491. static void
  492. base_erase_indexes(
  493. Container& container, Index from, Index to)
  494. {
  495. ContainerElement::get_links().erase(container, from, to);
  496. }
  497. };
  498. template <
  499. class Container
  500. , class DerivedPolicies
  501. , class ProxyHandler
  502. , class Data
  503. , class Index
  504. >
  505. struct slice_helper
  506. {
  507. static object
  508. base_get_slice(Container& container, PySliceObject* slice)
  509. {
  510. Index from, to;
  511. base_get_slice_data(container, slice, from, to);
  512. return DerivedPolicies::get_slice(container, from, to);
  513. }
  514. static void
  515. base_get_slice_data(
  516. Container& container, PySliceObject* slice, Index& from_, Index& to_)
  517. {
  518. if (Py_None != slice->step) {
  519. PyErr_SetString( PyExc_IndexError, "slice step size not supported.");
  520. throw_error_already_set();
  521. }
  522. Index min_index = DerivedPolicies::get_min_index(container);
  523. Index max_index = DerivedPolicies::get_max_index(container);
  524. if (Py_None == slice->start) {
  525. from_ = min_index;
  526. }
  527. else {
  528. long from = extract<long>( slice->start);
  529. if (from < 0) // Negative slice index
  530. from += max_index;
  531. if (from < 0) // Clip lower bounds to zero
  532. from = 0;
  533. from_ = boost::numeric_cast<Index>(from);
  534. if (from_ > max_index) // Clip upper bounds to max_index.
  535. from_ = max_index;
  536. }
  537. if (Py_None == slice->stop) {
  538. to_ = max_index;
  539. }
  540. else {
  541. long to = extract<long>( slice->stop);
  542. if (to < 0)
  543. to += max_index;
  544. if (to < 0)
  545. to = 0;
  546. to_ = boost::numeric_cast<Index>(to);
  547. if (to_ > max_index)
  548. to_ = max_index;
  549. }
  550. }
  551. static void
  552. base_set_slice(Container& container, PySliceObject* slice, PyObject* v)
  553. {
  554. Index from, to;
  555. base_get_slice_data(container, slice, from, to);
  556. extract<Data&> elem(v);
  557. // try if elem is an exact Data
  558. if (elem.check())
  559. {
  560. ProxyHandler::base_replace_indexes(container, from, to, 1);
  561. DerivedPolicies::set_slice(container, from, to, elem());
  562. }
  563. else
  564. {
  565. // try to convert elem to Data
  566. extract<Data> elem(v);
  567. if (elem.check())
  568. {
  569. ProxyHandler::base_replace_indexes(container, from, to, 1);
  570. DerivedPolicies::set_slice(container, from, to, elem());
  571. }
  572. else
  573. {
  574. // Otherwise, it must be a list or some container
  575. handle<> l_(python::borrowed(v));
  576. object l(l_);
  577. std::vector<Data> temp;
  578. for (int i = 0; i < l.attr("__len__")(); i++)
  579. {
  580. object elem(l[i]);
  581. extract<Data const&> x(elem);
  582. // try if elem is an exact Data type
  583. if (x.check())
  584. {
  585. temp.push_back(x());
  586. }
  587. else
  588. {
  589. // try to convert elem to Data type
  590. extract<Data> x(elem);
  591. if (x.check())
  592. {
  593. temp.push_back(x());
  594. }
  595. else
  596. {
  597. PyErr_SetString(PyExc_TypeError,
  598. "Invalid sequence element");
  599. throw_error_already_set();
  600. }
  601. }
  602. }
  603. ProxyHandler::base_replace_indexes(container, from, to,
  604. temp.end()-temp.begin());
  605. DerivedPolicies::set_slice(container, from, to,
  606. temp.begin(), temp.end());
  607. }
  608. }
  609. }
  610. static void
  611. base_delete_slice(Container& container, PySliceObject* slice)
  612. {
  613. Index from, to;
  614. base_get_slice_data(container, slice, from, to);
  615. ProxyHandler::base_erase_indexes(container, from, to);
  616. DerivedPolicies::delete_slice(container, from, to);
  617. }
  618. };
  619. template <
  620. class Container
  621. , class DerivedPolicies
  622. , class ProxyHandler
  623. , class Data
  624. , class Index
  625. >
  626. struct no_slice_helper
  627. {
  628. static void
  629. slicing_not_suported()
  630. {
  631. PyErr_SetString(PyExc_RuntimeError, "Slicing not supported");
  632. throw_error_already_set();
  633. }
  634. static object
  635. base_get_slice(Container& /*container*/, PySliceObject* /*slice*/)
  636. {
  637. slicing_not_suported();
  638. return object();
  639. }
  640. static void
  641. base_set_slice(Container& /*container*/, PySliceObject* /*slice*/, PyObject* /*v*/)
  642. {
  643. slicing_not_suported();
  644. }
  645. static void
  646. base_delete_slice(Container& /*container*/, PySliceObject* /*slice*/)
  647. {
  648. slicing_not_suported();
  649. }
  650. };
  651. #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
  652. }} // namespace python::detail
  653. #endif
  654. template <class Container, class Index, class Policies>
  655. inline typename Policies::data_type*
  656. get_pointer(
  657. python::detail::container_element<Container, Index, Policies> const& p)
  658. {
  659. // Get the pointer of a container_element smart pointer
  660. return p.get();
  661. }
  662. #ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
  663. // Don't hide these other get_pointer overloads
  664. using boost::python::get_pointer;
  665. using boost::get_pointer;
  666. }} // namespace python::detail
  667. #endif
  668. } // namespace boost
  669. #endif // INDEXING_SUITE_DETAIL_JDG20036_HPP