StableArray.h

Go to the documentation of this file.
00001 #ifndef SimTK_SimTKCOMMON_STABLEARRAY_H_
00002 #define SimTK_SimTKCOMMON_STABLEARRAY_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                      SimTK Core: SimTKcommon                               *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK Core biosimulation toolkit originating from      *
00008  * Simbios, the NIH National Center for Physics-Based Simulation of           *
00009  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
00010  * Medical Research, grant U54 GM072970. See https://simtk.org.               *
00011  *                                                                            *
00012  * Portions copyright (c) 2005-7 Stanford University and the Authors.         *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Permission is hereby granted, free of charge, to any person obtaining a    *
00017  * copy of this software and associated documentation files (the "Software"), *
00018  * to deal in the Software without restriction, including without limitation  *
00019  * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
00020  * and/or sell copies of the Software, and to permit persons to whom the      *
00021  * Software is furnished to do so, subject to the following conditions:       *
00022  *                                                                            *
00023  * The above copyright notice and this permission notice shall be included in *
00024  * all copies or substantial portions of the Software.                        *
00025  *                                                                            *
00026  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
00027  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
00028  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
00029  * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
00030  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
00031  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
00032  * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
00033  * -------------------------------------------------------------------------- */
00034 
00035 #include "SimTKcommon/internal/common.h"
00036 #include "SimTKcommon/internal/Array.h"
00037 
00038 #include <cstddef>
00039 #include <cassert>
00040 
00041 namespace SimTK {
00042 
00062 template <class T> class StableArray {
00063 public:
00064     StableArray() : nOccupiedSlots(0) { }
00065 
00066     // Allocate and fill every slot with the same value.
00067     explicit StableArray(size_t z, const T& ival=T()) : stuff(z), nOccupiedSlots(z) {
00068         for (size_t i=0; i<z; ++i) stuff[i] = new T(ival);
00069     }
00070 
00071     // Copy constructor must preserve slot numbers.
00072     StableArray(const StableArray& s) : stuff(s.size(),0), nOccupiedSlots(0) {
00073         for (size_t i=0; i<s.size(); ++i) 
00074             if (!s.empty(i)) initializeEmptyElement(i, s[i]);
00075         assert(nItems() == s.nItems());
00076     }
00077 
00078     // Assignment must preserve slot numbers.
00079     StableArray& operator=(const StableArray& s) {
00080         clear();
00081         stuff.resize(s.size(),0);
00082         for (size_t i=0; i<s.size(); ++i) 
00083             if (!s.empty(i)) initializeEmptyElement(i, s[i]);
00084         assert(nItems() == s.nItems());
00085         return *this;
00086     }
00087 
00088     ~StableArray() { clear(); }
00089 
00090     bool empty() const { return stuff.size()==0; }
00091     bool empty(size_t i) const {
00092         assert(i < stuff.size());
00093         return stuff[i] == 0;
00094     }
00095     size_t size()   const {return stuff.size();}
00096     size_t nItems() const {return nOccupiedSlots;}
00097 
00098     // This routine preserves as many items as possible and fills
00099     // in all empty slots with default values. The array will
00100     // thus have exactly newz slots with nItems==newz.
00101     // I'm not sure this is useful for anything.
00102     void resize(size_t newz, const T& ival=T()) {
00103         const size_t oldz = stuff.size();
00104         // If we're throwing anything away, destruct it.
00105         for (size_t i=newz; i < oldz; ++i)
00106             eraseElementIfNecessary(i);
00107         stuff.resize(newz,0);
00108         // Fill in all empty slots with default values.
00109         for (size_t i=0; i < newz; ++i)
00110             initializeElementIfNecessary(i,ival);
00111         assert(nItems() == newz);
00112     }
00113 
00114     void clear() {
00115         for (size_t i=0; i < stuff.size(); ++i)
00116             eraseElementIfNecessary(i);
00117         stuff.resize(0);
00118         assert(nItems()==0);
00119     }
00120 
00121     // You can push a new item onto the end, or put one in an
00122     // empty slot.
00123     void push_back(const T& t) {
00124         stuff.push_back(new T(t));
00125         ++nOccupiedSlots;
00126     }
00127 
00128     // Remove the last element and shrink the list by 1. If the second-to-the-last
00129     // was empty we'll reduce the length more, so that pop_back() guarantees either
00130     // that the the last element (back()) is not empty, or the entire list is empty.
00131     // Don't call this on an empty array.
00132     void pop_back() {
00133         assert(!empty() && stuff.back());
00134         eraseOccupiedElement(stuff.size()-1);   // last element *better* be occupied!
00135 
00136         // Skip over any exposed empties. No need to adjust count.
00137         do { stuff.pop_back(); } while (!stuff.empty() && !stuff.back());
00138     }
00139 
00140     void insertAt(size_t i, const T& t) {
00141         assert(i <= stuff.size());
00142         if (i == size()) push_back(t);
00143         else initializeEmptyElement(i,t);
00144     }
00145 
00146     size_t findFreeSlot() const {
00147         if (nItems() == size())
00148             return size();  // no room at the inn!
00149         for (size_t i=0; i<size(); ++i)
00150             if (empty(i)) return i;
00151         assert(false); // where's the empty slot???
00152         return size_t(-1);
00153     }
00154 
00155     // Look for the first occupied slot at or after i. Returns
00156     // size() (that is, one past the end) if none found. Use like this:
00157     //     for (size_t i=findNextItem(0); i < size(); i=findNextItem(i+1))
00158     //         do something with item[i] here
00159     size_t findNextItem(size_t i) {
00160         assert(i < stuff.size());
00161         for (; i < stuff.size() && !stuff[i]; ++i);
00162         return i;
00163     }
00164 
00165     // Insert the item in the first available slot, or grow the array
00166     // by one and stick it on the end if there are no free slots. The
00167     // slot in which it was placed is returned.
00168     size_t insert(const T& t) {
00169         const size_t free = findFreeSlot();
00170         insertAt(free, t);
00171         return free;
00172     }
00173 
00174 
00175     // Erasing an element slot if it isn't already empty. If we erase the
00176     // last element we don't have to leave a hole, and in fact we might
00177     // expose a hole in the second-to-the-last element too. In that 
00178     // case we erase by resizing away trailing detritus, otherwise we'll
00179     // make a hole.
00180     void erase(size_t i) {
00181         if (i == stuff.size()-1) pop_back();
00182         else eraseElementIfNecessary(i);
00183     }
00184 
00185     // This returns the first *occupied* element and blows up if there isn't one.
00186     const T& front() const {
00187         const size_t firstItem = findNextItem(0);
00188         assert(firstItem < stuff.size());
00189         return *stuff[firstItem];
00190     }
00191     T& front() {
00192         const size_t firstItem = findNextItem(0);
00193         assert(firstItem < stuff.size());
00194         return *stuff[firstItem];
00195     }
00196 
00197     // We don't need to search for back() because the rules here ensure that the
00198     // last element is not empty.
00199     const T& back()  const {assert(!empty() && stuff.back()); return *stuff.back();}
00200     T&       back()        {assert(!empty() && stuff.back()); return *stuff.back();}
00201 
00202     const T& operator[](size_t i) const {
00203         assert(i < stuff.size() && stuff[i]);
00204         return *stuff[i];
00205     }
00206     T& operator[](size_t i) {
00207         assert(i < stuff.size() && stuff[i]);
00208         return *stuff[i];
00209     }
00210 
00211 private:
00212     size_t          nOccupiedSlots; // not counting empty slots
00213     Array_<T*>      stuff;
00214 
00215     // Note that this can leave empty slots at the end of the list which
00216     // is not a legitimate condition for the StableArray.
00217 
00218     void eraseOccupiedElement(size_t i) {
00219         assert(i < stuff.size() && stuff[i]);
00220         delete stuff[i]; stuff[i]=0; --nOccupiedSlots;
00221     }
00222 
00223     void initializeEmptyElement(size_t i, const T& t) {
00224         assert(i < stuff.size() && !stuff[i]);
00225         stuff[i] = new T(t); ++nOccupiedSlots;
00226     }
00227 
00228     void eraseElementIfNecessary(size_t i) {
00229         assert(i < stuff.size());
00230         if (stuff[i]) eraseOccupiedElement(i);
00231     }
00232 
00233     void initializeElementIfNecessary(size_t i, const T& t) {
00234         assert(i < stuff.size());
00235         if (!stuff[i]) initializeEmptyElement(i,t);
00236     }
00237 
00238 };
00239 
00240 } // namespace SimTK
00241   
00242 #endif // SimTK_SimTKCOMMON_STABLEARRAY_H_

Generated on Thu Aug 12 16:37:26 2010 for SimTKcore by  doxygen 1.6.1