xrootd
XrdClientVector.hh
Go to the documentation of this file.
1 
2 // //
3 // XrdClientIdxVector //
4 // //
5 // Author: Fabrizio Furano (INFN Padova, 2006) //
6 // //
7 // A vector class optimized for insertions and deletions //
8 // indexed access takes O(1) //
9 // insertion takes O(1) plus a very small fraction of O(n) //
10 // deletion takes O(1) plus a very small fraction of O(n) //
11 // //
12 // Better suited than XrdClientVector to hold complex objects //
13 // //
15 
16 // $Id$
17 
18 
19 #ifndef XRD_CLIIDXVEC_H
20 #define XRD_CLIIDXVEC_H
21 
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "XrdSys/XrdSysHeaders.hh"
26 
27 
28 #define IDXVEC_MINCAPACITY 128
29 
30 template<class T>
32 
33 
34 private:
35 
36  // We keep the corrected size of T
37  int sizeof_t;
38 
39  char *rawdata; // A raw mem block to hold (casted) T instances
40 
41  struct myindex {
42  long offs; // Offset to a T inside rawdata
43  bool notempty;
44  } *index;
45 
46  // the number of holes inside rawdata
47  // each hole is sizeof_t bytes
48  int holecount;
49 
50  long size, mincap;
52 
53  // Completely packs rawdata
54  // Eventually adjusts the sizes in order to contain at least
55  // newsize elements
56  int BufRealloc(int newsize);
57 
58  inline void Init(int cap = -1) {
59  if (rawdata) free(rawdata);
60  if (index) free(index);
61 
62  mincap = (cap > 0) ? cap : IDXVEC_MINCAPACITY;
63 
64  rawdata = static_cast<char *>(malloc(mincap * sizeof_t));
65 
66  index = static_cast<myindex *>(malloc(mincap * sizeof(myindex)));
67 
68  if (!rawdata || !index) {
69  std::cerr << "XrdClientIdxVector::Init .... out of memory. sizeof_t=" << sizeof_t <<
70  " sizeof(myindex)=" << sizeof(myindex) << " capacity=" << mincap << std::endl;
71  abort();
72  }
73 
74  // and we make every item as empty, i.e. not pointing to anything
75  memset(index, 0, mincap * sizeof(myindex));
76 
77  holecount = 0;
78 
79  size = 0;
81  }
82 
83  // Makes a null position... not to be exposed
84  // Because after this the element pointed to by el becomes invalid
85  // Typically el will be moved at the end, at the size+holecount position
86  void DestroyElem(myindex *el) {
87  reinterpret_cast<T*>(rawdata+el->offs)->~T();
88  // el->notempty = false;
89  }
90 
91  void put(T& item, long pos) {
92  // Puts an element in position pos
93  // Hence write at pos in the index array
94  // Use a new chunk of rawdata if the item does not point to a chunk
95  if (size+holecount >= capacity) {
96  std::cerr << "XrdClientIdxVector::put .... internal error." << std::endl;
97  abort();
98  }
99 
100  T *p;
101  long offs = (size+holecount)*sizeof_t;
102 
103  if (index[pos].notempty) {
104  offs = index[pos].offs;
105 
106  // did we fill a hole?
107  holecount--;
108  }
109 
110  p = new(rawdata + offs) T(item);
111 
112  if (p) {
113  index[pos].offs = offs;
114  index[pos].notempty = true;
115  }
116  else {
117  std::cerr << "XrdClientIdxVector::put .... out of memory." << std::endl;
118  abort();
119  }
120 
121  }
122 
123 public:
124 
125  inline int GetSize() const { return size; }
126 
127  void Clear() {
128  for (long i = 0; i < size; i++)
129  if (index[i].notempty) DestroyElem(&index[i]);
130 
131  Init(mincap);
132  }
133 
134  XrdClientVector(int cap = -1):
135  sizeof_t(0), rawdata(0), index(0)
136  {
137  // We calculate a size which is aligned on 4-bytes
138  sizeof_t = (sizeof(T) + 3) >> 2 << 2;
139  Init(cap);
140  }
141 
143  rawdata(0), index(0) {
144 
145  sizeof_t = (sizeof(T) + 3) >> 2 << 2;
146 
147  Init(v.capacity);
148  BufRealloc(v.size);
149 
150  for (int i = 0; i < v.size; i++)
151  Push_back( v[i] );
152  }
153 
155  for (long i = 0; i < size; i++)
156  if (index[i].notempty) DestroyElem(&index[i]);
157 
158  if (rawdata) free(rawdata);
159  if (index) free(index);
160  }
161 
162  void Resize(int newsize) {
163  long oldsize = size;
164 
165  if (newsize > oldsize) {
166  BufRealloc(newsize);
167  T *item = new T;
168  // Add new elements if needed
169  for (long i = oldsize; i < newsize; i++) {
170  put(*item, size++);
171  }
172  delete item;
173  }
174  else {
175  for (long i = oldsize; i > newsize; i--)
176  Erase(i-1, false);
177  }
178  }
179 
180  void Push_back(T& item) {
181 
182  if ( BufRealloc(size+1) )
183  put(item, size++);
184 
185  }
186 
187 // // Inserts an item in the given position
188 // void Insert(T& item, int pos) {
189 
190 // if (pos >= size) {
191 // Push_back(item);
192 // return;
193 // }
194 
195 // if ( BufRealloc(size+1) ) {
196 
197 // memmove(&index[pos+1], &index[pos], (size+holecount-pos) * sizeof(myindex));
198 // index[pos].notempty = false;
199 // size++;
200 // put(item, pos);
201 // }
202 
203 // }
204 
205 
206  // Inserts an item in the given position
207  void Insert(T& item, int pos) {
208 
209  if (pos >= size) {
210  Push_back(item);
211  return;
212  }
213 
214  if ( BufRealloc(size+1) ) {
215 
216  if (holecount > 0) {
217  struct myindex tmpi = index[size];
218  memmove(&index[pos+1], &index[pos], (size-pos) * sizeof(myindex));
219  index[pos] = tmpi;
220  } else {
221  memmove(&index[pos+1], &index[pos], (size-pos) * sizeof(myindex));
222  index[pos].notempty = false;
223  }
224 
225  size++;
226  put(item, pos);
227  }
228 
229  }
230 
231 // // Removes a single element in position pos
232 // void Erase(unsigned int pos, bool dontrealloc=true) {
233 // // We make the position empty, then move the free index to the end
234 // DestroyElem(index + pos);
235 
236 // index[size+holecount] = index[pos];
237 // holecount++;
238 
239 // memmove(&index[pos], &index[pos+1], (size+holecount-pos) * sizeof(myindex));
240 
241 // size--;
242 
243 // if (!dontrealloc)
244 // BufRealloc(size);
245 
246 // }
247 
248  // Removes a single element in position pos
249  void Erase(unsigned int pos, bool dontrealloc=true) {
250  // We make the position empty, then move the free index to the end of the full items
251  DestroyElem(index + pos);
252 
253  struct myindex tmpi = index[pos];
254  holecount++;
255 
256  memmove(&index[pos], &index[pos+1], (size-pos-1) * sizeof(myindex));
257 
258  size--;
259  index[size] = tmpi;
260  if (!dontrealloc)
261  BufRealloc(size);
262 
263  }
264 
265  T Pop_back() {
266  T r( At(size-1) );
267 
269 
270  holecount++;
271  size--;
272  //BufRealloc(size);
273 
274  return (r);
275  }
276 
277  T Pop_front() {
278  T res;
279 
280  res = At(0);
281 
282  Erase(0);
283  return (res);
284  }
285 
286  // Bounded array like access
287  inline T &At(int pos) {
288  // if ( (pos < 0) || (pos >= size) )
289  // abort();
290 
291  return *( reinterpret_cast<T*>(rawdata + index[pos].offs));
292  }
293 
294  inline T &operator[] (int pos) {
295  return At(pos);
296  }
297 
298 };
299 
300 
301 // Completely packs rawdata if needed
302 // Eventually adjusts the sizes in order to fit newsize elements
303 template <class T>
305 
306  // If for some reason we have too many holes, we repack everything
307  // this is very heavy!!
308  if ((size+holecount >= capacity-2) && (holecount > 4*size))
309  while (size+holecount >= capacity-2) {
310  long lastempty = size+holecount-1; // The first hole to fill
311 
312  // Pack everything in rawdata
313  // Keep the pointers updated
314 
315  // Do the trick
316 
317  // Move the last filled to the first encountered hole
318  memmove(rawdata + index[lastempty].offs, rawdata + index[lastempty].offs + sizeof_t,
319  (size+holecount)*sizeof_t - index[lastempty].offs );
320 
321  // Drop the index
322  index[lastempty].notempty = false;
323  holecount--;
324 
325  // Adjust all the pointers to the subsequent chunks
326  for (long i = 0; i < size+holecount; i++)
327  if (index[i].notempty && (index[i].offs > index[lastempty].offs))
328  index[i].offs -= sizeof_t;
329 
330  }
331 
332  if (newsize > maxsize) maxsize = newsize;
333 
334  while (newsize+holecount > capacity*2/3) {
335  // Too near to the end?
336  // double the capacity
337 
338  capacity *= 2;
339 
340  rawdata = static_cast<char *>(realloc(rawdata, capacity*sizeof_t));
341  if (!rawdata) {
342  std::cerr << "XrdClientIdxVector::BufRealloc .... out of memory." << std::endl;
343  abort();
344  }
345 
346  index = static_cast<myindex *>(realloc(index, capacity*sizeof(myindex)));
347  memset(index+capacity/2, 0, capacity*sizeof(myindex)/2);
348 
349  }
350 
351  while ((newsize+holecount < capacity/3) && (capacity > 2*mincap)) {
352  // Too near to the beginning?
353  // half the capacity
354 
355 
356  capacity /= 2;
357 
358  rawdata = static_cast<char *>(realloc(rawdata, capacity*sizeof_t));
359  if (!rawdata) {
360  std::cerr << "XrdClientIdxVector::BufRealloc .... out of memory." << std::endl;
361  abort();
362  }
363 
364  index = static_cast<myindex *>(realloc(index, capacity*sizeof(myindex)));
365 
366  }
367 
368  return 1;
369 
370 }
371 
372 
373 #endif