Zero  0.1.0
dynarray.h
Go to the documentation of this file.
1 /* -*- mode:C++; c-basic-offset:4 -*-
2  Shore-MT -- Multi-threaded port of the SHORE storage manager
3 
4  Copyright (c) 2007-2009
5  Data Intensive Applications and Systems Labaratory (DIAS)
6  Ecole Polytechnique Federale de Lausanne
7 
8  All Rights Reserved.
9 
10  Permission to use, copy, modify and distribute this software and
11  its documentation is hereby granted, provided that both the
12  copyright notice and this permission notice appear in all copies of
13  the software, derivative works or modified versions, and any
14  portions thereof, and that both notices appear in supporting
15  documentation.
16 
17  This code is distributed in the hope that it will be useful, but
18  WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
20  DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
21  RESULTING FROM THE USE OF THIS SOFTWARE.
22 */
23 /*<std-header orig-src='shore' incl-file-exclusion='DYNARRAY_H'>
24 
25  $Id: dynarray.h,v 1.2 2010/06/23 23:42:57 nhall Exp $
26 
27 SHORE -- Scalable Heterogeneous Object REpository
28 
29 Copyright (c) 1994-99 Computer Sciences Department, University of
30  Wisconsin -- Madison
31 All Rights Reserved.
32 
33 Permission to use, copy, modify and distribute this software and its
34 documentation is hereby granted, provided that both the copyright
35 notice and this permission notice appear in all copies of the
36 software, derivative works or modified versions, and any portions
37 thereof, and that both notices appear in supporting documentation.
38 
39 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
40 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
41 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
42 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 
44 This software was developed with support by the Advanced Research
45 Project Agency, ARPA order number 018 (formerly 8230), monitored by
46 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
47 Further funding for this work was provided by DARPA through
48 Rome Research Laboratory Contract No. F30602-97-2-0247.
49 
50 */
51 
52 #ifndef __DYNARRAY_H
53 #define __DYNARRAY_H
54 
57 #include <cstddef>
58 #include <cstdint>
59 #include <cerrno>
60 #include <algorithm>
61 
62 /* A memory-mapped array which exploits the capabilities provided by
63  mmap in order to grow dynamically without moving existing data or
64  wasting memory.
65 
66  Ideal for situations where you don't know the final size of the
67  array, the potential maximum is known but very large, and a
68  threaded environment makes it unsafe to resize by reallocating.
69 
70  NOTE: the array only supports growing, under the assumption that
71  any array which can shrink safely at all can shrink safely to size
72  zero (with the data copied to a new, smaller dynarray)
73 
74  This approach makes the most sense in a 64-bit environment where
75  address space is cheap.
76 
77  Note that most systems cannot reserve more than 2-8TB of
78  contiguous address space (32-128TB total), most likely because most
79  machines don't have that much swap space anyway.
80 
81  */
82 struct dynarray {
83 
84  /* Attempts to initialize the array with a capacity of /max_size/ bytes
85  of address space and /size()/ zero.
86 
87  If /align/ is a non-zero power of two, the resulting memory
88  will be aligned as requested.
89 
90  @return 0 on success, appropriate errno on failure
91  */
92  int init(size_t max_size, size_t align = 0);
93 
94  /* Attempts to make a deep copy of /to_copy/, setting my capacity
95  to the larger of /to_copy.capacity()/ and /max_size/
96 
97  @return 0 on success, appropriate errno on failure
98  */
99  int init(dynarray const& to_copy, size_t max_size = 0);
100 
101  /* Destroys the existing mapping, if any, and returns the object
102  to its uninitialized state
103  */
104  int fini();
105 
106  /* The reserved size of this mapping. The limit is set at
107  initialization and cannot change later.
108  */
109  size_t capacity() const {
110  return _capacity;
111  }
112 
113  /* Maps in memory to bring the total to /new_size/ bytes.
114 
115  @return 0, or an appropriate errno on failure
116  EINVAL - new_size < size()
117  */
118  int resize(size_t new_size);
119 
120  /* Ensures that at least /new_size/ bytes are ready to use.
121 
122  In order to ensure array management is O(1) work per insertion,
123  this function will always at least double the size of the array
124  if /new_size > size()/.
125 
126  Unlike /resize/ this function accepts any value of /new_size/
127  (doing nothing if the array is already big enough).
128 
129  @return 0 or an errno.
130  */
131  int ensure_capacity(size_t min_size);
132 
133  /* The currently available size. Assuming sufficient memory is
134  available the array can grow to /capacity()/ bytes -- using
135  calls to /resize()/.
136  */
137  size_t size() const {
138  return _size;
139  }
140 
141  operator char*() {
142  return _base;
143  }
144 
145  operator char const*() const {
146  return _base;
147  }
148 
149  dynarray() : _base(0),
150  _size(0),
151  _capacity(0) {}
152 
153 private:
154  // only safe if we're willing to throw exceptions (use init() and memcpy() instead)
155  dynarray(dynarray const& other);
156 
157  dynarray& operator=(dynarray const& other);
158 
159  char* _base;
160 
161  size_t _size;
162 
163  size_t _capacity;
164 };
165 
166 /* Think std::vector except backed by a dynarray.
167 
168  */
169 template<typename T>
170 struct dynvector {
171 
172  /* Initialize an empty dynvector with /limit() == max_count/
173 
174  @return 0 on success or an appropriate errno
175  */
176  int init(size_t max_count) {
177  return _arr.init(count2bytes(max_count));
178  }
179 
180  /* Destroy all contained objects and deallocate memory, returning
181  the object to its uninitialized state.
182 
183  @return 0 on success or an appropriate errno
184  */
185  int fini() {
186  for (size_t i = 0; i < _size; i++) {
187  (*this)[i].~T();
188  }
189 
190  _size = 0;
191  return _arr.fini();
192  }
193 
194  /* The largest number of elements the underlying dynarray instance
195  can accommodate
196  */
197  size_t limit() const {
198  return bytes2count(_arr.capacity());
199  }
200 
201  /* The current capacity of this dynvector (= elements worth of
202  allocated memory)
203  */
204  size_t capacity() const {
205  return bytes2count(_arr.size());
206  }
207 
208  /* The current logical size of this dynvector (= elements pushed
209  so far)
210  */
211  size_t size() const {
212  return _size;
213  }
214 
215  /* Ensure space for the requested number of elements.
216 
217  Spare capacity is managed automatically, but this method can be
218  useful if the caller knows the structure will grow rapidly or
219  needs to ensure early on that all the needed capacity is
220  available (e.g. Linux... overcommit.. OoM killer).
221 
222  @return 0 on success or an appropriate errno
223  */
224  int reserve(size_t new_capacity) {
225  return _arr.ensure_capacity(count2bytes(new_capacity));
226  }
227 
228  /* Default-construct objects at-end (if needed) to make /size() == new_size/
229 
230  @return 0 on success or an appropriate errno
231  */
232  int resize(size_t new_size) {
233  if (int err = reserve(new_size)) {
234  return err;
235  }
236 
237  for (size_t i = size(); i < new_size; i++) {
238  new(_at(i).c) T;
239  }
240 
241  _size = new_size;
242  return 0;
243  }
244 
245  /* Add /obj/ at-end, incrementing /size()/ by one
246 
247  @return 0 on success or an appropriate errno
248  */
249  int push_back(T const& obj) {
250  size_t new_size = _size + 1;
251  if (int err = reserve(new_size)) {
252  return err;
253  }
254 
255  new(_at(_size).c) T(obj);
256  _size = new_size;
257  return 0;
258  }
259 
260  T& back() {
261  return this->operator[](size() - 1);
262  }
263 
264  T const& back() const {
265  return this->operator[](size() - 1);
266  }
267 
268  /* Returns the ith element of the array; it is the caller's
269  responsibility to ensure the index is in bounds.
270  */
271  T& operator[](size_t i) {
272  return *_at(i).t;
273  }
274 
275  T const& operator[](size_t i) const {
276  return *_at(i).tc;
277  }
278 
279  dynvector() : _size(0),
280  _align_offset(0) {}
281 
282 private:
283  union ptr {
284  char const* cc;
285  T const* tc;
286  char* c;
287  T* t;
288  };
289 
290  static size_t count2bytes(size_t count) {
291  return count * sizeof(T);
292  }
293 
294  static size_t bytes2count(size_t bytes) {
295  return bytes / sizeof(T);
296  }
297 
298  ptr _at(size_t idx) const {
299  ptr rval = {_arr + count2bytes(idx)};
300  return rval;
301  }
302 
303  dynarray _arr;
304 
305  size_t _size; // element count, not bytes!!
306  size_t _align_offset;
307 };
308 
309 
311 #endif // __DYNARRAY_H
#define T
Definition: w_okvl_inl.h:45