1 // (C) Copyright David Abrahams and Thomas Becker 2000. Permission to 2 // copy, use, modify, sell and distribute this software is granted 3 // provided this copyright notice appears in all copies. This software 4 // is provided "as is" without express or implied warranty, and with 5 // no claim as to its suitability for any purpose. 6 // 7 // Compilers Tested: 8 // ================= 9 // Metrowerks Codewarrior Pro 7.2, 8.3 10 // gcc 2.95.3 11 // gcc 3.2 12 // Microsoft VC 6sp5 (test fails due to some compiler bug) 13 // Microsoft VC 7 (works) 14 // Microsoft VC 7.1 15 // Intel 5 16 // Intel 6 17 // Intel 7.1 18 // Intel 8 19 // Borland 5.5.1 (broken due to lack of support from Boost.Tuples) 20 21 #ifndef BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_ 22 # define BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_ 23 24 #include <stddef.h> 25 #include <boost/iterator.hpp> 26 #include <boost/iterator/iterator_traits.hpp> 27 #include <boost/iterator/iterator_facade.hpp> 28 #include <boost/iterator/iterator_adaptor.hpp> // for enable_if_convertible 29 #include <boost/iterator/iterator_categories.hpp> 30 #include <boost/detail/iterator.hpp> 31 32 #include <boost/iterator/detail/minimum_category.hpp> 33 34 #include <boost/tuple/tuple.hpp> 35 36 #include <boost/type_traits/is_same.hpp> 37 #include <boost/mpl/and.hpp> 38 #include <boost/mpl/apply.hpp> 39 #include <boost/mpl/eval_if.hpp> 40 #include <boost/mpl/lambda.hpp> 41 #include <boost/mpl/placeholders.hpp> 42 #include <boost/mpl/aux_/lambda_support.hpp> 43 44 namespace boost { 45 46 // Zip iterator forward declaration for zip_iterator_base 47 template<typename IteratorTuple> 48 class zip_iterator; 49 50 // One important design goal of the zip_iterator is to isolate all 51 // functionality whose implementation relies on the current tuple 52 // implementation. This goal has been achieved as follows: Inside 53 // the namespace detail there is a namespace tuple_impl_specific. 54 // This namespace encapsulates all functionality that is specific 55 // to the current Boost tuple implementation. More precisely, the 56 // namespace tuple_impl_specific provides the following tuple 57 // algorithms and meta-algorithms for the current Boost tuple 58 // implementation: 59 // 60 // tuple_meta_transform 61 // tuple_meta_accumulate 62 // tuple_transform 63 // tuple_for_each 64 // 65 // If the tuple implementation changes, all that needs to be 66 // replaced is the implementation of these four (meta-)algorithms. 67 68 namespace detail 69 { 70 71 // Functors to be used with tuple algorithms 72 // 73 template<typename DiffType> 74 class advance_iterator 75 { 76 public: advance_iterator(DiffType step)77 advance_iterator(DiffType step) : m_step(step) {} 78 79 template<typename Iterator> operator ()(Iterator & it) const80 void operator()(Iterator& it) const 81 { it += m_step; } 82 83 private: 84 DiffType m_step; 85 }; 86 // 87 struct increment_iterator 88 { 89 template<typename Iterator> operator ()boost::detail::increment_iterator90 void operator()(Iterator& it) 91 { ++it; } 92 }; 93 // 94 struct decrement_iterator 95 { 96 template<typename Iterator> operator ()boost::detail::decrement_iterator97 void operator()(Iterator& it) 98 { --it; } 99 }; 100 // 101 struct dereference_iterator 102 { 103 template<typename Iterator> 104 struct apply 105 { 106 typedef typename 107 iterator_traits<Iterator>::reference 108 type; 109 }; 110 111 template<typename Iterator> operator ()boost::detail::dereference_iterator112 typename apply<Iterator>::type operator()(Iterator const& it) 113 { return *it; } 114 }; 115 116 117 // The namespace tuple_impl_specific provides two meta- 118 // algorithms and two algorithms for tuples. 119 // 120 namespace tuple_impl_specific 121 { 122 // Meta-transform algorithm for tuples 123 // 124 template<typename Tuple, class UnaryMetaFun> 125 struct tuple_meta_transform; 126 127 template<typename Tuple, class UnaryMetaFun> 128 struct tuple_meta_transform_impl 129 { 130 typedef tuples::cons< 131 typename mpl::apply1< 132 typename mpl::lambda<UnaryMetaFun>::type 133 , typename Tuple::head_type 134 >::type 135 , typename tuple_meta_transform< 136 typename Tuple::tail_type 137 , UnaryMetaFun 138 >::type 139 > type; 140 }; 141 142 template<typename Tuple, class UnaryMetaFun> 143 struct tuple_meta_transform 144 : mpl::eval_if< 145 boost::is_same<Tuple, tuples::null_type> 146 , mpl::identity<tuples::null_type> 147 , tuple_meta_transform_impl<Tuple, UnaryMetaFun> 148 > 149 { 150 }; 151 152 // Meta-accumulate algorithm for tuples. Note: The template 153 // parameter StartType corresponds to the initial value in 154 // ordinary accumulation. 155 // 156 template<class Tuple, class BinaryMetaFun, class StartType> 157 struct tuple_meta_accumulate; 158 159 template< 160 typename Tuple 161 , class BinaryMetaFun 162 , typename StartType 163 > 164 struct tuple_meta_accumulate_impl 165 { 166 typedef typename mpl::apply2< 167 typename mpl::lambda<BinaryMetaFun>::type 168 , typename Tuple::head_type 169 , typename tuple_meta_accumulate< 170 typename Tuple::tail_type 171 , BinaryMetaFun 172 , StartType 173 >::type 174 >::type type; 175 }; 176 177 template< 178 typename Tuple 179 , class BinaryMetaFun 180 , typename StartType 181 > 182 struct tuple_meta_accumulate 183 : mpl::eval_if< 184 #if BOOST_WORKAROUND(BOOST_MSVC, == 1200) 185 mpl::or_< 186 #endif 187 boost::is_same<Tuple, tuples::null_type> 188 #if BOOST_WORKAROUND(BOOST_MSVC, == 1200) 189 , boost::is_same<Tuple,int> 190 > 191 #endif 192 , mpl::identity<StartType> 193 , tuple_meta_accumulate_impl< 194 Tuple 195 , BinaryMetaFun 196 , StartType 197 > 198 > 199 { 200 }; 201 202 #if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ 203 || ( \ 204 BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, != 0) && defined(_MSC_VER) \ 205 ) 206 // Not sure why intel's partial ordering fails in this case, but I'm 207 // assuming int's an MSVC bug-compatibility feature. 208 209 # define BOOST_TUPLE_ALGO_DISPATCH 210 # define BOOST_TUPLE_ALGO(algo) algo##_impl 211 # define BOOST_TUPLE_ALGO_TERMINATOR , int 212 # define BOOST_TUPLE_ALGO_RECURSE , ... 213 #else 214 # define BOOST_TUPLE_ALGO(algo) algo 215 # define BOOST_TUPLE_ALGO_TERMINATOR 216 # define BOOST_TUPLE_ALGO_RECURSE 217 #endif 218 219 // transform algorithm for tuples. The template parameter Fun 220 // must be a unary functor which is also a unary metafunction 221 // class that computes its return type based on its argument 222 // type. For example: 223 // 224 // struct to_ptr 225 // { 226 // template <class Arg> 227 // struct apply 228 // { 229 // typedef Arg* type; 230 // } 231 // 232 // template <class Arg> 233 // Arg* operator()(Arg x); 234 // }; 235 template<typename Fun> BOOST_TUPLE_ALGO(tuple_transform)236 tuples::null_type BOOST_TUPLE_ALGO(tuple_transform) 237 (tuples::null_type const&, Fun BOOST_TUPLE_ALGO_TERMINATOR) 238 { return tuples::null_type(); } 239 240 template<typename Tuple, typename Fun> 241 typename tuple_meta_transform< 242 Tuple 243 , Fun 244 >::type 245 BOOST_TUPLE_ALGO(tuple_transform)246 BOOST_TUPLE_ALGO(tuple_transform)( 247 const Tuple& t, 248 Fun f 249 BOOST_TUPLE_ALGO_RECURSE 250 ) 251 { 252 typedef typename tuple_meta_transform< 253 BOOST_DEDUCED_TYPENAME Tuple::tail_type 254 , Fun 255 >::type transformed_tail_type; 256 257 return tuples::cons< 258 BOOST_DEDUCED_TYPENAME mpl::apply1< 259 Fun, BOOST_DEDUCED_TYPENAME Tuple::head_type 260 >::type 261 , transformed_tail_type 262 >( 263 f(boost::tuples::get<0>(t)), tuple_transform(t.get_tail(), f) 264 ); 265 } 266 267 #ifdef BOOST_TUPLE_ALGO_DISPATCH 268 template<typename Tuple, typename Fun> 269 typename tuple_meta_transform< 270 Tuple 271 , Fun 272 >::type 273 tuple_transform(const Tuple & t,Fun f)274 tuple_transform( 275 const Tuple& t, 276 Fun f 277 ) 278 { 279 return tuple_transform_impl(t, f, 1); 280 } 281 #endif 282 283 // for_each algorithm for tuples. 284 // 285 template<typename Fun> BOOST_TUPLE_ALGO(tuple_for_each)286 Fun BOOST_TUPLE_ALGO(tuple_for_each)( 287 tuples::null_type 288 , Fun f BOOST_TUPLE_ALGO_TERMINATOR 289 ) 290 { return f; } 291 292 293 template<typename Tuple, typename Fun> BOOST_TUPLE_ALGO(tuple_for_each)294 Fun BOOST_TUPLE_ALGO(tuple_for_each)( 295 Tuple& t 296 , Fun f BOOST_TUPLE_ALGO_RECURSE) 297 { 298 f( t.get_head() ); 299 return tuple_for_each(t.get_tail(), f); 300 } 301 302 #ifdef BOOST_TUPLE_ALGO_DISPATCH 303 template<typename Tuple, typename Fun> 304 Fun tuple_for_each(Tuple & t,Fun f)305 tuple_for_each( 306 Tuple& t, 307 Fun f 308 ) 309 { 310 return tuple_for_each_impl(t, f, 1); 311 } 312 #endif 313 314 // Equality of tuples. NOTE: "==" for tuples currently (7/2003) 315 // has problems under some compilers, so I just do my own. 316 // No point in bringing in a bunch of #ifdefs here. This is 317 // going to go away with the next tuple implementation anyway. 318 // tuple_equal(tuples::null_type,tuples::null_type)319 bool tuple_equal(tuples::null_type, tuples::null_type) 320 { return true; } 321 322 template<typename Tuple1, typename Tuple2> tuple_equal(Tuple1 const & t1,Tuple2 const & t2)323 bool tuple_equal( 324 Tuple1 const& t1, 325 Tuple2 const& t2 326 ) 327 { 328 return t1.get_head() == t2.get_head() && 329 tuple_equal(t1.get_tail(), t2.get_tail()); 330 } 331 } 332 // 333 // end namespace tuple_impl_specific 334 335 template<typename Iterator> 336 struct iterator_reference 337 { 338 typedef typename iterator_traits<Iterator>::reference type; 339 }; 340 341 #ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT 342 // Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work 343 // out well. Instantiating the nested apply template also 344 // requires instantiating iterator_traits on the 345 // placeholder. Instead we just specialize it as a metafunction 346 // class. 347 template<> 348 struct iterator_reference<mpl::_1> 349 { 350 template <class T> 351 struct apply : iterator_reference<T> {}; 352 }; 353 #endif 354 355 // Metafunction to obtain the type of the tuple whose element types 356 // are the reference types of an iterator tuple. 357 // 358 template<typename IteratorTuple> 359 struct tuple_of_references 360 : tuple_impl_specific::tuple_meta_transform< 361 IteratorTuple, 362 iterator_reference<mpl::_1> 363 > 364 { 365 }; 366 367 // Metafunction to obtain the minimal traversal tag in a tuple 368 // of iterators. 369 // 370 template<typename IteratorTuple> 371 struct minimum_traversal_category_in_iterator_tuple 372 { 373 typedef typename tuple_impl_specific::tuple_meta_transform< 374 IteratorTuple 375 , iterator_traversal<> 376 >::type tuple_of_traversal_tags; 377 378 typedef typename tuple_impl_specific::tuple_meta_accumulate< 379 tuple_of_traversal_tags 380 , minimum_category<> 381 , random_access_traversal_tag 382 >::type type; 383 }; 384 385 #if BOOST_WORKAROUND(BOOST_MSVC, == 1200) // ETI workaround 386 template <> 387 struct minimum_traversal_category_in_iterator_tuple<int> 388 { 389 typedef int type; 390 }; 391 #endif 392 393 // We need to call tuple_meta_accumulate with mpl::and_ as the 394 // accumulating functor. To this end, we need to wrap it into 395 // a struct that has exactly two arguments (that is, template 396 // parameters) and not five, like mpl::and_ does. 397 // 398 template<typename Arg1, typename Arg2> 399 struct and_with_two_args 400 : mpl::and_<Arg1, Arg2> 401 { 402 }; 403 404 # ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT 405 // Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work 406 // out well. In this case I think it's an MPL bug 407 template<> 408 struct and_with_two_args<mpl::_1,mpl::_2> 409 { 410 template <class A1, class A2> 411 struct apply : mpl::and_<A1,A2> 412 {}; 413 }; 414 # endif 415 416 /////////////////////////////////////////////////////////////////// 417 // 418 // Class zip_iterator_base 419 // 420 // Builds and exposes the iterator facade type from which the zip 421 // iterator will be derived. 422 // 423 template<typename IteratorTuple> 424 struct zip_iterator_base 425 { 426 private: 427 // Reference type is the type of the tuple obtained from the 428 // iterators' reference types. 429 typedef typename 430 detail::tuple_of_references<IteratorTuple>::type reference; 431 432 // Value type is the same as reference type. 433 typedef reference value_type; 434 435 // Difference type is the first iterator's difference type 436 typedef typename iterator_traits< 437 typename tuples::element<0, IteratorTuple>::type 438 >::difference_type difference_type; 439 440 // Traversal catetgory is the minimum traversal category in the 441 // iterator tuple. 442 typedef typename 443 detail::minimum_traversal_category_in_iterator_tuple< 444 IteratorTuple 445 >::type traversal_category; 446 public: 447 448 // The iterator facade type from which the zip iterator will 449 // be derived. 450 typedef iterator_facade< 451 zip_iterator<IteratorTuple>, 452 value_type, 453 traversal_category, 454 reference, 455 difference_type 456 > type; 457 }; 458 459 template <> 460 struct zip_iterator_base<int> 461 { 462 typedef int type; 463 }; 464 } 465 466 ///////////////////////////////////////////////////////////////////// 467 // 468 // zip_iterator class definition 469 // 470 template<typename IteratorTuple> 471 class zip_iterator : 472 public detail::zip_iterator_base<IteratorTuple>::type 473 { 474 475 // Typedef super_t as our base class. 476 typedef typename 477 detail::zip_iterator_base<IteratorTuple>::type super_t; 478 479 // iterator_core_access is the iterator's best friend. 480 friend class iterator_core_access; 481 482 public: 483 484 // Construction 485 // ============ 486 487 // Default constructor zip_iterator()488 zip_iterator() { } 489 490 // Constructor from iterator tuple zip_iterator(IteratorTuple iterator_tuple)491 zip_iterator(IteratorTuple iterator_tuple) 492 : m_iterator_tuple(iterator_tuple) 493 { } 494 495 // Copy constructor 496 template<typename OtherIteratorTuple> zip_iterator(const zip_iterator<OtherIteratorTuple> & other,typename enable_if_convertible<OtherIteratorTuple,IteratorTuple>::type * =0)497 zip_iterator( 498 const zip_iterator<OtherIteratorTuple>& other, 499 typename enable_if_convertible< 500 OtherIteratorTuple, 501 IteratorTuple 502 >::type* = 0 503 ) : m_iterator_tuple(other.get_iterator_tuple()) 504 {} 505 506 // Get method for the iterator tuple. get_iterator_tuple() const507 const IteratorTuple& get_iterator_tuple() const 508 { return m_iterator_tuple; } 509 510 private: 511 512 // Implementation of Iterator Operations 513 // ===================================== 514 515 // Dereferencing returns a tuple built from the dereferenced 516 // iterators in the iterator tuple. dereference() const517 typename super_t::reference dereference() const 518 { 519 return detail::tuple_impl_specific::tuple_transform( 520 get_iterator_tuple(), 521 detail::dereference_iterator() 522 ); 523 } 524 525 // Two zip iterators are equal if all iterators in the iterator 526 // tuple are equal. NOTE: It should be possible to implement this 527 // as 528 // 529 // return get_iterator_tuple() == other.get_iterator_tuple(); 530 // 531 // but equality of tuples currently (7/2003) does not compile 532 // under several compilers. No point in bringing in a bunch 533 // of #ifdefs here. 534 // 535 template<typename OtherIteratorTuple> equal(const zip_iterator<OtherIteratorTuple> & other) const536 bool equal(const zip_iterator<OtherIteratorTuple>& other) const 537 { 538 return detail::tuple_impl_specific::tuple_equal( 539 get_iterator_tuple(), 540 other.get_iterator_tuple() 541 ); 542 } 543 544 // Advancing a zip iterator means to advance all iterators in the 545 // iterator tuple. advance(typename super_t::difference_type n)546 void advance(typename super_t::difference_type n) 547 { 548 detail::tuple_impl_specific::tuple_for_each( 549 m_iterator_tuple, 550 detail::advance_iterator<BOOST_DEDUCED_TYPENAME super_t::difference_type>(n) 551 ); 552 } 553 // Incrementing a zip iterator means to increment all iterators in 554 // the iterator tuple. increment()555 void increment() 556 { 557 detail::tuple_impl_specific::tuple_for_each( 558 m_iterator_tuple, 559 detail::increment_iterator() 560 ); 561 } 562 563 // Decrementing a zip iterator means to decrement all iterators in 564 // the iterator tuple. decrement()565 void decrement() 566 { 567 detail::tuple_impl_specific::tuple_for_each( 568 m_iterator_tuple, 569 detail::decrement_iterator() 570 ); 571 } 572 573 // Distance is calculated using the first iterator in the tuple. 574 template<typename OtherIteratorTuple> distance_to(const zip_iterator<OtherIteratorTuple> & other) const575 typename super_t::difference_type distance_to( 576 const zip_iterator<OtherIteratorTuple>& other 577 ) const 578 { 579 return boost::tuples::get<0>(other.get_iterator_tuple()) - 580 boost::tuples::get<0>(this->get_iterator_tuple()); 581 } 582 583 // Data Members 584 // ============ 585 586 // The iterator tuple. 587 IteratorTuple m_iterator_tuple; 588 589 }; 590 591 // Make function for zip iterator 592 // 593 template<typename IteratorTuple> 594 zip_iterator<IteratorTuple> make_zip_iterator(IteratorTuple t)595 make_zip_iterator(IteratorTuple t) 596 { return zip_iterator<IteratorTuple>(t); } 597 598 } 599 600 #endif 601