vector_assign.hpp 23 KB

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