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