segment_split.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /* Copyright 2016-2024 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/config.hpp>
  14. #include <boost/iterator/iterator_facade.hpp>
  15. #include <boost/poly_collection/detail/iterator_traits.hpp>
  16. #include <utility>
  17. #if defined(BOOST_MSVC)
  18. #pragma warning(push)
  19. #pragma warning(disable:4714) /* marked as __forceinline not inlined */
  20. #endif
  21. namespace boost{
  22. namespace poly_collection{
  23. namespace detail{
  24. /* breakdown of an iterator range into local_base_iterator segments */
  25. template<typename PolyCollectionIterator>
  26. class segment_splitter
  27. {
  28. using traits=iterator_traits<PolyCollectionIterator>;
  29. using local_base_iterator=typename traits::local_base_iterator;
  30. using base_segment_info_iterator=typename traits::base_segment_info_iterator;
  31. using type_index=typename traits::type_index;
  32. public:
  33. struct info
  34. {
  35. const type_index& type_info()const noexcept{return info_;}
  36. local_base_iterator begin()const noexcept{return begin_;}
  37. local_base_iterator end()const noexcept{return end_;}
  38. const type_index& info_;
  39. local_base_iterator begin_,end_;
  40. };
  41. struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
  42. {
  43. iterator()=default;
  44. private:
  45. friend class segment_splitter;
  46. friend class boost::iterator_core_access;
  47. iterator(
  48. base_segment_info_iterator it,
  49. const PolyCollectionIterator& first,const PolyCollectionIterator& last):
  50. it{it},pfirst{&first},plast{&last}{}
  51. iterator(
  52. const PolyCollectionIterator& first,const PolyCollectionIterator& last):
  53. it{traits::base_segment_info_iterator_from(first)},
  54. pfirst{&first},plast{&last}
  55. {}
  56. info dereference()const noexcept
  57. {
  58. return {
  59. it->type_info(),
  60. it==traits::base_segment_info_iterator_from(*pfirst)?
  61. traits::local_base_iterator_from(*pfirst):it->begin(),
  62. it==traits::base_segment_info_iterator_from(*plast)?
  63. traits::local_base_iterator_from(*plast):it->end()
  64. };
  65. }
  66. bool equal(const iterator& x)const noexcept{return it==x.it;}
  67. void increment()noexcept{++it;}
  68. base_segment_info_iterator it;
  69. const PolyCollectionIterator* pfirst;
  70. const PolyCollectionIterator* plast;
  71. };
  72. segment_splitter(
  73. const PolyCollectionIterator& first,const PolyCollectionIterator& last):
  74. pfirst{&first},plast{&last}{}
  75. iterator begin()const noexcept{return {*pfirst,*plast};}
  76. iterator end()const noexcept
  77. {
  78. auto slast=traits::base_segment_info_iterator_from(*plast);
  79. if(slast!=traits::end_base_segment_info_iterator_from(*plast))++slast;
  80. return {slast,*plast,*plast};
  81. }
  82. private:
  83. const PolyCollectionIterator* pfirst;
  84. const PolyCollectionIterator* plast;
  85. };
  86. template<typename PolyCollectionIterator>
  87. segment_splitter<PolyCollectionIterator>
  88. segment_split(
  89. const PolyCollectionIterator& first,const PolyCollectionIterator& last)
  90. {
  91. return {first,last};
  92. }
  93. #if 1
  94. /* equivalent to for(auto i:segment_split(first,last))f(i) */
  95. template<typename PolyCollectionIterator,typename F>
  96. BOOST_FORCEINLINE void for_each_segment(
  97. const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
  98. {
  99. using traits=iterator_traits<PolyCollectionIterator>;
  100. using info=typename segment_splitter<PolyCollectionIterator>::info;
  101. auto sfirst=traits::base_segment_info_iterator_from(first),
  102. slast=traits::base_segment_info_iterator_from(last),
  103. send=traits::end_base_segment_info_iterator_from(last);
  104. auto lbfirst=traits::local_base_iterator_from(first),
  105. lblast=traits::local_base_iterator_from(last);
  106. if(sfirst!=slast){
  107. for(;;){
  108. f(info{sfirst->type_info(),lbfirst,sfirst->end()});
  109. ++sfirst;
  110. if(sfirst==slast)break;
  111. lbfirst=sfirst->begin();
  112. }
  113. if(sfirst!=send)f(info{sfirst->type_info(),sfirst->begin(),lblast});
  114. }
  115. else if(sfirst!=send){
  116. f(info{sfirst->type_info(),lbfirst,lblast});
  117. }
  118. }
  119. #else
  120. template<typename PolyCollectionIterator,typename F>
  121. BOOST_FORCEINLINE void for_each_segment(
  122. const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
  123. {
  124. for(auto i:segment_split(first,last))f(i);
  125. }
  126. #endif
  127. } /* namespace poly_collection::detail */
  128. } /* namespace poly_collection */
  129. } /* namespace boost */
  130. #if defined(BOOST_MSVC)
  131. #pragma warning(pop) /* C4714 */
  132. #endif
  133. #endif