utilities.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. Copyright 2005-2007 Adobe Systems Incorporated
  3. Use, modification and distribution are subject to the Boost Software License,
  4. Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt).
  6. See http://opensource.adobe.com/gil for most recent version including documentation.
  7. */
  8. /*************************************************************************************************/
  9. #ifndef GIL_UTILITIES_H
  10. #define GIL_UTILITIES_H
  11. #include "gil_config.hpp"
  12. #include <functional>
  13. #include <boost/config/no_tr1/cmath.hpp>
  14. #include <cstddef>
  15. #include <algorithm>
  16. #include <utility>
  17. #include <iterator>
  18. #include <boost/static_assert.hpp>
  19. #include <boost/type_traits.hpp>
  20. #include <boost/mpl/size.hpp>
  21. #include <boost/mpl/distance.hpp>
  22. #include <boost/mpl/begin.hpp>
  23. #include <boost/mpl/find.hpp>
  24. #include <boost/mpl/range_c.hpp>
  25. #include <boost/iterator/iterator_adaptor.hpp>
  26. #include <boost/iterator/iterator_facade.hpp>
  27. ////////////////////////////////////////////////////////////////////////////////////////
  28. /// \file
  29. /// \brief Various utilities not specific to the image library. Some are non-standard STL extensions or generic iterator adaptors
  30. /// \author Lubomir Bourdev and Hailin Jin \n
  31. /// Adobe Systems Incorporated
  32. /// \date 2005-2007 \n Last updated on September 18, 2007
  33. ///
  34. ///
  35. ////////////////////////////////////////////////////////////////////////////////////////
  36. namespace boost { namespace gil {
  37. /**
  38. \addtogroup PointModel
  39. Example:
  40. \code
  41. point2<std::ptrdiff_t> p(3,2);
  42. assert((p[0] == p.x) && (p[1] == p.y));
  43. assert(axis_value<0>(p) == 3);
  44. assert(axis_value<1>(p) == 2);
  45. \endcode
  46. */
  47. ////////////////////////////////////////////////////////////////////////////////////////
  48. // CLASS point2
  49. ///
  50. /// \brief 2D point both axes of which have the same dimension type
  51. /// \ingroup PointModel
  52. /// Models: Point2DConcept
  53. ///
  54. ////////////////////////////////////////////////////////////////////////////////////////
  55. template <typename T>
  56. class point2 {
  57. public:
  58. typedef T value_type;
  59. template <std::size_t D> struct axis { typedef value_type coord_t; };
  60. static const std::size_t num_dimensions=2;
  61. point2() : x(0), y(0) {}
  62. point2(T newX, T newY) : x(newX), y(newY) {}
  63. point2(const point2& p) : x(p.x), y(p.y) {}
  64. ~point2() {}
  65. point2& operator=(const point2& p) { x=p.x; y=p.y; return *this; }
  66. point2 operator<<(std::ptrdiff_t shift) const { return point2(x<<shift,y<<shift); }
  67. point2 operator>>(std::ptrdiff_t shift) const { return point2(x>>shift,y>>shift); }
  68. point2& operator+=(const point2& p) { x+=p.x; y+=p.y; return *this; }
  69. point2& operator-=(const point2& p) { x-=p.x; y-=p.y; return *this; }
  70. point2& operator/=(double t) { x/=t; y/=t; return *this; }
  71. const T& operator[](std::size_t i) const { return this->*mem_array[i]; }
  72. T& operator[](std::size_t i) { return this->*mem_array[i]; }
  73. T x,y;
  74. private:
  75. // this static array of pointers to member variables makes operator[] safe and doesn't seem to exhibit any performance penalty
  76. static T point2<T>::* const mem_array[num_dimensions];
  77. };
  78. template <typename T>
  79. T point2<T>::* const point2<T>::mem_array[point2<T>::num_dimensions] = { &point2<T>::x, &point2<T>::y };
  80. /// \ingroup PointModel
  81. template <typename T> GIL_FORCEINLINE
  82. bool operator==(const point2<T>& p1, const point2<T>& p2) { return (p1.x==p2.x && p1.y==p2.y); }
  83. /// \ingroup PointModel
  84. template <typename T> GIL_FORCEINLINE
  85. bool operator!=(const point2<T>& p1, const point2<T>& p2) { return p1.x!=p2.x || p1.y!=p2.y; }
  86. /// \ingroup PointModel
  87. template <typename T> GIL_FORCEINLINE
  88. point2<T> operator+(const point2<T>& p1, const point2<T>& p2) { return point2<T>(p1.x+p2.x,p1.y+p2.y); }
  89. /// \ingroup PointModel
  90. template <typename T> GIL_FORCEINLINE
  91. point2<T> operator-(const point2<T>& p) { return point2<T>(-p.x,-p.y); }
  92. /// \ingroup PointModel
  93. template <typename T> GIL_FORCEINLINE
  94. point2<T> operator-(const point2<T>& p1, const point2<T>& p2) { return point2<T>(p1.x-p2.x,p1.y-p2.y); }
  95. /// \ingroup PointModel
  96. template <typename T> GIL_FORCEINLINE
  97. point2<double> operator/(const point2<T>& p, double t) { return t==0 ? point2<double>(0,0):point2<double>(p.x/t,p.y/t); }
  98. /// \ingroup PointModel
  99. template <typename T> GIL_FORCEINLINE
  100. point2<T> operator*(const point2<T>& p, std::ptrdiff_t t) { return point2<T>(p.x*t,p.y*t); }
  101. /// \ingroup PointModel
  102. template <typename T> GIL_FORCEINLINE
  103. point2<T> operator*(std::ptrdiff_t t, const point2<T>& p) { return point2<T>(p.x*t,p.y*t); }
  104. /// \ingroup PointModel
  105. template <std::size_t K, typename T> GIL_FORCEINLINE
  106. const T& axis_value(const point2<T>& p) { return p[K]; }
  107. /// \ingroup PointModel
  108. template <std::size_t K, typename T> GIL_FORCEINLINE
  109. T& axis_value( point2<T>& p) { return p[K]; }
  110. ////////////////////////////////////////////////////////////////////////////////////////
  111. ///
  112. /// Rounding of real numbers / points to integers / integer points
  113. ///
  114. ////////////////////////////////////////////////////////////////////////////////////////
  115. inline std::ptrdiff_t iround(float x ) { return static_cast<std::ptrdiff_t>(x + (x < 0.0f ? -0.5f : 0.5f)); }
  116. inline std::ptrdiff_t iround(double x) { return static_cast<std::ptrdiff_t>(x + (x < 0.0 ? -0.5 : 0.5)); }
  117. inline std::ptrdiff_t ifloor(float x ) { return static_cast<std::ptrdiff_t>(std::floor(x)); }
  118. inline std::ptrdiff_t ifloor(double x) { return static_cast<std::ptrdiff_t>(std::floor(x)); }
  119. inline std::ptrdiff_t iceil(float x ) { return static_cast<std::ptrdiff_t>(std::ceil(x)); }
  120. inline std::ptrdiff_t iceil(double x) { return static_cast<std::ptrdiff_t>(std::ceil(x)); }
  121. /**
  122. \addtogroup PointAlgorithm
  123. Example:
  124. \code
  125. assert(iround(point2<double>(3.1, 3.9)) == point2<std::ptrdiff_t>(3,4));
  126. \endcode
  127. */
  128. /// \ingroup PointAlgorithm
  129. inline point2<std::ptrdiff_t> iround(const point2<float >& p) { return point2<std::ptrdiff_t>(iround(p.x),iround(p.y)); }
  130. /// \ingroup PointAlgorithm
  131. inline point2<std::ptrdiff_t> iround(const point2<double>& p) { return point2<std::ptrdiff_t>(iround(p.x),iround(p.y)); }
  132. /// \ingroup PointAlgorithm
  133. inline point2<std::ptrdiff_t> ifloor(const point2<float >& p) { return point2<std::ptrdiff_t>(ifloor(p.x),ifloor(p.y)); }
  134. /// \ingroup PointAlgorithm
  135. inline point2<std::ptrdiff_t> ifloor(const point2<double>& p) { return point2<std::ptrdiff_t>(ifloor(p.x),ifloor(p.y)); }
  136. /// \ingroup PointAlgorithm
  137. inline point2<std::ptrdiff_t> iceil (const point2<float >& p) { return point2<std::ptrdiff_t>(iceil(p.x), iceil(p.y)); }
  138. /// \ingroup PointAlgorithm
  139. inline point2<std::ptrdiff_t> iceil (const point2<double>& p) { return point2<std::ptrdiff_t>(iceil(p.x), iceil(p.y)); }
  140. ////////////////////////////////////////////////////////////////////////////////////////
  141. ///
  142. /// computing size with alignment
  143. ///
  144. ////////////////////////////////////////////////////////////////////////////////////////
  145. template <typename T>
  146. inline T align(T val, std::size_t alignment) {
  147. return val+(alignment - val%alignment)%alignment;
  148. }
  149. /// \brief Helper base class for pixel dereference adaptors.
  150. /// \ingroup PixelDereferenceAdaptorModel
  151. ///
  152. template <typename ConstT, typename Value, typename Reference, typename ConstReference,
  153. typename ArgType, typename ResultType, bool IsMutable>
  154. struct deref_base : public std::unary_function<ArgType, ResultType> {
  155. typedef ConstT const_t;
  156. typedef Value value_type;
  157. typedef Reference reference;
  158. typedef ConstReference const_reference;
  159. BOOST_STATIC_CONSTANT(bool, is_mutable = IsMutable);
  160. };
  161. /// \brief Composes two dereference function objects. Similar to std::unary_compose but needs to pull some typedefs from the component types. Models: PixelDereferenceAdaptorConcept
  162. /// \ingroup PixelDereferenceAdaptorModel
  163. ///
  164. template <typename D1, typename D2>
  165. class deref_compose : public deref_base<
  166. deref_compose<typename D1::const_t, typename D2::const_t>,
  167. typename D1::value_type, typename D1::reference, typename D1::const_reference,
  168. typename D2::argument_type, typename D1::result_type, D1::is_mutable && D2::is_mutable>
  169. {
  170. public:
  171. D1 _fn1;
  172. D2 _fn2;
  173. typedef typename D2::argument_type argument_type;
  174. typedef typename D1::result_type result_type;
  175. deref_compose() {}
  176. deref_compose(const D1& x, const D2& y) : _fn1(x), _fn2(y) {}
  177. deref_compose(const deref_compose& dc) : _fn1(dc._fn1), _fn2(dc._fn2) {}
  178. template <typename _D1, typename _D2> deref_compose(const deref_compose<_D1,_D2>& dc) : _fn1(dc._fn1), _fn2(dc._fn2) {}
  179. result_type operator()(argument_type x) const { return _fn1(_fn2(x)); }
  180. result_type operator()(argument_type x) { return _fn1(_fn2(x)); }
  181. };
  182. // reinterpret_cast is implementation-defined. Static cast is not.
  183. template <typename OutPtr, typename In> GIL_FORCEINLINE
  184. OutPtr gil_reinterpret_cast( In* p) { return static_cast<OutPtr>(static_cast<void*>(p)); }
  185. template <typename OutPtr, typename In> GIL_FORCEINLINE
  186. const OutPtr gil_reinterpret_cast_c(const In* p) { return static_cast<const OutPtr>(static_cast<const void*>(p)); }
  187. namespace detail {
  188. ////////////////////////////////////////////////////////////////////////////////////////
  189. ///
  190. /// \brief copy_n taken from SGI STL.
  191. ///
  192. ////////////////////////////////////////////////////////////////////////////////////////
  193. template <class InputIter, class Size, class OutputIter>
  194. std::pair<InputIter, OutputIter> _copy_n(InputIter first, Size count,
  195. OutputIter result,
  196. std::input_iterator_tag) {
  197. for ( ; count > 0; --count) {
  198. *result = *first;
  199. ++first;
  200. ++result;
  201. }
  202. return std::pair<InputIter, OutputIter>(first, result);
  203. }
  204. template <class RAIter, class Size, class OutputIter>
  205. inline std::pair<RAIter, OutputIter>
  206. _copy_n(RAIter first, Size count, OutputIter result, std::random_access_iterator_tag) {
  207. RAIter last = first + count;
  208. return std::pair<RAIter, OutputIter>(last, std::copy(first, last, result));
  209. }
  210. template <class InputIter, class Size, class OutputIter>
  211. inline std::pair<InputIter, OutputIter>
  212. _copy_n(InputIter first, Size count, OutputIter result) {
  213. return _copy_n(first, count, result, typename std::iterator_traits<InputIter>::iterator_category());
  214. }
  215. template <class InputIter, class Size, class OutputIter>
  216. inline std::pair<InputIter, OutputIter>
  217. copy_n(InputIter first, Size count, OutputIter result) {
  218. return detail::_copy_n(first, count, result);
  219. }
  220. /// \brief identity taken from SGI STL.
  221. template <typename T>
  222. struct identity : public std::unary_function<T,T> {
  223. const T& operator()(const T& val) const { return val; }
  224. };
  225. /*************************************************************************************************/
  226. /// \brief plus function object whose arguments may be of different type.
  227. template <typename T1, typename T2>
  228. struct plus_asymmetric : public std::binary_function<T1,T2,T1> {
  229. T1 operator()(T1 f1, T2 f2) const {
  230. return f1+f2;
  231. }
  232. };
  233. /*************************************************************************************************/
  234. /// \brief operator++ wrapped in a function object
  235. template <typename T>
  236. struct inc : public std::unary_function<T,T> {
  237. T operator()(T x) const { return ++x; }
  238. };
  239. /*************************************************************************************************/
  240. /// \brief operator-- wrapped in a function object
  241. template <typename T>
  242. struct dec : public std::unary_function<T,T> {
  243. T operator()(T x) const { return --x; }
  244. };
  245. /// \brief Returns the index corresponding to the first occurrance of a given given type in
  246. // a given MPL RandomAccessSequence (or size if the type is not present)
  247. template <typename Types, typename T>
  248. struct type_to_index
  249. : public mpl::distance<typename mpl::begin<Types>::type,
  250. typename mpl::find<Types,T>::type>::type {};
  251. } // namespace detail
  252. /// \ingroup ColorSpaceAndLayoutModel
  253. /// \brief Represents a color space and ordering of channels in memory
  254. template <typename ColorSpace, typename ChannelMapping = mpl::range_c<int,0,mpl::size<ColorSpace>::value> >
  255. struct layout {
  256. typedef ColorSpace color_space_t;
  257. typedef ChannelMapping channel_mapping_t;
  258. };
  259. /// \brief A version of swap that also works with reference proxy objects
  260. template <typename Value, typename T1, typename T2> // where value_type<T1> == value_type<T2> == Value
  261. void swap_proxy(T1& left, T2& right) {
  262. Value tmp = left;
  263. left = right;
  264. right = tmp;
  265. }
  266. /// \brief Run-time detection of whether the underlying architecture is little endian
  267. inline bool little_endian() {
  268. short tester = 0x0001;
  269. return *(char*)&tester!=0;
  270. }
  271. /// \brief Run-time detection of whether the underlying architecture is big endian
  272. inline bool big_endian() {
  273. return !little_endian();
  274. }
  275. } } // namespace boost::gil
  276. #endif