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