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 
00037 #include <cstddef>
00038 #include <cassert>
00039 #include <vector>
00040 
00041 namespace SimTK {
00042 
00061 template <class T> class StableArray {
00062 public:
00063     StableArray() : nOccupiedSlots(0) { }
00064 
00065     // Allocate and fill every slot with the same value.
00066     explicit StableArray(size_t z, const T& ival=T()) : stuff(z), nOccupiedSlots(z) {
00067         for (size_t i=0; i<z; ++i) stuff[i] = new T(ival);
00068     }
00069 
00070     // Copy constructor must preserve slot numbers.
00071     StableArray(const StableArray& s) : stuff(s.size(),0), nOccupiedSlots(0) {
00072         for (size_t i=0; i<s.size(); ++i) 
00073             if (!s.empty(i)) initializeEmptyElement(i, s[i]);
00074         assert(nItems() == s.nItems());
00075     }
00076 
00077     // Assignment must preserve slot numbers.
00078     StableArray& operator=(const StableArray& s) {
00079         clear();
00080         stuff.resize(s.size(),0);
00081         for (size_t i=0; i<s.size(); ++i) 
00082             if (!s.empty(i)) initializeEmptyElement(i, s[i]);
00083         assert(nItems() == s.nItems());
00084         return *this;
00085     }
00086 
00087     ~StableArray() { clear(); }
00088 
00089     bool empty() const { return stuff.size()==0; }
00090     bool empty(size_t i) const {
00091         assert(i < stuff.size());
00092         return stuff[i] == 0;
00093     }
00094     size_t size()   const {return stuff.size();}
00095     size_t nItems() const {return nOccupiedSlots;}
00096 
00097     // This routine preserves as many items as possible and fills
00098     // in all empty slots with default values. The array will
00099     // thus have exactly newz slots with nItems==newz.
00100     // I'm not sure this is useful for anything.
00101     void resize(size_t newz, const T& ival=T()) {
00102         const size_t oldz = stuff.size();
00103         // If we're throwing anything away, destruct it.
00104         for (size_t i=newz; i < oldz; ++i)
00105             eraseElementIfNecessary(i);
00106         stuff.resize(newz,0);
00107         // Fill in all empty slots with default values.
00108         for (size_t i=0; i < newz; ++i)
00109             initializeElementIfNecessary(i,ival);
00110         assert(nItems() == newz);
00111     }
00112 
00113     void clear() {
00114         for (size_t i=0; i < stuff.size(); ++i)
00115             eraseElementIfNecessary(i);
00116         stuff.resize(0);
00117         assert(nItems()==0);
00118     }
00119 
00120     // You can push a new item onto the end, or put one in an
00121     // empty slot.
00122     void push_back(const T& t) {
00123         stuff.push_back(new T(t));
00124         ++nOccupiedSlots;
00125     }
00126 
00127     // Remove the last element and shrink the list by 1. If the second-to-the-last
00128     // was empty we'll reduce the length more, so that pop_back() guarantees either
00129     // that the the last element (back()) is not empty, or the entire list is empty.
00130     // Don't call this on an empty array.
00131     void pop_back() {
00132         assert(!empty() && stuff.back());
00133         eraseOccupiedElement(stuff.size()-1);   // last element *better* be occupied!
00134 
00135         // Skip over any exposed empties. No need to adjust count.
00136         do { stuff.pop_back(); } while (!stuff.empty() && !stuff.back());
00137     }
00138 
00139     void insertAt(size_t i, const T& t) {
00140         assert(i <= stuff.size());
00141         if (i == size()) push_back(t);
00142         else initializeEmptyElement(i,t);
00143     }
00144 
00145     size_t findFreeSlot() const {
00146         if (nItems() == size())
00147             return size();  // no room at the inn!
00148         for (size_t i=0; i<size(); ++i)
00149             if (empty(i)) return i;
00150         assert(false); // where's the empty slot???
00151         return size_t(-1);
00152     }
00153 
00154     // Look for the first occupied slot at or after i. Returns
00155     // size() (that is, one past the end) if none found. Use like this:
00156     //     for (size_t i=findNextItem(0); i < size(); i=findNextItem(i+1))
00157     //         do something with item[i] here
00158     size_t findNextItem(size_t i) {
00159         assert(i < stuff.size());
00160         for (; i < stuff.size() && !stuff[i]; ++i);
00161         return i;
00162     }
00163 
00164     // Insert the item in the first available slot, or grow the array
00165     // by one and stick it on the end if there are no free slots. The
00166     // slot in which it was placed is returned.
00167     size_t insert(const T& t) {
00168         const size_t free = findFreeSlot();
00169         insertAt(free, t);
00170         return free;
00171     }
00172 
00173 
00174     // Erasing an element slot if it isn't already empty. If we erase the
00175     // last element we don't have to leave a hole, and in fact we might
00176     // expose a hole in the second-to-the-last element too. In that 
00177     // case we erase by resizing away trailing detritus, otherwise we'll
00178     // make a hole.
00179     void erase(size_t i) {
00180         if (i == stuff.size()-1) pop_back();
00181         else eraseElementIfNecessary(i);
00182     }
00183 
00184     // This returns the first *occupied* element and blows up if there isn't one.
00185     const T& front() const {
00186         const size_t firstItem = findNextItem(0);
00187         assert(firstItem < stuff.size());
00188         return *stuff[firstItem];
00189     }
00190     T& front() {
00191         const size_t firstItem = findNextItem(0);
00192         assert(firstItem < stuff.size());
00193         return *stuff[firstItem];
00194     }
00195 
00196     // We don't need to search for back() because the rules here ensure that the
00197     // last element is not empty.
00198     const T& back()  const {assert(!empty() && stuff.back()); return *stuff.back();}
00199     T&       back()        {assert(!empty() && stuff.back()); return *stuff.back();}
00200 
00201     const T& operator[](size_t i) const {
00202         assert(i < stuff.size() && stuff[i]);
00203         return *stuff[i];
00204     }
00205     T& operator[](size_t i) {
00206         assert(i < stuff.size() && stuff[i]);
00207         return *stuff[i];
00208     }
00209 
00210 private:
00211     size_t          nOccupiedSlots; // not counting empty slots
00212     std::vector<T*> stuff;
00213 
00214     // Note that this can leave empty slots at the end of the list which
00215     // is not a legitimate condition for the StableArray.
00216 
00217     void eraseOccupiedElement(size_t i) {
00218         assert(i < stuff.size() && stuff[i]);
00219         delete stuff[i]; stuff[i]=0; --nOccupiedSlots;
00220     }
00221 
00222     void initializeEmptyElement(size_t i, const T& t) {
00223         assert(i < stuff.size() && !stuff[i]);
00224         stuff[i] = new T(t); ++nOccupiedSlots;
00225     }
00226 
00227     void eraseElementIfNecessary(size_t i) {
00228         assert(i < stuff.size());
00229         if (stuff[i]) eraseOccupiedElement(i);
00230     }
00231 
00232     void initializeElementIfNecessary(size_t i, const T& t) {
00233         assert(i < stuff.size());
00234         if (!stuff[i]) initializeEmptyElement(i,t);
00235     }
00236 
00237 };
00238 
00239 } // namespace SimTK
00240   
00241 #endif // SimTK_SimTKCOMMON_STABLEARRAY_H_

Generated on Thu Feb 28 01:34:32 2008 for SimTKcommon by  doxygen 1.4.7