1 //
2 //  Copyright (c) 2000-2002
3 //  Joerg Walter, Mathias Koch
4 //
5 //  Distributed under the Boost Software License, Version 1.0. (See
6 //  accompanying file LICENSE_1_0.txt or copy at
7 //  http://www.boost.org/LICENSE_1_0.txt)
8 //
9 //  The authors gratefully acknowledge the support of
10 //  GeNeSys mbH & Co. KG in producing this work.
11 //
12 
13 #ifndef _BOOST_UBLAS_VECTOR_ASSIGN_
14 #define _BOOST_UBLAS_VECTOR_ASSIGN_
15 
16 #include <boost/numeric/ublas/functional.hpp> // scalar_assign
17 // Required for make_conformant storage
18 #include <vector>
19 
20 // Iterators based on ideas of Jeremy Siek
21 
22 namespace boost { namespace numeric { namespace ublas {
23 namespace detail {
24 
25     // Weak equality check - useful to compare equality two arbitary vector expression results.
26     // Since the actual expressions are unknown, we check for and arbitary error bound
27     // on the relative error.
28     // For a linear expression the infinity norm makes sense as we do not know how the elements will be
29     // combined in the expression. False positive results are inevitable for arbirary expressions!
30     template<class E1, class E2, class S>
31     BOOST_UBLAS_INLINE
equals(const vector_expression<E1> & e1,const vector_expression<E2> & e2,S epsilon,S min_norm)32     bool equals (const vector_expression<E1> &e1, const vector_expression<E2> &e2, S epsilon, S min_norm) {
33         return norm_inf (e1 - e2) <= epsilon *
34                std::max<S> (std::max<S> (norm_inf (e1), norm_inf (e2)), min_norm);
35     }
36 
37     template<class E1, class E2>
38     BOOST_UBLAS_INLINE
expression_type_check(const vector_expression<E1> & e1,const vector_expression<E2> & e2)39     bool expression_type_check (const vector_expression<E1> &e1, const vector_expression<E2> &e2) {
40         typedef typename type_traits<typename promote_traits<typename E1::value_type,
41                                      typename E2::value_type>::promote_type>::real_type real_type;
42         return equals (e1, e2, BOOST_UBLAS_TYPE_CHECK_EPSILON, BOOST_UBLAS_TYPE_CHECK_MIN);
43     }
44 
45 
46     // Make sparse proxies conformant
47     template<class V, class E>
48     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
make_conformant(V & v,const vector_expression<E> & e)49     void make_conformant (V &v, const vector_expression<E> &e) {
50         BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
51         typedef typename V::size_type size_type;
52         typedef typename V::difference_type difference_type;
53         typedef typename V::value_type value_type;
54         // FIXME unbounded_array with push_back maybe better
55         std::vector<size_type> index;
56         typename V::iterator it (v.begin ());
57         typename V::iterator it_end (v.end ());
58         typename E::const_iterator ite (e ().begin ());
59         typename E::const_iterator ite_end (e ().end ());
60         if (it != it_end && ite != ite_end) {
61             size_type it_index = it.index (), ite_index = ite.index ();
62             for (;;) {
63                 difference_type compare = it_index - ite_index;
64                 if (compare == 0) {
65                     ++ it, ++ ite;
66                     if (it != it_end && ite != ite_end) {
67                         it_index = it.index ();
68                         ite_index = ite.index ();
69                     } else
70                         break;
71                 } else if (compare < 0) {
72                     increment (it, it_end, - compare);
73                     if (it != it_end)
74                         it_index = it.index ();
75                     else
76                         break;
77                 } else if (compare > 0) {
78                     if (*ite != value_type/*zero*/())
79                         index.push_back (ite.index ());
80                     ++ ite;
81                     if (ite != ite_end)
82                         ite_index = ite.index ();
83                     else
84                         break;
85                 }
86             }
87         }
88 
89         while (ite != ite_end) {
90             if (*ite != value_type/*zero*/())
91                 index.push_back (ite.index ());
92             ++ ite;
93         }
94         for (size_type k = 0; k < index.size (); ++ k)
95             v (index [k]) = value_type/*zero*/();
96     }
97 
98 }//namespace detail
99 
100 
101     // Explicitly iterating
102     template<template <class T1, class T2> class F, class V, class T>
103     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
iterating_vector_assign_scalar(V & v,const T & t)104     void iterating_vector_assign_scalar (V &v, const T &t) {
105         typedef F<typename V::iterator::reference, T> functor_type;
106         typedef typename V::difference_type difference_type;
107         difference_type size (v.size ());
108         typename V::iterator it (v.begin ());
109         BOOST_UBLAS_CHECK (v.end () - it == size, bad_size ());
110 #ifndef BOOST_UBLAS_USE_DUFF_DEVICE
111         while (-- size >= 0)
112             functor_type::apply (*it, t), ++ it;
113 #else
114         DD (size, 4, r, (functor_type::apply (*it, t), ++ it));
115 #endif
116     }
117     // Explicitly case
118     template<template <class T1, class T2> class F, class V, class T>
119     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
indexing_vector_assign_scalar(V & v,const T & t)120     void indexing_vector_assign_scalar (V &v, const T &t) {
121         typedef F<typename V::reference, T> functor_type;
122         typedef typename V::size_type size_type;
123         size_type size (v.size ());
124 #ifndef BOOST_UBLAS_USE_DUFF_DEVICE
125         for (size_type i = 0; i < size; ++ i)
126             functor_type::apply (v (i), t);
127 #else
128         size_type i (0);
129         DD (size, 4, r, (functor_type::apply (v (i), t), ++ i));
130 #endif
131     }
132 
133     // Dense (proxy) case
134     template<template <class T1, class T2> class F, class V, class T>
135     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_assign_scalar(V & v,const T & t,dense_proxy_tag)136     void vector_assign_scalar (V &v, const T &t, dense_proxy_tag) {
137 #ifdef BOOST_UBLAS_USE_INDEXING
138         indexing_vector_assign_scalar<F> (v, t);
139 #elif BOOST_UBLAS_USE_ITERATING
140         iterating_vector_assign_scalar<F> (v, t);
141 #else
142         typedef typename V::size_type size_type;
143         size_type size (v.size ());
144         if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
145             iterating_vector_assign_scalar<F> (v, t);
146         else
147             indexing_vector_assign_scalar<F> (v, t);
148 #endif
149     }
150     // Packed (proxy) case
151     template<template <class T1, class T2> class F, class V, class T>
152     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_assign_scalar(V & v,const T & t,packed_proxy_tag)153     void vector_assign_scalar (V &v, const T &t, packed_proxy_tag) {
154         typedef F<typename V::iterator::reference, T> functor_type;
155         typedef typename V::difference_type difference_type;
156         typename V::iterator it (v.begin ());
157         difference_type size (v.end () - it);
158         while (-- size >= 0)
159             functor_type::apply (*it, t), ++ it;
160     }
161     // Sparse (proxy) case
162     template<template <class T1, class T2> class F, class V, class T>
163     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_assign_scalar(V & v,const T & t,sparse_proxy_tag)164     void vector_assign_scalar (V &v, const T &t, sparse_proxy_tag) {
165         typedef F<typename V::iterator::reference, T> functor_type;
166         typename V::iterator it (v.begin ());
167         typename V::iterator it_end (v.end ());
168         while (it != it_end)
169             functor_type::apply (*it, t), ++ it;
170     }
171 
172     // Dispatcher
173     template<template <class T1, class T2> class F, class V, class T>
174     BOOST_UBLAS_INLINE
vector_assign_scalar(V & v,const T & t)175     void vector_assign_scalar (V &v, const T &t) {
176         typedef typename V::storage_category storage_category;
177         vector_assign_scalar<F> (v, t, storage_category ());
178     }
179 
180     template<class SC, bool COMPUTED, class RI>
181     struct vector_assign_traits {
182         typedef SC storage_category;
183     };
184 
185     template<bool COMPUTED>
186     struct vector_assign_traits<dense_tag, COMPUTED, packed_random_access_iterator_tag> {
187         typedef packed_tag storage_category;
188     };
189     template<>
190     struct vector_assign_traits<dense_tag, false, sparse_bidirectional_iterator_tag> {
191         typedef sparse_tag storage_category;
192     };
193     template<>
194     struct vector_assign_traits<dense_tag, true, sparse_bidirectional_iterator_tag> {
195         typedef sparse_proxy_tag storage_category;
196     };
197 
198     template<bool COMPUTED>
199     struct vector_assign_traits<dense_proxy_tag, COMPUTED, packed_random_access_iterator_tag> {
200         typedef packed_proxy_tag storage_category;
201     };
202     template<>
203     struct vector_assign_traits<dense_proxy_tag, false, sparse_bidirectional_iterator_tag> {
204         typedef sparse_proxy_tag storage_category;
205     };
206     template<>
207     struct vector_assign_traits<dense_proxy_tag, true, sparse_bidirectional_iterator_tag> {
208         typedef sparse_proxy_tag storage_category;
209     };
210 
211     template<>
212     struct vector_assign_traits<packed_tag, false, sparse_bidirectional_iterator_tag> {
213         typedef sparse_tag storage_category;
214     };
215     template<>
216     struct vector_assign_traits<packed_tag, true, sparse_bidirectional_iterator_tag> {
217         typedef sparse_proxy_tag storage_category;
218     };
219 
220     template<bool COMPUTED>
221     struct vector_assign_traits<packed_proxy_tag, COMPUTED, sparse_bidirectional_iterator_tag> {
222         typedef sparse_proxy_tag storage_category;
223     };
224 
225     template<>
226     struct vector_assign_traits<sparse_tag, true, dense_random_access_iterator_tag> {
227         typedef sparse_proxy_tag storage_category;
228     };
229     template<>
230     struct vector_assign_traits<sparse_tag, true, packed_random_access_iterator_tag> {
231         typedef sparse_proxy_tag storage_category;
232     };
233     template<>
234     struct vector_assign_traits<sparse_tag, true, sparse_bidirectional_iterator_tag> {
235         typedef sparse_proxy_tag storage_category;
236     };
237 
238     // Explicitly iterating
239     template<template <class T1, class T2> class F, class V, class E>
240     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
iterating_vector_assign(V & v,const vector_expression<E> & e)241     void iterating_vector_assign (V &v, const vector_expression<E> &e) {
242         typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
243         typedef typename V::difference_type difference_type;
244         difference_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
245         typename V::iterator it (v.begin ());
246         BOOST_UBLAS_CHECK (v.end () - it == size, bad_size ());
247         typename E::const_iterator ite (e ().begin ());
248         BOOST_UBLAS_CHECK (e ().end () - ite == size, bad_size ());
249 #ifndef BOOST_UBLAS_USE_DUFF_DEVICE
250         while (-- size >= 0)
251             functor_type::apply (*it, *ite), ++ it, ++ ite;
252 #else
253         DD (size, 2, r, (functor_type::apply (*it, *ite), ++ it, ++ ite));
254 #endif
255     }
256     // Explicitly indexing
257     template<template <class T1, class T2> class F, class V, class E>
258     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
indexing_vector_assign(V & v,const vector_expression<E> & e)259     void indexing_vector_assign (V &v, const vector_expression<E> &e) {
260         typedef F<typename V::reference, typename E::value_type> functor_type;
261         typedef typename V::size_type size_type;
262         size_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
263 #ifndef BOOST_UBLAS_USE_DUFF_DEVICE
264         for (size_type i = 0; i < size; ++ i)
265             functor_type::apply (v (i), e () (i));
266 #else
267         size_type i (0);
268         DD (size, 2, r, (functor_type::apply (v (i), e () (i)), ++ i));
269 #endif
270     }
271 
272     // Dense (proxy) case
273     template<template <class T1, class T2> class F, class V, class E>
274     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_assign(V & v,const vector_expression<E> & e,dense_proxy_tag)275     void vector_assign (V &v, const vector_expression<E> &e, dense_proxy_tag) {
276 #ifdef BOOST_UBLAS_USE_INDEXING
277         indexing_vector_assign<F> (v, e);
278 #elif BOOST_UBLAS_USE_ITERATING
279         iterating_vector_assign<F> (v, e);
280 #else
281         typedef typename V::size_type size_type;
282         size_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
283         if (size >= BOOST_UBLAS_ITERATOR_THRESHOLD)
284             iterating_vector_assign<F> (v, e);
285         else
286             indexing_vector_assign<F> (v, e);
287 #endif
288     }
289     // Packed (proxy) case
290     template<template <class T1, class T2> class F, class V, class E>
291     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_assign(V & v,const vector_expression<E> & e,packed_proxy_tag)292     void vector_assign (V &v, const vector_expression<E> &e, packed_proxy_tag) {
293         BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
294         typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
295         typedef typename V::difference_type difference_type;
296         typedef typename V::value_type value_type;
297 #if BOOST_UBLAS_TYPE_CHECK
298         vector<value_type> cv (v.size ());
299         indexing_vector_assign<scalar_assign> (cv, v);
300         indexing_vector_assign<F> (cv, e);
301 #endif
302         typename V::iterator it (v.begin ());
303         typename V::iterator it_end (v.end ());
304         typename E::const_iterator ite (e ().begin ());
305         typename E::const_iterator ite_end (e ().end ());
306         difference_type it_size (it_end - it);
307         difference_type ite_size (ite_end - ite);
308         if (it_size > 0 && ite_size > 0) {
309             difference_type size ((std::min) (difference_type (it.index () - ite.index ()), ite_size));
310             if (size > 0) {
311                 ite += size;
312                 ite_size -= size;
313             }
314         }
315         if (it_size > 0 && ite_size > 0) {
316             difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
317             if (size > 0) {
318                 it_size -= size;
319 //Disabled warning C4127 because the conditional expression is constant
320 #ifdef _MSC_VER
321 #pragma warning(push)
322 #pragma warning(disable: 4127)
323 #endif
324                 if (!functor_type::computed) {
325 #ifdef _MSC_VER
326 #pragma warning(pop)
327 #endif
328                     while (-- size >= 0)    // zeroing
329                         functor_type::apply (*it, value_type/*zero*/()), ++ it;
330                 } else {
331                     it += size;
332                 }
333             }
334         }
335         difference_type size ((std::min) (it_size, ite_size));
336         it_size -= size;
337         ite_size -= size;
338         while (-- size >= 0)
339             functor_type::apply (*it, *ite), ++ it, ++ ite;
340         size = it_size;
341 //Disabled warning C4127 because the conditional expression is constant
342 #ifdef _MSC_VER
343 #pragma warning(push)
344 #pragma warning(disable: 4127)
345 #endif
346         if (!functor_type::computed) {
347 #ifdef _MSC_VER
348 #pragma warning(pop)
349 #endif
350             while (-- size >= 0)    // zeroing
351                 functor_type::apply (*it, value_type/*zero*/()), ++ it;
352         } else {
353             it += size;
354         }
355 #if BOOST_UBLAS_TYPE_CHECK
356         if (! disable_type_check<bool>::value)
357             BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
358                                external_logic ("external logic or bad condition of inputs"));
359 #endif
360     }
361     // Sparse case
362     template<template <class T1, class T2> class F, class V, class E>
363     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_assign(V & v,const vector_expression<E> & e,sparse_tag)364     void vector_assign (V &v, const vector_expression<E> &e, sparse_tag) {
365         BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
366         typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
367 //Disabled warning C4127 because the conditional expression is constant
368 #ifdef _MSC_VER
369 #pragma warning(push)
370 #pragma warning(disable: 4127)
371 #endif
372         BOOST_STATIC_ASSERT ((!functor_type::computed));
373 #ifdef _MSC_VER
374 #pragma warning(pop)
375 #endif
376         typedef typename V::value_type value_type;
377 #if BOOST_UBLAS_TYPE_CHECK
378         vector<value_type> cv (v.size ());
379         indexing_vector_assign<scalar_assign> (cv, v);
380         indexing_vector_assign<F> (cv, e);
381 #endif
382         v.clear ();
383         typename E::const_iterator ite (e ().begin ());
384         typename E::const_iterator ite_end (e ().end ());
385         while (ite != ite_end) {
386             value_type t (*ite);
387             if (t != value_type/*zero*/())
388                 v.insert_element (ite.index (), t);
389             ++ ite;
390         }
391 #if BOOST_UBLAS_TYPE_CHECK
392         if (! disable_type_check<bool>::value)
393             BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
394                                external_logic ("external logic or bad condition of inputs"));
395 #endif
396     }
397     // Sparse proxy or functional case
398     template<template <class T1, class T2> class F, class V, class E>
399     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_assign(V & v,const vector_expression<E> & e,sparse_proxy_tag)400     void vector_assign (V &v, const vector_expression<E> &e, sparse_proxy_tag) {
401         BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
402         typedef F<typename V::iterator::reference, typename E::value_type> functor_type;
403         typedef typename V::size_type size_type;
404         typedef typename V::difference_type difference_type;
405         typedef typename V::value_type value_type;
406 
407 #if BOOST_UBLAS_TYPE_CHECK
408         vector<value_type> cv (v.size ());
409         indexing_vector_assign<scalar_assign> (cv, v);
410         indexing_vector_assign<F> (cv, e);
411 #endif
412         detail::make_conformant (v, e);
413 
414         typename V::iterator it (v.begin ());
415         typename V::iterator it_end (v.end ());
416         typename E::const_iterator ite (e ().begin ());
417         typename E::const_iterator ite_end (e ().end ());
418         if (it != it_end && ite != ite_end) {
419             size_type it_index = it.index (), ite_index = ite.index ();
420             for (;;) {
421                 difference_type compare = it_index - ite_index;
422                 if (compare == 0) {
423                     functor_type::apply (*it, *ite);
424                     ++ it, ++ ite;
425                     if (it != it_end && ite != ite_end) {
426                         it_index = it.index ();
427                         ite_index = ite.index ();
428                     } else
429                         break;
430                 } else if (compare < 0) {
431 //Disabled warning C4127 because the conditional expression is constant
432 #ifdef _MSC_VER
433 #pragma warning(push)
434 #pragma warning(disable: 4127)
435 #endif
436                     if (!functor_type::computed) {
437 #ifdef _MSC_VER
438 #pragma warning(pop)
439 #endif
440                         functor_type::apply (*it, value_type/*zero*/());
441                         ++ it;
442                     } else
443                         increment (it, it_end, - compare);
444                     if (it != it_end)
445                         it_index = it.index ();
446                     else
447                         break;
448                 } else if (compare > 0) {
449                     increment (ite, ite_end, compare);
450                     if (ite != ite_end)
451                         ite_index = ite.index ();
452                     else
453                         break;
454                 }
455             }
456         }
457 //Disabled warning C4127 because the conditional expression is constant
458 #ifdef _MSC_VER
459 #pragma warning(push)
460 #pragma warning(disable: 4127)
461 #endif
462         if (!functor_type::computed) {
463 #ifdef _MSC_VER
464 #pragma warning(pop)
465 #endif
466             while (it != it_end) {  // zeroing
467                 functor_type::apply (*it, value_type/*zero*/());
468                 ++ it;
469             }
470         } else {
471             it = it_end;
472         }
473 #if BOOST_UBLAS_TYPE_CHECK
474         if (! disable_type_check<bool>::value)
475             BOOST_UBLAS_CHECK (detail::expression_type_check (v, cv),
476                                external_logic ("external logic or bad condition of inputs"));
477 #endif
478     }
479 
480     // Dispatcher
481     template<template <class T1, class T2> class F, class V, class E>
482     BOOST_UBLAS_INLINE
vector_assign(V & v,const vector_expression<E> & e)483     void vector_assign (V &v, const vector_expression<E> &e) {
484         typedef typename vector_assign_traits<typename V::storage_category,
485                                               F<typename V::reference, typename E::value_type>::computed,
486                                               typename E::const_iterator::iterator_category>::storage_category storage_category;
487         vector_assign<F> (v, e, storage_category ());
488     }
489 
490     template<class SC, class RI>
491     struct vector_swap_traits {
492         typedef SC storage_category;
493     };
494 
495     template<>
496     struct vector_swap_traits<dense_proxy_tag, sparse_bidirectional_iterator_tag> {
497         typedef sparse_proxy_tag storage_category;
498     };
499 
500     template<>
501     struct vector_swap_traits<packed_proxy_tag, sparse_bidirectional_iterator_tag> {
502         typedef sparse_proxy_tag storage_category;
503     };
504 
505     // Dense (proxy) case
506     template<template <class T1, class T2> class F, class V, class E>
507     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_swap(V & v,vector_expression<E> & e,dense_proxy_tag)508     void vector_swap (V &v, vector_expression<E> &e, dense_proxy_tag) {
509         typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
510         typedef typename V::difference_type difference_type;
511         difference_type size (BOOST_UBLAS_SAME (v.size (), e ().size ()));
512         typename V::iterator it (v.begin ());
513         typename E::iterator ite (e ().begin ());
514         while (-- size >= 0)
515             functor_type::apply (*it, *ite), ++ it, ++ ite;
516     }
517     // Packed (proxy) case
518     template<template <class T1, class T2> class F, class V, class E>
519     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_swap(V & v,vector_expression<E> & e,packed_proxy_tag)520     void vector_swap (V &v, vector_expression<E> &e, packed_proxy_tag) {
521         typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
522         typedef typename V::difference_type difference_type;
523         typename V::iterator it (v.begin ());
524         typename V::iterator it_end (v.end ());
525         typename E::iterator ite (e ().begin ());
526         typename E::iterator ite_end (e ().end ());
527         difference_type it_size (it_end - it);
528         difference_type ite_size (ite_end - ite);
529         if (it_size > 0 && ite_size > 0) {
530             difference_type size ((std::min) (difference_type (it.index () - ite.index ()), ite_size));
531             if (size > 0) {
532                 ite += size;
533                 ite_size -= size;
534             }
535         }
536         if (it_size > 0 && ite_size > 0) {
537             difference_type size ((std::min) (difference_type (ite.index () - it.index ()), it_size));
538             if (size > 0)
539                 it_size -= size;
540         }
541         difference_type size ((std::min) (it_size, ite_size));
542         it_size -= size;
543         ite_size -= size;
544         while (-- size >= 0)
545             functor_type::apply (*it, *ite), ++ it, ++ ite;
546     }
547     // Sparse proxy case
548     template<template <class T1, class T2> class F, class V, class E>
549     // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
vector_swap(V & v,vector_expression<E> & e,sparse_proxy_tag)550     void vector_swap (V &v, vector_expression<E> &e, sparse_proxy_tag) {
551         BOOST_UBLAS_CHECK (v.size () == e ().size (), bad_size ());
552         typedef F<typename V::iterator::reference, typename E::iterator::reference> functor_type;
553         typedef typename V::size_type size_type;
554         typedef typename V::difference_type difference_type;
555 
556         detail::make_conformant (v, e);
557         // FIXME should be a seperate restriction for E
558         detail::make_conformant (e (), v);
559 
560         typename V::iterator it (v.begin ());
561         typename V::iterator it_end (v.end ());
562         typename E::iterator ite (e ().begin ());
563         typename E::iterator ite_end (e ().end ());
564         if (it != it_end && ite != ite_end) {
565             size_type it_index = it.index (), ite_index = ite.index ();
566             for (;;) {
567                 difference_type compare = it_index - ite_index;
568                 if (compare == 0) {
569                     functor_type::apply (*it, *ite);
570                     ++ it, ++ ite;
571                     if (it != it_end && ite != ite_end) {
572                         it_index = it.index ();
573                         ite_index = ite.index ();
574                     } else
575                         break;
576                 } else if (compare < 0) {
577                     increment (it, it_end, - compare);
578                     if (it != it_end)
579                         it_index = it.index ();
580                     else
581                         break;
582                 } else if (compare > 0) {
583                     increment (ite, ite_end, compare);
584                     if (ite != ite_end)
585                         ite_index = ite.index ();
586                     else
587                         break;
588                 }
589             }
590         }
591 
592 #if BOOST_UBLAS_TYPE_CHECK
593         increment (ite, ite_end);
594         increment (it, it_end);
595 #endif
596     }
597 
598     // Dispatcher
599     template<template <class T1, class T2> class F, class V, class E>
600     BOOST_UBLAS_INLINE
vector_swap(V & v,vector_expression<E> & e)601     void vector_swap (V &v, vector_expression<E> &e) {
602         typedef typename vector_swap_traits<typename V::storage_category,
603                                             typename E::const_iterator::iterator_category>::storage_category storage_category;
604         vector_swap<F> (v, e, storage_category ());
605     }
606 
607 }}}
608 
609 #endif
610