Chris@101
|
1 /* Copyright 2003-2015 Joaquin M Lopez Munoz.
|
Chris@16
|
2 * Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
3 * (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
4 * http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5 *
|
Chris@16
|
6 * See http://www.boost.org/libs/multi_index for library home page.
|
Chris@16
|
7 */
|
Chris@16
|
8
|
Chris@16
|
9 #ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_OPS_HPP
|
Chris@16
|
10 #define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_OPS_HPP
|
Chris@16
|
11
|
Chris@101
|
12 #if defined(_MSC_VER)
|
Chris@16
|
13 #pragma once
|
Chris@16
|
14 #endif
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
Chris@16
|
17 #include <algorithm>
|
Chris@16
|
18 #include <boost/multi_index/detail/rnd_index_ptr_array.hpp>
|
Chris@16
|
19 #include <functional>
|
Chris@16
|
20
|
Chris@16
|
21 namespace boost{
|
Chris@16
|
22
|
Chris@16
|
23 namespace multi_index{
|
Chris@16
|
24
|
Chris@16
|
25 namespace detail{
|
Chris@16
|
26
|
Chris@16
|
27 /* Common code for random_access_index memfuns having templatized and
|
Chris@16
|
28 * non-templatized versions.
|
Chris@16
|
29 */
|
Chris@16
|
30
|
Chris@16
|
31 template<typename Node,typename Allocator,typename Predicate>
|
Chris@16
|
32 Node* random_access_index_remove(
|
Chris@101
|
33 random_access_index_ptr_array<Allocator>& ptrs,Predicate pred)
|
Chris@16
|
34 {
|
Chris@16
|
35 typedef typename Node::value_type value_type;
|
Chris@16
|
36 typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
|
Chris@16
|
37
|
Chris@16
|
38 impl_ptr_pointer first=ptrs.begin(),
|
Chris@16
|
39 res=first,
|
Chris@16
|
40 last=ptrs.end();
|
Chris@16
|
41 for(;first!=last;++first){
|
Chris@16
|
42 if(!pred(
|
Chris@16
|
43 const_cast<const value_type&>(Node::from_impl(*first)->value()))){
|
Chris@16
|
44 if(first!=res){
|
Chris@16
|
45 std::swap(*first,*res);
|
Chris@16
|
46 (*first)->up()=first;
|
Chris@16
|
47 (*res)->up()=res;
|
Chris@16
|
48 }
|
Chris@16
|
49 ++res;
|
Chris@16
|
50 }
|
Chris@16
|
51 }
|
Chris@16
|
52 return Node::from_impl(*res);
|
Chris@16
|
53 }
|
Chris@16
|
54
|
Chris@16
|
55 template<typename Node,typename Allocator,class BinaryPredicate>
|
Chris@16
|
56 Node* random_access_index_unique(
|
Chris@101
|
57 random_access_index_ptr_array<Allocator>& ptrs,BinaryPredicate binary_pred)
|
Chris@16
|
58 {
|
Chris@16
|
59 typedef typename Node::value_type value_type;
|
Chris@16
|
60 typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
|
Chris@16
|
61
|
Chris@16
|
62 impl_ptr_pointer first=ptrs.begin(),
|
Chris@16
|
63 res=first,
|
Chris@16
|
64 last=ptrs.end();
|
Chris@16
|
65 if(first!=last){
|
Chris@16
|
66 for(;++first!=last;){
|
Chris@16
|
67 if(!binary_pred(
|
Chris@16
|
68 const_cast<const value_type&>(Node::from_impl(*res)->value()),
|
Chris@16
|
69 const_cast<const value_type&>(Node::from_impl(*first)->value()))){
|
Chris@16
|
70 ++res;
|
Chris@16
|
71 if(first!=res){
|
Chris@16
|
72 std::swap(*first,*res);
|
Chris@16
|
73 (*first)->up()=first;
|
Chris@16
|
74 (*res)->up()=res;
|
Chris@16
|
75 }
|
Chris@16
|
76 }
|
Chris@16
|
77 }
|
Chris@16
|
78 ++res;
|
Chris@16
|
79 }
|
Chris@16
|
80 return Node::from_impl(*res);
|
Chris@16
|
81 }
|
Chris@16
|
82
|
Chris@16
|
83 template<typename Node,typename Allocator,typename Compare>
|
Chris@16
|
84 void random_access_index_inplace_merge(
|
Chris@16
|
85 const Allocator& al,
|
Chris@16
|
86 random_access_index_ptr_array<Allocator>& ptrs,
|
Chris@101
|
87 BOOST_DEDUCED_TYPENAME Node::impl_ptr_pointer first1,Compare comp)
|
Chris@16
|
88 {
|
Chris@16
|
89 typedef typename Node::value_type value_type;
|
Chris@16
|
90 typedef typename Node::impl_pointer impl_pointer;
|
Chris@16
|
91 typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
|
Chris@16
|
92
|
Chris@16
|
93 auto_space<impl_pointer,Allocator> spc(al,ptrs.size());
|
Chris@16
|
94
|
Chris@16
|
95 impl_ptr_pointer first0=ptrs.begin(),
|
Chris@16
|
96 last0=first1,
|
Chris@16
|
97 last1=ptrs.end(),
|
Chris@16
|
98 out=spc.data();
|
Chris@16
|
99 while(first0!=last0&&first1!=last1){
|
Chris@16
|
100 if(comp(
|
Chris@16
|
101 const_cast<const value_type&>(Node::from_impl(*first1)->value()),
|
Chris@16
|
102 const_cast<const value_type&>(Node::from_impl(*first0)->value()))){
|
Chris@16
|
103 *out++=*first1++;
|
Chris@16
|
104 }
|
Chris@16
|
105 else{
|
Chris@16
|
106 *out++=*first0++;
|
Chris@16
|
107 }
|
Chris@16
|
108 }
|
Chris@16
|
109 std::copy(&*first0,&*last0,&*out);
|
Chris@16
|
110 std::copy(&*first1,&*last1,&*out);
|
Chris@16
|
111
|
Chris@16
|
112 first1=ptrs.begin();
|
Chris@16
|
113 out=spc.data();
|
Chris@16
|
114 while(first1!=last1){
|
Chris@16
|
115 *first1=*out++;
|
Chris@16
|
116 (*first1)->up()=first1;
|
Chris@16
|
117 ++first1;
|
Chris@16
|
118 }
|
Chris@16
|
119 }
|
Chris@16
|
120
|
Chris@16
|
121 /* sorting */
|
Chris@16
|
122
|
Chris@16
|
123 /* auxiliary stuff */
|
Chris@16
|
124
|
Chris@16
|
125 template<typename Node,typename Compare>
|
Chris@16
|
126 struct random_access_index_sort_compare:
|
Chris@16
|
127 std::binary_function<
|
Chris@16
|
128 typename Node::impl_pointer,
|
Chris@16
|
129 typename Node::impl_pointer,bool>
|
Chris@16
|
130 {
|
Chris@16
|
131 random_access_index_sort_compare(Compare comp_=Compare()):comp(comp_){}
|
Chris@16
|
132
|
Chris@16
|
133 bool operator()(
|
Chris@16
|
134 typename Node::impl_pointer x,typename Node::impl_pointer y)const
|
Chris@16
|
135 {
|
Chris@16
|
136 typedef typename Node::value_type value_type;
|
Chris@16
|
137
|
Chris@16
|
138 return comp(
|
Chris@16
|
139 const_cast<const value_type&>(Node::from_impl(x)->value()),
|
Chris@16
|
140 const_cast<const value_type&>(Node::from_impl(y)->value()));
|
Chris@16
|
141 }
|
Chris@16
|
142
|
Chris@16
|
143 private:
|
Chris@16
|
144 Compare comp;
|
Chris@16
|
145 };
|
Chris@16
|
146
|
Chris@16
|
147 template<typename Node,typename Allocator,class Compare>
|
Chris@16
|
148 void random_access_index_sort(
|
Chris@16
|
149 const Allocator& al,
|
Chris@16
|
150 random_access_index_ptr_array<Allocator>& ptrs,
|
Chris@101
|
151 Compare comp)
|
Chris@16
|
152 {
|
Chris@16
|
153 /* The implementation is extremely simple: an auxiliary
|
Chris@16
|
154 * array of pointers is sorted using stdlib facilities and
|
Chris@16
|
155 * then used to rearrange the index. This is suboptimal
|
Chris@16
|
156 * in space and time, but has some advantages over other
|
Chris@16
|
157 * possible approaches:
|
Chris@16
|
158 * - Use std::stable_sort() directly on ptrs using some
|
Chris@16
|
159 * special iterator in charge of maintaining pointers
|
Chris@16
|
160 * and up() pointers in sync: we cannot guarantee
|
Chris@16
|
161 * preservation of the container invariants in the face of
|
Chris@16
|
162 * exceptions, if, for instance, std::stable_sort throws
|
Chris@16
|
163 * when ptrs transitorily contains duplicate elements.
|
Chris@16
|
164 * - Rewrite the internal algorithms of std::stable_sort
|
Chris@16
|
165 * adapted for this case: besides being a fair amount of
|
Chris@16
|
166 * work, making a stable sort compatible with Boost.MultiIndex
|
Chris@16
|
167 * invariants (basically, no duplicates or missing elements
|
Chris@16
|
168 * even if an exception is thrown) is complicated, error-prone
|
Chris@16
|
169 * and possibly won't perform much better than the
|
Chris@16
|
170 * solution adopted.
|
Chris@16
|
171 */
|
Chris@16
|
172
|
Chris@16
|
173 if(ptrs.size()<=1)return;
|
Chris@16
|
174
|
Chris@16
|
175 typedef typename Node::impl_pointer impl_pointer;
|
Chris@16
|
176 typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
|
Chris@16
|
177 typedef random_access_index_sort_compare<
|
Chris@16
|
178 Node,Compare> ptr_compare;
|
Chris@16
|
179
|
Chris@16
|
180 impl_ptr_pointer first=ptrs.begin();
|
Chris@16
|
181 impl_ptr_pointer last=ptrs.end();
|
Chris@16
|
182 auto_space<
|
Chris@16
|
183 impl_pointer,
|
Chris@16
|
184 Allocator> spc(al,ptrs.size());
|
Chris@16
|
185 impl_ptr_pointer buf=spc.data();
|
Chris@16
|
186
|
Chris@16
|
187 std::copy(&*first,&*last,&*buf);
|
Chris@16
|
188 std::stable_sort(&*buf,&*buf+ptrs.size(),ptr_compare(comp));
|
Chris@16
|
189
|
Chris@16
|
190 while(first!=last){
|
Chris@16
|
191 *first=*buf++;
|
Chris@16
|
192 (*first)->up()=first;
|
Chris@16
|
193 ++first;
|
Chris@16
|
194 }
|
Chris@16
|
195 }
|
Chris@16
|
196
|
Chris@16
|
197 } /* namespace multi_index::detail */
|
Chris@16
|
198
|
Chris@16
|
199 } /* namespace multi_index */
|
Chris@16
|
200
|
Chris@16
|
201 } /* namespace boost */
|
Chris@16
|
202
|
Chris@16
|
203 #endif
|