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