Modules | Alphabetical List | Class List | Directories | File List | GIL Home Page

# color_base_algorithm.hpp

Go to the documentation of this file.

    00001 /*
    00002     Copyright 2005-2007 Adobe Systems Incorporated
    00003
    00004     Use, modification and distribution are subject to the Boost Software License,
    00005     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    00006     http://www.boost.org/LICENSE_1_0.txt).
    00007
    00008     See http://opensource.adobe.com/gil for most recent version including documentation.
    00009 */
    00010
    00011 /*************************************************************************************************/
    00012
    00013 #ifndef GIL_COLOR_BASE_ALGORITHM_HPP
    00014 #define GIL_COLOR_BASE_ALGORITHM_HPP
    00015
    00024
    00025 #include <algorithm>
    00026 #include <boost/type_traits.hpp>
    00027 #include <boost/utility/enable_if.hpp>
    00028 #include <boost/mpl/contains.hpp>
    00029 #include <boost/mpl/at.hpp>
    00030 #include "gil_config.hpp"
    00031 #include "gil_concept.hpp"
    00032 #include "utilities.hpp"
    00033
    00034 namespace boost { namespace gil {
    00035
    00036
    00042
    00055
    00056
    00057 template <typename ColorBase>
    00058 struct size : public mpl::size<typename ColorBase::layout_t::color_space_t> {};
    00059
    00065
    00092
    00093
    00094 template <typename ColorBase, int K> struct kth_semantic_element_type {
    00095     BOOST_STATIC_CONSTANT(int, semantic_index = (mpl::at_c<typename ColorBase::layout_t::channel_mapping_t,K>::type::value));
    00096     typedef typename kth_element_type<ColorBase, semantic_index>::type type;
    00097 };
    00098
    00101 template <typename ColorBase, int K> struct kth_semantic_element_reference_type {
    00102     BOOST_STATIC_CONSTANT(int, semantic_index = (mpl::at_c<typename ColorBase::layout_t::channel_mapping_t,K>::type::value));
    00103     typedef typename kth_element_reference_type<ColorBase,semantic_index>::type type;
    00104     static type       get(ColorBase& cb) { return at_c<semantic_index>(cb); }
    00105 };
    00106
    00109 template <typename ColorBase, int K> struct kth_semantic_element_const_reference_type {
    00110     BOOST_STATIC_CONSTANT(int, semantic_index = (mpl::at_c<typename ColorBase::layout_t::channel_mapping_t,K>::type::value));
    00111     typedef typename kth_element_const_reference_type<ColorBase,semantic_index>::type type;
    00112     static type       get(const ColorBase& cb) { return at_c<semantic_index>(cb); }
    00113 };
    00114
    00117 template <int K, typename ColorBase> inline
    00118 typename disable_if<is_const<ColorBase>,typename kth_semantic_element_reference_type<ColorBase,K>::type>::type
    00119 semantic_at_c(ColorBase& p) {
    00120     return kth_semantic_element_reference_type<ColorBase,K>::get(p);
    00121 }
    00122
    00125 template <int K, typename ColorBase> inline
    00126 typename kth_semantic_element_const_reference_type<ColorBase,K>::type
    00127 semantic_at_c(const ColorBase& p) {
    00128     return kth_semantic_element_const_reference_type<ColorBase,K>::get(p);
    00129 }
    00130
    00136
    00156
    00157
    00158 template <typename ColorBase, typename Color>
    00159 struct contains_color : public mpl::contains<typename ColorBase::layout_t::color_space_t,Color> {};
    00160
    00161 template <typename ColorBase, typename Color>
    00162 struct color_index_type : public detail::type_to_index<typename ColorBase::layout_t::color_space_t,Color> {};
    00163
    00166 template <typename ColorBase, typename Color>
    00167 struct color_element_type : public kth_semantic_element_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
    00168
    00171 template <typename ColorBase, typename Color>
    00172 struct color_element_reference_type : public kth_semantic_element_reference_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
    00173
    00176 template <typename ColorBase, typename Color>
    00177 struct color_element_const_reference_type : public kth_semantic_element_const_reference_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
    00178
    00181 template <typename ColorBase, typename Color>
    00182 typename color_element_reference_type<ColorBase,Color>::type get_color(ColorBase& cb, Color=Color()) {
    00183     return color_element_reference_type<ColorBase,Color>::get(cb);
    00184 }
    00185
    00188 template <typename ColorBase, typename Color>
    00189 typename color_element_const_reference_type<ColorBase,Color>::type get_color(const ColorBase& cb, Color=Color()) {
    00190     return color_element_const_reference_type<ColorBase,Color>::get(cb);
    00191 }
    00192
    00198
    00210
    00211
    00212 template <typename ColorBase>
    00213 struct element_type : public kth_element_type<ColorBase, 0> {};
    00214
    00217 template <typename ColorBase>
    00218 struct element_reference_type : public kth_element_reference_type<ColorBase, 0> {};
    00219
    00222 template <typename ColorBase>
    00223 struct element_const_reference_type : public kth_element_const_reference_type<ColorBase, 0> {};
    00224
    00225
    00226 namespace detail {
    00227
    00228 // compile-time recursion for per-element operations on color bases
    00229 template <int N>
    00230 struct element_recursion {
    00231     //static_equal
    00232     template <typename P1,typename P2>
    00233     static bool static_equal(const P1& p1, const P2& p2) {
    00234         return element_recursion<N-1>::static_equal(p1,p2) &&
    00235                semantic_at_c<N-1>(p1)==semantic_at_c<N-1>(p2);
    00236     }
    00237     //static_copy
    00238     template <typename P1,typename P2>
    00239     static void static_copy(const P1& p1, P2& p2) {
    00240         element_recursion<N-1>::static_copy(p1,p2);
    00241         semantic_at_c<N-1>(p2)=semantic_at_c<N-1>(p1);
    00242     }
    00243     //static_fill
    00244     template <typename P,typename T2>
    00245     static void static_fill(P& p, T2 v) {
    00246         element_recursion<N-1>::static_fill(p,v);
    00247         semantic_at_c<N-1>(p)=v;
    00248     }
    00249     //static_generate
    00250     template <typename Dst,typename Op>
    00251     static void static_generate(Dst& dst, Op op) {
    00252         element_recursion<N-1>::static_generate(dst,op);
    00253         semantic_at_c<N-1>(dst)=op();
    00254     }
    00255     //static_for_each with one source
    00256     template <typename P1,typename Op>
    00257     static Op static_for_each(P1& p1, Op op) {
    00258         Op op2(element_recursion<N-1>::static_for_each(p1,op));
    00259         op2(semantic_at_c<N-1>(p1));
    00260         return op2;
    00261     }
    00262     template <typename P1,typename Op>
    00263     static Op static_for_each(const P1& p1, Op op) {
    00264         Op op2(element_recursion<N-1>::static_for_each(p1,op));
    00265         op2(semantic_at_c<N-1>(p1));
    00266         return op2;
    00267     }
    00268     //static_for_each with two sources
    00269     template <typename P1,typename P2,typename Op>
    00270     static Op static_for_each(P1& p1, P2& p2, Op op) {
    00271         Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
    00272         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
    00273         return op2;
    00274     }
    00275     template <typename P1,typename P2,typename Op>
    00276     static Op static_for_each(P1& p1, const P2& p2, Op op) {
    00277         Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
    00278         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
    00279         return op2;
    00280     }
    00281     template <typename P1,typename P2,typename Op>
    00282     static Op static_for_each(const P1& p1, P2& p2, Op op) {
    00283         Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
    00284         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
    00285         return op2;
    00286     }
    00287     template <typename P1,typename P2,typename Op>
    00288     static Op static_for_each(const P1& p1, const P2& p2, Op op) {
    00289         Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
    00290         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
    00291         return op2;
    00292     }
    00293     //static_for_each with three sources
    00294     template <typename P1,typename P2,typename P3,typename Op>
    00295     static Op static_for_each(P1& p1, P2& p2, P3& p3, Op op) {
    00296         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
    00297         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
    00298         return op2;
    00299     }
    00300     template <typename P1,typename P2,typename P3,typename Op>
    00301     static Op static_for_each(P1& p1, P2& p2, const P3& p3, Op op) {
    00302         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
    00303         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
    00304         return op2;
    00305     }
    00306     template <typename P1,typename P2,typename P3,typename Op>
    00307     static Op static_for_each(P1& p1, const P2& p2, P3& p3, Op op) {
    00308         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
    00309         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
    00310         return op2;
    00311     }
    00312     template <typename P1,typename P2,typename P3,typename Op>
    00313     static Op static_for_each(P1& p1, const P2& p2, const P3& p3, Op op) {
    00314         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
    00315         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
    00316         return op2;
    00317     }
    00318     template <typename P1,typename P2,typename P3,typename Op>
    00319     static Op static_for_each(const P1& p1, P2& p2, P3& p3, Op op) {
    00320         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
    00321         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
    00322         return op2;
    00323     }
    00324     template <typename P1,typename P2,typename P3,typename Op>
    00325     static Op static_for_each(const P1& p1, P2& p2, const P3& p3, Op op) {
    00326         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
    00327         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
    00328         return op2;
    00329     }
    00330     template <typename P1,typename P2,typename P3,typename Op>
    00331     static Op static_for_each(const P1& p1, const P2& p2, P3& p3, Op op) {
    00332         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
    00333         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
    00334         return op2;
    00335     }
    00336     template <typename P1,typename P2,typename P3,typename Op>
    00337     static Op static_for_each(const P1& p1, const P2& p2, const P3& p3, Op op) {
    00338         Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
    00339         op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
    00340         return op2;
    00341     }
    00342     //static_transform with one source
    00343     template <typename P1,typename Dst,typename Op>
    00344     static Op static_transform(P1& src, Dst& dst, Op op) {
    00345         Op op2(element_recursion<N-1>::static_transform(src,dst,op));
    00346         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src));
    00347         return op2;
    00348     }
    00349     template <typename P1,typename Dst,typename Op>
    00350     static Op static_transform(const P1& src, Dst& dst, Op op) {
    00351         Op op2(element_recursion<N-1>::static_transform(src,dst,op));
    00352         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src));
    00353         return op2;
    00354     }
    00355     //static_transform with two sources
    00356     template <typename P1,typename P2,typename Dst,typename Op>
    00357     static Op static_transform(P1& src1, P2& src2, Dst& dst, Op op) {
    00358         Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
    00359         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
    00360         return op2;
    00361     }
    00362     template <typename P1,typename P2,typename Dst,typename Op>
    00363     static Op static_transform(P1& src1, const P2& src2, Dst& dst, Op op) {
    00364         Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
    00365         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
    00366         return op2;
    00367     }
    00368     template <typename P1,typename P2,typename Dst,typename Op>
    00369     static Op static_transform(const P1& src1, P2& src2, Dst& dst, Op op) {
    00370         Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
    00371         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
    00372         return op2;
    00373     }
    00374     template <typename P1,typename P2,typename Dst,typename Op>
    00375     static Op static_transform(const P1& src1, const P2& src2, Dst& dst, Op op) {
    00376         Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
    00377         semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
    00378         return op2;
    00379     }
    00380 };
    00381
    00382 // Termination condition of the compile-time recursion for element operations on a color base
    00383 template<> struct element_recursion<0> {
    00384     //static_equal
    00385     template <typename P1,typename P2>
    00386     static bool static_equal(const P1&, const P2&) { return true; }
    00387     //static_copy
    00388     template <typename P1,typename P2>
    00389     static void static_copy(const P1&, const P2&) {}
    00390     //static_fill
    00391     template <typename P, typename T2>
    00392     static void static_fill(const P&, T2) {}
    00393     //static_generate
    00394     template <typename Dst,typename Op>
    00395     static void static_generate(const Dst&,Op){}
    00396     //static_for_each with one source
    00397     template <typename P1,typename Op>
    00398     static Op static_for_each(const P1&,Op op){return op;}
    00399     //static_for_each with two sources
    00400     template <typename P1,typename P2,typename Op>
    00401     static Op static_for_each(const P1&,const P2&,Op op){return op;}
    00402     //static_for_each with three sources
    00403     template <typename P1,typename P2,typename P3,typename Op>
    00404     static Op static_for_each(const P1&,const P2&,const P3&,Op op){return op;}
    00405     //static_transform with one source
    00406     template <typename P1,typename Dst,typename Op>
    00407     static Op static_transform(const P1&,const Dst&,Op op){return op;}
    00408     //static_transform with two sources
    00409     template <typename P1,typename P2,typename Dst,typename Op>
    00410     static Op static_transform(const P1&,const P2&,const Dst&,Op op){return op;}
    00411 };
    00412
    00413 // std::min and std::max don't have the mutable overloads...
    00414 template <typename Q> inline const Q& mutable_min(const Q& x, const Q& y) { return x<y ? x : y; }
    00415 template <typename Q> inline       Q& mutable_min(      Q& x,       Q& y) { return x<y ? x : y; }
    00416 template <typename Q> inline const Q& mutable_max(const Q& x, const Q& y) { return x<y ? y : x; }
    00417 template <typename Q> inline       Q& mutable_max(      Q& x,       Q& y) { return x<y ? y : x; }
    00418
    00419
    00420 // compile-time recursion for min/max element
    00421 template <int N>
    00422 struct min_max_recur {
    00423     template <typename P> static typename element_const_reference_type<P>::type max_(const P& p) {
    00424         return mutable_max(min_max_recur<N-1>::max_(p),semantic_at_c<N-1>(p));
    00425     }
    00426     template <typename P> static typename element_reference_type<P>::type       max_(      P& p) {
    00427         return mutable_max(min_max_recur<N-1>::max_(p),semantic_at_c<N-1>(p));
    00428     }
    00429     template <typename P> static typename element_const_reference_type<P>::type min_(const P& p) {
    00430         return mutable_min(min_max_recur<N-1>::min_(p),semantic_at_c<N-1>(p));
    00431     }
    00432     template <typename P> static typename element_reference_type<P>::type       min_(      P& p) {
    00433         return mutable_min(min_max_recur<N-1>::min_(p),semantic_at_c<N-1>(p));
    00434     }
    00435 };
    00436
    00437 // termination condition of the compile-time recursion for min/max element
    00438 template <>
    00439 struct min_max_recur<1> {
    00440     template <typename P> static typename element_const_reference_type<P>::type max_(const P& p) { return semantic_at_c<0>(p); }
    00441     template <typename P> static typename element_reference_type<P>::type       max_(      P& p) { return semantic_at_c<0>(p); }
    00442     template <typename P> static typename element_const_reference_type<P>::type min_(const P& p) { return semantic_at_c<0>(p); }
    00443     template <typename P> static typename element_reference_type<P>::type       min_(      P& p) { return semantic_at_c<0>(p); }
    00444 };
    00445 }  // namespace detail
    00446
    00447
    00463 template <typename P>
    00464 GIL_FORCEINLINE
    00465 typename element_const_reference_type<P>::type static_max(const P& p) { return detail::min_max_recur<size<P>::value>::max_(p); }
    00466
    00467 template <typename P>
    00468 GIL_FORCEINLINE
    00469 typename element_reference_type<P>::type       static_max(      P& p) { return detail::min_max_recur<size<P>::value>::max_(p); }
    00470
    00471 template <typename P>
    00472 GIL_FORCEINLINE
    00473 typename element_const_reference_type<P>::type static_min(const P& p) { return detail::min_max_recur<size<P>::value>::min_(p); }
    00474
    00475 template <typename P>
    00476 GIL_FORCEINLINE
    00477 typename element_reference_type<P>::type       static_min(      P& p) { return detail::min_max_recur<size<P>::value>::min_(p); }
    00479
    00497 template <typename P1,typename P2>
    00498 GIL_FORCEINLINE
    00499 bool static_equal(const P1& p1, const P2& p2) { return detail::element_recursion<size<P1>::value>::static_equal(p1,p2); }
    00500
    00502
    00520 template <typename Src,typename Dst>
    00521 GIL_FORCEINLINE
    00522 void static_copy(const Src& src, Dst& dst) {  detail::element_recursion<size<Dst>::value>::static_copy(src,dst); }
    00523
    00525
    00539 template <typename P,typename V>
    00540 GIL_FORCEINLINE
    00541 void static_fill(P& p, const V& v) {  detail::element_recursion<size<P>::value>::static_fill(p,v); }
    00543
    00565 template <typename P1,typename Op>
    00566 GIL_FORCEINLINE
    00567 void static_generate(P1& dst,Op op)                      { detail::element_recursion<size<P1>::value>::static_generate(dst,op); }
    00569
    00598 //static_transform with one source
    00599 template <typename Src,typename Dst,typename Op>
    00600 GIL_FORCEINLINE
    00601 Op static_transform(Src& src,Dst& dst,Op op)              { return detail::element_recursion<size<Dst>::value>::static_transform(src,dst,op); }
    00602 template <typename Src,typename Dst,typename Op>
    00603 GIL_FORCEINLINE
    00604 Op static_transform(const Src& src,Dst& dst,Op op)              { return detail::element_recursion<size<Dst>::value>::static_transform(src,dst,op); }
    00605 //static_transform with two sources
    00606 template <typename P2,typename P3,typename Dst,typename Op>
    00607 GIL_FORCEINLINE
    00608 Op static_transform(P2& p2,P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
    00609 template <typename P2,typename P3,typename Dst,typename Op>
    00610 GIL_FORCEINLINE
    00611 Op static_transform(P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
    00612 template <typename P2,typename P3,typename Dst,typename Op>
    00613 GIL_FORCEINLINE
    00614 Op static_transform(const P2& p2,P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
    00615 template <typename P2,typename P3,typename Dst,typename Op>
    00616 GIL_FORCEINLINE
    00617 Op static_transform(const P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
    00619
    00647 //static_for_each with one source
    00648 template <typename P1,typename Op>
    00649 GIL_FORCEINLINE
    00650 Op static_for_each(      P1& p1, Op op)                          { return detail::element_recursion<size<P1>::value>::static_for_each(p1,op); }
    00651 template <typename P1,typename Op>
    00652 GIL_FORCEINLINE
    00653 Op static_for_each(const P1& p1, Op op)                          { return detail::element_recursion<size<P1>::value>::static_for_each(p1,op); }
    00654 //static_for_each with two sources
    00655 template <typename P1,typename P2,typename Op>
    00656 GIL_FORCEINLINE
    00657 Op static_for_each(P1& p1,      P2& p2, Op op)             { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
    00658 template <typename P1,typename P2,typename Op>
    00659 GIL_FORCEINLINE
    00660 Op static_for_each(P1& p1,const P2& p2, Op op)             { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
    00661 template <typename P1,typename P2,typename Op>
    00662 GIL_FORCEINLINE
    00663 Op static_for_each(const P1& p1,      P2& p2, Op op)             { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
    00664 template <typename P1,typename P2,typename Op>
    00665 GIL_FORCEINLINE
    00666 Op static_for_each(const P1& p1,const P2& p2, Op op)             { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
    00667 //static_for_each with three sources
    00668 template <typename P1,typename P2,typename P3,typename Op>
    00669 GIL_FORCEINLINE
    00670 Op static_for_each(P1& p1,P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
    00671 template <typename P1,typename P2,typename P3,typename Op>
    00672 GIL_FORCEINLINE
    00673 Op static_for_each(P1& p1,P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
    00674 template <typename P1,typename P2,typename P3,typename Op>
    00675 GIL_FORCEINLINE
    00676 Op static_for_each(P1& p1,const P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
    00677 template <typename P1,typename P2,typename P3,typename Op>
    00678 GIL_FORCEINLINE
    00679 Op static_for_each(P1& p1,const P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
    00680 template <typename P1,typename P2,typename P3,typename Op>
    00681 GIL_FORCEINLINE
    00682 Op static_for_each(const P1& p1,P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
    00683 template <typename P1,typename P2,typename P3,typename Op>
    00684 GIL_FORCEINLINE
    00685 Op static_for_each(const P1& p1,P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
    00686 template <typename P1,typename P2,typename P3,typename Op>
    00687 GIL_FORCEINLINE
    00688 Op static_for_each(const P1& p1,const P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
    00689 template <typename P1,typename P2,typename P3,typename Op>
    00690 GIL_FORCEINLINE
    00691 Op static_for_each(const P1& p1,const P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
    00693
    00694 } }  // namespace boost::gil
    00695
    00696 #endif