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.4 2012/01/02 21:52:21 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 00095 /* Destroys the existing mapping, if any, and returns the object 00096 to its uninitialized state 00097 */ 00098 int fini(); 00099 00100 /* The reserved size of this mapping. The limit is set at 00101 initialization and cannot change later. 00102 */ 00103 size_t capacity() const { return _capacity; } 00104 00105 /* Maps in memory to bring the total to /new_size/ bytes. 00106 00107 @return 0, or an appropriate errno on failure 00108 EINVAL - new_size < size() 00109 */ 00110 int resize(size_t new_size); 00111 00112 /* Ensures that at least /new_size/ bytes are ready to use. 00113 00114 In order to ensure array management is O(1) work per insertion, 00115 this function will always at least double the size of the array 00116 if /new_size > size()/. 00117 00118 Unlike /resize/ this function accepts any value of /new_size/ 00119 (doing nothing if the array is already big enough). 00120 00121 @return 0 or an errno. 00122 */ 00123 int ensure_capacity(size_t min_size); 00124 00125 /* The currently available size. Assuming sufficient memory is 00126 available the array can grow to /capacity()/ bytes -- using 00127 calls to /resize()/. 00128 */ 00129 size_t size() const { return _size; } 00130 00131 operator char*() { return _base; } 00132 operator char const*() const { return _base; } 00133 00134 dynarray() : _base(0), _size(0), _capacity(0) { } 00135 00136 private: 00137 // only safe if we're willing to throw exceptions (use init() and memcpy() instead) 00138 dynarray(dynarray const &other); 00139 dynarray &operator=(dynarray const &other); 00140 00141 char* _base; 00142 size_t _size; 00143 size_t _capacity; 00144 }; 00145 00146 00147 00148 /* Think std::vector except backed by a dynarray. 00149 00150 */ 00151 template<typename T> 00152 struct dynvector { 00153 00154 /* Initialize an empty dynvector with /limit() == max_count/ 00155 00156 @return 0 on success or an appropriate errno 00157 */ 00158 int init(size_t max_count) { 00159 return _arr.init(count2bytes(max_count)); 00160 } 00161 00162 /* Destroy all contained objects and deallocate memory, returning 00163 the object to its uninitialized state. 00164 00165 @return 0 on success or an appropriate errno 00166 */ 00167 int fini() { 00168 for(size_t i=0; i < _size; i++) 00169 (*this)[i].~T(); 00170 00171 _size = 0; 00172 return _arr.fini(); 00173 } 00174 00175 /* The largest number of elements the underlying dynarray instance 00176 can accommodate 00177 */ 00178 size_t limit() const { 00179 return bytes2count(_arr.capacity()); 00180 } 00181 00182 /* The current capacity of this dynvector (= elements worth of 00183 allocated memory) 00184 */ 00185 size_t capacity() const { 00186 return bytes2count(_arr.size()); 00187 } 00188 00189 /* The current logical size of this dynvector (= elements pushed 00190 so far) 00191 */ 00192 size_t size() const { 00193 return _size; 00194 } 00195 00196 /* Ensure space for the requested number of elements. 00197 00198 Spare capacity is managed automatically, but this method can be 00199 useful if the caller knows the structure will grow rapidly or 00200 needs to ensure early on that all the needed capacity is 00201 available (e.g. Linux... overcommit.. OoM killer). 00202 00203 @return 0 on success or an appropriate errno 00204 */ 00205 int reserve(size_t new_capacity) { 00206 return _arr.ensure_capacity(count2bytes(new_capacity)); 00207 } 00208 00209 /* Default-construct objects at-end (if needed) to make /size() == new_size/ 00210 00211 @return 0 on success or an appropriate errno 00212 */ 00213 int resize(size_t new_size) { 00214 if(int err=reserve(new_size)) 00215 return err; 00216 00217 for(size_t i=size(); i < new_size; i++) 00218 new (_at(i).c) T; 00219 00220 _size = new_size; 00221 return 0; 00222 } 00223 00224 /* Add /obj/ at-end, incrementing /size()/ by one 00225 00226 @return 0 on success or an appropriate errno 00227 */ 00228 int push_back(T const &obj) { 00229 size_t new_size = _size+1; 00230 if(int err=reserve(new_size)) 00231 return err; 00232 00233 new (_at(_size).c) T(obj); 00234 _size = new_size; 00235 return 0; 00236 } 00237 00238 T &back() { return this->operator[](size()-1); } 00239 T const &back() const { return this->operator[](size()-1); } 00240 00241 /* Returns the ith element of the array; it is the caller's 00242 responsibility to ensure the index is in bounds. 00243 */ 00244 T &operator[](size_t i) { return *_at(i).t; } 00245 T const &operator[](size_t i) const { return *_at(i).tc; } 00246 00247 dynvector() : _size(0), _align_offset(0) { } 00248 00249 private: 00250 union ptr { char const* cc; T const* tc; char* c; T* t; }; 00251 static size_t count2bytes(size_t count) { return count*sizeof(T); } 00252 static size_t bytes2count(size_t bytes) { return bytes/sizeof(T); } 00253 00254 ptr _at(size_t idx) const { 00255 ptr rval = {_arr + count2bytes(idx)}; 00256 return rval; 00257 } 00258 00259 dynarray _arr; 00260 size_t _size; // element count, not bytes!! 00261 size_t _align_offset; 00262 }; 00263 00264 00265 /**\endcond skip */ 00266 #endif