00001 #ifndef _STR_SimpleMulti_H_ // -*- mode: c++; c-file-style: "hopper"; -*- 00002 00003 /* 00004 * Copyright 1991-2002 Eric M. Hopper <hopper@omnifarious.org> 00005 * 00006 * This program is free software; you can redistribute it and/or modify it 00007 * under the terms of the GNU Lesser General Public License as published 00008 * by the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, but 00012 * WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00019 */ 00020 00021 #ifdef __GNUG__ 00022 # pragma interface 00023 #endif 00024 00025 /* $Header: /home/hopper/src/cvs/C++/StrMod/StrMod/SimpleMulti.h,v 1.11 2002/08/29 00:58:04 hopper Exp $ */ 00026 00027 // For log, see ../ChangeLog 00028 00029 #include <list> 00030 #include <StrMod/StreamModule.h> 00031 00032 #define _STR_SimpleMulti_H_ 00033 00034 namespace strmod { 00035 namespace unievent { 00036 class Dispatcher; 00037 }; 00038 }; 00039 00040 namespace strmod { 00041 namespace strmod { 00042 00043 /** \class SimpleMultiplexer SimpleMulti.h StrMod/SimpleMulti.h 00044 * \brief Use this module of you need one source copied to many 00045 * destinations, and/or many streams combined into one. 00046 * 00047 * This implements a simple multiplexer that duplicates all input on the 00048 * 'single' side to all the plugs attached to the 'multi' side, and combines all 00049 * the data from the 'multi' side into one flow on the 'single' side. 00050 * 00051 * A 'multi' side plug that isn't plugged in is considered to be dead, and no 00052 * data is routed to it. This prevents the stream from backing up. 00053 * 00054 * Currently, 'multi' side plug deletion is implemented by simply unplugging the 00055 * plug. Please don't take advantage of this detail. In the future, 'multi' 00056 * side plugs will be actually deleted. 00057 */ 00058 class SimpleMultiplexer : public StreamModule 00059 { 00060 protected: 00061 class MultiPlug; 00062 friend class MultiPlug; 00063 class SinglePlug; 00064 friend class SinglePlug; 00065 00066 public: 00067 //! The two sides available in a SimpleMultiplexer 00068 enum PublicSides { 00069 SingleSide, //!< Writing to this plug writes to all plugs connected to MultiSide plugs. 00070 MultiSide //!< Writing to his plug writes to the plug connected to the SingleSide plug. 00071 }; 00072 static const STR_ClassIdent identifier; 00073 00074 /** Construct a SimpleMultiplexer 00075 * 00076 * The strmod::unievent::Dispatcher is needed for making sure data from all 00077 * MultiSide plugs is handled fairly. Whenever the SimpleMultiplexer gets 00078 * data from a MultiPlug, it flags that plug as non-writeable and posts an 00079 * event to a strmod::unievent::Dispatcher. When that event is fired, it 00080 * resets all MultiPlugs to being writeable again. The prevens any MultiPlug 00081 * from monopolizing the SinglePlug. 00082 * 00083 * @param disp The strmod::unievent::Dispatcher to post to. */ 00084 00085 SimpleMultiplexer(unievent::Dispatcher &disp); 00086 //! Also destroys all Plug's and any unsent data. 00087 virtual ~SimpleMultiplexer(); 00088 00089 inline virtual int AreYouA(const lcore::ClassIdent &cid) const; 00090 00091 inline virtual bool canCreate(int side) const; 00092 virtual bool ownsPlug(const Plug *plug) const; 00093 virtual bool deletePlug(Plug *plug); 00094 00095 protected: 00096 class SinglePlug : public Plug { 00097 friend class SimpleMultiplexer; 00098 friend class MultiPlug; 00099 public: 00100 static const STR_ClassIdent identifier; 00101 00102 inline virtual int AreYouA(const lcore::ClassIdent &cid) const; 00103 00104 //: Which module owns this plug? 00105 inline SimpleMultiplexer &getParent() const; 00106 00107 //: What side is this plug on? 00108 virtual int side() const { return(SingleSide); } 00109 00110 protected: 00111 inline SinglePlug(SimpleMultiplexer &parent); 00112 inline virtual ~SinglePlug(); 00113 00114 virtual const lcore::ClassIdent *i_GetIdent() const { 00115 return &identifier; 00116 } 00117 00118 //: See base class. 00119 virtual const StrChunkPtr i_Read(); 00120 00121 //: See base class. 00122 virtual void i_Write(const StrChunkPtr &ptr); 00123 00124 //: Because I try to be a 'pass-through' module. 00125 virtual bool needsNotifyWriteable() const { return(true); } 00126 //: Not really a 'pass-through' read module. 00127 virtual bool needsNotifyReadable() const { return(false); } 00128 00129 //: Rather complicated, see the long explanation. 00130 // 00131 // <p>If other is writeable, and there is no pending 'update writeable 00132 // status' event, update all multi-plugs to be writeable.</p> 00133 // <p>If other isn't writeable, then update all multi-plugs to be 00134 // non-writeable.</p> 00135 virtual void otherIsWriteable(); 00136 }; 00137 00138 /** Called whenever a plug is disconnected. 00139 * Used here to record a MultiPlug as having read the mchunk_ if it's 00140 * disconnected while it's waiting to be read from. 00141 * 00142 * Also calls StreamModule::plugDisconnected so that PDstrategy handling and 00143 * things can be done there. 00144 */ 00145 inline virtual void plugDisconnected(Plug *plug); 00146 00147 virtual Plug *i_MakePlug(int side); 00148 00149 /** If a scan event isn't posted, post one. 00150 * A scan is always posted because a piece of data came into a MultiPlug, and 00151 * data is only allowed to into a MultiPlug once per scan. 00152 * 00153 * Data coming into a plug is also cause for that plug to be considered last 00154 * when checking for data to pull in through a plug. 00155 */ 00156 inline void postScan(MultiPlug &toend); 00157 //! Post a scan event to dispatcher_. 00158 void doPost(); 00159 //! Move a MultiPlug to the end of the list. 00160 void moveToEnd(MultiPlug &toend); 00161 00162 //! Process the fact that a MultiPlug read the mchunk_. 00163 void multiDidRead(MultiPlug &mplug); 00164 00165 /** \name Count adjusting functions. 00166 * These functions maintain a count of MultiPlugs that are in a particular 00167 * state. The counts are used for adjusting the SingPlug's readable or 00168 * writeable state. This provides a way for the plugs, which don't directly 00169 * know about eachother, to communicate. 00170 * 00171 * adjustMultiWriteables adjusts the number of MultiPlugs who's partners are 00172 * writeable. If there are none, the SinglePlug's state is changed to not be 00173 * writeable. A write to a SinglePlug where there are no MultiPlug partners 00174 * to forward that data onto would be counterproductive and introduce 00175 * unecessary buffering. 00176 * 00177 * adjustMultiReadables adjusts the number of MultiPlugs who's partners are 00178 * readable. If there are no such MultiPlugs, then the SinglePlug won't be 00179 * able to be read from. If there is even one MultiPlug who's partner is 00180 * readable, then a read from the SinglePlug will read from that MultiPlug's 00181 * partner, so the SinglePlug should be set to readable. 00182 */ 00183 //@{ 00184 //! Use to say which direction an adjustment should go in. 00185 enum AdjDir { 00186 ADJ_Down, //< Lower the number. 00187 ADJ_Up //< Raise the number. 00188 }; 00189 00190 /** Adjust the number of MultiPlugs who's partners are in a readable state. 00191 * This may cause the SinglePlug's readable state to change. 00192 */ 00193 void adjustMultiReadables(AdjDir dir); 00194 /** Adjust the number of MultiPlugs who's partners are in a writeable state. 00195 * This may cause the SinglePlug's writeable state to change. 00196 */ 00197 void adjustMultiWriteables(AdjDir dir); 00198 //@} 00199 00200 /** This is called by ScanEvent when its triggerEvent method is called. 00201 * This resets the 'haswritten' flags of all the MultiPlugs to false. 00202 * 00203 * This flag is used to ensure that one MultiPlug can't monopolize the 00204 * SinglePlug. A MultiPlug that has written is not allowed to write again 00205 * until all other MultiPlugs also have a chance to write. 00206 */ 00207 void doScan(); 00208 00209 private: 00210 typedef std::list<MultiPlug *> MPlugList; 00211 class mpother_readable_p; 00212 friend class mpother_readable_p; 00213 class mp_notpluggedin_p; 00214 class mp_written_p; 00215 friend class mp_written_p; 00216 class auto_mpptr; 00217 friend class auto_mpptr; 00218 class ScanEvent; 00219 friend class ScanEvent; 00220 00221 SinglePlug splug_; 00222 bool splug_created_; 00223 MPlugList mplugs_; 00224 MPlugList delplugs_; 00225 bool scan_posted_; 00226 StrChunkPtr mchunk_; 00227 ScanEvent * const scan_; 00228 unievent::Dispatcher &dispatcher_; 00229 unsigned int readable_multis_; 00230 unsigned int readable_multiothers_; 00231 unsigned int writeable_multiothers_; 00232 }; 00233 00234 //-----------------------------inline functions-------------------------------- 00235 00236 inline int SimpleMultiplexer::AreYouA(const lcore::ClassIdent &cid) const 00237 { 00238 return((identifier == cid) || StreamModule::AreYouA(cid)); 00239 } 00240 00241 inline bool SimpleMultiplexer::canCreate(int side) const 00242 { 00243 if (side == SingleSide) { 00244 return(!splug_created_); 00245 } else if (side == MultiSide) { 00246 return(true); 00247 } else { 00248 return(false); 00249 } 00250 } 00251 00252 inline void SimpleMultiplexer::postScan(MultiPlug &toend) 00253 { 00254 if (!scan_posted_) 00255 { 00256 scan_posted_ = true; 00257 doPost(); 00258 } 00259 moveToEnd(toend); 00260 } 00261 00262 //-- 00263 00264 inline int SimpleMultiplexer::SinglePlug::AreYouA(const lcore::ClassIdent &cid) const 00265 { 00266 return((identifier == cid) || Plug::AreYouA(cid)); 00267 } 00268 00269 inline SimpleMultiplexer::SinglePlug::SinglePlug(SimpleMultiplexer &parent) 00270 : Plug(parent) 00271 { 00272 } 00273 00274 inline SimpleMultiplexer::SinglePlug::~SinglePlug() 00275 { 00276 } 00277 00278 inline SimpleMultiplexer &SimpleMultiplexer::SinglePlug::getParent() const 00279 { 00280 return(static_cast<SimpleMultiplexer &>(Plug::getParent())); 00281 } 00282 00283 }; // namespace strmod 00284 }; // namespace strmod 00285 00286 #endif
1.3-rc1