libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/sound/algorithm.hpp
Go to the documentation of this file.
00001 
00015 /*
00016  *  Copyright (C) 2010 Juan Pedro Bolivar Puente
00017  *
00018  *  This file is part of Psychosynth.
00019  *   
00020  *  Psychosynth is free software: you can redistribute it and/or modify
00021  *  it under the terms of the GNU General Public License as published by
00022  *  the Free Software Foundation, either version 3 of the License, or
00023  *  (at your option) any later version.
00024  *
00025  *  Psychosynth is distributed in the hope that it will be useful,
00026  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00027  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00028  *  GNU General Public License for more details.
00029  *
00030  *  You should have received a copy of the GNU General Public License
00031  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00032  *
00033  */
00034 
00035 /*
00036  *  Copyright 2005-2007 Adobe Systems Incorporated
00037  * 
00038  *  Use, modification and distribution are subject to the Boost
00039  *  Software License, Version 1.0. (See accompanying file
00040  *  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
00041  */
00042 
00043 #ifndef PSYNTH_SOUND_ALGORITHM_HPP
00044 #define PSYNTH_SOUND_ALGORITHM_HPP
00045 
00046 #include <cassert>
00047 #include <cstddef>
00048 #include <cstring>
00049 #include <algorithm>
00050 #include <iterator>
00051 #include <memory>
00052 #include <typeinfo>
00053 
00054 #include <psynth/base/compat.hpp>
00055 #include <psynth/base/concept.hpp>
00056 #include <psynth/sound/concept.hpp>
00057 #include <psynth/sound/channel_base_algorithm.hpp>
00058 #include <psynth/sound/buffer_range.hpp>
00059 #include <psynth/sound/buffer_range_factory.hpp>
00060 #include <psynth/sound/bit_aligned_frame_iterator.hpp>
00061 
00062 //#ifdef _MSC_VER
00063 //#pragma warning(push)
00064 //#pragma warning(disable : 4244)
00065 // conversion from 'psynth::image<V,Alloc>::coord_t' to 'int', possible
00066 // loss of data (visual studio compiler doesn't realize that the two
00067 // types are the same)
00068 //#endif
00069 
00070 namespace psynth
00071 {
00072 namespace sound
00073 {
00074 
00075 template <typename SamplePtr, typename ChannelSpace>
00076 struct planar_frame_iterator;
00077 template <typename Iterator>
00078 class memory_based_step_iterator;
00079 
00081 struct error_type {};
00082 
00142 template <typename Derived, typename Result = void>
00143 struct binary_operation_obj
00144 {
00145     typedef Result result_type;
00146 
00147     template <typename V1, typename V2> PSYNTH_FORCEINLINE
00148     result_type operator () (const std::pair<const V1*, const V2*>& p) const
00149     {
00150         return apply (*p.first, *p.second,
00151                       typename ranges_are_compatible<V1,V2>::type());
00152     }
00153 
00154     template <typename V1, typename V2> PSYNTH_FORCEINLINE
00155     result_type operator () (const V1& v1, const V2& v2) const
00156     {
00157         return apply (v1, v2, typename ranges_are_compatible<V1,V2>::type ());
00158     }
00159 
00160     result_type operator () (const error_type&) const
00161     {
00162         throw std::bad_cast();
00163     }
00164     
00165 private:
00166 
00167     // dispatch from apply overload to a function with distinct name
00168     template <typename V1, typename V2> PSYNTH_FORCEINLINE
00169     result_type apply(const V1& v1, const V2& v2, boost::mpl::false_) const
00170     {
00171         return ((const Derived*) this)->apply_incompatible (v1,v2);
00172     }
00173 
00174     // dispatch from apply overload to a function with distinct name
00175     template <typename V1, typename V2> PSYNTH_FORCEINLINE
00176     result_type apply(const V1& v1, const V2& v2, boost::mpl::true_) const
00177     {
00178         return ((const Derived*)this)->apply_compatible(v1,v2);
00179     }
00180 
00181     // function with distinct name - it can be overloaded by subclasses
00182     template <typename V1, typename V2> PSYNTH_FORCEINLINE
00183     result_type apply_incompatible (const V1& v1, const V2& v2) const
00184     {
00185         throw std::bad_cast();
00186     }
00187 };
00188 
00189 } /* namespace sound */
00190 } /* namespace psynth */
00191 
00192 
00199 namespace std
00200 {
00201 
00207 template<typename T, typename Cs> 
00208 PSYNTH_FORCEINLINE psynth::sound::frame<T,Cs>* 
00209 copy (psynth::sound::frame<T,Cs>* first,
00210       psynth::sound::frame<T,Cs>* last, 
00211       psynth::sound::frame<T,Cs>* dst)
00212 { 
00213     return (psynth::sound::frame<T,Cs>*) std::copy (
00214         (unsigned char*) first,
00215         (unsigned char*) last,
00216         (unsigned char*) dst);
00217 }
00218 
00224 template<typename T, typename Cs> 
00225 PSYNTH_FORCEINLINE psynth::sound::frame<T,Cs>* 
00226 copy (const psynth::sound::frame<T,Cs>* first,
00227       const psynth::sound::frame<T,Cs>* last, 
00228       psynth::sound::frame<T,Cs>* dst)
00229 { 
00230     return (psynth::sound::frame<T,Cs>*) std::copy(
00231         (unsigned char*) first,
00232         (unsigned char*) last,
00233         (unsigned char*) dst);
00234 }
00235 
00236 } /* namespace std */
00237 
00238 namespace psynth
00239 {
00240 namespace sound
00241 {
00242 namespace detail
00243 {
00244 
00245 template <typename I, typename O>
00246 struct copy_fn
00247 { 
00248     PSYNTH_FORCEINLINE I operator() (I first, I last, O dst) const
00249     {
00250         return std::copy (first, last, dst);
00251     } 
00252 };
00253 
00254 } /* namespace detail */
00255 } /* namespace sound */
00256 } /* namespace psynth */
00257 
00258 namespace std
00259 {
00260 
00266 template<typename Cs, typename IC1, typename IC2> PSYNTH_FORCEINLINE
00267 psynth::sound::planar_frame_iterator<IC2,Cs>
00268 copy (psynth::sound::planar_frame_iterator<IC1,Cs> first,
00269       psynth::sound::planar_frame_iterator<IC1,Cs> last,
00270       psynth::sound::planar_frame_iterator<IC2,Cs> dst)
00271 { 
00272     psynth::base::psynth_function_requires <
00273         psynth::sound::SamplesCompatibleConcept<
00274             typename std::iterator_traits<IC1>::value_type,
00275             typename std::iterator_traits<IC2>::value_type> >();
00276     static_for_each (first, last, dst, psynth::sound::detail::copy_fn<IC1,IC2>());
00277     return dst + (last - first);
00278 }
00279 
00280 } // namespace std
00281 
00282 
00283 namespace psynth
00284 {
00285 namespace sound
00286 {
00287 
00292 template <typename Range1, typename Range2> PSYNTH_FORCEINLINE
00293 void copy_frames (const Range1& src, const Range2& dst)
00294 { 
00295     assert (src.size () == dst.size ());
00296     std::copy (src.begin(), src.end(), dst.begin());
00297 }
00298 
00311 namespace detail
00312 {
00313 
00314 template <typename CC>
00315 class copy_and_convert_frames_fn :
00316         public binary_operation_obj <copy_and_convert_frames_fn<CC> >
00317 {
00318 private:
00319     CC _cc;
00320 
00321 public:
00322     typedef typename
00323     binary_operation_obj<copy_and_convert_frames_fn<CC> >::result_type
00324     result_type;
00325 
00326     copy_and_convert_frames_fn () {}
00327 
00328     copy_and_convert_frames_fn (CC cc_in)
00329         : _cc(cc_in)
00330     {}
00331     
00332     // when the two channel spaces are incompatible, a channel
00333     // conversion is performed
00334     template <typename V1, typename V2> PSYNTH_FORCEINLINE 
00335     result_type apply_incompatible (const V1& src, const V2& dst) const
00336     {
00337         copy_frames (channel_converted_range<typename V2::value_type>(src, _cc),
00338                      dst);
00339     }
00340 
00341     // If the two channel spaces are compatible, copy_and_convert is
00342     // just copy
00343     template <typename V1, typename V2> PSYNTH_FORCEINLINE 
00344     result_type apply_compatible (const V1& src, const V2& dst) const
00345     {
00346          copy_frames (src,dst);
00347     }
00348 };
00349 
00350 } /* namespace detail */
00351 
00355 template <typename V1, typename V2,typename CC> 
00356 PSYNTH_FORCEINLINE 
00357 void copy_and_convert_frames (const V1& src, const V2& dst, CC cc)
00358 {
00359     detail::copy_and_convert_frames_fn<CC> ccp (cc);
00360     ccp (src, dst);
00361 }
00362 
00363 struct default_channel_converter;
00364 
00368 template <typename Range1, typename Range2> 
00369 PSYNTH_FORCEINLINE 
00370 void copy_and_convert_frames (const Range1& src, const Range2& dst)
00371 { 
00372     detail::copy_and_convert_frames_fn<default_channel_converter> ccp;
00373     ccp (src, dst);
00374 }
00375 
00376 }  /* namespace sound */
00377 }  /* namespace psynth */
00378 
00379 
00389 namespace psynth
00390 {
00391 namespace sound
00392 {
00393 
00394 namespace detail
00395 {
00396 
00398 struct std_fill_type
00399 {
00400     template <typename It, typename P>
00401     void operator () (It first, It last, const P& p_in)
00402     {
00403         std::fill (first, last, p_in);
00404     }
00405 };
00406 
00408 template <typename It, typename P>
00409 PSYNTH_FORCEINLINE 
00410 void fill_aux (It first, It last, const P& p, boost::mpl::true_)
00411 {
00412     static_for_each (first, last, p, std_fill_type ());
00413 }
00414 
00416 template <typename It, typename P>
00417 PSYNTH_FORCEINLINE 
00418 void fill_aux(It first, It last, const P& p, boost::mpl::false_)
00419 {
00420     std::fill (first, last, p);
00421 }
00422 
00423 } /* namespace detail */
00424 
00429 template <typename Range, typename Value> PSYNTH_FORCEINLINE 
00430 void fill_frames (const Range& buf_range, const Value& val)
00431 {
00432     detail::fill_aux (buf_range.begin (), buf_range.end (), 
00433                       val, is_planar<Range>());
00434 }
00435 
00440 template <typename Range, typename Value> PSYNTH_FORCEINLINE 
00441 void fill_frames (Range& buf_range, const Value& val)
00442 {
00443     detail::fill_aux (buf_range.begin (), buf_range.end (), 
00444                       val, is_planar<Range>());
00445 }
00446 
00447 namespace detail
00448 {
00449 
00450 template <typename It> PSYNTH_FORCEINLINE
00451 void destruct_range_impl (It first, It last, boost::mpl::true_)
00452 {
00453     typedef typename std::iterator_traits<It>::value_type value_t;
00454     if (boost::has_trivial_destructor<value_t>::value)
00455         return;
00456     while (first != last) {
00457         first->~value_t ();
00458         ++first;
00459     }
00460 }
00461 
00462 template <typename It> PSYNTH_FORCEINLINE
00463 void destruct_range_impl (It, It, boost::mpl::false_) {}
00464 
00465 template <typename It> PSYNTH_FORCEINLINE
00466 void destruct_range (It first, It last)
00467 {
00468     destruct_range_impl (first, last, typename boost::is_pointer<It>::type ());
00469 }
00470 
00471 struct std_destruct_t
00472 {
00473     template <typename It> void operator ()(It first, It last) const
00474     {
00475         destruct_range (first,last);
00476     }
00477 };
00478 
00480 template <typename It>
00481 PSYNTH_FORCEINLINE 
00482 void destruct_aux (It first, It last, boost::mpl::true_)
00483 {
00484     static_for_each (first, last, std_destruct_t ());
00485 }
00486 
00488 template <typename It>
00489 PSYNTH_FORCEINLINE 
00490 void destruct_aux (It first, It last, boost::mpl::false_)
00491 {
00492     destruct_range (first,last);
00493 }
00494 
00495 } /* namespace detail */
00496 
00501 template <typename Range> PSYNTH_FORCEINLINE 
00502 void destruct_frames (const Range& buf_range)
00503 {
00504     detail::destruct_aux (buf_range.begin (), buf_range.end (),
00505                           is_planar<Range>());
00506 }
00507 
00508 
00517 namespace detail
00518 {
00519 
00525 template <typename It, typename P>
00526 PSYNTH_FORCEINLINE 
00527 void uninitialized_fill_aux (It first, It last,
00528                              const P& p, boost::mpl::true_)
00529 {
00530     int sample=0;
00531     try {
00532         typedef typename std::iterator_traits<It>::value_type frame_t;
00533         while (sample < num_samples<frame_t>::value) {
00534             std::uninitialized_fill (dynamic_at_c (first, sample),
00535                                      dynamic_at_c (last,  sample), 
00536                                      dynamic_at_c (p,     sample));
00537             ++ sample;
00538         }
00539     }
00540     catch (...)
00541     {
00542         for (int c = 0; c < sample; ++c)
00543             destruct_range (dynamic_at_c (first,c), dynamic_at_c (last,c));
00544         throw;
00545     }
00546 }
00547 
00553 template <typename It, typename P>
00554 PSYNTH_FORCEINLINE 
00555 void uninitialized_fill_aux (It first, It last,
00556                              const P& p, boost::mpl::false_)
00557 {
00558     std::uninitialized_fill (first, last, p);
00559 }
00560 
00561 } /* namespace detail */
00562 
00570 template <typename Range, typename Value> 
00571 PSYNTH_FORCEINLINE
00572 void uninitialized_fill_frames (const Range& buf_range, const Value& val)
00573 {
00574     detail::uninitialized_fill_aux (buf_range.begin(),
00575                                     buf_range.end(), 
00576                                     val, is_planar<Range>());
00577 }
00578 
00588 namespace detail
00589 {
00590 
00591 template <typename It> PSYNTH_FORCEINLINE 
00592 void default_construct_range_impl (It first, It last, boost::mpl::true_)
00593 {
00594     typedef typename std::iterator_traits<It>::value_type value_t;
00595     It first1=first;
00596     try {
00597         while (first!=last) {
00598             new (first) value_t ();
00599             ++first;
00600         }
00601     } catch (...) {
00602         destruct_range (first1, first);
00603         throw;
00604     }
00605 }
00606 
00607 template <typename It> PSYNTH_FORCEINLINE 
00608 void default_construct_range_impl (It, It, boost::mpl::false_) {}
00609 
00610 template <typename It> PSYNTH_FORCEINLINE 
00611 void default_construct_range (It first, It last)
00612 {
00613     default_construct_range_impl (
00614         first, last, typename boost::is_pointer<It>::type());
00615 }
00616 
00618 template <typename It>
00619 PSYNTH_FORCEINLINE 
00620 void default_construct_aux (It first, It last, boost::mpl::true_)
00621 {
00622     int sample=0;
00623     try {
00624         typedef typename std::iterator_traits<It>::value_type frame_t;
00625         while (sample < num_samples<frame_t>::value) {
00626             default_construct_range (dynamic_at_c (first, sample),
00627                                      dynamic_at_c (last, sample));
00628             ++sample;
00629         }
00630     } catch (...) {
00631         for (int c=0; c<sample; ++c)
00632             destruct_range (dynamic_at_c(first,c), dynamic_at_c(last,c));
00633         throw;
00634     }
00635 }
00636 
00638 template <typename It>
00639 PSYNTH_FORCEINLINE 
00640 void default_construct_aux (It first, It last, boost::mpl::false_)
00641 {
00642     default_construct_range (first, last);
00643 }
00644 
00645 template <typename Range, bool IsPlanar>
00646 struct has_trivial_frame_constructor :
00647     public boost::has_trivial_constructor <typename Range::value_type> {};
00648 
00649 template <typename Range>
00650 struct has_trivial_frame_constructor<Range, true> :
00651     public boost::has_trivial_constructor <
00652     typename sample_type<Range>::type> {};
00653 
00654 } /* namespace detail */
00655 
00665 template <typename Range> 
00666 PSYNTH_FORCEINLINE
00667 void default_construct_frames (const Range& buf_range)
00668 {
00669     if (detail::has_trivial_frame_constructor<
00670             Range, is_planar<Range>::value>::value)
00671         return;
00672  
00673     detail::default_construct_aux (buf_range.begin (),
00674                                    buf_range.end (),
00675                                    is_planar<Range>());
00676 }
00677 
00678 namespace detail
00679 {
00680 
00682 template <typename It1, typename It2>
00683 PSYNTH_FORCEINLINE 
00684 void uninitialized_copy_aux (It1 first1, It1 last1,
00685                              It2 first2, boost::mpl::true_)
00686 {
00687     int sample = 0;
00688     try {
00689         typedef typename std::iterator_traits<It1>::value_type frame_t;
00690         while (sample < num_samples<frame_t>::value) {
00691             std::uninitialized_copy (dynamic_at_c (first1,sample),
00692                                      dynamic_at_c (last1,sample),
00693                                      dynamic_at_c (first2,sample));
00694             ++ sample;
00695         }
00696     } catch (...) {
00697         It2 last2 = first2;
00698         std::advance (last2, std::distance (first1, last1));
00699         for (int c = 0; c < sample; ++c)
00700             destruct_range (dynamic_at_c (first2, c),
00701                             dynamic_at_c (last2, c));
00702         throw;
00703     }
00704 }
00705 
00707 template <typename It1, typename It2>
00708 PSYNTH_FORCEINLINE 
00709 void uninitialized_copy_aux (It1 first1, It1 last1,
00710                              It2 first2, boost::mpl::false_)
00711 {
00712     std::uninitialized_copy(first1,last1,first2);
00713 }
00714 
00715 } /* namespace detail */
00716 
00724 template <typename Range1, typename Range2>
00725 PSYNTH_FORCEINLINE
00726 void uninitialized_copy_frames (const Range1& range1, const Range2& range2)
00727 {
00728     typedef boost::mpl::bool_<is_planar<Range1>::value &&
00729                               is_planar<Range2>::value> is_planar;
00730     assert (range1.size () == range2.size ());
00731     
00732     detail::uninitialized_copy_aux (range1.begin (), range1.end (), 
00733                                     range2.begin (), is_planar ());
00734 }
00735 
00749 template <typename V, typename F>
00750 PSYNTH_FORCEINLINE
00751 F for_each_frame (const V& buf, F fun)
00752 {
00753     return std::for_each (buf.begin (), buf.end(), fun);
00754 }
00755 
00767 template <typename Range, typename F>
00768 PSYNTH_FORCEINLINE
00769 F for_each_frame_position (const Range& buf, F fun)
00770 {
00771     for (auto loc = buf.begin (); loc != buf.end (); ++loc)
00772         fun (loc);
00773     
00774     return fun;
00775 }
00776 
00785 template <typename Range, typename F>
00786 PSYNTH_FORCEINLINE
00787 void generate_frames (const Range& v, F fun)
00788 {
00789     std::generate (v.begin (), v.end (), fun);
00790 }
00791 
00797 template <typename I1, typename I2> PSYNTH_FORCEINLINE
00798 bool equal_n (I1 i1, std::ptrdiff_t n, I2 i2);
00799 
00800 namespace detail
00801 {
00802 
00803 template <typename I1, typename I2>
00804 struct equal_n_fn
00805 {
00806     PSYNTH_FORCEINLINE
00807     bool operator () (I1 i1, std::ptrdiff_t n, I2 i2) const
00808     {
00809         return std::equal (i1, i1+n, i2);
00810     }
00811 };
00812 
00818 template<typename T, typename Cs>
00819 struct equal_n_fn<const frame<T,Cs>*, const frame<T,Cs>*>
00820 {
00821     PSYNTH_FORCEINLINE
00822     bool operator () (const frame<T,Cs>* i1, std::ptrdiff_t n,
00823                       const frame<T,Cs>* i2) const
00824     { 
00825         return memcmp (i1, i2, n * sizeof (frame<T,Cs>)) == 0;
00826     }
00827 };
00828 
00829 template<typename T, typename Cs>
00830 struct equal_n_fn<frame<T,Cs>*, frame<T,Cs>*> :
00831     equal_n_fn<const frame<T,Cs>*, const frame<T,Cs>*> {};
00832 
00840 template<typename IC, typename Cs>
00841 struct equal_n_fn<planar_frame_iterator<IC,Cs>,
00842                   planar_frame_iterator<IC,Cs> >
00843 {
00844     PSYNTH_FORCEINLINE
00845     bool operator () (const planar_frame_iterator<IC,Cs> i1,
00846                       std::ptrdiff_t n,
00847                       const planar_frame_iterator<IC,Cs> i2) const
00848     { 
00849         ptrdiff_t num_bytes = n * sizeof (
00850             typename std::iterator_traits<IC>::value_type);
00851 
00852         for (std::ptrdiff_t i=0; i<boost::mpl::size<Cs>::value; ++i)
00853             if (memcmp (dynamic_at_c (i1, i),
00854                         dynamic_at_c (i2, i), num_bytes) != 0)
00855                 return false;
00856         return true;
00857     }
00858 };
00859 
00860 } /* namespace detail */
00861 
00862 template <typename I1, typename I2> PSYNTH_FORCEINLINE
00863 bool equal_n (I1 i1, std::ptrdiff_t n, I2 i2)
00864 {
00865     return detail::equal_n_fn<I1,I2>() (i1, n, i2);
00866 }
00867 
00868 } /* namespace sound */
00869 } /* namespace psynth */
00870 
00871 namespace std
00872 {
00893 } /* namespace std */
00894 
00895 namespace psynth
00896 {
00897 namespace sound
00898 {
00899 
00904 template <typename Range1, typename Range2> PSYNTH_FORCEINLINE 
00905 bool equal_frames (const Range1& v1, const Range2& v2)
00906 {
00907     assert (v1.size() == v2.size());
00908     return std::equal (v1.begin (), v1.end (), v2.begin ());
00909     // std::equal has overloads with PSYNTH iterators for optimal
00910     // performance
00911     // @todo Not anymore actually. 
00912 }
00913 
00924 template <typename Range1, typename Range2, typename F> PSYNTH_FORCEINLINE 
00925 F transform_frames (const Range1& src, const Range2& dst, F fun)
00926 {
00927     assert (src.size() == dst.size());
00928     for (std::ptrdiff_t x = 0; x < src.size (); ++x)
00929         dst [x] = fun (src [x]);
00930     return fun;
00931 }
00932 
00937 template <typename Range1, typename Range2, typename Range3, typename F>
00938 PSYNTH_FORCEINLINE 
00939 F transform_frames (const Range1& src1, const Range2& src2,
00940                     const Range3& dst, F fun)
00941 {
00942     assert (src1.size () == dst.size() &&
00943             src2.size () == dst.size ());
00944     for (std::ptrdiff_t x = 0; x < dst.size (); ++x)
00945             dst [x] = fun (src1 [x], src2 [x]);
00946     return fun;
00947 }
00948 
00960 template <typename Range1, typename Range2, typename F> PSYNTH_FORCEINLINE 
00961 F transform_frame_positions (const Range1& src,const Range2& dst, F fun)
00962 {
00963     assert (src.size () == dst.size ());
00964     typename Range1::iterator loc = src.begin ();
00965 
00966     for (std::ptrdiff_t x = 0; x < src.size (); ++x, ++loc)
00967         dst [x] = fun (loc);
00968         
00969     return fun;
00970 }
00971 
00976 template <typename Range1, typename Range2, typename Range3, typename F>
00977 PSYNTH_FORCEINLINE 
00978 F transform_frame_positions (const Range1& src1,
00979                              const Range2& src2,
00980                              const Range3& dst, F fun)
00981 {
00982     assert (src1.size () == dst.size ());
00983     assert (src2.size () == dst.size ());
00984     typename Range1::iterator loc1 = src1.begin ();
00985     typename Range2::iterator loc2 = src2.begin ();
00986     for (std::ptrdiff_t x = 0; x < src1.width();
00987          ++x, ++loc1, ++loc2)
00988         dst [x] = fun (loc1, loc2);
00989         
00990     return fun;
00991 }
00992 
00993 }  /* namespace sound */
00994 }  /* namespace psynth */
00995 
00996 //#ifdef _MSC_VER
00997 //#pragma warning(pop)
00998 //#endif
00999 
01000 #endif /* PSYNTH_SOUND_ALGORITHM */