NptArray.h

00001 /*****************************************************************
00002 |
00003 |   Neptune - Arrays
00004 |
00005 |   (c) 2001-2006 Gilles Boccon-Gibod
00006 |   Author: Gilles Boccon-Gibod (bok@bok.net)
00007 |
00008 ****************************************************************/
00009 
00010 #ifndef _NPT_ARRAY_H_
00011 #define _NPT_ARRAY_H_
00012 
00013 /*----------------------------------------------------------------------
00014 |   includes
00015 +---------------------------------------------------------------------*/
00016 #include "NptConfig.h"
00017 #if defined(NPT_CONFIG_HAVE_NEW_H)
00018 #include <new>
00019 #endif
00020 #include "NptTypes.h"
00021 #include "NptResults.h"
00022 
00023 /*----------------------------------------------------------------------
00024 |   constants
00025 +---------------------------------------------------------------------*/
00026 const int NPT_ARRAY_INITIAL_MAX_SIZE = 128; // bytes
00027 
00028 /*----------------------------------------------------------------------
00029 |   NPT_Array
00030 +---------------------------------------------------------------------*/
00031 template <typename T> 
00032 class NPT_Array 
00033 {
00034 public:
00035     // types
00036     typedef T Element;
00037     typedef T* Iterator;
00038 
00039     // methods
00040     NPT_Array<T>(): m_Capacity(0), m_ItemCount(0), m_Items(0) {}
00041     explicit NPT_Array<T>(NPT_Cardinal count);
00042     NPT_Array<T>(NPT_Cardinal count, const T& item);
00043     NPT_Array<T>(const T* items, NPT_Cardinal item_count);
00044    ~NPT_Array<T>();
00045     NPT_Array<T>(const NPT_Array<T>& copy);
00046     NPT_Array<T>& operator=(const NPT_Array<T>& copy);
00047     bool          operator==(const NPT_Array<T>& other) const;
00048     bool          operator!=(const NPT_Array<T>& other) const;
00049     NPT_Cardinal GetItemCount() const { return m_ItemCount; }
00050     NPT_Result   Add(const T& item);
00051     T& operator[](NPT_Ordinal pos)             { return m_Items[pos]; }
00052     const T& operator[](NPT_Ordinal pos) const { return m_Items[pos]; }
00053     NPT_Result   Erase(Iterator which);
00054     NPT_Result   Erase(NPT_Ordinal which) { return Erase(&m_Items[which]); }
00055     NPT_Result   Erase(Iterator first, Iterator last);
00056     NPT_Result   Erase(NPT_Ordinal first, NPT_Ordinal last) { return Erase(&m_Items[first], &m_Items[last]); }
00057     NPT_Result   Insert(Iterator where, const T& item, NPT_Cardinal count = 1);
00058     NPT_Result   Reserve(NPT_Cardinal count);
00059     NPT_Cardinal GetCapacity(NPT_Cardinal count) const;
00060     NPT_Result   Resize(NPT_Cardinal count);
00061     NPT_Result   Resize(NPT_Cardinal count, const T& fill);
00062     NPT_Result   Clear();
00063     bool         Contains(const T& data) const;
00064     Iterator     GetFirstItem() const { return m_ItemCount?&m_Items[0]:NULL; }
00065     Iterator     GetLastItem() const  { return m_ItemCount?m_Items[&m_ItemCount-1]:NULL; }
00066     Iterator     GetItem(NPT_Ordinal n) { return n<m_ItemCount?&m_Items[n]:NULL; }
00067 
00068     // template list operations
00069     // keep these template members defined here because MSV6 does not let
00070     // us define them later
00071     template <typename X> 
00072     NPT_Result Apply(const X& function) const
00073     {                                  
00074         for (unsigned int i=0; i<m_ItemCount; i++) function(m_Items[i]);
00075         return NPT_SUCCESS;
00076     }
00077 
00078     template <typename X, typename P>
00079     NPT_Result ApplyUntil(const X& function, const P& predicate, bool* match = NULL) const
00080     {                                  
00081         for (unsigned int i=0; i<m_ItemCount; i++) {
00082             NPT_Result return_value;
00083             if (predicate(function(m_Items[i]), return_value)) {
00084                 if (match) *match = true;
00085                 return return_value;
00086             }
00087         }
00088         if (match) *match = false;
00089         return NPT_SUCCESS;
00090     }
00091 
00092     template <typename X> 
00093     T* Find(const X& predicate, NPT_Ordinal n=0) const
00094     {
00095         for (unsigned int i=0; i<m_ItemCount; i++) {
00096             if (predicate(m_Items[i])) {
00097                 if (n == 0) return &m_Items[i];
00098                 --n;
00099             }
00100         }
00101         return NULL;
00102     }
00103 
00104 protected:
00105     // methods
00106     T* Allocate(NPT_Cardinal count, NPT_Cardinal& allocated);
00107 
00108     // members
00109     NPT_Cardinal m_Capacity;
00110     NPT_Cardinal m_ItemCount;
00111     T*           m_Items;
00112 };
00113 
00114 /*----------------------------------------------------------------------
00115 |   NPT_Array<T>::NPT_Array<T>
00116 +---------------------------------------------------------------------*/
00117 template <typename T>
00118 inline
00119 NPT_Array<T>::NPT_Array(NPT_Cardinal count) :
00120     m_Capacity(0),
00121     m_ItemCount(0),
00122     m_Items(0)
00123 {
00124     Reserve(count);
00125 }
00126 
00127 /*----------------------------------------------------------------------
00128 |   NPT_Array<T>::NPT_Array<T>
00129 +---------------------------------------------------------------------*/
00130 template <typename T>
00131 inline
00132 NPT_Array<T>::NPT_Array(const NPT_Array<T>& copy) :
00133     m_Capacity(0),
00134     m_ItemCount(0),
00135     m_Items(0)
00136 {
00137     Reserve(copy.GetItemCount());
00138     for (NPT_Ordinal i=0; i<copy.m_ItemCount; i++) {
00139         new ((void*)&m_Items[i]) T(copy.m_Items[i]);
00140     }
00141     m_ItemCount = copy.m_ItemCount;
00142 }
00143 
00144 /*----------------------------------------------------------------------
00145 |   NPT_Array<T>::NPT_Array<T>
00146 +---------------------------------------------------------------------*/
00147 template <typename T>
00148 inline
00149 NPT_Array<T>::NPT_Array(NPT_Cardinal count, const T& item) :
00150     m_Capacity(0),
00151     m_ItemCount(count),
00152     m_Items(0)    
00153 {
00154     Reserve(count);
00155     for (NPT_Ordinal i=0; i<count; i++) {
00156         new ((void*)&m_Items[i]) T(item);
00157     }
00158 }
00159 
00160 /*----------------------------------------------------------------------
00161 |   NPT_Array<T>::NPT_Array<T>
00162 +---------------------------------------------------------------------*/
00163 template <typename T>
00164 inline
00165 NPT_Array<T>::NPT_Array(const T* items, NPT_Cardinal item_count) :
00166     m_Capacity(0),
00167     m_ItemCount(item_count),
00168     m_Items(0)    
00169 {
00170     Reserve(item_count);
00171     for (NPT_Ordinal i=0; i<item_count; i++) {
00172         new ((void*)&m_Items[i]) T(items[i]);
00173     }
00174 }
00175 
00176 /*----------------------------------------------------------------------
00177 |   NPT_Array<T>::~NPT_Array<T>
00178 +---------------------------------------------------------------------*/
00179 template <typename T>
00180 inline
00181 NPT_Array<T>::~NPT_Array()
00182 {
00183     // remove all items
00184     Clear();
00185 
00186     // free the memory
00187     ::operator delete((void*)m_Items);
00188 }
00189 
00190 /*----------------------------------------------------------------------
00191 |   NPT_Array<T>::operator=
00192 +---------------------------------------------------------------------*/
00193 template <typename T>
00194 NPT_Array<T>&
00195 NPT_Array<T>::operator=(const NPT_Array<T>& copy)
00196 {
00197     // do nothing if we're assigning to ourselves
00198     if (this == &copy) return *this;
00199 
00200     // destroy all elements
00201     Clear();
00202 
00203     // copy all elements from the other object
00204     Reserve(copy.GetItemCount());
00205     m_ItemCount = copy.m_ItemCount;
00206     for (NPT_Ordinal i=0; i<copy.m_ItemCount; i++) {
00207         new ((void*)&m_Items[i]) T(copy.m_Items[i]);
00208     }
00209 
00210     return *this;
00211 }
00212 
00213 /*----------------------------------------------------------------------
00214 |   NPT_Array<T>::Clear
00215 +---------------------------------------------------------------------*/
00216 template <typename T>
00217 NPT_Result
00218 NPT_Array<T>::Clear()
00219 {
00220     // destroy all items
00221     for (NPT_Ordinal i=0; i<m_ItemCount; i++) {
00222         m_Items[i].~T();
00223     }
00224 
00225     m_ItemCount = 0;
00226 
00227     return NPT_SUCCESS;
00228 }
00229 
00230 /*----------------------------------------------------------------------
00231 |   NPT_Array<T>::Allocate
00232 +---------------------------------------------------------------------*/
00233 template <typename T>
00234 T*
00235 NPT_Array<T>::Allocate(NPT_Cardinal count, NPT_Cardinal& allocated) 
00236 {
00237     if (m_Capacity) {
00238         allocated = 2*m_Capacity;
00239     } else {
00240         // start with just enough elements to fill 
00241         // NPT_ARRAY_INITIAL_MAX_SIZE worth of memory
00242         allocated = NPT_ARRAY_INITIAL_MAX_SIZE/sizeof(T);
00243         if (allocated == 0) allocated = 1;
00244     }
00245     if (allocated < count) allocated = count;
00246 
00247     // allocate the items
00248     return (T*)::operator new(allocated*sizeof(T));
00249 }
00250 
00251 /*----------------------------------------------------------------------
00252 |   NPT_Array<T>::Reserve
00253 +---------------------------------------------------------------------*/
00254 template <typename T>
00255 NPT_Result
00256 NPT_Array<T>::Reserve(NPT_Cardinal count)
00257 {
00258     if (count <= m_Capacity) return NPT_SUCCESS;
00259 
00260     // (re)allocate the items
00261     NPT_Cardinal new_capacity;
00262     T* new_items = Allocate(count, new_capacity);
00263     if (new_items == NULL) {
00264         return NPT_ERROR_OUT_OF_MEMORY;
00265     }
00266     if (m_ItemCount && m_Items) {
00267         for (unsigned int i=0; i<m_ItemCount; i++) {
00268             // construct the copy
00269             new ((void*)&new_items[i])T(m_Items[i]);
00270 
00271             // destroy the item
00272             m_Items[i].~T();
00273         }
00274     }
00275     ::operator delete((void*)m_Items);
00276     m_Items = new_items;
00277     m_Capacity = new_capacity;
00278 
00279     return NPT_SUCCESS;
00280 }
00281 
00282 /*----------------------------------------------------------------------
00283 |   NPT_Array<T>::Add
00284 +---------------------------------------------------------------------*/
00285 template <typename T>
00286 inline
00287 NPT_Result
00288 NPT_Array<T>::Add(const T& item)
00289 {
00290     // ensure capacity
00291     NPT_Result result = Reserve(m_ItemCount+1);
00292     if (result != NPT_SUCCESS) return result;
00293 
00294     // store the item
00295     new ((void*)&m_Items[m_ItemCount++]) T(item);
00296 
00297     return NPT_SUCCESS;
00298 }
00299 
00300 /*----------------------------------------------------------------------
00301 |   NPT_Array<T>::Erase
00302 +---------------------------------------------------------------------*/
00303 template <typename T>
00304 inline
00305 NPT_Result
00306 NPT_Array<T>::Erase(Iterator which)
00307 {
00308     return Erase(which, which);
00309 }
00310 
00311 /*----------------------------------------------------------------------
00312 |   NPT_Array<T>::Erase
00313 +---------------------------------------------------------------------*/
00314 template <typename T>
00315 NPT_Result
00316 NPT_Array<T>::Erase(Iterator first, Iterator last)
00317 {
00318     // check parameters
00319     if (first == NULL || last == NULL) return NPT_ERROR_INVALID_PARAMETERS;
00320 
00321     // check the bounds
00322     NPT_Ordinal first_index = (NPT_Ordinal)(NPT_POINTER_TO_LONG(first-m_Items));
00323     NPT_Ordinal last_index  = (NPT_Ordinal)(NPT_POINTER_TO_LONG(last-m_Items));
00324     if (first_index >= m_ItemCount ||
00325         last_index  >= m_ItemCount ||
00326         first_index > last_index) {
00327         return NPT_ERROR_INVALID_PARAMETERS;
00328     }
00329 
00330     // shift items to the left
00331     NPT_Cardinal interval = last_index-first_index+1;
00332     NPT_Cardinal shifted = m_ItemCount-last_index-1;
00333     for (NPT_Ordinal i=first_index; i<first_index+shifted; i++) {
00334         m_Items[i] = m_Items[i+interval];
00335     }
00336 
00337     // destruct the remaining items
00338     for (NPT_Ordinal i=first_index+shifted; i<m_ItemCount; i++) {
00339         m_Items[i].~T();
00340     }
00341 
00342     // update the item count
00343     m_ItemCount -= interval;
00344 
00345     return NPT_SUCCESS;
00346 }
00347 
00348 /*----------------------------------------------------------------------
00349 |   NPT_Array<T>::Insert
00350 +---------------------------------------------------------------------*/
00351 template <typename T>
00352 NPT_Result
00353 NPT_Array<T>::Insert(Iterator where, const T& item, NPT_Cardinal repeat)
00354 {
00355     // check bounds
00356     NPT_Ordinal where_index = where?((NPT_Ordinal)NPT_POINTER_TO_LONG(where-m_Items)):m_ItemCount;
00357     if (where > &m_Items[m_ItemCount] || repeat == 0) return NPT_ERROR_INVALID_PARAMETERS;
00358 
00359     NPT_Cardinal needed = m_ItemCount+repeat;
00360     if (needed > m_Capacity) {
00361         // allocate more memory
00362         NPT_Cardinal new_capacity;
00363         T* new_items = Allocate(needed, new_capacity);
00364         if (new_items == NULL) return NPT_ERROR_OUT_OF_MEMORY;
00365         m_Capacity = new_capacity;
00366 
00367         // move the items before the insertion point
00368         for (NPT_Ordinal i=0; i<where_index; i++) {
00369             new((void*)&new_items[i])T(m_Items[i]);
00370             m_Items[i].~T();
00371         }
00372 
00373         // move the items after the insertion point
00374         for (NPT_Ordinal i=where_index; i<m_ItemCount; i++) {
00375             new((void*)&new_items[i+repeat])T(m_Items[i]);
00376             m_Items[i].~T();
00377         }
00378 
00379         // use the new items instead of the current ones
00380         ::operator delete((void*)m_Items);
00381         m_Items = new_items;
00382     } else {
00383         // shift items after the insertion point to the right
00384         for (NPT_Ordinal i=m_ItemCount; i>where_index; i--) {
00385             new((void*)&m_Items[i+repeat-1])T(m_Items[i-1]);
00386             m_Items[i-1].~T();
00387         }
00388     }
00389 
00390     // insert the new items
00391     for (NPT_Cardinal i=where_index; i<where_index+repeat; i++) {
00392         new((void*)&m_Items[i])T(item);
00393     }
00394 
00395     // update the item count
00396     m_ItemCount += repeat;
00397 
00398     return NPT_SUCCESS;
00399 }
00400 
00401 /*----------------------------------------------------------------------
00402 |   NPT_Array<T>::Resize
00403 +---------------------------------------------------------------------*/
00404 template <typename T>
00405 NPT_Result
00406 NPT_Array<T>::Resize(NPT_Cardinal size)
00407 {
00408     if (size < m_ItemCount) {
00409         // shrink
00410         for (NPT_Ordinal i=size; i<m_ItemCount; i++) {
00411             m_Items[i].~T();
00412         }
00413         m_ItemCount = size;
00414     } else if (size > m_ItemCount) {
00415         return Resize(size, T());
00416     }
00417 
00418     return NPT_SUCCESS;
00419 }
00420 
00421 /*----------------------------------------------------------------------
00422 |   NPT_Array<T>::Resize
00423 +---------------------------------------------------------------------*/
00424 template <typename T>
00425 NPT_Result
00426 NPT_Array<T>::Resize(NPT_Cardinal size, const T& fill)
00427 {
00428     if (size < m_ItemCount) {
00429         return Resize(size);
00430     } else if (size > m_ItemCount) {
00431         Reserve(size);
00432         for (NPT_Ordinal i=m_ItemCount; i<size; i++) {
00433             new ((void*)&m_Items[i]) T(fill);
00434         }
00435         m_ItemCount = size;
00436     }
00437 
00438     return NPT_SUCCESS;
00439 }
00440 
00441 /*----------------------------------------------------------------------
00442 |   NPT_Array<T>::Contains
00443 +---------------------------------------------------------------------*/
00444 template <typename T>
00445 bool
00446 NPT_Array<T>::Contains(const T& data) const
00447 {
00448     for (NPT_Ordinal i=0; i<m_ItemCount; i++) {
00449         if (m_Items[i] == data) return true;
00450     }
00451 
00452     return false;
00453 }
00454 
00455 /*----------------------------------------------------------------------
00456 |   NPT_Array<T>::operator==
00457 +---------------------------------------------------------------------*/
00458 template <typename T>
00459 bool
00460 NPT_Array<T>::operator==(const NPT_Array<T>& other) const
00461 {
00462     // we need the same number of items
00463     if (other.m_ItemCount != m_ItemCount) return false;
00464 
00465     // compare all items
00466     for (NPT_Ordinal i=0; i<m_ItemCount; i++) {
00467         if (!(m_Items[i] == other.m_Items[i])) return false;
00468     }
00469 
00470     return true;
00471 }
00472 
00473 /*----------------------------------------------------------------------
00474 |   NPT_Array<T>::operator!=
00475 +---------------------------------------------------------------------*/
00476 template <typename T>
00477 inline
00478 bool
00479 NPT_Array<T>::operator!=(const NPT_Array<T>& other) const
00480 {
00481     return !(*this == other);
00482 }
00483 
00484 #endif // _NPT_ARRAY_H_
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496 
00497