Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

SimpleMulti.h

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

Generated on Wed Jan 29 00:32:44 2003 for libNet by doxygen1.3-rc1