segment_split.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /* Copyright 2016-2017 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See http://www.boost.org/libs/poly_collection for library home page.
  7. */
  8. #ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP
  9. #define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/iterator/iterator_facade.hpp>
  14. #include <boost/poly_collection/detail/iterator_traits.hpp>
  15. #include <typeinfo>
  16. #include <utility>
  17. namespace boost{
  18. namespace poly_collection{
  19. namespace detail{
  20. /* breakdown of an iterator range into local_base_iterator segments */
  21. template<typename PolyCollectionIterator>
  22. class segment_splitter
  23. {
  24. using traits=iterator_traits<PolyCollectionIterator>;
  25. using local_base_iterator=typename traits::local_base_iterator;
  26. using base_segment_info_iterator=typename traits::base_segment_info_iterator;
  27. public:
  28. struct info
  29. {
  30. const std::type_info& type_info()const noexcept{return *pinfo_;}
  31. local_base_iterator begin()const noexcept{return begin_;}
  32. local_base_iterator end()const noexcept{return end_;}
  33. const std::type_info* pinfo_;
  34. local_base_iterator begin_,end_;
  35. };
  36. struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
  37. {
  38. iterator()=default;
  39. private:
  40. friend class segment_splitter;
  41. friend class boost::iterator_core_access;
  42. iterator(
  43. base_segment_info_iterator it,
  44. const PolyCollectionIterator& first,const PolyCollectionIterator& last):
  45. it{it},pfirst{&first},plast{&last}{}
  46. iterator(
  47. const PolyCollectionIterator& first,const PolyCollectionIterator& last):
  48. it{traits::base_segment_info_iterator_from(first)},
  49. pfirst{&first},plast{&last}
  50. {}
  51. info dereference()const noexcept
  52. {
  53. return {
  54. &it->type_info(),
  55. it==traits::base_segment_info_iterator_from(*pfirst)?
  56. traits::local_base_iterator_from(*pfirst):it->begin(),
  57. it==traits::base_segment_info_iterator_from(*plast)?
  58. traits::local_base_iterator_from(*plast):it->end()
  59. };
  60. }
  61. bool equal(const iterator& x)const noexcept{return it==x.it;}
  62. void increment()noexcept{++it;}
  63. base_segment_info_iterator it;
  64. const PolyCollectionIterator* pfirst;
  65. const PolyCollectionIterator* plast;
  66. };
  67. segment_splitter(
  68. const PolyCollectionIterator& first,const PolyCollectionIterator& last):
  69. pfirst{&first},plast{&last}{}
  70. iterator begin()const noexcept{return {*pfirst,*plast};}
  71. iterator end()const noexcept
  72. {
  73. auto slast=traits::base_segment_info_iterator_from(*plast);
  74. if(slast!=traits::end_base_segment_info_iterator_from(*plast))++slast;
  75. return {slast,*plast,*plast};
  76. }
  77. private:
  78. const PolyCollectionIterator* pfirst;
  79. const PolyCollectionIterator* plast;
  80. };
  81. template<typename PolyCollectionIterator>
  82. segment_splitter<PolyCollectionIterator>
  83. segment_split(
  84. const PolyCollectionIterator& first,const PolyCollectionIterator& last)
  85. {
  86. return {first,last};
  87. }
  88. #if 1
  89. /* equivalent to for(auto i:segment_split(first,last))f(i) */
  90. template<typename PolyCollectionIterator,typename F>
  91. void for_each_segment(
  92. const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
  93. {
  94. using traits=iterator_traits<PolyCollectionIterator>;
  95. using info=typename segment_splitter<PolyCollectionIterator>::info;
  96. auto sfirst=traits::base_segment_info_iterator_from(first),
  97. slast=traits::base_segment_info_iterator_from(last),
  98. send=traits::end_base_segment_info_iterator_from(last);
  99. auto lbfirst=traits::local_base_iterator_from(first),
  100. lblast=traits::local_base_iterator_from(last);
  101. if(sfirst!=slast){
  102. for(;;){
  103. f(info{&sfirst->type_info(),lbfirst,sfirst->end()});
  104. ++sfirst;
  105. if(sfirst==slast)break;
  106. lbfirst=sfirst->begin();
  107. }
  108. if(sfirst!=send)f(info{&sfirst->type_info(),sfirst->begin(),lblast});
  109. }
  110. else if(sfirst!=send){
  111. f(info{&sfirst->type_info(),lbfirst,lblast});
  112. }
  113. }
  114. #else
  115. template<typename PolyCollectionIterator,typename F>
  116. void for_each_segment(
  117. const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
  118. {
  119. for(auto i:segment_split(first,last))f(i);
  120. }
  121. #endif
  122. } /* namespace poly_collection::detail */
  123. } /* namespace poly_collection */
  124. } /* namespace boost */
  125. #endif