1 // Copyright (c) Microsoft. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 #pragma once
5 
6 #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
7 
8 namespace bond
9 {
10 namespace python
11 {
12 
13 // Indexing suite equivalent to boost::python::vector_indexing_suite but for
14 // containers that don't support random access iterator.
15 
16 template <typename T, bool NoProxy, typename DerivedPolicies>
17 class list_indexing_suite;
18 
19 namespace detail
20 {
21     template <typename T, bool NoProxy>
22     class final_list_derived_policies
23         : public bond::python::list_indexing_suite<
24             T,
25             NoProxy,
26             final_list_derived_policies<T, NoProxy> >
27     {};
28 }
29 
30 template <
31     typename T,
32     bool NoProxy = false,
33     typename DerivedPolicies = detail::final_list_derived_policies<T, NoProxy>
34 >
35 class list_indexing_suite
36     : public boost::python::vector_indexing_suite<T, NoProxy, DerivedPolicies>
37 {
38     typedef boost::python::vector_indexing_suite<T, NoProxy, DerivedPolicies> base;
39 public:
40     typedef typename base::data_type data_type;
41     typedef typename base::index_type index_type;
42     typedef typename base::key_type key_type;
43 
44     static
45     typename std::conditional<
46         std::is_class<data_type>::value,
47         data_type&,
48         data_type
49     >::type
get_item(T & list,index_type i)50     get_item(T& list, index_type i)
51     {
52         return *advance(list.begin(), i);
53     }
54 
55     static void
set_item(T & list,index_type i,data_type const & v)56     set_item(T& list, index_type i, data_type const& v)
57     {
58         *advance(list.begin(), i) = v;
59     }
60 
61     static void
delete_item(T & list,index_type i)62     delete_item(T& list, index_type i)
63     {
64         list.erase(advance(list.begin(), i));
65     }
66 
67     static boost::python::object
get_slice(T & list,index_type from,index_type to)68     get_slice(T& list, index_type from, index_type to)
69     {
70         if (from > to)
71             return boost::python::object(T());
72 
73         auto s = slice(list, from, to);
74         return boost::python::object(T(s.first, s.second));
75     }
76 
77     static void
set_slice(T & list,index_type from,index_type to,data_type const & v)78     set_slice(T& list, index_type from, index_type to, data_type const& v)
79     {
80         if (to >= from)
81         {
82             auto s = slice(list, from, to);
83             list.erase(s.first, s.second);
84             list.insert(advance(list.begin(), from), v);
85         }
86     }
87 
88     template <typename Iter>
89     static void
set_slice(T & list,index_type from,index_type to,Iter first,Iter last)90     set_slice(T& list, index_type from,
91         index_type to, Iter first, Iter last)
92     {
93         if (to >= from)
94         {
95             auto s = slice(list, from, to);
96             list.erase(s.first, s.second);
97             list.insert(advance(list.begin(), from), first, last);
98         }
99     }
100 
101     static void
delete_slice(T & list,index_type from,index_type to)102     delete_slice(T& list, index_type from, index_type to)
103     {
104         if (to >= from)
105         {
106             auto s = slice(list, from, to);
107             list.erase(s.first, s.second);
108         }
109     }
110 
111 private:
112     static
113     typename T::iterator
advance(typename T::iterator it,typename T::difference_type i)114     advance(typename T::iterator it, typename T::difference_type i)
115     {
116         return std::advance(it, i), it;
117     }
118 
119     static
120     std::pair<typename T::iterator, typename T::iterator>
slice(T & list,index_type from,index_type to)121     slice(T& list, index_type from, index_type to)
122     {
123         BOOST_ASSERT(to >= from);
124 
125         std::pair<typename T::iterator, typename T::iterator> s;
126 
127         s.first = list.begin();
128         std::advance(s.first, from);
129 
130         s.second = s.first;
131         std::advance(s.second, to - from);
132 
133         return s;
134     }
135 };
136 
137 } // namespace python
138 
139 } // namespace bond
140