Simbody
|
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*,size_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_