• 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 #include <boost/gil/channel.hpp>
9 #include <boost/gil/channel_algorithm.hpp>
10 #include <boost/gil/typedefs.hpp>
11 
12 #include <cstdint>
13 #include <exception>
14 #include <iostream>
15 #include <type_traits>
16 
17 #if defined(BOOST_CLANG)
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wfloat-equal"
20 #elif BOOST_GCC >= 40700
21 #pragma GCC diagnostic push
22 #pragma GCC diagnostic ignored "-Wfloat-equal"
23 #elif BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
24 #pragma warning(push)
25 #pragma warning(disable:4512) //assignment operator could not be generated
26 #endif
27 
28 using namespace boost::gil;
29 using namespace std;
30 
31 void error_if(bool);
32 
33 auto c8_min   = channel_traits<uint8_t>::min_value();
34 auto c8_max   = channel_traits<uint8_t>::max_value();
35 auto c8s_min  = channel_traits<int8_t>::min_value();
36 auto c8s_max  = channel_traits<int8_t>::max_value();
37 auto c16_min  = channel_traits<uint16_t>::min_value();
38 auto c16_max  = channel_traits<uint16_t>::max_value();
39 auto c16s_min = channel_traits<int16_t>::min_value();
40 auto c16s_max = channel_traits<int16_t>::max_value();
41 auto c32_min  = channel_traits<uint32_t>::min_value();
42 auto c32_max  = channel_traits<uint32_t>::max_value();
43 auto c32s_min = channel_traits<int32_t>::min_value();
44 auto c32s_max = channel_traits<int32_t>::max_value();
45 auto c32f_min = channel_traits<float32_t>::min_value();
46 auto c32f_max = channel_traits<float32_t>::max_value();
47 
48 
49 template <typename ChannelTestCore>
50 struct do_test : public ChannelTestCore {
51     using channel_t = typename ChannelTestCore::channel_t;
52     using channel_value_t = typename channel_traits<channel_t>::value_type;
53 
do_testdo_test54     do_test() : ChannelTestCore() {
55         error_if(this->_min_v != channel_traits<channel_t>::min_value());
56         error_if(this->_max_v != channel_traits<channel_t>::max_value());
57     }
58 
test_alldo_test59     void test_all() {
60         test_channel_invert();
61         test_channel_convert();
62         test_channel_multiply();
63         test_channel_math();
64     }
65 
test_mutabledo_test66     void test_mutable(std::false_type) {}
test_mutabledo_test67     void test_mutable(std::true_type) {
68         channel_value_t mv=this->_min_v;
69         ++this->_min_v; this->_min_v++;
70         --this->_min_v; this->_min_v--;
71         error_if(mv!=this->_min_v);
72 
73         this->_min_v+=1;
74         this->_min_v-=1;
75         error_if(mv!=this->_min_v);
76 
77         this->_min_v*=1;
78         this->_min_v/=1;
79         error_if(mv!=this->_min_v);
80 
81          this->_min_v = 1;    // assignable to scalar
82          this->_min_v = mv;   // and to value type
83 
84          // test swap
85          channel_value_t v1=this->_min_v;
86          channel_value_t v2=this->_max_v;
87          swap(this->_min_v, this->_max_v);
88 
89          channel_value_t v3=this->_min_v;
90          channel_value_t v4=this->_max_v;
91          error_if(v1!=v4 || v2!=v3);
92     }
93 
test_channel_mathdo_test94     void test_channel_math() {
95         error_if(this->_min_v >= this->_max_v);
96         error_if(this->_max_v <= this->_min_v);
97         error_if(this->_min_v > this->_max_v);
98         error_if(this->_max_v < this->_min_v);
99         error_if(this->_max_v == this->_min_v);
100         error_if(!(this->_max_v != this->_min_v));
101 
102         error_if(this->_min_v * 1 != this->_min_v);
103         error_if(this->_min_v / 1 != this->_min_v);
104 
105         error_if((this->_min_v + 1) + 1 != (this->_min_v + 2));
106         error_if((this->_max_v - 1) - 1 != (this->_max_v - 2));
107 
108         error_if(this->_min_v != 1 && this->_min_v==1);  // comparable to integral
109 
110 
111         test_mutable(std::integral_constant<bool, channel_traits<channel_t>::is_mutable>());
112     }
113 
114 
test_channel_invertdo_test115     void test_channel_invert() {
116         error_if(channel_invert(this->_min_v) != this->_max_v);
117         error_if(channel_invert(this->_max_v) != this->_min_v);
118     }
119 
test_channel_multiplydo_test120     void test_channel_multiply() {
121         error_if(channel_multiply(this->_min_v, this->_min_v) != this->_min_v);
122         error_if(channel_multiply(this->_max_v, this->_max_v) != this->_max_v);
123         error_if(channel_multiply(this->_max_v, this->_min_v) != this->_min_v);
124     }
125 
test_channel_convertdo_test126     void test_channel_convert() {
127         channel_value_t  v_min, v_max;
128 
129         v_min=channel_convert<channel_t>(c8_min);
130         v_max=channel_convert<channel_t>(c8_max);
131         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
132 
133         v_min=channel_convert<channel_t>(c8s_min);
134         v_max=channel_convert<channel_t>(c8s_max);
135         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
136 
137         v_min=channel_convert<channel_t>(c16_min);
138         v_max=channel_convert<channel_t>(c16_max);
139         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
140 
141         v_min=channel_convert<channel_t>(c16s_min);
142         v_max=channel_convert<channel_t>(c16s_max);
143         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
144 
145         v_min=channel_convert<channel_t>(c32_min);
146         v_max=channel_convert<channel_t>(c32_max);
147         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
148 
149         v_min=channel_convert<channel_t>(c32s_min);
150         v_max=channel_convert<channel_t>(c32s_max);
151         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
152 
153         v_min=channel_convert<channel_t>(c32f_min);
154         v_max=channel_convert<channel_t>(c32f_max);
155         error_if(v_min!=this->_min_v || v_max!=this->_max_v);
156     }
157 };
158 
159 // Different core classes depending on the different types of channels - channel values, references and subbyte references
160 // The cores ensure there are two members, _min_v and _max_v initialized with the minimum and maximum channel value.
161 // The different channel types have different ways to initialize them, thus require different cores
162 
163 // For channel values simply initialize the value directly
164 template <typename ChannelValue>
165 class value_core {
166 protected:
167     using channel_t = ChannelValue;
168     channel_t _min_v;
169     channel_t _max_v;
170 
value_core()171     value_core()
172         : _min_v(channel_traits<ChannelValue>::min_value())
173         , _max_v(channel_traits<ChannelValue>::max_value())
174     {
175         boost::function_requires<ChannelValueConcept<ChannelValue> >();
176     }
177 };
178 
179 // For channel references we need to have separate channel values
180 template <typename ChannelRef>
181 class reference_core : public value_core<typename channel_traits<ChannelRef>::value_type>
182 {
183     using parent_t = value_core<typename channel_traits<ChannelRef>::value_type>;
184 
185 protected:
186     using channel_t = ChannelRef;
187     channel_t _min_v;
188     channel_t _max_v;
189 
reference_core()190     reference_core()
191         : parent_t()
192         , _min_v(parent_t::_min_v)
193         , _max_v(parent_t::_max_v)
194     {
195         boost::function_requires<ChannelConcept<ChannelRef> >();
196     }
197 };
198 
199 // For subbyte channel references we need to store the bit buffers somewhere
200 template <typename ChannelSubbyteRef, typename ChannelMutableRef = ChannelSubbyteRef>
201 class packed_reference_core {
202 protected:
203     using channel_t = ChannelSubbyteRef;
204     using integer_t = typename channel_t::integer_t;
205     channel_t _min_v, _max_v;
206 
207     integer_t _min_buf, _max_buf;
208 
packed_reference_core()209     packed_reference_core() : _min_v(&_min_buf), _max_v(&_max_buf) {
210         ChannelMutableRef b1(&_min_buf), b2(&_max_buf);
211         b1 = channel_traits<channel_t>::min_value();
212         b2 = channel_traits<channel_t>::max_value();
213 
214         boost::function_requires<ChannelConcept<ChannelSubbyteRef> >();
215     }
216 };
217 
218 template <typename ChannelSubbyteRef, typename ChannelMutableRef = ChannelSubbyteRef>
219 class packed_dynamic_reference_core {
220 protected:
221     using channel_t = ChannelSubbyteRef;
222     channel_t _min_v, _max_v;
223 
224     typename channel_t::integer_t _min_buf, _max_buf;
225 
packed_dynamic_reference_core(int first_bit1=1,int first_bit2=2)226     packed_dynamic_reference_core(int first_bit1=1, int first_bit2=2) : _min_v(&_min_buf,first_bit1), _max_v(&_max_buf,first_bit2) {
227         ChannelMutableRef b1(&_min_buf,1), b2(&_max_buf,2);
228         b1 = channel_traits<channel_t>::min_value();
229         b2 = channel_traits<channel_t>::max_value();
230 
231         boost::function_requires<ChannelConcept<ChannelSubbyteRef> >();
232     }
233 };
234 
235 
236 template <typename ChannelValue>
test_channel_value()237 void test_channel_value() {
238     do_test<value_core<ChannelValue> >().test_all();
239 }
240 
241 template <typename ChannelRef>
test_channel_reference()242 void test_channel_reference() {
243     do_test<reference_core<ChannelRef> >().test_all();
244 }
245 
246 template <typename ChannelSubbyteRef>
test_packed_channel_reference()247 void test_packed_channel_reference() {
248     do_test<packed_reference_core<ChannelSubbyteRef,ChannelSubbyteRef> >().test_all();
249 }
250 
251 template <typename ChannelSubbyteRef, typename MutableRef>
test_const_packed_channel_reference()252 void test_const_packed_channel_reference() {
253     do_test<packed_reference_core<ChannelSubbyteRef,MutableRef> >().test_all();
254 }
255 
256 template <typename ChannelSubbyteRef>
test_packed_dynamic_channel_reference()257 void test_packed_dynamic_channel_reference() {
258     do_test<packed_dynamic_reference_core<ChannelSubbyteRef,ChannelSubbyteRef> >().test_all();
259 }
260 
261 template <typename ChannelSubbyteRef, typename MutableRef>
test_const_packed_dynamic_channel_reference()262 void test_const_packed_dynamic_channel_reference() {
263     do_test<packed_dynamic_reference_core<ChannelSubbyteRef,MutableRef> >().test_all();
264 }
265 
266 template <typename ChannelValue>
test_channel_value_impl()267 void test_channel_value_impl() {
268     test_channel_value<ChannelValue>();
269     test_channel_reference<ChannelValue&>();
270     test_channel_reference<const ChannelValue&>();
271 }
272 
273 /////////////////////////////////////////////////////////
274 ///
275 /// A channel archetype - to test the minimum requirements of the concept
276 ///
277 /////////////////////////////////////////////////////////
278 
279 struct channel_value_archetype;
280 struct channel_archetype {
281     // equality comparable
operator ==(const channel_archetype &,const channel_archetype &)282     friend bool operator==(const channel_archetype&,const channel_archetype&) { return true; }
operator !=(const channel_archetype &,const channel_archetype &)283     friend bool operator!=(const channel_archetype&,const channel_archetype&) { return false; }
284     // less-than comparable
operator <(const channel_archetype &,const channel_archetype &)285     friend bool operator<(const channel_archetype&,const channel_archetype&) { return false; }
286     // convertible to a scalar
operator std::uint8_tchannel_archetype287     operator std::uint8_t() const { return 0; }
288 
289 
operator ++channel_archetype290     channel_archetype& operator++() { return *this; }
operator --channel_archetype291     channel_archetype& operator--() { return *this; }
operator ++channel_archetype292     channel_archetype  operator++(int) { return *this; }
operator --channel_archetype293     channel_archetype  operator--(int) { return *this; }
294 
operator +=channel_archetype295     template <typename Scalar> channel_archetype operator+=(Scalar) { return *this; }
operator -=channel_archetype296     template <typename Scalar> channel_archetype operator-=(Scalar) { return *this; }
operator *=channel_archetype297     template <typename Scalar> channel_archetype operator*=(Scalar) { return *this; }
operator /=channel_archetype298     template <typename Scalar> channel_archetype operator/=(Scalar) { return *this; }
299 
300     using value_type = channel_value_archetype;
301     using reference = channel_archetype;
302     using const_reference = channel_archetype const;
303     using pointer = channel_value_archetype *;
304     using const_pointer = channel_value_archetype const*;
305     static constexpr bool is_mutable=true;
306 
307     static value_type min_value();
308     static value_type max_value();
309 };
310 
311 
312 struct channel_value_archetype : public channel_archetype {
channel_value_archetypechannel_value_archetype313     channel_value_archetype() {}                                        // default constructible
channel_value_archetypechannel_value_archetype314     channel_value_archetype(const channel_value_archetype&) {}          // copy constructible
operator =channel_value_archetype315     channel_value_archetype& operator=(const channel_value_archetype&){return *this;} // assignable
channel_value_archetypechannel_value_archetype316     channel_value_archetype(std::uint8_t) {}
317 };
318 
min_value()319 channel_value_archetype channel_archetype::min_value() { return channel_value_archetype(); }
max_value()320 channel_value_archetype channel_archetype::max_value() { return channel_value_archetype(); }
321 
322 
test_packed_channel_reference()323 void test_packed_channel_reference()
324 {
325     using channel16_0_5_reference_t = packed_channel_reference<std::uint16_t, 0, 5, true>;
326     using channel16_5_6_reference_t = packed_channel_reference<std::uint16_t, 5, 6, true>;
327     using channel16_11_5_reference_t = packed_channel_reference<std::uint16_t, 11, 5, true>;
328 
329     std::uint16_t data=0;
330     channel16_0_5_reference_t   channel1(&data);
331     channel16_5_6_reference_t   channel2(&data);
332     channel16_11_5_reference_t  channel3(&data);
333 
334     channel1=channel_traits<channel16_0_5_reference_t>::max_value();
335     channel2=channel_traits<channel16_5_6_reference_t>::max_value();
336     channel3=channel_traits<channel16_11_5_reference_t>::max_value();
337     error_if(data!=65535);
338 
339     test_packed_channel_reference<channel16_0_5_reference_t>();
340     test_packed_channel_reference<channel16_5_6_reference_t>();
341     test_packed_channel_reference<channel16_11_5_reference_t>();
342 }
343 
test_packed_dynamic_channel_reference()344 void test_packed_dynamic_channel_reference()
345 {
346     using channel16_5_reference_t = packed_dynamic_channel_reference<std::uint16_t, 5, true>;
347     using channel16_6_reference_t = packed_dynamic_channel_reference<std::uint16_t, 6, true>;
348 
349     std::uint16_t data=0;
350     channel16_5_reference_t  channel1(&data,0);
351     channel16_6_reference_t  channel2(&data,5);
352     channel16_5_reference_t  channel3(&data,11);
353 
354     channel1=channel_traits<channel16_5_reference_t>::max_value();
355     channel2=channel_traits<channel16_6_reference_t>::max_value();
356     channel3=channel_traits<channel16_5_reference_t>::max_value();
357     error_if(data!=65535);
358 
359     test_packed_dynamic_channel_reference<channel16_5_reference_t>();
360 }
361 
test_channel()362 void test_channel() {
363     test_channel_value_impl<uint8_t>();
364     test_channel_value_impl<int8_t>();
365     test_channel_value_impl<uint16_t>();
366     test_channel_value_impl<int16_t>();
367     test_channel_value_impl<uint32_t>();
368     test_channel_value_impl<int16_t>();
369 
370     test_channel_value_impl<float32_t>();
371 
372     test_packed_channel_reference();
373     test_packed_dynamic_channel_reference();
374 
375     // Do only compile-time tests for the archetype (because asserts like val1<val2 fail)
376     boost::function_requires<MutableChannelConcept<channel_archetype> >();
377 
378     do_test<value_core<channel_value_archetype> >();
379     do_test<reference_core<channel_archetype> >();
380     do_test<reference_core<const channel_archetype&> >();
381 }
382 
main()383 int main()
384 {
385     try
386     {
387         test_channel();
388 
389         return EXIT_SUCCESS;
390     }
391     catch (std::exception const& e)
392     {
393         std::cerr << e.what() << std::endl;
394         return EXIT_FAILURE;
395     }
396     catch (...)
397     {
398         return EXIT_FAILURE;
399     }
400 }
401 
402 // TODO:
403 // - provide algorithm performance overloads for scoped channel and packed channels
404 // - Update concepts and documentation
405 // - What to do about pointer types?!
406 // - Performance!!
407 //      - is channel_convert the same as native?
408 //      - is operator++ on float32_t the same as native? How about if operator++ is defined in scoped_channel to do _value++?
409