00001 /* -*- mode:C++; c-basic-offset:4 -*- 00002 Shore-MT -- Multi-threaded port of the SHORE storage manager 00003 00004 Copyright (c) 2007-2009 00005 Data Intensive Applications and Systems Labaratory (DIAS) 00006 Ecole Polytechnique Federale de Lausanne 00007 00008 All Rights Reserved. 00009 00010 Permission to use, copy, modify and distribute this software and 00011 its documentation is hereby granted, provided that both the 00012 copyright notice and this permission notice appear in all copies of 00013 the software, derivative works or modified versions, and any 00014 portions thereof, and that both notices appear in supporting 00015 documentation. 00016 00017 This code is distributed in the hope that it will be useful, but 00018 WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS 00020 DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 00021 RESULTING FROM THE USE OF THIS SOFTWARE. 00022 */ 00023 /*<std-header orig-src='shore' incl-file-exclusion='DYNARRAY_H'> 00024 00025 $Id: dynarray.h,v 1.2 2010/06/23 23:42:57 nhall Exp $ 00026 00027 SHORE -- Scalable Heterogeneous Object REpository 00028 00029 Copyright (c) 1994-99 Computer Sciences Department, University of 00030 Wisconsin -- Madison 00031 All Rights Reserved. 00032 00033 Permission to use, copy, modify and distribute this software and its 00034 documentation is hereby granted, provided that both the copyright 00035 notice and this permission notice appear in all copies of the 00036 software, derivative works or modified versions, and any portions 00037 thereof, and that both notices appear in supporting documentation. 00038 00039 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY 00040 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS 00041 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND 00042 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 00043 00044 This software was developed with support by the Advanced Research 00045 Project Agency, ARPA order number 018 (formerly 8230), monitored by 00046 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518. 00047 Further funding for this work was provided by DARPA through 00048 Rome Research Laboratory Contract No. F30602-97-2-0247. 00049 00050 */ 00051 00052 #ifndef __DYNARRAY_H 00053 #define __DYNARRAY_H 00054 00055 /**\cond skip */ 00056 00057 #include <stddef.h> 00058 #include <stdint.h> 00059 #include <errno.h> 00060 #include <algorithm> 00061 00062 /* A memory-mapped array which exploits the capabilities provided by 00063 mmap in order to grow dynamically without moving existing data or 00064 wasting memory. 00065 00066 Ideal for situations where you don't know the final size of the 00067 array, the potential maximum is known but very large, and a 00068 threaded environment makes it unsafe to resize by reallocating. 00069 00070 NOTE: the array only supports growing, under the assumption that 00071 any array which can shrink safely at all can shrink safely to size 00072 zero (with the data copied to a new, smaller dynarray) 00073 00074 This approach makes the most sense in a 64-bit environment where 00075 address space is cheap. 00076 00077 Note that most systems cannot reserve more than 2-8TB of 00078 contiguous address space (32-128TB total), most likely because most 00079 machines don't have that much swap space anyway. 00080 00081 */ 00082 struct dynarray { 00083 00084 /* Attempts to initialize the array with a capacity of /max_size/ bytes 00085 of address space and /size()/ zero. 00086 00087 If /align/ is a non-zero power of two, the resulting memory 00088 will be aligned as requested. 00089 00090 @return 0 on success, appropriate errno on failure 00091 */ 00092 int init(size_t max_size, size_t align=0); 00093 00094 /* Attempts to make a deep copy of /to_copy/, setting my capacity 00095 to the larger of /to_copy.capacity()/ and /max_size/ 00096 00097 @return 0 on success, appropriate errno on failure 00098 */ 00099 int init(dynarray const &to_copy, size_t max_size=0); 00100 00101 /* Destroys the existing mapping, if any, and returns the object 00102 to its uninitialized state 00103 */ 00104 int fini(); 00105 00106 /* The reserved size of this mapping. The limit is set at 00107 initialization and cannot change later. 00108 */ 00109 size_t capacity() const { return _capacity; } 00110 00111 /* Maps in memory to bring the total to /new_size/ bytes. 00112 00113 @return 0, or an appropriate errno on failure 00114 EINVAL - new_size < size() 00115 */ 00116 int resize(size_t new_size); 00117 00118 /* Ensures that at least /new_size/ bytes are ready to use. 00119 00120 In order to ensure array management is O(1) work per insertion, 00121 this function will always at least double the size of the array 00122 if /new_size > size()/. 00123 00124 Unlike /resize/ this function accepts any value of /new_size/ 00125 (doing nothing if the array is already big enough). 00126 00127 @return 0 or an errno. 00128 */ 00129 int ensure_capacity(size_t min_size); 00130 00131 /* The currently available size. Assuming sufficient memory is 00132 available the array can grow to /capacity()/ bytes -- using 00133 calls to /resize()/. 00134 */ 00135 size_t size() const { return _size; } 00136 00137 operator char*() { return _base; } 00138 operator char const*() const { return _base; } 00139 00140 dynarray() : _base(0), _size(0), _capacity(0) { } 00141 00142 private: 00143 // only safe if we're willing to throw exceptions (use init() and memcpy() instead) 00144 dynarray(dynarray const &other); 00145 dynarray &operator=(dynarray const &other); 00146 00147 char* _base; 00148 size_t _size; 00149 size_t _capacity; 00150 }; 00151 00152 00153 00154 /* Think std::vector except backed by a dynarray. 00155 00156 */ 00157 template<typename T> 00158 struct dynvector { 00159 00160 /* Initialize an empty dynvector with /limit() == max_count/ 00161 00162 @return 0 on success or an appropriate errno 00163 */ 00164 int init(size_t max_count) { 00165 return _arr.init(count2bytes(max_count)); 00166 } 00167 00168 /* Destroy all contained objects and deallocate memory, returning 00169 the object to its uninitialized state. 00170 00171 @return 0 on success or an appropriate errno 00172 */ 00173 int fini() { 00174 for(size_t i=0; i < _size; i++) 00175 (*this)[i].~T(); 00176 00177 _size = 0; 00178 return _arr.fini(); 00179 } 00180 00181 /* The largest number of elements the underlying dynarray instance 00182 can accommodate 00183 */ 00184 size_t limit() const { 00185 return bytes2count(_arr.capacity()); 00186 } 00187 00188 /* The current capacity of this dynvector (= elements worth of 00189 allocated memory) 00190 */ 00191 size_t capacity() const { 00192 return bytes2count(_arr.size()); 00193 } 00194 00195 /* The current logical size of this dynvector (= elements pushed 00196 so far) 00197 */ 00198 size_t size() const { 00199 return _size; 00200 } 00201 00202 /* Ensure space for the requested number of elements. 00203 00204 Spare capacity is managed automatically, but this method can be 00205 useful if the caller knows the structure will grow rapidly or 00206 needs to ensure early on that all the needed capacity is 00207 available (e.g. Linux... overcommit.. OoM killer). 00208 00209 @return 0 on success or an appropriate errno 00210 */ 00211 int reserve(size_t new_capacity) { 00212 return _arr.ensure_capacity(count2bytes(new_capacity)); 00213 } 00214 00215 /* Default-construct objects at-end (if needed) to make /size() == new_size/ 00216 00217 @return 0 on success or an appropriate errno 00218 */ 00219 int resize(size_t new_size) { 00220 if(int err=reserve(new_size)) 00221 return err; 00222 00223 for(size_t i=size(); i < new_size; i++) 00224 new (_at(i).c) T; 00225 00226 _size = new_size; 00227 return 0; 00228 } 00229 00230 /* Add /obj/ at-end, incrementing /size()/ by one 00231 00232 @return 0 on success or an appropriate errno 00233 */ 00234 int push_back(T const &obj) { 00235 size_t new_size = _size+1; 00236 if(int err=reserve(new_size)) 00237 return err; 00238 00239 new (_at(_size).c) T(obj); 00240 _size = new_size; 00241 return 0; 00242 } 00243 00244 T &back() { return this->operator[](size()-1); } 00245 T const &back() const { return this->operator[](size()-1); } 00246 00247 /* Returns the ith element of the array; it is the caller's 00248 responsibility to ensure the index is in bounds. 00249 */ 00250 T &operator[](size_t i) { return *_at(i).t; } 00251 T const &operator[](size_t i) const { return *_at(i).tc; } 00252 00253 dynvector() : _size(0), _align_offset(0) { } 00254 00255 private: 00256 union ptr { char const* cc; T const* tc; char* c; T* t; }; 00257 static size_t count2bytes(size_t count) { return count*sizeof(T); } 00258 static size_t bytes2count(size_t bytes) { return bytes/sizeof(T); } 00259 00260 ptr _at(size_t idx) const { 00261 ptr rval = {_arr + count2bytes(idx)}; 00262 return rval; 00263 } 00264 00265 dynarray _arr; 00266 size_t _size; // element count, not bytes!! 00267 size_t _align_offset; 00268 }; 00269 00270 00271 /**\endcond skip */ 00272 #endif