Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | Related Pages | Examples

fifo.h

00001 //  Copyright (c) 1996-2002 by Autodesk, Inc.
00002 //
00003 //  By using this code, you are agreeing to the terms and conditions of
00004 //  the License Agreement included in the documentation for this code.
00005 //
00006 //  AUTODESK MAKES NO WARRANTIES, EXPRESS OR IMPLIED, AS TO THE CORRECTNESS
00007 //  OF THIS CODE OR ANY DERIVATIVE WORKS WHICH INCORPORATE IT. AUTODESK
00008 //  PROVIDES THE CODE ON AN "AS-IS" BASIS AND EXPLICITLY DISCLAIMS ANY
00009 //  LIABILITY, INCLUDING CONSEQUENTIAL AND INCIDENTAL DAMAGES FOR ERRORS,
00010 //  OMISSIONS, AND OTHER PROBLEMS IN THE CODE.
00011 //
00012 //  Use, duplication, or disclosure by the U.S. Government is subject to
00013 //  restrictions set forth in FAR 52.227-19 (Commercial Computer Software
00014 //  Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) (Rights in Technical
00015 //  Data and Computer Software), as applicable.
00016 //
00017 
00018 #if !defined FIFO_HEADER
00019 #define FIFO_HEADER
00020 
00021 #include "whiptk/whipcore.h"
00022 
00023 #define WD_FIFO_SLACK_FRACTION 0.25
00024 
00026 template<class _ItemType>
00027 class WT_FIFO
00028 {
00029 private:
00030 
00031     int            m_size;         // The number of generic items being held in the FIFO.
00032     int            m_capacity;     // The number of items that can fit in the current FIFO.
00033     int            m_start;        // The position of the first item in the FIFO ring buffer.
00034     _ItemType *    m_buffer;       // The FIFO buffer itself.
00035 
00036     WT_FIFO (WT_FIFO const &)
00037       : m_size(0)
00038       , m_capacity(0)
00039       , m_start(0)
00040       , m_buffer(WD_Null)
00041     {
00042         WD_Complain ("cannot copy WT_FIFO");
00043     } // prohibited
00044 
00045     WT_FIFO & operator= (WT_FIFO const &)
00046     {
00047         WD_Complain ("cannot assign WT_FIFO");
00048         return *this;
00049     } // prohibited
00050 
00051 public:
00052 
00054     WT_FIFO()
00055         : m_size(0)
00056         , m_capacity(0)
00057         , m_start(0)
00058         , m_buffer(WD_Null)
00059     { }
00060 
00062     WT_FIFO(int initial_size)
00063         : m_size(0)
00064         , m_capacity(initial_size + 1)
00065         , m_start(0)
00066         , m_buffer(WD_Null)
00067     {
00068         m_buffer = new _ItemType[initial_size + 1];
00069         if (!m_buffer)
00070             throw WT_Result::Out_Of_Memory_Error;
00071     }
00072 
00074     ~WT_FIFO()
00075     {
00076         delete []m_buffer;
00077     }
00078 
00080     int size() const
00081     {
00082         return m_size;
00083     }
00084 
00086     WT_Result add(
00087         int add_size, 
00088         _ItemType const * add_buffer 
00089         );
00091 
00092     void fetch(
00093         int fetch_size, 
00094         int start_item, 
00095         _ItemType * fetch_buffer 
00096         ) const;
00098 
00099     void remove(
00100         int remove_size, 
00101         _ItemType * remove_buffer 
00102         );
00104 
00105     void remove(
00106         int remove_size
00107         );
00109     void clear_all();
00111 
00115     int pointer_to_index(
00116         _ItemType const * ptr 
00117         ) const;
00119 
00121     _ItemType &  item(int index) const;
00123     void       pop();
00124 
00125 };
00126 
00127 template<class _ItemType>
00128 WT_Result WT_FIFO<_ItemType>::add(int add_size, _ItemType const * add_buffer)
00129 {
00130     WD_Assert(add_size > 0);
00131     WD_Assert(add_buffer);
00132 
00133     // Will we overflow the current buffer?
00134     if ( (m_size + add_size) > m_capacity)
00135     {
00136         // We're about to overflow the FIFO buffer, so let's allocate
00137         // a bigger FIFO buffer and copy the old one into it.
00138         _ItemType *    new_buffer;
00139         int            new_capacity;
00140 
00141         new_capacity  = m_size + add_size + 1;
00142         new_capacity += (int)(new_capacity * WD_FIFO_SLACK_FRACTION);
00143         new_buffer = new _ItemType[new_capacity];
00144         if (!new_buffer)
00145             return WT_Result::Out_Of_Memory_Error;
00146 
00147         if ( (m_start + m_size) <= m_capacity)
00148         {
00149             // The data doesn't wrap around the ring buffer in the orig. buffer,
00150             // so it is an easy copy to the new buffer.
00151             //WD_COPY_MEMORY(m_buffer + m_start, m_size, new_buffer);
00152             _ItemType *    source = m_buffer + m_start;
00153             _ItemType *    dest   = new_buffer;
00154             for (int loop = 0; loop < m_size; loop++)
00155                 *dest++ = *source++;
00156         }
00157         else
00158         {
00159             int    split_size = m_capacity - m_start;
00160             // The data is wrapped around in the source ring buffer.  Need to do
00161             // more work to copy it to the new buffer.
00162             // WD_COPY_MEMORY(m_buffer + m_start, split_size         , new_buffer);
00163             // WD_COPY_MEMORY(m_buffer          , m_size - split_size, new_buffer + split_size);
00164             _ItemType *     source = m_buffer + m_start;
00165             _ItemType *     dest   = new_buffer;
00166             int             loop;
00167 
00168             for (loop = 0; loop < split_size; loop++)
00169                 *dest++ = *source++;
00170 
00171             source = m_buffer;
00172             for (loop = 0; loop < (m_size - split_size); loop++)
00173                 *dest++ = *source++;
00174         }
00175 
00176         m_start = 0;
00177         m_capacity = new_capacity;
00178         delete []m_buffer;
00179         m_buffer = new_buffer;
00180     } // If orig buffer would have overflowed
00181 
00182     // Now add the new data to the buffer
00183 
00184     // Find the tail end where we start adding to the FIFO.  Note that the "tail" might
00185     // be "behind" the start if we've wrapped around the ring buffer.
00186     int tail = m_start + m_size;
00187     if (tail >= m_capacity)
00188         tail -= m_capacity;
00189 
00190     if ( (tail + add_size) <= m_capacity)
00191     {
00192         // The new data wont wrap around the ring buffer,
00193         // so it is an easy copy into the buffer.
00194         // WD_COPY_MEMORY(add_buffer, add_size, m_buffer + tail);
00195         _ItemType const *    source = add_buffer;
00196         _ItemType *        dest   = m_buffer + tail;
00197         for (int loop = 0; loop < add_size; loop++)
00198             *dest++ = *source++;
00199     }
00200     else
00201     {
00202         int    split_size = m_capacity - tail;
00203         // The new data will wrap around the ring buffer.  Need to do
00204         // more work to copy it in two chunks.
00205         // WD_COPY_MEMORY(add_buffer             , split_size           , m_buffer + tail);
00206         // WD_COPY_MEMORY(add_buffer + split_size, add_size - split_size, m_buffer       );
00207         _ItemType const *   source = add_buffer;
00208         _ItemType *         dest   = m_buffer + tail;
00209         int                 loop;
00210 
00211         for (loop = 0; loop < split_size; loop++)
00212             *dest++ = *source++;
00213 
00214         dest = m_buffer;
00215         for (loop = 0; loop < (add_size - split_size); loop++)
00216             *dest++ = *source++;
00217     }
00218 
00219     m_size += add_size;
00220 
00221     return WT_Result::Success;
00222 }
00223 
00224 template<class _ItemType>
00225 void WT_FIFO<_ItemType>::fetch(int fetch_size, int start_item, _ItemType * users_buffer) const
00226 {
00227     // Make sure that this FIFO has at least the amount of data that was asked for.
00228     WD_Assert((fetch_size + start_item) <= m_size);
00229     WD_Assert(users_buffer);
00230 
00231     int    pseudo_start = m_start + start_item;
00232     if (pseudo_start >= m_capacity)
00233         pseudo_start -= m_capacity;
00234 
00235     // Copy the data out of the FIFO and into the user's buffer.
00236     if ( (pseudo_start + fetch_size) <= m_capacity)
00237     {
00238         // The *requested* data doesn't wrap around the ring buffer,
00239         // so it is an easy copy to the user's buffer.
00240         _ItemType *    source = m_buffer + pseudo_start;
00241         _ItemType *    dest   = users_buffer;
00242         for (int loop = 0; loop < fetch_size; loop++)
00243             *dest++ = *source++;
00244     }
00245     else
00246     {
00247         int    split_size = m_capacity - pseudo_start;
00248         // The data is wrapped around in the FIFO ring buffer.  Need to do
00249         // more work to copy it to the user's buffer.
00250         _ItemType *     source = m_buffer + pseudo_start;
00251         _ItemType *     dest   = users_buffer;
00252         int             loop;
00253 
00254         for (loop = 0; loop < split_size; loop++)
00255             *dest++ = *source++;
00256 
00257         source = m_buffer;
00258         for (loop = 0; loop < (fetch_size - split_size); loop++)
00259             *dest++ = *source++;
00260     }
00261 }
00262 
00263 template<class _ItemType>
00264 void WT_FIFO<_ItemType>::remove(int remove_size, _ItemType * remove_buffer)
00265 {
00266     fetch(remove_size, 0, remove_buffer);
00267     // Now adjust for the fact that data was removed from the ring buffer.
00268     remove(remove_size);
00269 }
00270 
00271 
00272 template<class _ItemType>
00273 void WT_FIFO<_ItemType>::remove(int remove_size)
00274 {
00275     // Make sure that this FIFO has at least the amount of data that was asked for.
00276     WD_Assert(remove_size <= m_size);
00277     WD_Assert(remove_size >= 0);
00278 
00279 
00280     // Adjust for the fact that data was removed from the ring buffer.
00281     m_start += remove_size;
00282     if (m_start >= m_capacity)
00283         m_start -= m_capacity;
00284 
00285     m_size -= remove_size;
00286 
00287     if (!m_size)
00288         m_start = 0;
00289 
00290     WD_Assert (m_size >= 0);
00291     WD_Assert (m_start >= 0);
00292     WD_Assert (m_start < m_capacity);
00293 }
00294 
00295 template<class _ItemType>
00296 void WT_FIFO<_ItemType>::pop()
00297 {
00298     // pop the last added item off the fifo queue
00299     // (a little lifo routine)
00300     WD_Assert(1 <= m_size);
00301 
00302     m_size--;
00303     if (!m_size)
00304         m_start = 0;
00305 
00306     WD_Assert (m_size >= 0);
00307     WD_Assert (m_start >= 0);
00308     WD_Assert (m_start < m_capacity);
00309 }
00310 
00311 template<class _ItemType>
00312 _ItemType & WT_FIFO<_ItemType>::item(int index) const
00313 {
00314     // Make sure that this FIFO has at least the amount of data that was asked for.
00315     WD_Assert(index < m_size);
00316 
00317     // Copy the data out of the FIFO and into the user's buffer.
00318     int    position = m_start + index;
00319     if (position >= m_capacity)
00320     {
00321         // The *requested* data wrapped around the ring buffer.
00322         position -= m_capacity;
00323     }
00324 
00325     return m_buffer[position];
00326 }
00327 
00328 template<class _ItemType>
00329 void    WT_FIFO<_ItemType>::clear_all()
00330 {
00331     m_start = 0;
00332     m_size = 0;
00333 }
00334 
00335 template<class _ItemType>
00336 int WT_FIFO<_ItemType>::pointer_to_index(_ItemType const * ptr) const
00337 {
00338 
00339     WD_Assert(ptr >= m_buffer);
00340     WD_Assert(ptr < (m_buffer + m_capacity));
00341 
00342     int    pseudo_index = ptr - m_buffer;
00343 
00344     // See if we wrap around or not
00345     if (pseudo_index < m_start)
00346         pseudo_index += m_capacity;
00347 
00348     WD_Assert(pseudo_index < (m_start + m_size));
00349     return pseudo_index - m_start;
00350 }
00351 
00352 #endif // FIFO_HEADER

Generated on Tue May 17 12:07:44 2005 for Autodesk DWF Whip 2D Toolkit by  doxygen 1.4.1