Simbody  3.4 (development)
StableArray.h
Go to the documentation of this file.
00001 #ifndef SimTK_SimTKCOMMON_STABLEARRAY_H_
00002 #define SimTK_SimTKCOMMON_STABLEARRAY_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                       Simbody(tm): SimTKcommon                             *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK 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/home/simbody.  *
00011  *                                                                            *
00012  * Portions copyright (c) 2005-12 Stanford University and the Authors.        *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
00017  * not use this file except in compliance with the License. You may obtain a  *
00018  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
00019  *                                                                            *
00020  * Unless required by applicable law or agreed to in writing, software        *
00021  * distributed under the License is distributed on an "AS IS" BASIS,          *
00022  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
00023  * See the License for the specific language governing permissions and        *
00024  * limitations under the License.                                             *
00025  * -------------------------------------------------------------------------- */
00026 
00027 #include "SimTKcommon/internal/common.h"
00028 #include "SimTKcommon/internal/Array.h"
00029 
00030 #include <cstddef>
00031 #include <cassert>
00032 
00033 namespace SimTK {
00034 
00054 template <class T> class StableArray {
00055 public:
00056     StableArray() : nOccupiedSlots(0) { }
00057 
00058     // Allocate and fill every slot with the same value.
00059     explicit StableArray(size_t z, const T& ival=T()) : stuff(z), nOccupiedSlots(z) {
00060         for (size_t i=0; i<z; ++i) stuff[i] = new T(ival);
00061     }
00062 
00063     // Copy constructor must preserve slot numbers.
00064     StableArray(const StableArray& s) : stuff(s.size(),0), nOccupiedSlots(0) {
00065         for (size_t i=0; i<s.size(); ++i) 
00066             if (!s.empty(i)) initializeEmptyElement(i, s[i]);
00067         assert(nItems() == s.nItems());
00068     }
00069 
00070     // Assignment must preserve slot numbers.
00071     StableArray& operator=(const StableArray& s) {
00072         clear();
00073         stuff.resize(s.size(),0);
00074         for (size_t i=0; i<s.size(); ++i) 
00075             if (!s.empty(i)) initializeEmptyElement(i, s[i]);
00076         assert(nItems() == s.nItems());
00077         return *this;
00078     }
00079 
00080     ~StableArray() { clear(); }
00081 
00082     bool empty() const { return stuff.size()==0; }
00083     bool empty(size_t i) const {
00084         assert(i < stuff.size());
00085         return stuff[i] == 0;
00086     }
00087     size_t size()   const {return stuff.size();}
00088     size_t nItems() const {return nOccupiedSlots;}
00089 
00090     // This routine preserves as many items as possible and fills
00091     // in all empty slots with default values. The array will
00092     // thus have exactly newz slots with nItems==newz.
00093     // I'm not sure this is useful for anything.
00094     void resize(size_t newz, const T& ival=T()) {
00095         const size_t oldz = stuff.size();
00096         // If we're throwing anything away, destruct it.
00097         for (size_t i=newz; i < oldz; ++i)
00098             eraseElementIfNecessary(i);
00099         stuff.resize(newz,0);
00100         // Fill in all empty slots with default values.
00101         for (size_t i=0; i < newz; ++i)
00102             initializeElementIfNecessary(i,ival);
00103         assert(nItems() == newz);
00104     }
00105 
00106     void clear() {
00107         for (size_t i=0; i < stuff.size(); ++i)
00108             eraseElementIfNecessary(i);
00109         stuff.resize(0);
00110         assert(nItems()==0);
00111     }
00112 
00113     // You can push a new item onto the end, or put one in an
00114     // empty slot.
00115     void push_back(const T& t) {
00116         stuff.push_back(new T(t));
00117         ++nOccupiedSlots;
00118     }
00119 
00120     // Remove the last element and shrink the list by 1. If the second-to-the-last
00121     // was empty we'll reduce the length more, so that pop_back() guarantees either
00122     // that the the last element (back()) is not empty, or the entire list is empty.
00123     // Don't call this on an empty array.
00124     void pop_back() {
00125         assert(!empty() && stuff.back());
00126         eraseOccupiedElement(stuff.size()-1);   // last element *better* be occupied!
00127 
00128         // Skip over any exposed empties. No need to adjust count.
00129         do { stuff.pop_back(); } while (!stuff.empty() && !stuff.back());
00130     }
00131 
00132     void insertAt(size_t i, const T& t) {
00133         assert(i <= stuff.size());
00134         if (i == size()) push_back(t);
00135         else initializeEmptyElement(i,t);
00136     }
00137 
00138     size_t findFreeSlot() const {
00139         if (nItems() == size())
00140             return size();  // no room at the inn!
00141         for (size_t i=0; i<size(); ++i)
00142             if (empty(i)) return i;
00143         assert(false); // where's the empty slot???
00144         return size_t(-1);
00145     }
00146 
00147     // Look for the first occupied slot at or after i. Returns
00148     // size() (that is, one past the end) if none found. Use like this:
00149     //     for (size_t i=findNextItem(0); i < size(); i=findNextItem(i+1))
00150     //         do something with item[i] here
00151     size_t findNextItem(size_t i) {
00152         assert(i < stuff.size());
00153         for (; i < stuff.size() && !stuff[i]; ++i);
00154         return i;
00155     }
00156 
00157     // Insert the item in the first available slot, or grow the array
00158     // by one and stick it on the end if there are no free slots. The
00159     // slot in which it was placed is returned.
00160     size_t insert(const T& t) {
00161         const size_t free = findFreeSlot();
00162         insertAt(free, t);
00163         return free;
00164     }
00165 
00166 
00167     // Erasing an element slot if it isn't already empty. If we erase the
00168     // last element we don't have to leave a hole, and in fact we might
00169     // expose a hole in the second-to-the-last element too. In that 
00170     // case we erase by resizing away trailing detritus, otherwise we'll
00171     // make a hole.
00172     void erase(size_t i) {
00173         if (i == stuff.size()-1) pop_back();
00174         else eraseElementIfNecessary(i);
00175     }
00176 
00177     // This returns the first *occupied* element and blows up if there isn't one.
00178     const T& front() const {
00179         const size_t firstItem = findNextItem(0);
00180         assert(firstItem < stuff.size());
00181         return *stuff[firstItem];
00182     }
00183     T& front() {
00184         const size_t firstItem = findNextItem(0);
00185         assert(firstItem < stuff.size());
00186         return *stuff[firstItem];
00187     }
00188 
00189     // We don't need to search for back() because the rules here ensure that the
00190     // last element is not empty.
00191     const T& back()  const {assert(!empty() && stuff.back()); return *stuff.back();}
00192     T&       back()        {assert(!empty() && stuff.back()); return *stuff.back();}
00193 
00194     const T& operator[](size_t i) const {
00195         assert(i < stuff.size() && stuff[i]);
00196         return *stuff[i];
00197     }
00198     T& operator[](size_t i) {
00199         assert(i < stuff.size() && stuff[i]);
00200         return *stuff[i];
00201     }
00202 
00203 private:
00204     size_t              nOccupiedSlots; // not counting empty slots
00205     Array_<T*,size_t>   stuff;
00206 
00207     // Note that this can leave empty slots at the end of the list which
00208     // is not a legitimate condition for the StableArray.
00209 
00210     void eraseOccupiedElement(size_t i) {
00211         assert(i < stuff.size() && stuff[i]);
00212         delete stuff[i]; stuff[i]=0; --nOccupiedSlots;
00213     }
00214 
00215     void initializeEmptyElement(size_t i, const T& t) {
00216         assert(i < stuff.size() && !stuff[i]);
00217         stuff[i] = new T(t); ++nOccupiedSlots;
00218     }
00219 
00220     void eraseElementIfNecessary(size_t i) {
00221         assert(i < stuff.size());
00222         if (stuff[i]) eraseOccupiedElement(i);
00223     }
00224 
00225     void initializeElementIfNecessary(size_t i, const T& t) {
00226         assert(i < stuff.size());
00227         if (!stuff[i]) initializeEmptyElement(i,t);
00228     }
00229 
00230 };
00231 
00232 } // namespace SimTK
00233   
00234 #endif // SimTK_SimTKCOMMON_STABLEARRAY_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines