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     for (NPT_Ordinal i=0; i<copy.m_ItemCount; i++) {
00206         new ((void*)&m_Items[i]) T(copy.m_Items[i]);
00207     }
00208 
00209     return *this;
00210 }
00211 
00212 /*----------------------------------------------------------------------
00213 |   NPT_Array<T>::Clear
00214 +---------------------------------------------------------------------*/
00215 template <typename T>
00216 NPT_Result
00217 NPT_Array<T>::Clear()
00218 {
00219     // destroy all items
00220     for (NPT_Ordinal i=0; i<m_ItemCount; i++) {
00221         m_Items[i].~T();
00222     }
00223 
00224     m_ItemCount = 0;
00225 
00226     return NPT_SUCCESS;
00227 }
00228 
00229 /*----------------------------------------------------------------------
00230 |   NPT_Array<T>::Allocate
00231 +---------------------------------------------------------------------*/
00232 template <typename T>
00233 T*
00234 NPT_Array<T>::Allocate(NPT_Cardinal count, NPT_Cardinal& allocated) 
00235 {
00236     if (m_Capacity) {
00237         allocated = 2*m_Capacity;
00238     } else {
00239         // start with just enough elements to fill 
00240         // NPT_ARRAY_INITIAL_MAX_SIZE worth of memory
00241         allocated = NPT_ARRAY_INITIAL_MAX_SIZE/sizeof(T);
00242         if (allocated == 0) allocated = 1;
00243     }
00244     if (allocated < count) allocated = count;
00245 
00246     // allocate the items
00247     return (T*)::operator new(allocated*sizeof(T));
00248 }
00249 
00250 /*----------------------------------------------------------------------
00251 |   NPT_Array<T>::Reserve
00252 +---------------------------------------------------------------------*/
00253 template <typename T>
00254 NPT_Result
00255 NPT_Array<T>::Reserve(NPT_Cardinal count)
00256 {
00257     if (count <= m_Capacity) return NPT_SUCCESS;
00258 
00259     // (re)allocate the items
00260     NPT_Cardinal new_capacity;
00261     T* new_items = Allocate(count, new_capacity);
00262     if (new_items == NULL) {
00263         return NPT_ERROR_OUT_OF_MEMORY;
00264     }
00265     if (m_ItemCount && m_Items) {
00266         for (unsigned int i=0; i<m_ItemCount; i++) {
00267             // construct the copy
00268             new ((void*)&new_items[i])T(m_Items[i]);
00269 
00270             // destroy the item
00271             m_Items[i].~T();
00272         }
00273     }
00274     ::operator delete((void*)m_Items);
00275     m_Items = new_items;
00276     m_Capacity = new_capacity;
00277 
00278     return NPT_SUCCESS;
00279 }
00280 
00281 /*----------------------------------------------------------------------
00282 |   NPT_Array<T>::Add
00283 +---------------------------------------------------------------------*/
00284 template <typename T>
00285 inline
00286 NPT_Result
00287 NPT_Array<T>::Add(const T& item)
00288 {
00289     // ensure capacity
00290     NPT_Result result = Reserve(m_ItemCount+1);
00291     if (result != NPT_SUCCESS) return result;
00292 
00293     // store the item
00294     new ((void*)&m_Items[m_ItemCount++]) T(item);
00295 
00296     return NPT_SUCCESS;
00297 }
00298 
00299 /*----------------------------------------------------------------------
00300 |   NPT_Array<T>::Erase
00301 +---------------------------------------------------------------------*/
00302 template <typename T>
00303 inline
00304 NPT_Result
00305 NPT_Array<T>::Erase(Iterator which)
00306 {
00307     return Erase(which, which);
00308 }
00309 
00310 /*----------------------------------------------------------------------
00311 |   NPT_Array<T>::Erase
00312 +---------------------------------------------------------------------*/
00313 template <typename T>
00314 NPT_Result
00315 NPT_Array<T>::Erase(Iterator first, Iterator last)
00316 {
00317     // check parameters
00318     if (first == NULL || last == NULL) return NPT_ERROR_INVALID_PARAMETERS;
00319 
00320     // check the bounds
00321     NPT_Ordinal first_index = (NPT_Ordinal)(NPT_POINTER_TO_LONG(first-m_Items));
00322     NPT_Ordinal last_index  = (NPT_Ordinal)(NPT_POINTER_TO_LONG(last-m_Items));
00323     if (first_index >= m_ItemCount ||
00324         last_index  >= m_ItemCount ||
00325         first_index > last_index) {
00326         return NPT_ERROR_INVALID_PARAMETERS;
00327     }
00328 
00329     // shift items to the left
00330     NPT_Cardinal interval = last_index-first_index+1;
00331     NPT_Cardinal shifted = m_ItemCount-last_index-1;
00332     for (NPT_Ordinal i=first_index; i<first_index+shifted; i++) {
00333         m_Items[i] = m_Items[i+interval];
00334     }
00335 
00336     // destruct the remaining items
00337     for (NPT_Ordinal i=first_index+shifted; i<m_ItemCount; i++) {
00338         m_Items[i].~T();
00339     }
00340 
00341     // update the item count
00342     m_ItemCount -= interval;
00343 
00344     return NPT_SUCCESS;
00345 }
00346 
00347 /*----------------------------------------------------------------------
00348 |   NPT_Array<T>::Insert
00349 +---------------------------------------------------------------------*/
00350 template <typename T>
00351 NPT_Result
00352 NPT_Array<T>::Insert(Iterator where, const T& item, NPT_Cardinal repeat)
00353 {
00354     // check bounds
00355     NPT_Ordinal where_index = where?((NPT_Ordinal)NPT_POINTER_TO_LONG(where-m_Items)):m_ItemCount;
00356     if (where > &m_Items[m_ItemCount] || repeat == 0) return NPT_ERROR_INVALID_PARAMETERS;
00357 
00358     NPT_Cardinal needed = m_ItemCount+repeat;
00359     if (needed < m_Capacity) {
00360         // allocate more memory
00361         NPT_Cardinal new_capacity;
00362         T* new_items = Allocate(needed, new_capacity);
00363         if (new_items == NULL) return NPT_ERROR_OUT_OF_MEMORY;
00364         m_Capacity = new_capacity;
00365 
00366         // move the items before the insertion point
00367         for (NPT_Ordinal i=0; i<where_index; i++) {
00368             new((void*)&new_items[i])T(m_Items[i]);
00369             m_Items[i].~T();
00370         }
00371 
00372         // move the items after the insertion point
00373         for (NPT_Ordinal i=where_index; i<m_ItemCount; i++) {
00374             new((void*)&new_items[i+repeat])T(m_Items[i]);
00375             m_Items[i].~T();
00376         }
00377 
00378         // use the new items instead of the current ones
00379         ::operator delete((void*)m_Items);
00380         m_Items = new_items;
00381     } else {
00382         // shift items after the insertion point to the right
00383         for (NPT_Ordinal i=m_ItemCount; i>where_index; i--) {
00384             new((void*)&m_Items[i+repeat-1])T(m_Items[i-1]);
00385             m_Items[i-1].~T();
00386         }
00387     }
00388 
00389     // insert the new items
00390     for (NPT_Cardinal i=where_index; i<where_index+repeat; i++) {
00391         new((void*)&m_Items[i])T(item);
00392     }
00393 
00394     // update the item count
00395     m_ItemCount += repeat;
00396 
00397     return NPT_SUCCESS;
00398 }
00399 
00400 /*----------------------------------------------------------------------
00401 |   NPT_Array<T>::Resize
00402 +---------------------------------------------------------------------*/
00403 template <typename T>
00404 NPT_Result
00405 NPT_Array<T>::Resize(NPT_Cardinal size)
00406 {
00407     if (size < m_ItemCount) {
00408         // shrink
00409         for (NPT_Ordinal i=size; i<m_ItemCount; i++) {
00410             m_Items[i].~T();
00411         }
00412         m_ItemCount = size;
00413     } else if (size > m_ItemCount) {
00414         return Resize(size, T());
00415     }
00416 
00417     return NPT_SUCCESS;
00418 }
00419 
00420 /*----------------------------------------------------------------------
00421 |   NPT_Array<T>::Resize
00422 +---------------------------------------------------------------------*/
00423 template <typename T>
00424 NPT_Result
00425 NPT_Array<T>::Resize(NPT_Cardinal size, const T& fill)
00426 {
00427     if (size < m_ItemCount) {
00428         return Resize(size);
00429     } else if (size > m_ItemCount) {
00430         Reserve(size);
00431         for (NPT_Ordinal i=m_ItemCount; i<size; i++) {
00432             new ((void*)&m_Items[i]) T(fill);
00433         }
00434         m_ItemCount = size;
00435     }
00436 
00437     return NPT_SUCCESS;
00438 }
00439 
00440 /*----------------------------------------------------------------------
00441 |   NPT_Array<T>::Contains
00442 +---------------------------------------------------------------------*/
00443 template <typename T>
00444 bool
00445 NPT_Array<T>::Contains(const T& data) const
00446 {
00447     for (NPT_Ordinal i=0; i<m_ItemCount; i++) {
00448         if (m_Items[i] == data) return true;
00449     }
00450 
00451     return false;
00452 }
00453 
00454 /*----------------------------------------------------------------------
00455 |   NPT_Array<T>::operator==
00456 +---------------------------------------------------------------------*/
00457 template <typename T>
00458 bool
00459 NPT_Array<T>::operator==(const NPT_Array<T>& other) const
00460 {
00461     // we need the same number of items
00462     if (other.m_ItemCount != m_ItemCount) return false;
00463 
00464     // compare all items
00465     for (NPT_Ordinal i=0; i<m_ItemCount; i++) {
00466         if (!(m_Items[i] == other.m_Items[i])) return false;
00467     }
00468 
00469     return true;
00470 }
00471 
00472 /*----------------------------------------------------------------------
00473 |   NPT_Array<T>::operator!=
00474 +---------------------------------------------------------------------*/
00475 template <typename T>
00476 inline
00477 bool
00478 NPT_Array<T>::operator!=(const NPT_Array<T>& other) const
00479 {
00480     return !(*this == other);
00481 }
00482 
00483 #endif // _NPT_ARRAY_H_
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496