• 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 #ifndef BOOST_GIL_UTILITIES_HPP
9 #define BOOST_GIL_UTILITIES_HPP
10 
11 #include <boost/gil/detail/mp11.hpp>
12 
13 #include <boost/config.hpp>
14 
15 #if defined(BOOST_CLANG)
16 #pragma clang diagnostic push
17 #pragma clang diagnostic ignored "-Wconversion"
18 #endif
19 
20 #if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
21 #pragma GCC diagnostic push
22 #pragma GCC diagnostic ignored "-Wconversion"
23 #endif
24 
25 #include <boost/iterator/iterator_adaptor.hpp>
26 #include <boost/iterator/iterator_facade.hpp>
27 
28 #if defined(BOOST_CLANG)
29 #pragma clang diagnostic pop
30 #endif
31 
32 #if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
33 #pragma GCC diagnostic pop
34 #endif
35 
36 #include <algorithm>
37 #include <cmath>
38 #include <cstddef>
39 #include <functional>
40 #include <iterator>
41 #include <utility>
42 #include <type_traits>
43 
44 namespace boost { namespace gil {
45 
46 /// Various utilities not specific to the image library.
47 /// Some are non-standard STL extensions or generic iterator adaptors
48 
49 ////////////////////////////////////////////////////////////////////////////////
50 ///  Rounding of real numbers / points to integers / integer points
51 ////////////////////////////////////////////////////////////////////////////////
52 
iround(float x)53 inline std::ptrdiff_t iround(float x)
54 {
55     return static_cast<std::ptrdiff_t>(x + (x < 0.0f ? -0.5f : 0.5f));
56 }
57 
iround(double x)58 inline std::ptrdiff_t iround(double x)
59 {
60     return static_cast<std::ptrdiff_t>(x + (x < 0.0 ? -0.5 : 0.5));
61 }
62 
ifloor(float x)63 inline std::ptrdiff_t ifloor(float x)
64 {
65     return static_cast<std::ptrdiff_t>(std::floor(x));
66 }
67 
ifloor(double x)68 inline std::ptrdiff_t ifloor(double x)
69 {
70     return static_cast<std::ptrdiff_t>(std::floor(x));
71 }
72 
iceil(float x)73 inline std::ptrdiff_t iceil(float x)
74 {
75     return static_cast<std::ptrdiff_t>(std::ceil(x));
76 }
77 
iceil(double x)78 inline std::ptrdiff_t iceil(double x)
79 {
80     return static_cast<std::ptrdiff_t>(std::ceil(x));
81 }
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 ///  computing size with alignment
85 ////////////////////////////////////////////////////////////////////////////////
86 
87 template <typename T>
align(T val,std::size_t alignment)88 inline T align(T val, std::size_t alignment)
89 {
90     return val+(alignment - val%alignment)%alignment;
91 }
92 
93 /// \brief Helper base class for pixel dereference adaptors.
94 /// \ingroup PixelDereferenceAdaptorModel
95 ///
96 template
97 <
98     typename ConstT,
99     typename Value,
100     typename Reference,
101     typename ConstReference,
102     typename ArgType,
103     typename ResultType,
104     bool IsMutable
105 >
106 struct deref_base
107 {
108     using argument_type = ArgType;
109     using result_type = ResultType;
110     using const_t = ConstT;
111     using value_type = Value;
112     using reference = Reference;
113     using const_reference = ConstReference;
114     static constexpr bool is_mutable = IsMutable;
115 };
116 
117 /// \brief Composes two dereference function objects. Similar to std::unary_compose but needs to pull some aliases from the component types.  Models: PixelDereferenceAdaptorConcept
118 /// \ingroup PixelDereferenceAdaptorModel
119 ///
120 template <typename D1, typename D2>
121 class deref_compose : public deref_base
122 <
123     deref_compose<typename D1::const_t, typename D2::const_t>,
124     typename D1::value_type,
125     typename D1::reference,
126     typename D1::const_reference,
127     typename D2::argument_type,
128     typename D1::result_type,
129     D1::is_mutable && D2::is_mutable
130 >
131 {
132 public:
133     D1 _fn1;
134     D2 _fn2;
135 
136     using argument_type = typename D2::argument_type;
137     using result_type = typename D1::result_type;
138 
139     deref_compose() = default;
deref_compose(const D1 & x,const D2 & y)140     deref_compose(const D1& x, const D2& y) : _fn1(x), _fn2(y) {}
deref_compose(const deref_compose & dc)141     deref_compose(const deref_compose& dc)  : _fn1(dc._fn1), _fn2(dc._fn2) {}
142 
143     template <typename _D1, typename _D2>
deref_compose(const deref_compose<_D1,_D2> & dc)144     deref_compose(const deref_compose<_D1,_D2>& dc)
145         : _fn1(dc._fn1), _fn2(dc._fn2)
146     {}
147 
operator ()(argument_type x) const148     result_type operator()(argument_type x) const { return _fn1(_fn2(x)); }
operator ()(argument_type x)149     result_type operator()(argument_type x)       { return _fn1(_fn2(x)); }
150 };
151 
152 // reinterpret_cast is implementation-defined. Static cast is not.
153 template <typename OutPtr, typename In>
154 BOOST_FORCEINLINE
gil_reinterpret_cast(In * p)155 OutPtr gil_reinterpret_cast(In* p)
156 {
157     return static_cast<OutPtr>(static_cast<void*>(p));
158 }
159 
160 template <typename OutPtr, typename In> BOOST_FORCEINLINE
gil_reinterpret_cast_c(const In * p)161 const OutPtr gil_reinterpret_cast_c(const In* p)
162 {
163     return static_cast<const OutPtr>(static_cast<const void*>(p));
164 }
165 
166 namespace detail {
167 
168 ////////////////////////////////////////////////////////////////////////////////
169 ///  \brief copy_n taken from SGI STL.
170 ////////////////////////////////////////////////////////////////////////////////
171 
172 template <class InputIter, class Size, class OutputIter>
_copy_n(InputIter first,Size count,OutputIter result,std::input_iterator_tag)173 std::pair<InputIter, OutputIter> _copy_n(InputIter first, Size count,
174     OutputIter result, std::input_iterator_tag)
175 {
176    for ( ; count > 0; --count)
177    {
178       *result = *first;
179       ++first;
180       ++result;
181    }
182    return std::pair<InputIter, OutputIter>(first, result);
183 }
184 
185 template <class RAIter, class Size, class OutputIter>
186 inline std::pair<RAIter, OutputIter>
_copy_n(RAIter first,Size count,OutputIter result,std::random_access_iterator_tag)187 _copy_n(RAIter first, Size count, OutputIter result, std::random_access_iterator_tag)
188 {
189    RAIter last = first + count;
190    return std::pair<RAIter, OutputIter>(last, std::copy(first, last, result));
191 }
192 
193 template <class InputIter, class Size, class OutputIter>
194 inline std::pair<InputIter, OutputIter>
_copy_n(InputIter first,Size count,OutputIter result)195 _copy_n(InputIter first, Size count, OutputIter result)
196 {
197    return _copy_n(first, count, result, typename std::iterator_traits<InputIter>::iterator_category());
198 }
199 
200 template <class InputIter, class Size, class OutputIter>
201 inline std::pair<InputIter, OutputIter>
copy_n(InputIter first,Size count,OutputIter result)202 copy_n(InputIter first, Size count, OutputIter result)
203 {
204     return detail::_copy_n(first, count, result);
205 }
206 
207 /// \brief identity taken from SGI STL.
208 template <typename T>
209 struct identity
210 {
211     using argument_type = T;
212     using result_type = T;
operator ()boost::gil::detail::identity213     const T& operator()(const T& val) const { return val; }
214 };
215 
216 /// \brief plus function object whose arguments may be of different type.
217 template <typename T1, typename T2>
218 struct plus_asymmetric {
219     using first_argument_type = T1;
220     using second_argument_type = T2;
221     using result_type = T1;
operator ()boost::gil::detail::plus_asymmetric222     T1 operator()(T1 f1, T2 f2) const
223     {
224         return f1+f2;
225     }
226 };
227 
228 /// \brief operator++ wrapped in a function object
229 template <typename T>
230 struct inc
231 {
232     using argument_type = T;
233     using result_type = T;
operator ()boost::gil::detail::inc234     T operator()(T x) const { return ++x; }
235 };
236 
237 /// \brief operator-- wrapped in a function object
238 template <typename T>
239 struct dec
240 {
241     using argument_type = T;
242     using result_type = T;
operator ()boost::gil::detail::dec243     T operator()(T x) const { return --x; }
244 };
245 
246 /// \brief Returns the index corresponding to the first occurrance of a given given type in
247 //         a given Boost.MP11-compatible list (or size if the type is not present)
248 template <typename Types, typename T>
249 struct type_to_index : mp11::mp_find<Types, T>
250 {
251     static_assert(mp11::mp_contains<Types, T>::value, "T should be element of Types");
252 };
253 
254 } // namespace detail
255 
256 /// \ingroup ColorSpaceAndLayoutModel
257 /// \brief Represents a color space and ordering of channels in memory
258 template
259 <
260     typename ColorSpace,
261     typename ChannelMapping = mp11::mp_iota
262     <
263         std::integral_constant<int, mp11::mp_size<ColorSpace>::value>
264     >
265 >
266 struct layout
267 {
268     using color_space_t = ColorSpace;
269     using channel_mapping_t = ChannelMapping;
270 
271     static_assert(mp11::mp_size<ColorSpace>::value > 0,
272         "color space should not be empty sequence");
273 };
274 
275 /// \brief A version of swap that also works with reference proxy objects
276 /// Where value_type<T1>  == value_type<T2> == Value
277 template <typename Value, typename T1, typename T2>
swap_proxy(T1 & left,T2 & right)278 void swap_proxy(T1& left, T2& right)
279 {
280     Value tmp = left;
281     left = right;
282     right = tmp;
283 }
284 
285 /// \brief Run-time detection of whether the underlying architecture is little endian
little_endian()286 BOOST_FORCEINLINE bool little_endian()
287 {
288     short tester = 0x0001;
289     return  *(char*)&tester!=0;
290 }
291 /// \brief Run-time detection of whether the underlying architecture is big endian
big_endian()292 BOOST_FORCEINLINE bool big_endian()
293 {
294     return !little_endian();
295 }
296 
297 }}  // namespace boost::gil
298 
299 #endif
300