00001 /* 00002 * Copyright (C) 1991-9 Eric M. Hopper <hopper@omnifarious.mn.org> 00003 * 00004 * This program is free software; you can redistribute it and/or modify it 00005 * under the terms of the GNU Lesser General Public License as published 00006 * by the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, but 00010 * WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 /* $Header: /home/hopper/src/cvs/C++/StrMod/StreamModule.cxx,v 1.12 2002/03/12 21:48:57 hopper Exp $ */ 00020 00021 // For log information, see ChangeLog 00022 00023 #ifdef __GNUG__ 00024 # pragma implementation "StreamModule.h" 00025 #endif 00026 00027 #include "StrMod/StreamModule.h" 00028 #include "StrMod/StrChunkPtr.h" 00029 00030 namespace strmod { 00031 namespace strmod { 00032 00033 //! A unique identifier for this class. 00034 const STR_ClassIdent StreamModule::identifier(1UL); 00035 //! A unique identifier for this class. 00036 const STR_ClassIdent StreamModule::Plug::identifier(2UL); 00037 00038 /*! 00039 * \param other A reference to the plug to plug into. <strong>(A pointer to 00040 * it is stored)</strong>. 00041 * 00042 * A pointer to \a other will be stored by the plug until it's unplugged or 00043 * destroyed. \a other is a reference because it's not allowed to be \c NULL. */ 00044 bool StreamModule::Plug::plugInto(Plug &other) 00045 { 00046 // Make sure neither plug is already plugged in. 00047 if ((other_ == NULL) && (other.other_ == NULL)) 00048 { 00049 other_ = &other; 00050 other.other_ = this; 00051 flags_.notifyonread_ = other.needsNotifyReadable(); 00052 other.flags_.notifyonread_ = needsNotifyReadable(); 00053 flags_.notifyonwrite_ = other.needsNotifyWriteable(); 00054 other.flags_.notifyonwrite_ = needsNotifyWriteable(); 00055 notifyOtherReadable(); 00056 if (other_ != NULL) 00057 { 00058 other_->notifyOtherReadable(); 00059 } 00060 notifyOtherWriteable(); 00061 if (other_ != NULL) 00062 { 00063 other_->notifyOtherWriteable(); 00064 } 00065 if (isReadable() && (pluggedInto() != NULL)) 00066 { 00067 pushLoop(); 00068 } 00069 if (isWriteable() && (pluggedInto() != NULL)) 00070 { 00071 pullLoop(); 00072 } 00073 return(true); 00074 } 00075 else 00076 { 00077 return(false); 00078 } 00079 } 00080 00081 /** \name Push and pulll loops 00082 * The loops that get everything done. 00083 * 00084 * Because of these loops, and the infrastructure that exists in the base 00085 * StreamModule and StreamModule::Plug class that calls them, you should never 00086 * have to call \c i_Read() or \c i_Write(). 00087 * 00088 * These member functions are part of that infrastructure. They handle 00089 * setting the \p iswriting_ and \p isreading_ flags properly. They also loop 00090 * until no more data can be moved in the direction they're moving it because 00091 * one Plug became unwriteable, or one plug became unreadable. 00092 * 00093 * In short, don't bypass them unless you really know what you're doing. 00094 */ 00095 //@{ 00096 /*! 00097 * This keeps the isreading and iswriting flags set until the loop exits. 00098 * 00099 * This loop can exit for a number of reasons, including disconnection, one 00100 * side 'drying up' and having nothing to read, or one side 'filling up' 00101 * and not being able to be written to. 00102 */ 00103 void StreamModule::Plug::pushLoop() 00104 { 00105 assert(isReadable() && (flags_.isreading_ == false)); 00106 00107 Plug *other = pluggedInto(); 00108 00109 assert(other != NULL); 00110 00111 if (other != NULL && other->isWriteable()) 00112 { 00113 other->setIsWriting(true); 00114 } 00115 setIsReading(true); 00116 while (flags_.canread_ && (other != NULL) && getFlagsFrom(*other).canwrite_) 00117 { 00118 other->i_Write(i_Read()); 00119 00120 if (pluggedInto() != other) 00121 { 00122 other->setIsWriting(false); 00123 other = pluggedInto(); 00124 if (other != NULL && other->isWriteable()) 00125 { 00126 other->setIsWriting(true); 00127 } 00128 } 00129 } 00130 setIsReading(false); 00131 if (other != NULL) 00132 { 00133 other->setIsWriting(false); 00134 } 00135 } 00136 00137 /*! 00138 * This keeps the isreading and iswriting flags set until the loop exits. 00139 * 00140 * This loop can exit for a number of reasons, including disconnection, one 00141 * side 'drying up' and having nothing to read, or one side 'filling up' and 00142 * not being able to be written to. 00143 */ 00144 void StreamModule::Plug::pullLoop() 00145 { 00146 assert(isWriteable() && (flags_.iswriting_ == false)); 00147 00148 Plug *other = pluggedInto(); 00149 00150 assert(other != NULL); 00151 00152 setIsWriting(true); 00153 if (other != NULL && other->isReadable()) 00154 { 00155 other->setIsReading(true); 00156 } 00157 while (flags_.canwrite_ && (other != NULL) && getFlagsFrom(*other).canread_) 00158 { 00159 i_Write(other->i_Read()); 00160 00161 if (pluggedInto() != other) 00162 { 00163 other->setIsReading(false); 00164 other = pluggedInto(); 00165 if (other != NULL && other->isReadable()) 00166 { 00167 other->setIsReading(true); 00168 } 00169 } 00170 } 00171 setIsWriting(false); 00172 if (other != NULL) 00173 { 00174 other->setIsReading(false); 00175 } 00176 } 00177 //@} 00178 00179 } // End namespace strmod 00180 } // End namespace strmod
1.3-rc1