4040#include < boost/range/algorithm/copy.hpp>
4141#include < string>
4242#include < map>
43+ #include < Dataflow/Network/share.h>
4344
4445namespace SCIRun {
4546namespace Dataflow {
@@ -54,13 +55,17 @@ class PortManager : boost::noncopyable
5455 PortMap ports_;
5556 DynamicMap isDynamic_;
5657 ModuleInterface* module_;
57-
58+ void checkDynamicPortInvariant (const std::string& name);
59+ void throwForPortNotFound (const PortId& id) const ;
60+ std::vector<T> findAllByName (const std::string& name) const ;
61+
5862public:
5963 PortManager ();
6064 size_t size () const ;
6165 size_t add (const T& item);
6266 void remove (const PortId& id);
6367 T operator [](const PortId& id);
68+ T operator [](const PortId& id) const ;
6469 std::vector<T> operator [](const std::string& name) const ;
6570 bool hasPort (const PortId& id) const ;
6671 void set_module (ModuleInterface* mod) { module_ = mod; }
@@ -88,12 +93,33 @@ PortManager<T>::add(const T& item)
8893{
8994 ports_[item->id ()] = item;
9095 isDynamic_[item->id ().name ] = item->isDynamic ();
96+
97+ if (item->isDynamic ())
98+ checkDynamicPortInvariant (item->id ().name );
99+
91100 // / @todo: who should manage port indexes?
92101 // item->setIndex(size() - 1);
93102 auto index = size () - 1 ;
94103 return index;
95104}
96105
106+ template <class T >
107+ void
108+ PortManager<T>::checkDynamicPortInvariant(const std::string& name)
109+ {
110+ auto byName = findAllByName (name);
111+ const size_t lastIndex = byName.size () - 1 ;
112+ std::vector<PortId> toRemove;
113+ for (int i = 0 ; i < byName.size (); ++i)
114+ {
115+ auto port = byName[i];
116+ if (0 == port->nconnections () && i != lastIndex)
117+ toRemove.push_back (port->id ());
118+ }
119+ BOOST_FOREACH (const PortId& id, toRemove)
120+ remove (id);
121+ }
122+
97123template <class T >
98124void
99125PortManager<T>::remove(const PortId& id)
@@ -120,40 +146,55 @@ PortManager<T>::operator[](const PortId& id)
120146 {
121147 if (isDynamic_[id.name ])
122148 {
123- auto byName = this -> operator [] (id.name );
149+ auto byName = findAllByName (id.name );
124150 if (byName.empty ())
125151 {
126- std::ostringstream ostr;
127- ostr << " PortManager tried to access a port that does not exist: " << id;
128- BOOST_THROW_EXCEPTION (PortOutOfBoundsException () << Core::ErrorMessage (ostr.str ()));
152+ throwForPortNotFound (id);
129153 }
130- auto newPort = byName[0 ]->clone ();
154+ auto newPort = boost::shared_ptr< typename T::element_type>( byName[0 ]->clone () );
131155 newPort->setId (id);
132- add (newPort);
156+ newPort-> setIndex ( add (newPort) );
133157 return newPort;
134158 }
159+ }
160+ return it->second ;
161+ }
135162
163+ template <class T >
164+ void
165+ PortManager<T>::throwForPortNotFound(const PortId& id) const
166+ {
167+ std::ostringstream ostr;
168+ ostr << " PortManager tried to access a port that does not exist: " << id;
169+ BOOST_THROW_EXCEPTION (PortOutOfBoundsException () << Core::ErrorMessage (ostr.str ()));
170+ }
136171
137- // / @todo: need a way to detect and create arbitrary dynamic ports from serialized files.
138- // if (id.dynamic)
139- // std::cout << "DYNAMIC PORT NEEDS TO INSERT ITSELF HERE SOMEHOW" << std::endl;
140- // else
141- // std::cout << "NOT SETTING PORT FLAGS CORRECT" << std::endl ;
142- // std::ostringstream ostr;
143- // ostr << "PortManager tried to access a port that does not exist: " << id;
144- // BOOST_THROW_EXCEPTION(PortOutOfBoundsException() << Core::ErrorMessage(ostr.str()) );
172+ template < class T >
173+ T
174+ PortManager<T>:: operator []( const PortId& id) const
175+ {
176+ auto it = ports_. find (id) ;
177+ if (it == ports_. end ())
178+ {
179+ throwForPortNotFound (id );
145180 }
146181 return it->second ;
147182}
148183
149184template <class T >
150185std::vector<T> PortManager<T>::operator [](const std::string& name) const
186+ {
187+ return findAllByName (name);
188+ }
189+
190+ template <class T >
191+ std::vector<T> PortManager<T>::findAllByName(const std::string& name) const
151192{
152193 std::vector<T> portsWithName;
153194
154195 boost::copy (
155196 ports_ | boost::adaptors::map_values
156- | boost::adaptors::filtered ([&](const T& port) { return port->get_portname () == name; }), std::back_inserter (portsWithName));
197+ | boost::adaptors::filtered ([&](const T& port) { return port->get_portname () == name; }), std::back_inserter (portsWithName));
157198
158199 if (portsWithName.empty ())
159200 {
0 commit comments