stride_iterator.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* Copyright 2016-2019 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_STRIDE_ITERATOR_HPP
  9. #define BOOST_POLY_COLLECTION_DETAIL_STRIDE_ITERATOR_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/detail/workaround.hpp>
  14. #include <boost/iterator/iterator_facade.hpp>
  15. #include <type_traits>
  16. namespace boost{
  17. namespace poly_collection{
  18. namespace detail{
  19. /* random-access iterator to Value elements laid out stride *chars* apart */
  20. template<typename Value>
  21. class stride_iterator:
  22. public boost::iterator_facade<
  23. stride_iterator<Value>,
  24. Value,
  25. boost::random_access_traversal_tag
  26. >
  27. {
  28. public:
  29. stride_iterator()=default;
  30. stride_iterator(Value* p,std::size_t stride)noexcept:p{p},stride_{stride}{}
  31. stride_iterator(const stride_iterator&)=default;
  32. stride_iterator& operator=(const stride_iterator&)=default;
  33. template<
  34. typename NonConstValue,
  35. typename std::enable_if<
  36. std::is_same<Value,const NonConstValue>::value>::type* =nullptr
  37. >
  38. stride_iterator(const stride_iterator<NonConstValue>& x)noexcept:
  39. p{x.p},stride_{x.stride_}{}
  40. template<
  41. typename NonConstValue,
  42. typename std::enable_if<
  43. std::is_same<Value,const NonConstValue>::value>::type* =nullptr
  44. >
  45. stride_iterator& operator=(const stride_iterator<NonConstValue>& x)noexcept
  46. {
  47. p=x.p;stride_=x.stride_;
  48. return *this;
  49. }
  50. /* interoperability with [Derived]Value* */
  51. stride_iterator& operator=(Value* p_)noexcept{p=p_;return *this;}
  52. operator Value*()const noexcept{return p;}
  53. template<
  54. typename DerivedValue,
  55. typename std::enable_if<
  56. std::is_base_of<Value,DerivedValue>::value&&
  57. (std::is_const<Value>::value||!std::is_const<DerivedValue>::value)
  58. >::type* =nullptr
  59. >
  60. explicit stride_iterator(DerivedValue* x)noexcept:
  61. p{x},stride_{sizeof(DerivedValue)}{}
  62. #if BOOST_WORKAROUND(BOOST_GCC_VERSION,>=40900)||\
  63. BOOST_WORKAROUND(BOOST_CLANG,>=1)&&\
  64. (__clang_major__>3 || __clang_major__==3 && __clang_minor__ >= 8)
  65. /* https://github.com/boostorg/poly_collection/issues/15 */
  66. #define BOOST_POLY_COLLECTION_NO_SANITIZE
  67. /* UBSan seems not to be supported in some environments */
  68. #if defined(BOOST_GCC_VERSION)
  69. #pragma GCC diagnostic push
  70. #pragma GCC diagnostic ignored "-Wattributes"
  71. #elif defined(BOOST_CLANG)
  72. #pragma clang diagnostic push
  73. #pragma clang diagnostic ignored "-Wattributes"
  74. #endif
  75. #endif
  76. template<
  77. typename DerivedValue,
  78. typename std::enable_if<
  79. std::is_base_of<Value,DerivedValue>::value&&
  80. (!std::is_const<Value>::value||std::is_const<DerivedValue>::value)
  81. >::type* =nullptr
  82. >
  83. #if defined(BOOST_POLY_COLLECTION_NO_SANITIZE)
  84. __attribute__((no_sanitize("undefined")))
  85. #endif
  86. explicit operator DerivedValue*()const noexcept
  87. {return static_cast<DerivedValue*>(p);}
  88. #if defined(BOOST_POLY_COLLECTION_NO_SANITIZE)
  89. #if defined(BOOST_GCC_VERSION)
  90. #pragma GCC diagnostic pop
  91. #elif defined(BOOST_CLANG)
  92. #pragma clang diagnostic pop
  93. #endif
  94. #undef BOOST_POLY_COLLECTION_NO_SANITIZE
  95. #endif
  96. std::size_t stride()const noexcept{return stride_;}
  97. private:
  98. template<typename>
  99. friend class stride_iterator;
  100. using char_pointer=typename std::conditional<
  101. std::is_const<Value>::value,
  102. const char*,
  103. char*
  104. >::type;
  105. static char_pointer char_ptr(Value* p)noexcept
  106. {return reinterpret_cast<char_pointer>(p);}
  107. static Value* value_ptr(char_pointer p)noexcept
  108. {return reinterpret_cast<Value*>(p);}
  109. friend class boost::iterator_core_access;
  110. Value& dereference()const noexcept{return *p;}
  111. bool equal(const stride_iterator& x)const noexcept{return p==x.p;}
  112. void increment()noexcept{p=value_ptr(char_ptr(p)+stride_);}
  113. void decrement()noexcept{p=value_ptr(char_ptr(p)-stride_);}
  114. template<typename Integral>
  115. void advance(Integral n)noexcept
  116. {p=value_ptr(char_ptr(p)+n*(std::ptrdiff_t)stride_);}
  117. std::ptrdiff_t distance_to(const stride_iterator& x)const noexcept
  118. {return (char_ptr(x.p)-char_ptr(p))/(std::ptrdiff_t)stride_;}
  119. Value* p;
  120. std::size_t stride_;
  121. };
  122. } /* namespace poly_collection::detail */
  123. } /* namespace poly_collection */
  124. } /* namespace boost */
  125. #endif