1 // This is mul/mbl/mbl_stl.h
2 #ifndef mbl_stl_h_
3 #define mbl_stl_h_
4 //:
5 // \file
6 // \brief Useful things missing from vcl_algorithm, etc.
7 // \author iscott
8 // \date  Dec 2001
9 // Actually, this is mostly an opportunity to mess around in STL to produce code
10 // which would be much simpler in ordinary C++. Stroustrup assures us that
11 // this approach is faster in general - which I don't really believe.
12 //
13 // \verbatim
14 //  Modifications
15 //   30 April 2004 - Martin Roberts -
16 //    Added quite a few little functors mainly to do with iterating through maps
17 //    for example a version of the non-standard select1st and select2nd
18 
19 #include <iostream>
20 #include <functional>
21 #include <vector>
22 #include <ostream>
23 #include <utility>
24 #ifdef _MSC_VER
25 #  include <vcl_msvc_warnings.h>
26 #endif
27 
28 //: Fill an output sequence with incrementing values.
29 // A bit like std::fill, but after each assignment, the value is incremented.
30 // \return the next value in the sequence.
31 template<class Out, class T>
mbl_stl_increments(Out first,Out last,T init)32 inline T mbl_stl_increments(Out first, Out last, T init)
33 {
34   for (; first != last; ++first, ++init) *first = init;
35   return init;
36 }
37 
38 //: Fill the first n values of an output sequence with incrementing values.
39 // A bit like std::fill_n, but after each assignment,
40 // the value is incremented.
41 // \return the next value in the sequence.
42 template<class Out, class Size, class T>
mbl_stl_increments_n(Out first,Size n,T init)43 inline T mbl_stl_increments_n(Out first, Size n, T init)
44 {
45   for (; 0 < n; ++first, --n, ++init) *first = init;
46   return init;
47 }
48 
49 //: Produces a first order sequence from the supplied unary function.
50 // The value produced at a given step is a function of the previous value.
51 // E.g. the following is equivalent to using mbl_stl_increments
52 // \code
53 // mbl_stl_sequence(A.begin(), A.end(), std::bind1st(std::plus<unsigned>(), 1u), 0u);
54 // \endcode
55 // \return the next value in the sequence.
56 template<class Out, class T, class UnOp>
mbl_stl_sequence(Out first,Out last,UnOp op,T init)57 inline T mbl_stl_sequence(Out first, Out last, UnOp op, T init)
58 {
59   for (;first != last; ++first, init = op(init)) *first = init;
60   return init;
61 }
62 
63 //: Produces a first order sequence of size n from the supplied function.
64 // The value produced at a given step is a function of the previous value.
65 // E.g. the following is equivalent to using mbl_stl_increments
66 // \return the next value in the sequence.
67 template<class Out, class Size, class T, class UnOp>
mbl_stl_sequence_n(Out first,Size n,UnOp op,T init)68 inline T mbl_stl_sequence_n(Out first, Size n, UnOp op, T init)
69 {
70   for (; 0 < n; ++first, --n, init = op(init)) *first = init;
71   return init;
72 }
73 
74 //: Clean out a range of pointers
75 // NB the dereferenced iterator must be a pointer
76 template<class iterType>
mbl_stl_clean(iterType first,iterType last)77 inline void mbl_stl_clean(iterType first, iterType last)
78 {
79   for (; first != last; ++first)
80   {
81     delete *first;
82     *first=nullptr;
83   }
84 }
85 
86 //: Copy elements in input range for which the supplied predicate is true
87 //Note bizarely although the STL provides remove_copy if etc etc
88 //the simple copy_if was dropped from the C++ standard
89 template<typename InputIterator,
90          typename OutputIterator,
91          typename Predicate>
mbl_stl_copy_if(InputIterator begin,InputIterator end,OutputIterator destBegin,Predicate pred)92     inline  OutputIterator mbl_stl_copy_if(InputIterator begin, InputIterator end,
93                                            OutputIterator destBegin,
94                                            Predicate pred)
95 {
96   while (begin != end)
97   {
98     if (pred(*begin))
99     {
100       *destBegin++ = *begin;
101     }
102     ++begin;
103   }
104   return destBegin;
105 }
106 
107 //----------------------------------------------------------------------------------------------
108 //Now some map related functors
109 //
110 //: select 1st element of a pair (e.g. for map iterators)
111 //NB something like this is in the SGI extension to the STL but is not included in the standard VCL
112 //However this is very useful with map iterators so include it here
113 template <class Pair>
114 struct mbl_stl_select1st
115 {
operatormbl_stl_select1st116   inline typename Pair::first_type const & operator()(Pair const & pair) const
117   {
118     return pair.first;
119   }
120 };
121 
122 //: select 2nd element of a pair (e.g. for map iterators)
123 //NB something like this is in the SGI extension to the STL but is not included in the standard VCL
124 //However this is very useful with map iterators so include it here
125 template <class Pair>
126 struct mbl_stl_select2nd
127 {
operatormbl_stl_select2nd128   inline typename Pair::second_type const & operator()(Pair const & pair) const
129   {
130     return pair.second;
131   }
132 };
133 
134 //Accumulate the second elements of a pair (e.g. for accumulating values through a map)
135 template <class Pair>
136 struct mbl_stl_add2nd
137 {
operatormbl_stl_add2nd138   inline typename Pair::second_type  operator()(typename Pair::second_type partSum, Pair const & x2 ) const
139   {
140     return partSum + x2.second;
141   }
142 };
143 
144 
145 // End of map/pair related functors
146 //------------------------------------------------------------------------------------
147 //: Given a vector of things, select an indexed element
148 //For use in eg STL transform algorithm to extract out required subset of (indexed) objects into a working vector
149 //e.g. given vector of indices and vector of values, copy out the required subset thus
150 // \code
151 // std::vector<T> subset
152 // subset.reserve(indices.size());
153 // std::transform(indices.begin(),indices.end(),
154 //               std::back_inserter(subset),
155 //               mbl_stl_index_functor(values));
156 // \endcode
157 template <class T>
158 class mbl_stl_index_functor
159 {
160   //This functor copies out  element vec[index]
161   //For use in eg STL transform algorithm to extract out required subset of (indexed) points into a working vector
162   //No bounds checking is done
163  private:
164   //:const reference to vector used to store the objects indexed
165   const std::vector<T >& vec_;
166 
167  public:
mbl_stl_index_functor(const std::vector<T> & vec)168   mbl_stl_index_functor(const std::vector<T >& vec): vec_(vec) {}
operator()169   inline const T& operator()(unsigned index) const { return vec_[index]; }
170 };
171 
172 
173 //------------------------------------------------------------------------------------
174 //: implementation class for use with mbl_stl_output
175 template <class Cont>
176 class mbl_stl_output_t1
177 {
178  public:
179   const Cont &c;
180   const char *sep;
mbl_stl_output_t1(const Cont & c,const char * sep)181   mbl_stl_output_t1(const Cont& c, const char * sep): c(c), sep(sep) {}
182 };
183 
184 //: implementation function for use with mbl_stl_output
185 template <class Cont> inline
186 std::ostream& operator<<(std::ostream& s, const mbl_stl_output_t1<Cont>& t)
187 {
188   if (t.c.empty()) return s;
189   typename Cont::const_iterator it=t.c.begin(), end=t.c.end();
190   s << *it;
191   ++it;
192   for (; it!=end; ++it)
193     s << t.sep << *it;
194   return s;
195 }
196 
197 //: Allow easy stream output of STL container contents.
198 // \verbatim
199 // std::vector<int> c;
200 // ...
201 // std::cout << "The contents of c using normal << notation" <<
202 //   mbl_stl_output(c) << std::endl;
203 // \endverbatim
204 template <class Cont> inline
205 mbl_stl_output_t1<Cont> mbl_stl_output(const Cont &c, const char * sep=" ")
206 {
207   return mbl_stl_output_t1<Cont>(c, sep);
208 }
209 
210 
211 //: Find first instance of common value in two sorted sequences.
212 // \return pair. Either *pair.first == *pair.second, or pair.first == finish1 && pair.second == finish2 if
213 // no matches are found.
214 template <class IT1, class IT2>
215 inline std::pair<IT1, IT2>
mbl_stl_find_common_value(IT1 start1,IT1 finish1,IT2 start2,IT2 finish2)216   mbl_stl_find_common_value(IT1 start1, IT1 finish1, IT2 start2, IT2 finish2)
217 {
218   std::pair<IT1, IT2> its(start1, start2);
219   while (true)
220   {
221     if (its.first == finish1 || its.second == finish2) return make_pair(finish1, finish2);
222 
223     else if (*its.first < *its.second)
224       ++its.first;
225     else if (*its.second < *its.first)
226       ++its.second;
227     else return its;
228   }
229 }
230 
231 
232 //: Find first instance of common value in two sequences sorted by specified comparator.
233 // \return pair. Either *pair.first == *pair.second, or pair.first == finish1 && pair.second == finish2 if
234 // no matches are found.
235 template <class IT1, class IT2, class CMP>
236 inline std::pair<IT1, IT2>
237   mbl_stl_find_common_value(IT1 start1, IT1 finish1, IT2 start2, IT2 finish2, CMP comp = CMP())
238 {
239   std::pair<IT1, IT2> its(start1, start2);
240   while (true)
241   {
242     if (its.first == finish1 || its.second == finish2) return make_pair(finish1, finish2);
243 
244     else if (comp(*its.first, *its.second))
245       ++its.first;
246     else if (comp(*its.second, *its.first))
247       ++its.second;
248     else return its;
249   }
250 }
251 
252 #endif // mbl_stl_h_
253