libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/new_graph/port.hpp
Go to the documentation of this file.
00001 
00011 /*
00012  *  Copyright (C) 2011 Juan Pedro BolĂ­var Puente
00013  *
00014  *  This file is part of Psychosynth.
00015  *   
00016  *  Psychosynth is free software: you can redistribute it and/or modify
00017  *  it under the terms of the GNU General Public License as published by
00018  *  the Free Software Foundation, either version 3 of the License, or
00019  *  (at your option) any later version.
00020  *
00021  *  Psychosynth is distributed in the hope that it will be useful,
00022  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  *  GNU General Public License for more details.
00025  *
00026  *  You should have received a copy of the GNU General Public License
00027  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00028  *
00029  */
00030 
00031 #ifndef PSYNTH_PORT_HPP_
00032 #define PSYNTH_PORT_HPP_
00033 
00034 #include <map>
00035 #include <list>
00036 #include <atomic>
00037 #include <iostream> // FIXME: remove
00038 
00039 #include <boost/any.hpp>
00040 #include <boost/range/iterator_range.hpp>
00041 #include <boost/intrusive/list.hpp>
00042 
00043 #include <psynth/base/type_value.hpp>
00044 #include <psynth/base/iterator.hpp>
00045 #include <psynth/new_graph/exception.hpp>
00046 #include <psynth/new_graph/node_fwd.hpp>
00047 #include <psynth/new_graph/processor_fwd.hpp>
00048 
00049 namespace psynth
00050 {
00051 namespace graph
00052 {
00053 
00054 PSYNTH_DECLARE_ERROR (error, port_error);
00055 PSYNTH_DECLARE_ERROR (port_error, port_type_error);
00056 PSYNTH_DECLARE_ERROR (port_error, port_patch_error);
00057 
00058 typedef std::map<std::string, boost::any> port_meta;
00059 extern const port_meta default_port_meta;
00060 
00061 class out_port_base;
00062 class in_port_base;
00063 
00064 class port_base : private boost::noncopyable
00065 {
00066 public:
00067     virtual base::type_value type () const = 0;
00068     virtual const port_meta& meta () const = 0;
00069     virtual void rt_context_update (rt_process_context&) {}
00070     
00071     std::string name ()
00072     { return _name; }
00073     
00074     node& owner ()
00075     { return *_owner; }
00076     const node& owner () const
00077     { return *_owner; }
00078     
00079     void _set_owner (node* new_owner = 0);
00080     void _set_name (std::string new_name);
00081     bool _has_owner () const
00082     { return _owner != 0; }
00083     
00084 protected:
00085     port_base (std::string name, node* owner);
00086         
00087 private:
00088     std::string _name;
00089     node* _owner;
00090 };
00091 
00092 struct out_port_referee_hook_tag;
00093 typedef boost::intrusive::list_member_hook<
00094     boost::intrusive::link_mode<boost::intrusive::auto_unlink>,
00095     boost::intrusive::tag<out_port_referee_hook_tag>
00096     >
00097 out_port_referee_hook;
00098 
00099 void check_port_compatibility (in_port_base& in, out_port_base& out);
00100 
00101 class in_port_base : public port_base
00102 {   
00103 public:
00104     out_port_referee_hook _out_port_referee_hook;
00105     
00106     virtual void connect (out_port_base& port);
00107     virtual void disconnect ();
00108     
00109     bool connected () const
00110     { return _source_port != 0; }
00111     bool rt_connected () const
00112     { return _rt_source_port != 0; }
00113 
00114     out_port_base& source ()
00115     { return *_source_port; }
00116     out_port_base& rt_source ()
00117     { return *_rt_source_port; }
00118     const out_port_base& source () const
00119     { return *_source_port; }
00120     const out_port_base& rt_source () const
00121     { return *_rt_source_port; }
00122 
00123     virtual bool rt_in_available () const;
00124     virtual void rt_process (rt_process_context& rt);
00125     
00126 protected:
00127     in_port_base (std::string name, graph::node* owner);
00128 
00133     void _connect (out_port_base* source);
00134     void _user_connect (out_port_base* source);
00135     void _rt_connect (out_port_base* source);
00136 
00137 private:
00138     out_port_base* _source_port;
00139     out_port_base* _rt_source_port;
00140 };
00141 
00142 namespace detail { class out_port_access; }
00143 
00144 class out_port_base : public port_base
00145 {
00146     typedef std::list<in_port_base*> reference_list;
00147     typedef boost::intrusive::list<
00148         in_port_base,
00149         boost::intrusive::constant_time_size<false>,
00150         boost::intrusive::member_hook<
00151             in_port_base,
00152             out_port_referee_hook,
00153             &in_port_base::_out_port_referee_hook> >
00154     rt_reference_list;
00155 
00156 public:
00157     typedef base::ptr_iterator<reference_list::iterator>
00158     reference_iterator;
00159     typedef base::ptr_iterator<reference_list::const_iterator>
00160     reference_const_iterator;
00161     typedef boost::iterator_range<reference_iterator>
00162     reference_range;
00163     typedef boost::iterator_range<reference_const_iterator>
00164     const_reference_range;
00165 
00166     void disconnect ();
00167     
00168     bool connected ()
00169     { return !_refs.empty (); }
00170     
00171     bool rt_connected ()
00172     { return !_rt_refs.empty (); }
00173     // FIXME: Add concurrent access to refs policy
00174 
00175     virtual bool rt_out_available () const
00176     { return true; }
00177     
00178     reference_range references ()
00179     { return reference_range (_refs.begin (), _refs.end ()); }
00180     const_reference_range references () const
00181     { return const_reference_range (_refs.begin (), _refs.end ()); }
00182     
00183 protected:
00184     out_port_base (std::string name, node* owner);
00185     
00186 private:
00187     void _add_reference (in_port_base*);
00188     void _del_reference (in_port_base*);
00189     
00190     friend class detail::out_port_access;
00191     
00192     reference_list    _refs;
00193     rt_reference_list _rt_refs;
00194 };
00195 
00196 namespace detail
00197 {
00198 
00199 struct out_port_access
00200 {
00201     static void add_reference (out_port_base& self, in_port_base* param)
00202     { self._add_reference (param); }
00203 
00204     static void del_reference (out_port_base& self, in_port_base* param)
00205     { self._del_reference (param); }
00206 };
00207 
00208 } /* namespace detail */
00209 
00210 template <typename T>
00211 class typed_out_port_base : public out_port_base
00212 {
00213 public:
00214     typedef T port_type;
00215     
00216     virtual T& rt_get_out () = 0;
00217     virtual const T& rt_get_out () const = 0;
00218 
00219     base::type_value type () const
00220     { return typeid (T); }
00221 
00222 protected:
00223     typed_out_port_base (std::string name, node* owner)
00224         : out_port_base (name, owner) {}
00225 };
00226 
00227 template <typename T>
00228 class typed_in_port_base : public in_port_base
00229 {
00230 public:
00231     typedef T port_type;
00232 
00233     virtual const T& rt_get_in () const = 0;
00234 
00235     base::type_value type () const
00236     { return typeid (T); }
00237 
00238 protected:
00239     typed_in_port_base (std::string name, node* owner)
00240         : in_port_base (name, owner) {}
00241 };
00242 
00243 template <typename T>
00244 class out_port : public typed_out_port_base<T>
00245 {
00246 public:
00247     typedef T port_type;
00248     
00249     out_port (std::string name, node* owner, const T& value = T())
00250         : typed_out_port_base<T> (name, owner)
00251         , _data (value){}
00252     
00253     T& rt_get_out ()
00254     { return _data; }
00255     
00256     const T& rt_get_out () const
00257     { return _data; }
00258     
00259     const port_meta& meta () const 
00260     { return default_port_meta; }  // FIXME !!!
00261     
00262 private:
00263     T _data;
00264 };
00265 
00266 template <typename T>
00267 class in_port : public typed_in_port_base<T>
00268 {
00269 public:
00270     in_port (std::string name, node* owner)
00271         : typed_in_port_base<T> (name, owner) {}
00272     
00273     const port_meta& meta () const 
00274     { return default_port_meta; } // FIXME !!!
00275 
00276     const T& rt_get_in () const
00277     {
00278         // Relies on the connection being made right!
00279         return static_cast<const out_port<T>&> (
00280             this->rt_source ()).rt_get_out ();
00281     }
00282     
00283 private:
00284 };
00285 
00290 template <class InPort,
00291           class OutPort>
00292 class forward_port_impl
00293     : public InPort
00294     , public OutPort
00295 {
00296 public:
00297     typedef typename InPort::port_type port_type;
00298     
00299     static_assert (
00300         std::is_same<typename InPort::port_type,
00301                      typename OutPort::port_type>::value,
00302         "Can not forward different types");
00303     
00304     void rt_context_update (rt_process_context& ctx)
00305     {
00306         InPort::rt_context_update (ctx);
00307         OutPort::rt_context_update (ctx);
00308     }
00309     
00310     base::type_value type () const
00311     { return typeid (port_type); }
00312 
00313     const port_meta& meta () const 
00314     { return default_port_meta; } // FIXME !!!
00315     
00316     const port_type& rt_get_out () const
00317     {
00318         if (InPort::rt_connected ())
00319             return this->rt_get_in ();
00320         return OutPort::rt_get_out ();
00321     }
00322 
00323     bool rt_out_available () const
00324     { return InPort::rt_connected (); }
00325 
00326 protected:
00327     forward_port_impl (std::string in_name,
00328                        std::string out_name,
00329                        node* in_owner,
00330                        node* out_owner)
00331         : InPort (in_name, in_owner)
00332         , OutPort (out_name, out_owner)
00333     {}
00334 };
00335 
00336 template <typename T>
00337 struct forward_port
00338     : public forward_port_impl<in_port<T>,
00339                                out_port<T> >
00340 {
00341     typedef forward_port_impl<in_port<T>, out_port<T> > base_type;
00342 
00343     forward_port (std::string in_name,
00344                   std::string out_name,
00345                   node* in_owner,
00346                   node* out_owner)
00347         : base_type (in_name, out_name,
00348                      in_owner, out_owner)
00349     {}
00350 };
00351 
00352 } /* namespace graph */
00353 } /* namespace psynth */
00354 
00355 #include <psynth/new_graph/port.tpp>
00356 
00357 #endif /* PSYNTH_PORT_HPP_ */