1 /*
2     Copyright 2005-2007 Adobe Systems Incorporated
3 
4     Use, modification and distribution are subject to the Boost Software License,
5     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6     http://www.boost.org/LICENSE_1_0.txt).
7 
8     See http://opensource.adobe.com/gil for most recent version including documentation.
9 */
10 // channel.cpp : Tests channel
11 //
12 
13 #include <exception>
14 #include <boost/gil/gil_config.hpp>
15 #include <boost/gil/channel_algorithm.hpp>
16 #include <boost/gil/gil_concept.hpp>
17 
18 using namespace boost::gil;
19 using namespace std;
20 
21 void error_if(bool);
22 
23 bits8   c8_min   =  channel_traits<bits8  >::min_value();
24 bits8   c8_max   =  channel_traits<bits8  >::max_value();
25 bits8s  c8s_min  =  channel_traits<bits8s >::min_value();
26 bits8s  c8s_max  =  channel_traits<bits8s >::max_value();
27 bits16  c16_min  =  channel_traits<bits16 >::min_value();
28 bits16  c16_max  =  channel_traits<bits16 >::max_value();
29 bits16s c16s_min =  channel_traits<bits16s>::min_value();
30 bits16s c16s_max =  channel_traits<bits16s>::max_value();
31 bits32  c32_min  =  channel_traits<bits32 >::min_value();
32 bits32  c32_max  =  channel_traits<bits32 >::max_value();
33 bits32s c32s_min =  channel_traits<bits32s>::min_value();
34 bits32s c32s_max =  channel_traits<bits32s>::max_value();
35 bits32f c32f_min =  channel_traits<bits32f>::min_value();
36 bits32f c32f_max =  channel_traits<bits32f>::max_value();
37 
38 
39 template <typename ChannelTestCore>
40 struct do_test : public ChannelTestCore {
41     typedef typename ChannelTestCore::channel_t channel_t;
42     typedef typename channel_traits<channel_t>::value_type channel_value_t;
43 
do_testdo_test44     do_test() : ChannelTestCore() {
45         error_if(this->_min_v != channel_traits<channel_t>::min_value());
46         error_if(this->_max_v != channel_traits<channel_t>::max_value());
47     }
48 
test_alldo_test49     void test_all() {
50         test_channel_invert();
51         test_channel_convert();
52         test_channel_multiply();
53         test_channel_math();
54     }
55 
test_mutabledo_test56     void test_mutable(boost::mpl::false_) {}
test_mutabledo_test57     void test_mutable(boost::mpl::true_) {
58         channel_value_t mv=this->_min_v;
59         ++this->_min_v; this->_min_v++;
60         --this->_min_v; this->_min_v--;
61         error_if(mv!=this->_min_v);
62 
63         this->_min_v+=1;
64         this->_min_v-=1;
65         error_if(mv!=this->_min_v);
66 
67         this->_min_v*=1;
68         this->_min_v/=1;
69         error_if(mv!=this->_min_v);
70 
71          this->_min_v = 1;    // assignable to scalar
72          this->_min_v = mv;   // and to value type
73 
74          // test swap
75          channel_value_t v1=this->_min_v;
76          channel_value_t v2=this->_max_v;
77          swap(this->_min_v, this->_max_v);
78 
79          channel_value_t v3=this->_min_v;
80          channel_value_t v4=this->_max_v;
81          error_if(v1!=v4 || v2!=v3);
82     }
83 
test_channel_mathdo_test84     void test_channel_math() {
85         error_if(this->_min_v >= this->_max_v);
86         error_if(this->_max_v <= this->_min_v);
87         error_if(this->_min_v > this->_max_v);
88         error_if(this->_max_v < this->_min_v);
89         error_if(this->_max_v == this->_min_v);
90         error_if(!(this->_max_v != this->_min_v));
91 
92         error_if(this->_min_v * 1 != this->_min_v);
93         error_if(this->_min_v / 1 != this->_min_v);
94 
95         error_if((this->_min_v + 1) + 1 != (this->_min_v + 2));
96         error_if((this->_max_v - 1) - 1 != (this->_max_v - 2));
97 
98         error_if(this->_min_v != 1 && this->_min_v==1);  // comparable to integral
99 
100 
101         test_mutable(boost::mpl::bool_<channel_traits<channel_t>::is_mutable>());
102     }
103 
104 
test_channel_invertdo_test105     void test_channel_invert() {
106         error_if(channel_invert(this->_min_v) != this->_max_v);
107         error_if(channel_invert(this->_max_v) != this->_min_v);
108     }
109 
test_channel_multiplydo_test110     void test_channel_multiply() {
111         error_if(channel_multiply(this->_min_v, this->_min_v) != this->_min_v);
112         error_if(channel_multiply(this->_max_v, this->_max_v) != this->_max_v);
113         error_if(channel_multiply(this->_max_v, this->_min_v) != this->_min_v);
114     }
115 
test_channel_convertdo_test116     void test_channel_convert() {
117         channel_value_t  v_min, v_max;
118 
119         v_min=channel_convert<channel_t>(c8_min);
120         v_max=channel_convert<channel_t>(c8_max);
121         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
122 
123         v_min=channel_convert<channel_t>(c8s_min);
124         v_max=channel_convert<channel_t>(c8s_max);
125         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
126 
127         v_min=channel_convert<channel_t>(c16_min);
128         v_max=channel_convert<channel_t>(c16_max);
129         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
130 
131         v_min=channel_convert<channel_t>(c16s_min);
132         v_max=channel_convert<channel_t>(c16s_max);
133         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
134 
135         v_min=channel_convert<channel_t>(c32_min);
136         v_max=channel_convert<channel_t>(c32_max);
137         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
138 
139         v_min=channel_convert<channel_t>(c32s_min);
140         v_max=channel_convert<channel_t>(c32s_max);
141         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
142 
143         v_min=channel_convert<channel_t>(c32f_min);
144         v_max=channel_convert<channel_t>(c32f_max);
145         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
146     }
147 };
148 
149 // Different core classes depending on the different types of channels - channel values, references and subbyte references
150 // The cores ensure there are two members, _min_v and _max_v initialized with the minimum and maximum channel value.
151 // The different channel types have different ways to initialize them, thus require different cores
152 
153 // For channel values simply initialize the value directly
154 template <typename ChannelValue>
155 class value_core {
156 protected:
157     typedef ChannelValue channel_t;
158     channel_t _min_v, _max_v;
159 
value_core()160     value_core() : _min_v(channel_traits<ChannelValue>::min_value()), _max_v(channel_traits<ChannelValue>::max_value()) {
161         boost::function_requires<ChannelValueConcept<ChannelValue> >();
162     }
163 };
164 
165 // For channel references we need to have separate channel values
166 template <typename ChannelRef>
167 class reference_core : public value_core<typename channel_traits<ChannelRef>::value_type> {
168     typedef value_core<typename channel_traits<ChannelRef>::value_type> parent_t;
169 protected:
170     typedef ChannelRef channel_t;
171     channel_t _min_v, _max_v;
172 
reference_core()173     reference_core() : parent_t(), _min_v(parent_t::_min_v), _max_v(parent_t::_max_v) {
174         boost::function_requires<ChannelConcept<ChannelRef> >();
175     }
176 };
177 
178 // For subbyte channel references we need to store the bit buffers somewhere
179 template <typename ChannelSubbyteRef, typename ChannelMutableRef = ChannelSubbyteRef>
180 class packed_reference_core {
181 protected:
182     typedef ChannelSubbyteRef channel_t;
183     typedef typename channel_t::integer_t integer_t;
184     channel_t _min_v, _max_v;
185 
186     integer_t _min_buf, _max_buf;
187 
packed_reference_core()188     packed_reference_core() : _min_v(&_min_buf), _max_v(&_max_buf) {
189         ChannelMutableRef b1(&_min_buf), b2(&_max_buf);
190         b1 = channel_traits<channel_t>::min_value();
191         b2 = channel_traits<channel_t>::max_value();
192 
193         boost::function_requires<ChannelConcept<ChannelSubbyteRef> >();
194     }
195 };
196 
197 template <typename ChannelSubbyteRef, typename ChannelMutableRef = ChannelSubbyteRef>
198 class packed_dynamic_reference_core {
199 protected:
200     typedef ChannelSubbyteRef channel_t;
201     channel_t _min_v, _max_v;
202 
203     typename channel_t::integer_t _min_buf, _max_buf;
204 
packed_dynamic_reference_core(int first_bit1=1,int first_bit2=2)205     packed_dynamic_reference_core(int first_bit1=1, int first_bit2=2) : _min_v(&_min_buf,first_bit1), _max_v(&_max_buf,first_bit2) {
206         ChannelMutableRef b1(&_min_buf,1), b2(&_max_buf,2);
207         b1 = channel_traits<channel_t>::min_value();
208         b2 = channel_traits<channel_t>::max_value();
209 
210         boost::function_requires<ChannelConcept<ChannelSubbyteRef> >();
211     }
212 };
213 
214 
215 template <typename ChannelValue>
test_channel_value()216 void test_channel_value() {
217     do_test<value_core<ChannelValue> >().test_all();
218 }
219 
220 template <typename ChannelRef>
test_channel_reference()221 void test_channel_reference() {
222     do_test<reference_core<ChannelRef> >().test_all();
223 }
224 
225 template <typename ChannelSubbyteRef>
test_packed_channel_reference()226 void test_packed_channel_reference() {
227     do_test<packed_reference_core<ChannelSubbyteRef,ChannelSubbyteRef> >().test_all();
228 }
229 
230 template <typename ChannelSubbyteRef, typename MutableRef>
test_const_packed_channel_reference()231 void test_const_packed_channel_reference() {
232     do_test<packed_reference_core<ChannelSubbyteRef,MutableRef> >().test_all();
233 }
234 
235 template <typename ChannelSubbyteRef>
test_packed_dynamic_channel_reference()236 void test_packed_dynamic_channel_reference() {
237     do_test<packed_dynamic_reference_core<ChannelSubbyteRef,ChannelSubbyteRef> >().test_all();
238 }
239 
240 template <typename ChannelSubbyteRef, typename MutableRef>
test_const_packed_dynamic_channel_reference()241 void test_const_packed_dynamic_channel_reference() {
242     do_test<packed_dynamic_reference_core<ChannelSubbyteRef,MutableRef> >().test_all();
243 }
244 
245 template <typename ChannelValue>
test_channel_value_impl()246 void test_channel_value_impl() {
247     test_channel_value<ChannelValue>();
248     test_channel_reference<ChannelValue&>();
249     test_channel_reference<const ChannelValue&>();
250 }
251 
252 /////////////////////////////////////////////////////////
253 ///
254 /// A channel archetype - to test the minimum requirements of the concept
255 ///
256 /////////////////////////////////////////////////////////
257 
258 struct channel_value_archetype;
259 struct channel_archetype {
260     // equality comparable
operator ==(const channel_archetype &,const channel_archetype &)261     friend bool operator==(const channel_archetype&,const channel_archetype&) { return true; }
operator !=(const channel_archetype &,const channel_archetype &)262     friend bool operator!=(const channel_archetype&,const channel_archetype&) { return false; }
263     // less-than comparable
operator <(const channel_archetype &,const channel_archetype &)264     friend bool operator<(const channel_archetype&,const channel_archetype&) { return false; }
265     // convertible to a scalar
operator bits8channel_archetype266     operator bits8() const { return 0; }
267 
268 
operator ++channel_archetype269     channel_archetype& operator++() { return *this; }
operator --channel_archetype270     channel_archetype& operator--() { return *this; }
operator ++channel_archetype271     channel_archetype  operator++(int) { return *this; }
operator --channel_archetype272     channel_archetype  operator--(int) { return *this; }
273 
operator +=channel_archetype274     template <typename Scalar> channel_archetype operator+=(Scalar) { return *this; }
operator -=channel_archetype275     template <typename Scalar> channel_archetype operator-=(Scalar) { return *this; }
operator *=channel_archetype276     template <typename Scalar> channel_archetype operator*=(Scalar) { return *this; }
operator /=channel_archetype277     template <typename Scalar> channel_archetype operator/=(Scalar) { return *this; }
278 
279     typedef channel_value_archetype         value_type;
280     typedef channel_archetype               reference;
281     typedef const channel_archetype         const_reference;
282     typedef channel_value_archetype*        pointer;
283     typedef const channel_value_archetype*  const_pointer;
284     BOOST_STATIC_CONSTANT(bool, is_mutable=true);
285 
286     static value_type min_value();
287     static value_type max_value();
288 };
289 
290 
291 struct channel_value_archetype : public channel_archetype {
channel_value_archetypechannel_value_archetype292     channel_value_archetype() {}                                        // default constructible
channel_value_archetypechannel_value_archetype293     channel_value_archetype(const channel_value_archetype&) {}          // copy constructible
operator =channel_value_archetype294     channel_value_archetype& operator=(const channel_value_archetype&){return *this;} // assignable
channel_value_archetypechannel_value_archetype295     channel_value_archetype(bits8) {}
296 };
297 
min_value()298 channel_value_archetype channel_archetype::min_value() { return channel_value_archetype(); }
max_value()299 channel_value_archetype channel_archetype::max_value() { return channel_value_archetype(); }
300 
301 
test_packed_channel_reference()302 void test_packed_channel_reference() {
303     typedef packed_channel_reference<boost::uint16_t, 0,5,true> channel16_0_5_reference_t;
304     typedef packed_channel_reference<boost::uint16_t, 5,6,true> channel16_5_6_reference_t;
305     typedef packed_channel_reference<boost::uint16_t, 11,5,true> channel16_11_5_reference_t;
306 
307     boost::uint16_t data=0;
308     channel16_0_5_reference_t   channel1(&data);
309     channel16_5_6_reference_t   channel2(&data);
310     channel16_11_5_reference_t  channel3(&data);
311 
312     channel1=channel_traits<channel16_0_5_reference_t>::max_value();
313     channel2=channel_traits<channel16_5_6_reference_t>::max_value();
314     channel3=channel_traits<channel16_11_5_reference_t>::max_value();
315     error_if(data!=65535);
316 
317     test_packed_channel_reference<channel16_0_5_reference_t>();
318     test_packed_channel_reference<channel16_5_6_reference_t>();
319     test_packed_channel_reference<channel16_11_5_reference_t>();
320 }
321 
test_packed_dynamic_channel_reference()322 void test_packed_dynamic_channel_reference() {
323     typedef packed_dynamic_channel_reference<boost::uint16_t,5,true> channel16_5_reference_t;
324     typedef packed_dynamic_channel_reference<boost::uint16_t,6,true> channel16_6_reference_t;
325 
326     boost::uint16_t data=0;
327     channel16_5_reference_t  channel1(&data,0);
328     channel16_6_reference_t  channel2(&data,5);
329     channel16_5_reference_t  channel3(&data,11);
330 
331     channel1=channel_traits<channel16_5_reference_t>::max_value();
332     channel2=channel_traits<channel16_6_reference_t>::max_value();
333     channel3=channel_traits<channel16_5_reference_t>::max_value();
334     error_if(data!=65535);
335 
336     test_packed_dynamic_channel_reference<channel16_5_reference_t>();
337 }
338 
test_channel()339 void test_channel() {
340     test_channel_value_impl<bits8>();
341     test_channel_value_impl<bits8s>();
342     test_channel_value_impl<bits16>();
343     test_channel_value_impl<bits16s>();
344     test_channel_value_impl<bits32>();
345     test_channel_value_impl<bits32s>();
346 
347     test_channel_value_impl<bits32f>();
348 
349     test_packed_channel_reference();
350     test_packed_dynamic_channel_reference();
351 
352     // Do only compile-time tests for the archetype (because asserts like val1<val2 fail)
353     boost::function_requires<MutableChannelConcept<channel_archetype> >();
354 
355     do_test<value_core<channel_value_archetype> >();
356     do_test<reference_core<channel_archetype> >();
357     do_test<reference_core<const channel_archetype&> >();
358 }
359 
main(int argc,char * argv[])360 int main(int argc, char* argv[]) {
361     test_channel();
362     return 0;
363 }
364 
365 // TODO:
366 // - provide algorithm performance overloads for scoped channel and packed channels
367 // - Update concepts and documentation
368 // - What to do about pointer types?!
369 // - Performance!!
370 //      - is channel_convert the same as native?
371 //      - is operator++ on bits32f the same as native? How about if operator++ is defined in scoped_channel to do _value++?
372 
373