• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 #include <boost/gil.hpp>
12 #include <boost/mp11.hpp>
13 
14 #include <type_traits>
15 
16 #include "interleaved_ref.hpp"
17 
18 // Example on how to create a pixel iterator
19 
20 namespace boost { namespace gil {
21 
22 // A model of an interleaved pixel iterator. Contains an iterator to the first channel of the current pixel
23 //
24 // Models:
25 //     MutablePixelIteratorConcept
26 //        PixelIteratorConcept
27 //           boost_concepts::RandomAccessTraversalConcept
28 //           PixelBasedConcept
29 //     HomogeneousPixelBasedConcept
30 //        PixelBasedConcept
31 //     ByteAdvanceableConcept
32 //     HasDynamicXStepTypeConcept
33 
34 template <typename ChannelPtr,  // Models Channel Iterator (examples: unsigned char* or const unsigned char*)
35           typename Layout>      // A layout (includes the color space and channel ordering)
36 struct interleaved_ptr : boost::iterator_facade
37     <
38         interleaved_ptr<ChannelPtr, Layout>,
39         pixel<typename std::iterator_traits<ChannelPtr>::value_type, Layout>,
40         boost::random_access_traversal_tag,
41         interleaved_ref<typename std::iterator_traits<ChannelPtr>::reference, Layout> const
42     >
43 {
44 private:
45     using parent_t = boost::iterator_facade
46         <
47             interleaved_ptr<ChannelPtr, Layout>,
48             pixel<typename std::iterator_traits<ChannelPtr>::value_type, Layout>,
49             boost::random_access_traversal_tag,
50             interleaved_ref
51             <
52                 typename std::iterator_traits<ChannelPtr>::reference,
53                 Layout
54             > const
55         >;
56 
57     using channel_t = typename std::iterator_traits<ChannelPtr>::value_type;
58 
59 public:
60     using reference = typename parent_t::reference;
61     using difference_type = typename parent_t::difference_type;
62 
interleaved_ptrboost::gil::interleaved_ptr63     interleaved_ptr() {}
interleaved_ptrboost::gil::interleaved_ptr64     interleaved_ptr(const interleaved_ptr& ptr) : _channels(ptr._channels) {}
interleaved_ptrboost::gil::interleaved_ptr65     template <typename CP> interleaved_ptr(const interleaved_ptr<CP,Layout>& ptr) : _channels(ptr._channels) {}
66 
interleaved_ptrboost::gil::interleaved_ptr67     interleaved_ptr(const ChannelPtr& channels) : _channels(channels) {}
68 
69     // Construct from a pointer to the reference type. Not required by concepts but important
interleaved_ptrboost::gil::interleaved_ptr70     interleaved_ptr(reference* pix) : _channels(&((*pix)[0])) {}
operator =boost::gil::interleaved_ptr71     interleaved_ptr& operator=(reference* pix) { _channels=&((*pix)[0]); return *this; }
72 
73     /// For some reason operator[] provided by boost::iterator_facade returns a custom class that is convertible to reference
74     /// We require our own reference because it is registered in iterator_traits
operator []boost::gil::interleaved_ptr75     reference operator[](difference_type d) const { return memunit_advanced_ref(*this,d*sizeof(channel_t));}
76 
77     // Put this for every iterator whose reference is a proxy type
operator ->boost::gil::interleaved_ptr78     reference operator->()                  const { return **this; }
79 
80     // Channels accessor (not required by any concept)
channelsboost::gil::interleaved_ptr81     const ChannelPtr& channels()            const { return _channels; }
channelsboost::gil::interleaved_ptr82           ChannelPtr& channels()                  { return _channels; }
83 
84     // Not required by concepts but useful
85     static const std::size_t num_channels = mp11::mp_size<typename Layout::color_space_t>::value;
86 private:
87     ChannelPtr _channels;
88     friend class boost::iterator_core_access;
89     template <typename CP, typename L> friend struct interleaved_ptr;
90 
incrementboost::gil::interleaved_ptr91     void increment()            { _channels+=num_channels; }
decrementboost::gil::interleaved_ptr92     void decrement()            { _channels-=num_channels; }
advanceboost::gil::interleaved_ptr93     void advance(std::ptrdiff_t d)   { _channels+=num_channels*d; }
94 
distance_toboost::gil::interleaved_ptr95     std::ptrdiff_t distance_to(const interleaved_ptr& it) const { return (it._channels-_channels)/num_channels; }
equalboost::gil::interleaved_ptr96     bool equal(const interleaved_ptr& it) const { return _channels==it._channels; }
97 
dereferenceboost::gil::interleaved_ptr98     reference dereference() const { return reference(_channels); }
99 };
100 
101 /////////////////////////////
102 //  PixelIteratorConcept
103 /////////////////////////////
104 
105 // 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
106 // 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
107 // iterator_traits::value_type. This is because sometimes multiple reference and pointer types share the same value type. An example of this is
108 // GIL's planar reference and iterator ("planar_pixel_reference" and "planar_pixel_iterator") which share the class "pixel" as the value_type. The
109 // class "pixel" is also the value type for interleaved pixel references. Here we are dealing with channels, not pixels, but the principles still apply.
110 template <typename ChannelPtr, typename Layout>
111 struct const_iterator_type<interleaved_ptr<ChannelPtr,Layout>> {
112 private:
113     using channel_ref_t = typename std::iterator_traits<ChannelPtr>::reference;
114     using channel_const_ptr_t = typename channel_traits<channel_ref_t>::const_pointer;
115 public:
116     using type = interleaved_ptr<channel_const_ptr_t, Layout>;
117 };
118 
119 template <typename ChannelPtr, typename Layout>
120 struct iterator_is_mutable<interleaved_ptr<ChannelPtr,Layout>> : std::true_type {};
121 template <typename Channel, typename Layout>
122 struct iterator_is_mutable<interleaved_ptr<const Channel*,Layout>> : std::false_type {};
123 
124 template <typename ChannelPtr, typename Layout>
125 struct is_iterator_adaptor<interleaved_ptr<ChannelPtr,Layout>> : std::false_type {};
126 
127 /////////////////////////////
128 //  PixelBasedConcept
129 /////////////////////////////
130 
131 template <typename ChannelPtr, typename Layout>
132 struct color_space_type<interleaved_ptr<ChannelPtr,Layout>>
133 {
134     using type = typename Layout::color_space_t;
135 };
136 
137 template <typename ChannelPtr, typename Layout>
138 struct channel_mapping_type<interleaved_ptr<ChannelPtr,Layout>>
139 {
140     using type = typename Layout::channel_mapping_t;
141 };
142 
143 template <typename ChannelPtr, typename Layout>
144 struct is_planar<interleaved_ptr<ChannelPtr,Layout>> : std::false_type {};
145 
146 /////////////////////////////
147 //  HomogeneousPixelBasedConcept
148 /////////////////////////////
149 
150 template <typename ChannelPtr, typename Layout>
151 struct channel_type<interleaved_ptr<ChannelPtr, Layout>>
152 {
153     using type = typename std::iterator_traits<ChannelPtr>::value_type;
154 };
155 
156 /////////////////////////////
157 //  ByteAdvanceableConcept
158 /////////////////////////////
159 
160 template <typename ChannelPtr, typename Layout>
memunit_step(const interleaved_ptr<ChannelPtr,Layout> &)161 inline std::ptrdiff_t memunit_step(const interleaved_ptr<ChannelPtr,Layout>&) {
162     return sizeof(typename std::iterator_traits<ChannelPtr>::value_type)*   // size of each channel in bytes
163            interleaved_ptr<ChannelPtr,Layout>::num_channels;                // times the number of channels
164 }
165 
166 template <typename ChannelPtr, typename Layout>
memunit_distance(const interleaved_ptr<ChannelPtr,Layout> & p1,const interleaved_ptr<ChannelPtr,Layout> & p2)167 inline std::ptrdiff_t memunit_distance(const interleaved_ptr<ChannelPtr,Layout>& p1, const interleaved_ptr<ChannelPtr,Layout>& p2) {
168     return memunit_distance(p1.channels(),p2.channels());
169 }
170 
171 template <typename ChannelPtr, typename Layout>
memunit_advance(interleaved_ptr<ChannelPtr,Layout> & p,std::ptrdiff_t diff)172 inline void memunit_advance(interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
173     memunit_advance(p.channels(), diff);
174 }
175 
176 template <typename ChannelPtr, typename Layout>
memunit_advanced(const interleaved_ptr<ChannelPtr,Layout> & p,std::ptrdiff_t diff)177 inline interleaved_ptr<ChannelPtr,Layout> memunit_advanced(const interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
178     interleaved_ptr<ChannelPtr,Layout> ret=p;
179     memunit_advance(ret, diff);
180     return ret;
181 }
182 
183 template <typename ChannelPtr, typename Layout>
memunit_advanced_ref(const interleaved_ptr<ChannelPtr,Layout> & p,std::ptrdiff_t diff)184 inline typename interleaved_ptr<ChannelPtr,Layout>::reference memunit_advanced_ref(const interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
185     interleaved_ptr<ChannelPtr,Layout> ret=p;
186     memunit_advance(ret, diff);
187     return *ret;
188 }
189 
190 /////////////////////////////
191 //  HasDynamicXStepTypeConcept
192 /////////////////////////////
193 
194 template <typename ChannelPtr, typename Layout>
195 struct dynamic_x_step_type<interleaved_ptr<ChannelPtr, Layout>>
196 {
197     using type = memory_based_step_iterator<interleaved_ptr<ChannelPtr, Layout>>;
198 };
199 } }  // namespace boost::gil
200 
201 #endif
202