dynarray.h

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

Generated on Thu Dec 9 08:42:27 2010 for Shore Storage Manager by  doxygen 1.4.7