interleaved_ptr.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_EXAMPLE_INTERLEAVED_PTR_HPP
  9. #define BOOST_GIL_EXAMPLE_INTERLEAVED_PTR_HPP
  10. #include <boost/gil.hpp>
  11. #include <boost/mp11.hpp>
  12. #include <type_traits>
  13. #include "interleaved_ref.hpp"
  14. // Example on how to create a pixel iterator
  15. namespace boost { namespace gil {
  16. // A model of an interleaved pixel iterator. Contains an iterator to the first channel of the current pixel
  17. //
  18. // Models:
  19. // MutablePixelIteratorConcept
  20. // PixelIteratorConcept
  21. // boost_concepts::RandomAccessTraversalConcept
  22. // PixelBasedConcept
  23. // HomogeneousPixelBasedConcept
  24. // PixelBasedConcept
  25. // ByteAdvanceableConcept
  26. // HasDynamicXStepTypeConcept
  27. template <typename ChannelPtr, // Models Channel Iterator (examples: unsigned char* or const unsigned char*)
  28. typename Layout> // A layout (includes the color space and channel ordering)
  29. struct interleaved_ptr : boost::iterator_facade
  30. <
  31. interleaved_ptr<ChannelPtr, Layout>,
  32. pixel<typename std::iterator_traits<ChannelPtr>::value_type, Layout>,
  33. boost::random_access_traversal_tag,
  34. interleaved_ref<typename std::iterator_traits<ChannelPtr>::reference, Layout> const
  35. >
  36. {
  37. private:
  38. using parent_t = boost::iterator_facade
  39. <
  40. interleaved_ptr<ChannelPtr, Layout>,
  41. pixel<typename std::iterator_traits<ChannelPtr>::value_type, Layout>,
  42. boost::random_access_traversal_tag,
  43. interleaved_ref
  44. <
  45. typename std::iterator_traits<ChannelPtr>::reference,
  46. Layout
  47. > const
  48. >;
  49. using channel_t = typename std::iterator_traits<ChannelPtr>::value_type;
  50. public:
  51. using reference = typename parent_t::reference;
  52. using difference_type = typename parent_t::difference_type;
  53. interleaved_ptr() {}
  54. interleaved_ptr(const interleaved_ptr& ptr) : _channels(ptr._channels) {}
  55. template <typename CP> interleaved_ptr(const interleaved_ptr<CP,Layout>& ptr) : _channels(ptr._channels) {}
  56. interleaved_ptr(const ChannelPtr& channels) : _channels(channels) {}
  57. // Construct from a pointer to the reference type. Not required by concepts but important
  58. interleaved_ptr(reference* pix) : _channels(&((*pix)[0])) {}
  59. interleaved_ptr& operator=(reference* pix) { _channels=&((*pix)[0]); return *this; }
  60. /// For some reason operator[] provided by boost::iterator_facade returns a custom class that is convertible to reference
  61. /// We require our own reference because it is registered in iterator_traits
  62. reference operator[](difference_type d) const { return memunit_advanced_ref(*this,d*sizeof(channel_t));}
  63. // Put this for every iterator whose reference is a proxy type
  64. reference operator->() const { return **this; }
  65. // Channels accessor (not required by any concept)
  66. const ChannelPtr& channels() const { return _channels; }
  67. ChannelPtr& channels() { return _channels; }
  68. // Not required by concepts but useful
  69. static const std::size_t num_channels = mp11::mp_size<typename Layout::color_space_t>::value;
  70. private:
  71. ChannelPtr _channels;
  72. friend class boost::iterator_core_access;
  73. template <typename CP, typename L> friend struct interleaved_ptr;
  74. void increment() { _channels+=num_channels; }
  75. void decrement() { _channels-=num_channels; }
  76. void advance(std::ptrdiff_t d) { _channels+=num_channels*d; }
  77. std::ptrdiff_t distance_to(const interleaved_ptr& it) const { return (it._channels-_channels)/num_channels; }
  78. bool equal(const interleaved_ptr& it) const { return _channels==it._channels; }
  79. reference dereference() const { return reference(_channels); }
  80. };
  81. /////////////////////////////
  82. // PixelIteratorConcept
  83. /////////////////////////////
  84. // To get from the channel pointer a channel pointer to const, we have to go through the channel traits, which take a model of channel
  85. // So we can get a model of channel from the channel pointer via iterator_traits. Notice that we take the iterator_traits::reference and not
  86. // iterator_traits::value_type. This is because sometimes multiple reference and pointer types share the same value type. An example of this is
  87. // GIL's planar reference and iterator ("planar_pixel_reference" and "planar_pixel_iterator") which share the class "pixel" as the value_type. The
  88. // class "pixel" is also the value type for interleaved pixel references. Here we are dealing with channels, not pixels, but the principles still apply.
  89. template <typename ChannelPtr, typename Layout>
  90. struct const_iterator_type<interleaved_ptr<ChannelPtr,Layout>> {
  91. private:
  92. using channel_ref_t = typename std::iterator_traits<ChannelPtr>::reference;
  93. using channel_const_ptr_t = typename channel_traits<channel_ref_t>::const_pointer;
  94. public:
  95. using type = interleaved_ptr<channel_const_ptr_t, Layout>;
  96. };
  97. template <typename ChannelPtr, typename Layout>
  98. struct iterator_is_mutable<interleaved_ptr<ChannelPtr,Layout>> : std::true_type {};
  99. template <typename Channel, typename Layout>
  100. struct iterator_is_mutable<interleaved_ptr<const Channel*,Layout>> : std::false_type {};
  101. template <typename ChannelPtr, typename Layout>
  102. struct is_iterator_adaptor<interleaved_ptr<ChannelPtr,Layout>> : std::false_type {};
  103. /////////////////////////////
  104. // PixelBasedConcept
  105. /////////////////////////////
  106. template <typename ChannelPtr, typename Layout>
  107. struct color_space_type<interleaved_ptr<ChannelPtr,Layout>>
  108. {
  109. using type = typename Layout::color_space_t;
  110. };
  111. template <typename ChannelPtr, typename Layout>
  112. struct channel_mapping_type<interleaved_ptr<ChannelPtr,Layout>>
  113. {
  114. using type = typename Layout::channel_mapping_t;
  115. };
  116. template <typename ChannelPtr, typename Layout>
  117. struct is_planar<interleaved_ptr<ChannelPtr,Layout>> : std::false_type {};
  118. /////////////////////////////
  119. // HomogeneousPixelBasedConcept
  120. /////////////////////////////
  121. template <typename ChannelPtr, typename Layout>
  122. struct channel_type<interleaved_ptr<ChannelPtr, Layout>>
  123. {
  124. using type = typename std::iterator_traits<ChannelPtr>::value_type;
  125. };
  126. /////////////////////////////
  127. // ByteAdvanceableConcept
  128. /////////////////////////////
  129. template <typename ChannelPtr, typename Layout>
  130. inline std::ptrdiff_t memunit_step(const interleaved_ptr<ChannelPtr,Layout>&) {
  131. return sizeof(typename std::iterator_traits<ChannelPtr>::value_type)* // size of each channel in bytes
  132. interleaved_ptr<ChannelPtr,Layout>::num_channels; // times the number of channels
  133. }
  134. template <typename ChannelPtr, typename Layout>
  135. inline std::ptrdiff_t memunit_distance(const interleaved_ptr<ChannelPtr,Layout>& p1, const interleaved_ptr<ChannelPtr,Layout>& p2) {
  136. return memunit_distance(p1.channels(),p2.channels());
  137. }
  138. template <typename ChannelPtr, typename Layout>
  139. inline void memunit_advance(interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
  140. memunit_advance(p.channels(), diff);
  141. }
  142. template <typename ChannelPtr, typename Layout>
  143. inline interleaved_ptr<ChannelPtr,Layout> memunit_advanced(const interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
  144. interleaved_ptr<ChannelPtr,Layout> ret=p;
  145. memunit_advance(ret, diff);
  146. return ret;
  147. }
  148. template <typename ChannelPtr, typename Layout>
  149. inline typename interleaved_ptr<ChannelPtr,Layout>::reference memunit_advanced_ref(const interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
  150. interleaved_ptr<ChannelPtr,Layout> ret=p;
  151. memunit_advance(ret, diff);
  152. return *ret;
  153. }
  154. /////////////////////////////
  155. // HasDynamicXStepTypeConcept
  156. /////////////////////////////
  157. template <typename ChannelPtr, typename Layout>
  158. struct dynamic_x_step_type<interleaved_ptr<ChannelPtr, Layout>>
  159. {
  160. using type = memory_based_step_iterator<interleaved_ptr<ChannelPtr, Layout>>;
  161. };
  162. } } // namespace boost::gil
  163. #endif