channel.cpp 14 KB

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