• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

ut_vector.h

Go to the documentation of this file.
00001 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
00002 
00003 /* AbiSource Program Utilities
00004  * Copyright (C) 1998-2000 AbiSource, Inc.
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00019  * 02110-1301 USA.
00020  */
00021 
00022 #ifndef UTVECTOR_H
00023 #define UTVECTOR_H
00024 
00025 /* pre-emptive dismissal; ut_types.h is needed by just about everything,
00026  * so even if it's commented out in-file that's still a lot of work for
00027  * the preprocessor to do...
00028  */
00029 #ifndef UT_TYPES_H
00030 #include "ut_types.h"
00031 #endif
00032 #include "ut_assert.h"
00033 #include "ut_debugmsg.h"
00034 // ----------------------------------------------------------------
00035 
00036 #define UT_VECTOR_CLEANUP(d, v, r) \
00037     do  {   int utv_max = v.getItemCount();             \
00038             for (int utv=utv_max-1; utv>=0; utv--)      \
00039             {                                           \
00040                 d utv_p = (d) v.getNthItem(utv);        \
00041                 UT_ASSERT_HARMLESS(utv_p);              \
00042                 if (utv_p)                              \
00043                     r (utv_p);                      \
00044             }                                           \
00045     } while (0)
00046 
00047 #define UT_VECTOR_SPARSECLEANUP(d, v, r) \
00048     do  {   int utv_max = v.getItemCount();             \
00049             for (int utv=utv_max-1; utv>=0; utv--)      \
00050             {                                           \
00051                 d utv_p = (d) v.getNthItem(utv);        \
00052                 if (utv_p)                              \
00053                     r (utv_p);                      \
00054             }                                           \
00055     } while (0)
00056 
00057 #define UT_VECTOR_PURGEALL(d, v) UT_VECTOR_CLEANUP(d, v, delete)
00058 #define UT_VECTOR_FREEALL(d, v) UT_VECTOR_CLEANUP(d, v, g_free)
00059 #define UT_VECTOR_SPARSEPURGEALL(d, v) UT_VECTOR_SPARSECLEANUP(d, v, delete)
00060 #define UT_VECTOR_SPARSEFREEALL(d, v) UT_VECTOR_SPARSECLEANUP(d, v, g_free)
00061 
00062 /* don't call this macro unless you are in Obj-C++ */
00063 /* release any non nil objective-C object of the array */
00064 #define UT_VECTOR_RELEASE(v) \
00065     {                       \
00066         int utv_max = v.getItemCount();             \
00067             for (int utv=utv_max-1; utv>=0; utv--)      \
00068             {                                           \
00069                 id utv_p = (id) v.getNthItem(utv);      \
00070                 [utv_p release];                                \
00071             }                                       \
00072     }
00073 
00074 
00075 template <class T> class UT_GenericVector
00076 {
00077 public:
00078     typedef int (*compar_fn_t) (const void *, const void *);
00079 
00080     // Real-life tests shown that vast majority of our vectors contain less than 4 items
00081     // and virtually all contains less than 32 elements; I have adjusted the initial
00082     // values accordingly. Where vectors are known to be larger, bigger values should be
00083     // passed to the constructor, and, if approprite, pre-allocation forced
00084     UT_GenericVector(UT_sint32 sizehint = 32, UT_sint32 baseincr = 4, bool bPrealloc = false);
00085     UT_GenericVector(const UT_GenericVector<T>&);
00086     UT_GenericVector<T>& operator=(const UT_GenericVector<T>&);
00087     virtual ~UT_GenericVector();
00088 
00089     UT_sint32   addItem(const T);
00090     inline UT_sint32    push_back(const T item) { return addItem(item); }
00091     bool                pop_back();
00092     inline const T  back() const            { return getLastItem(); }
00093 
00094     UT_sint32   addItem(const T p, UT_sint32 * pIndex);
00095 
00096     /* FIXME -- this function assumes that it is possible to do
00097      *          static_cast<T>(0)
00098      */
00099     inline T getNthItem(UT_sint32 n) const
00100     {
00101         UT_ASSERT_HARMLESS(m_pEntries);
00102         UT_ASSERT_HARMLESS(m_iCount > 0);
00103         UT_ASSERT_HARMLESS(n<m_iCount);
00104 
00105         if(n >= m_iCount || !m_pEntries) {
00106             return 0;
00107         }
00108         return m_pEntries[n];
00109     }
00110 
00111     const T     operator[](UT_sint32 i) const;
00112     UT_sint32   setNthItem(UT_sint32 ndx, T pNew, T * ppOld);
00113     const T     getFirstItem() const;
00114     const T     getLastItem() const;
00115     inline UT_sint32 getItemCount() const { return m_iCount; }
00116     UT_sint32   findItem(T) const;
00117 
00118     UT_sint32   insertItemAt(T, UT_sint32 ndx);
00119     UT_sint32   addItemSorted(const T p, int (*compar)(const void *, const void *));
00120     void        deleteNthItem(UT_sint32 n);
00121     void        clear();
00122     void        qsort(int (*compar)(const void *, const void *));
00123     UT_sint32   binarysearch(const void* key, int (*compar)(const void *, const void *)) const;
00124 
00125     bool        copy(const UT_GenericVector<T> *pVec);
00126     inline UT_sint32 size() const { return getItemCount(); }
00127 
00128 private:
00129     UT_sint32       grow(UT_sint32);
00130     UT_sint32       binarysearchForSlot(const void* key, compar_fn_t compar) const;
00131 
00132     T*          m_pEntries;
00133     UT_sint32       m_iCount;
00134     UT_sint32       m_iSpace;
00135     UT_sint32       m_iCutoffDouble;
00136     UT_sint32       m_iPostCutoffIncrement;
00137 };
00138 
00139 // TODO Rob: try to export like this once plugin loading is fixed:
00140 // template class ABI_EXPORT UT_GenericVector<void const *>;
00141 class ABI_EXPORT UT_Vector : public UT_GenericVector<void const *> {
00142 public:
00143     UT_Vector(UT_sint32 sizehint = 32, UT_sint32 baseincr = 4, bool bPrealloc = false)
00144     : UT_GenericVector<void const *>(sizehint, baseincr, bPrealloc)
00145     {}
00146 };
00147 
00148 // TODO Rob: try to export like this once plugin loading is fixed:
00149 // template class ABI_EXPORT UT_GenericVector<UT_sint32>;
00150 class ABI_EXPORT UT_NumberVector : public UT_GenericVector<UT_sint32> {
00151 public:
00152     UT_NumberVector(UT_sint32 sizehint = 32, UT_sint32 baseincr = 4, bool bPrealloc = false)
00153     : UT_GenericVector<UT_sint32>(sizehint, baseincr, bPrealloc)
00154     {}
00155 };
00156 
00157 #include <stdlib.h>
00158 #include <string.h>
00159 
00169 template <class T>
00170 UT_GenericVector<T>::UT_GenericVector(UT_sint32 sizehint, UT_sint32 baseincr, bool bPrealoc)
00171   : m_pEntries(NULL), m_iCount(0), m_iSpace(0),
00172     m_iCutoffDouble(sizehint), m_iPostCutoffIncrement(baseincr)
00173 {
00174     if(bPrealoc)
00175         grow(sizehint);
00176 }
00177 
00178 template <class T>
00179 UT_GenericVector<T>::UT_GenericVector(const UT_GenericVector<T>& utv)
00180   : m_pEntries(NULL), m_iCount(0), m_iSpace(0),
00181   m_iCutoffDouble(utv.m_iCutoffDouble),
00182   m_iPostCutoffIncrement(utv.m_iPostCutoffIncrement)
00183 {
00184     copy(&utv);
00185 }
00186 
00187 template <class T>
00188 UT_GenericVector<T>& UT_GenericVector<T>::operator=(const UT_GenericVector<T>& utv)
00189 {
00190     if(this != &utv)
00191     {
00192         m_iCutoffDouble = utv.m_iCutoffDouble;
00193         m_iPostCutoffIncrement = utv.m_iPostCutoffIncrement;
00194         copy(&utv);
00195     }
00196     return *this;
00197 }
00198 
00199 template <class T>
00200 void UT_GenericVector<T>::clear()
00201 {
00202     if(m_iCount > m_iCutoffDouble)
00203     {
00204         xxx_UT_DEBUGMSG(("Vector contained %d entries, allocated %d slots\n", m_iCount, m_iSpace));
00205     }
00206 
00207     m_iCount = 0;
00208     if (m_iSpace > 0)
00209         memset(m_pEntries, 0, m_iSpace * sizeof(T));
00210 }
00211 
00212 
00213 template <class T>
00214 UT_GenericVector<T>::~UT_GenericVector()
00215 {
00216     if(m_iCount >  m_iCutoffDouble)
00217     {
00218         xxx_UT_DEBUGMSG(("Vector contained %d entries, allocated %d slots\n", m_iCount, m_iSpace));
00219     }
00220 
00221     FREEP(m_pEntries);
00222 }
00223 
00224 /*
00225  This function is called everytime we want to insert a new element but don't have
00226  enough space.  In this case we grow the array to be _at least_ ndx size.
00227 */
00228 template <class T>
00229 UT_sint32 UT_GenericVector<T>::grow(UT_sint32 ndx)
00230 {
00231     UT_sint32 new_iSpace;
00232     if(!m_iSpace) {
00233         new_iSpace = m_iPostCutoffIncrement;
00234     }
00235     else if (m_iSpace < m_iCutoffDouble) {
00236         xxx_UT_DEBUGMSG(("Vector growing (%d -> %d\n", m_iSpace, ndx));
00237         new_iSpace = m_iSpace * 2;
00238     }
00239     else {
00240         new_iSpace = m_iSpace + m_iPostCutoffIncrement;
00241     }
00242 
00243     if (new_iSpace < ndx)
00244     {
00245         new_iSpace = ndx;
00246     }
00247 
00248     T * new_pEntries = static_cast<T *>(g_try_realloc(m_pEntries, new_iSpace * sizeof(T)));
00249     if (!new_pEntries) {
00250         return -1;
00251     }
00252     //Is this required? We always check Count first anyways.
00253     // TMN: Unfortunately it is, since the class GR_CharWidths
00254     // uses UT_GenericVector<T> as a sparse array!
00255     memset(&new_pEntries[m_iSpace], 0, (new_iSpace - m_iSpace) * sizeof(T));
00256     m_iSpace = new_iSpace;
00257     m_pEntries = new_pEntries;
00258 
00259     return 0;
00260 }
00261 
00262 template <class T>
00263 UT_sint32 UT_GenericVector<T>::insertItemAt(const T p, UT_sint32 ndx)
00264 {
00265     if (ndx > m_iCount + 1)
00266         return -1;
00267 
00268     if ((m_iCount+1) > m_iSpace)
00269     {
00270         UT_sint32 err = grow(0);
00271         if (err)
00272         {
00273             return err;
00274         }
00275     }
00276 
00277     // bump the elements -> thataway up to the ndxth position
00278     memmove(&m_pEntries[ndx+1], &m_pEntries[ndx], (m_iCount - ndx) * sizeof(T));
00279 
00280     m_pEntries[ndx] = (T)p;
00281     ++m_iCount;
00282 
00283     return 0;
00284 }
00285 
00286 template <class T>
00287 UT_sint32 UT_GenericVector<T>::addItem(const T p, UT_sint32 * pIndex)
00288 {
00289     UT_sint32 err = addItem(p);
00290     if (!err && pIndex)
00291         *pIndex = m_iCount-1;
00292     return err;
00293 }
00294 
00295 template <class T>
00296 UT_sint32 UT_GenericVector<T>::addItem(const T p)
00297 {
00298     if ((m_iCount+1) > m_iSpace)
00299     {
00300         UT_sint32 err = grow(0);
00301         if (err)
00302         {
00303             return err;
00304         }
00305     }
00306 
00307     m_pEntries[m_iCount++] = (T)p;  /*** bad, cast away const so we can build again ***/
00308 
00309     return 0;
00310 }
00311 
00312 template <class T>
00313 UT_sint32 UT_GenericVector<T>::addItemSorted(const T p, int (*compar)(const void *, const void *))
00314 {
00315     if (!m_iCount) {
00316         return addItem(p);
00317     }
00318 
00319     return insertItemAt( p, binarysearchForSlot((static_cast<void*>(const_cast<T*>(&p))), compar));
00320 }
00321 
00323 template <class T>
00324 bool UT_GenericVector<T>::pop_back()
00325 {
00326     if (m_iCount > 0)
00327     {
00328         --m_iCount;
00329         return true;
00330     }
00331     else
00332         return false;
00333 }
00334 
00335 template <class T>
00336 UT_sint32 UT_GenericVector<T>::setNthItem(UT_sint32 ndx, T pNew, T* ppOld)
00337 {
00338     const UT_sint32 old_iSpace = m_iSpace;
00339 
00340     if (ndx >= m_iSpace)
00341     {
00342         const UT_sint32 err = grow(ndx+1);
00343         if (err)
00344         {
00345             return err;
00346         }
00347     }
00348 
00349     if (ppOld)
00350     {
00351         *ppOld = (ndx < old_iSpace) ? m_pEntries[ndx] : 0;
00352     }
00353 
00354     m_pEntries[ndx] = pNew;
00355     if (ndx >= m_iCount)
00356     {
00357         m_iCount = ndx + 1;
00358     }
00359 
00360     return 0;
00361 }
00362 
00363 template <class T>
00364 const T UT_GenericVector<T>::getLastItem() const
00365 {
00366     UT_ASSERT_HARMLESS(m_iCount > 0);
00367 
00368     return m_pEntries[m_iCount-1];
00369 }
00370 
00371 template <class T>
00372 const T UT_GenericVector<T>::getFirstItem() const
00373 {
00374     UT_ASSERT_HARMLESS(m_iCount > 0);
00375     UT_ASSERT_HARMLESS(m_pEntries);
00376     if (!m_pEntries) {
00377         return T();
00378     }
00379     return m_pEntries[0];
00380 }
00381 
00382 template <class T>
00383 void UT_GenericVector<T>::deleteNthItem(UT_sint32 n)
00384 {
00385     UT_ASSERT_HARMLESS(n < m_iCount);
00386     UT_ASSERT_HARMLESS(m_iCount > 0);
00387 
00388     memmove(&m_pEntries[n], &m_pEntries[n+1], (m_iCount - (n + 1)) * sizeof(T));
00389 
00390     m_pEntries[m_iCount-1] = 0;
00391     m_iCount--;
00392 
00393     return;
00394 }
00395 
00396 template <class T>
00397 UT_sint32 UT_GenericVector<T>::findItem(T p) const
00398 {
00399     for (UT_sint32 i=0; i<m_iCount; i++)
00400     {
00401         if (m_pEntries[i] == p)
00402         {
00403             return i;
00404         }
00405     }
00406 
00407     return -1;
00408 }
00409 
00410 template <class T>
00411 void UT_GenericVector<T>::qsort(int (*compar)(const void *, const void *))
00412 {
00413 	::qsort(m_pEntries, m_iCount, sizeof(T), compar);
00414 }
00415 
00416 // this binary search finds the earliest element (lowest index)
00417 // in the vector which matches the key
00418 // based on code from Tim Bray's 'On the Goodness of Binary Search'
00419 // http://tbray.org/ongoing/When/200x/2003/03/22/Binary
00420 
00421 template <class T>
00422 UT_sint32 UT_GenericVector<T>::binarysearch(const void* key, compar_fn_t compar) const
00423 {
00424     UT_sint32 slot = binarysearchForSlot(key, compar);
00425 
00426     if ((slot == m_iCount) || (0 != (*compar)(key, &m_pEntries[slot])))
00427         return -1;
00428     else
00429         return slot;
00430 }
00431 
00432 template <class T>
00433 UT_sint32 UT_GenericVector<T>::binarysearchForSlot(const void* key, compar_fn_t compar) const
00434 {
00435     UT_sint32 high = m_iCount;
00436     UT_sint32 low = -1;
00437     UT_sint32 probe;
00438 
00439     while (high - low > 1)
00440     {
00441         int res;
00442         probe = (high + low) / 2;
00443         res = (*compar)(key, &m_pEntries[probe]);
00444         if (0 < res)
00445             low = probe;
00446         else
00447             high = probe;
00448     }
00449 
00450     return high;
00451 }
00452 
00453 template <class T>
00454 bool UT_GenericVector<T>::copy(const UT_GenericVector<T> *pVec)
00455 {
00456     clear();
00457 
00458     if (!pVec) {
00459         return false;
00460     }
00461 
00462     for (UT_sint32 i=0; i < pVec->m_iCount; i++)
00463     {
00464         UT_sint32 err;
00465 
00466         err = addItem(pVec->m_pEntries[i]);
00467         if(err == -1)
00468             return (err ? true : false);
00469     }
00470 
00471     return false;
00472 }
00473 
00474 template <class T>
00475 const T UT_GenericVector<T>::operator[](UT_sint32 i) const
00476 {
00477     return this->getNthItem(i);
00478 }
00479 
00480 
00481 #endif /* UTVECTOR_H */

Generated on Sun Feb 14 2021 for AbiWord by  doxygen 1.7.1