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.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

Generated on Mon Jan 2 15:13:56 2012 for Shore Storage Manager by  doxygen 1.4.7