• 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., 59 Temple Place - Suite 330, Boston, MA
00019  * 02111-1307, 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     memset(m_pEntries, 0, m_iSpace * sizeof(T));
00209 }
00210 
00211 
00212 template <class T>
00213 UT_GenericVector<T>::~UT_GenericVector()
00214 {
00215     if(m_iCount >  m_iCutoffDouble)
00216     {
00217         xxx_UT_DEBUGMSG(("Vector contained %d entries, allocated %d slots\n", m_iCount, m_iSpace));
00218     }
00219 
00220     FREEP(m_pEntries);
00221 }
00222 
00223 /*
00224  This function is called everytime we want to insert a new element but don't have
00225  enough space.  In this case we grow the array to be _at least_ ndx size.
00226 */
00227 template <class T>
00228 UT_sint32 UT_GenericVector<T>::grow(UT_sint32 ndx)
00229 {
00230     UT_sint32 new_iSpace;
00231     if(!m_iSpace) {
00232         new_iSpace = m_iPostCutoffIncrement;
00233     }
00234     else if (m_iSpace < m_iCutoffDouble) {
00235         xxx_UT_DEBUGMSG(("Vector growing (%d -> %d\n", m_iSpace, ndx));
00236         new_iSpace = m_iSpace * 2;
00237     }
00238     else {
00239         new_iSpace = m_iSpace + m_iPostCutoffIncrement;
00240     }
00241 
00242     if (new_iSpace < ndx)
00243     {
00244         new_iSpace = ndx;
00245     }
00246 
00247     T * new_pEntries = static_cast<T *>(g_try_realloc(m_pEntries, new_iSpace * sizeof(T)));
00248     if (!new_pEntries) {
00249         return -1;
00250     }
00251     //Is this required? We always check Count first anyways.
00252     // TMN: Unfortunately it is, since the class GR_CharWidths
00253     // uses UT_GenericVector<T> as a sparse array!
00254     memset(&new_pEntries[m_iSpace], 0, (new_iSpace - m_iSpace) * sizeof(T));
00255     m_iSpace = new_iSpace;
00256     m_pEntries = new_pEntries;
00257 
00258     return 0;
00259 }
00260 
00261 template <class T>
00262 UT_sint32 UT_GenericVector<T>::insertItemAt(const T p, UT_sint32 ndx)
00263 {
00264     if (ndx > m_iCount + 1)
00265         return -1;
00266 
00267     if ((m_iCount+1) > m_iSpace)
00268     {
00269         UT_sint32 err = grow(0);
00270         if (err)
00271         {
00272             return err;
00273         }
00274     }
00275 
00276     // bump the elements -> thataway up to the ndxth position
00277     memmove(&m_pEntries[ndx+1], &m_pEntries[ndx], (m_iCount - ndx) * sizeof(T));
00278 
00279     m_pEntries[ndx] = (T)p;
00280     ++m_iCount;
00281 
00282     return 0;
00283 }
00284 
00285 template <class T>
00286 UT_sint32 UT_GenericVector<T>::addItem(const T p, UT_sint32 * pIndex)
00287 {
00288     UT_sint32 err = addItem(p);
00289     if (!err && pIndex)
00290         *pIndex = m_iCount-1;
00291     return err;
00292 }
00293 
00294 template <class T>
00295 UT_sint32 UT_GenericVector<T>::addItem(const T p)
00296 {
00297     if ((m_iCount+1) > m_iSpace)
00298     {
00299         UT_sint32 err = grow(0);
00300         if (err)
00301         {
00302             return err;
00303         }
00304     }
00305 
00306     m_pEntries[m_iCount++] = (T)p;  /*** bad, cast away const so we can build again ***/
00307 
00308     return 0;
00309 }
00310 
00311 template <class T>
00312 UT_sint32 UT_GenericVector<T>::addItemSorted(const T p, int (*compar)(const void *, const void *))
00313 {
00314     if (!m_iCount) {
00315         return addItem(p);
00316     }
00317 
00318     return insertItemAt( p, binarysearchForSlot((static_cast<void*>(const_cast<T*>(&p))), compar));
00319 }
00320 
00322 template <class T>
00323 bool UT_GenericVector<T>::pop_back()
00324 {
00325     if (m_iCount > 0)
00326     {
00327         --m_iCount;
00328         return true;
00329     }
00330     else
00331         return false;
00332 }
00333 
00334 template <class T>
00335 UT_sint32 UT_GenericVector<T>::setNthItem(UT_sint32 ndx, T pNew, T* ppOld)
00336 {
00337     const UT_sint32 old_iSpace = m_iSpace;
00338 
00339     if (ndx >= m_iSpace)
00340     {
00341         const UT_sint32 err = grow(ndx+1);
00342         if (err)
00343         {
00344             return err;
00345         }
00346     }
00347 
00348     if (ppOld)
00349     {
00350         *ppOld = (ndx < old_iSpace) ? m_pEntries[ndx] : 0;
00351     }
00352 
00353     m_pEntries[ndx] = pNew;
00354     if (ndx >= m_iCount)
00355     {
00356         m_iCount = ndx + 1;
00357     }
00358 
00359     return 0;
00360 }
00361 
00362 template <class T>
00363 const T UT_GenericVector<T>::getLastItem() const
00364 {
00365     UT_ASSERT_HARMLESS(m_iCount > 0);
00366 
00367     return m_pEntries[m_iCount-1];
00368 }
00369 
00370 template <class T>
00371 const T UT_GenericVector<T>::getFirstItem() const
00372 {
00373     UT_ASSERT_HARMLESS(m_iCount > 0);
00374     UT_ASSERT_HARMLESS(m_pEntries);
00375 
00376     return m_pEntries[0];
00377 }
00378 
00379 template <class T>
00380 void UT_GenericVector<T>::deleteNthItem(UT_sint32 n)
00381 {
00382     UT_ASSERT_HARMLESS(n < m_iCount);
00383     UT_ASSERT_HARMLESS(m_iCount > 0);
00384 
00385     memmove(&m_pEntries[n], &m_pEntries[n+1], (m_iCount - (n + 1)) * sizeof(T));
00386 
00387     m_pEntries[m_iCount-1] = 0;
00388     m_iCount--;
00389 
00390     return;
00391 }
00392 
00393 template <class T>
00394 UT_sint32 UT_GenericVector<T>::findItem(T p) const
00395 {
00396     for (UT_sint32 i=0; i<m_iCount; i++)
00397     {
00398         if (m_pEntries[i] == p)
00399         {
00400             return i;
00401         }
00402     }
00403 
00404     return -1;
00405 }
00406 
00407 template <class T>
00408 void UT_GenericVector<T>::qsort(int (*compar)(const void *, const void *))
00409 {
00410 	::qsort(m_pEntries, m_iCount, sizeof(T), compar);
00411 }
00412 
00413 // this binary search finds the earliest element (lowest index)
00414 // in the vector which matches the key
00415 // based on code from Tim Bray's 'On the Goodness of Binary Search'
00416 // http://tbray.org/ongoing/When/200x/2003/03/22/Binary
00417 
00418 template <class T>
00419 UT_sint32 UT_GenericVector<T>::binarysearch(const void* key, compar_fn_t compar) const
00420 {
00421     UT_sint32 slot = binarysearchForSlot(key, compar);
00422 
00423     if ((slot == m_iCount) || (0 != (*compar)(key, &m_pEntries[slot])))
00424         return -1;
00425     else
00426         return slot;
00427 }
00428 
00429 template <class T>
00430 UT_sint32 UT_GenericVector<T>::binarysearchForSlot(const void* key, compar_fn_t compar) const
00431 {
00432     UT_sint32 high = m_iCount;
00433     UT_sint32 low = -1;
00434     UT_sint32 probe;
00435 
00436     while (high - low > 1)
00437     {
00438         int res;
00439         probe = (high + low) / 2;
00440         res = (*compar)(key, &m_pEntries[probe]);
00441         if (0 < res)
00442             low = probe;
00443         else
00444             high = probe;
00445     }
00446 
00447     return high;
00448 }
00449 
00450 template <class T>
00451 bool UT_GenericVector<T>::copy(const UT_GenericVector<T> *pVec)
00452 {
00453     clear();
00454 
00455     for (UT_sint32 i=0; i < pVec->m_iCount; i++)
00456     {
00457         UT_sint32 err;
00458 
00459         err = addItem(pVec->m_pEntries[i]);
00460         if(err == -1)
00461             return (err ? true : false);
00462     }
00463 
00464     return 0;
00465 }
00466 
00467 template <class T>
00468 const T UT_GenericVector<T>::operator[](UT_sint32 i) const
00469 {
00470     return this->getNthItem(i);
00471 }
00472 
00473 
00474 #endif /* UTVECTOR_H */

Generated on Mon May 28 2012 for AbiWord by  doxygen 1.7.1