#ifndef XRD_CLIIDXVEC_H
#define XRD_CLIIDXVEC_H
/******************************************************************************/
/* */
/* X r d C l i e n t V e c t o r . h h */
/* */
/* Author: Fabrizio Furano (INFN Padova, 2006) */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// A vector class optimized for insertions and deletions //
// indexed access takes O(1) //
// insertion takes O(1) plus a very small fraction of O(n) //
// deletion takes O(1) plus a very small fraction of O(n) //
// //
// Better suited than XrdClientVector to hold complex objects //
// //
//////////////////////////////////////////////////////////////////////////
#include
#include
#include "XrdSys/XrdSysHeaders.hh"
#define IDXVEC_MINCAPACITY 128
template
class XrdClientVector {
private:
// We keep the corrected size of T
int sizeof_t;
char *rawdata; // A raw mem block to hold (casted) T instances
struct myindex {
long offs; // Offset to a T inside rawdata
bool notempty;
} *index;
// the number of holes inside rawdata
// each hole is sizeof_t bytes
int holecount;
long size, mincap;
long capacity, maxsize;
// Completely packs rawdata
// Eventually adjusts the sizes in order to contain at least
// newsize elements
int BufRealloc(int newsize);
inline void Init(int cap = -1) {
if (rawdata) free(rawdata);
if (index) free(index);
mincap = (cap > 0) ? cap : IDXVEC_MINCAPACITY;
rawdata = static_cast(malloc(mincap * sizeof_t));
index = static_cast(malloc(mincap * sizeof(myindex)));
if (!rawdata || !index) {
std::cerr << "XrdClientIdxVector::Init .... out of memory. sizeof_t=" << sizeof_t <<
" sizeof(myindex)=" << sizeof(myindex) << " capacity=" << mincap << std::endl;
abort();
}
// and we make every item as empty, i.e. not pointing to anything
memset(index, 0, mincap * sizeof(myindex));
holecount = 0;
size = 0;
maxsize = capacity = mincap;
}
// Makes a null position... not to be exposed
// Because after this the element pointed to by el becomes invalid
// Typically el will be moved at the end, at the size+holecount position
void DestroyElem(myindex *el) {
reinterpret_cast(rawdata+el->offs)->~T();
// el->notempty = false;
}
void put(T& item, long pos) {
// Puts an element in position pos
// Hence write at pos in the index array
// Use a new chunk of rawdata if the item does not point to a chunk
if (size+holecount >= capacity) {
std::cerr << "XrdClientIdxVector::put .... internal error." << std::endl;
abort();
}
T *p;
long offs = (size+holecount)*sizeof_t;
if (index[pos].notempty) {
offs = index[pos].offs;
// did we fill a hole?
holecount--;
}
p = new(rawdata + offs) T(item);
if (p) {
index[pos].offs = offs;
index[pos].notempty = true;
}
else {
std::cerr << "XrdClientIdxVector::put .... out of memory." << std::endl;
abort();
}
}
public:
inline int GetSize() const { return size; }
void Clear() {
for (long i = 0; i < size; i++)
if (index[i].notempty) DestroyElem(&index[i]);
Init(mincap);
}
XrdClientVector(int cap = -1):
sizeof_t(0), rawdata(0), index(0)
{
// We calculate a size which is aligned on 4-bytes
sizeof_t = (sizeof(T) + 3) >> 2 << 2;
Init(cap);
}
XrdClientVector(XrdClientVector &v):
rawdata(0), index(0) {
sizeof_t = (sizeof(T) + 3) >> 2 << 2;
Init(v.capacity);
BufRealloc(v.size);
for (int i = 0; i < v.size; i++)
Push_back( v[i] );
}
~XrdClientVector() {
for (long i = 0; i < size; i++)
if (index[i].notempty) DestroyElem(&index[i]);
if (rawdata) free(rawdata);
if (index) free(index);
}
void Resize(int newsize) {
long oldsize = size;
if (newsize > oldsize) {
BufRealloc(newsize);
T *item = new T;
// Add new elements if needed
for (long i = oldsize; i < newsize; i++) {
put(*item, size++);
}
delete item;
}
else {
for (long i = oldsize; i > newsize; i--)
Erase(i-1, false);
}
}
void Push_back(T& item) {
if ( BufRealloc(size+1) )
put(item, size++);
}
// // Inserts an item in the given position
// void Insert(T& item, int pos) {
// if (pos >= size) {
// Push_back(item);
// return;
// }
// if ( BufRealloc(size+1) ) {
// memmove(&index[pos+1], &index[pos], (size+holecount-pos) * sizeof(myindex));
// index[pos].notempty = false;
// size++;
// put(item, pos);
// }
// }
// Inserts an item in the given position
void Insert(T& item, int pos) {
if (pos >= size) {
Push_back(item);
return;
}
if ( BufRealloc(size+1) ) {
if (holecount > 0) {
struct myindex tmpi = index[size];
memmove(&index[pos+1], &index[pos], (size-pos) * sizeof(myindex));
index[pos] = tmpi;
} else {
memmove(&index[pos+1], &index[pos], (size-pos) * sizeof(myindex));
index[pos].notempty = false;
}
size++;
put(item, pos);
}
}
// // Removes a single element in position pos
// void Erase(unsigned int pos, bool dontrealloc=true) {
// // We make the position empty, then move the free index to the end
// DestroyElem(index + pos);
// index[size+holecount] = index[pos];
// holecount++;
// memmove(&index[pos], &index[pos+1], (size+holecount-pos) * sizeof(myindex));
// size--;
// if (!dontrealloc)
// BufRealloc(size);
// }
// Removes a single element in position pos
void Erase(unsigned int pos, bool dontrealloc=true) {
// We make the position empty, then move the free index to the end of the full items
DestroyElem(index + pos);
struct myindex tmpi = index[pos];
holecount++;
memmove(&index[pos], &index[pos+1], (size-pos-1) * sizeof(myindex));
size--;
index[size] = tmpi;
if (!dontrealloc)
BufRealloc(size);
}
T Pop_back() {
T r( At(size-1) );
DestroyElem(index+size-1);
holecount++;
size--;
//BufRealloc(size);
return (r);
}
T Pop_front() {
T res;
res = At(0);
Erase(0);
return (res);
}
// Bounded array like access
inline T &At(int pos) {
if ((pos < 0) || (static_cast(pos) >=
static_cast(size))) abort();
return *( reinterpret_cast(rawdata + index[pos].offs));
}
inline T &operator[] (int pos) {
return At(pos);
}
};
// Completely packs rawdata if needed
// Eventually adjusts the sizes in order to fit newsize elements
template
int XrdClientVector::BufRealloc(int newsize) {
// If for some reason we have too many holes, we repack everything
// this is very heavy!!
if ((size+holecount >= capacity-2) && (holecount > 4*size))
while (size+holecount >= capacity-2) {
long lastempty = size+holecount-1; // The first hole to fill
// Pack everything in rawdata
// Keep the pointers updated
// Do the trick
// Move the last filled to the first encountered hole
memmove(rawdata + index[lastempty].offs, rawdata + index[lastempty].offs + sizeof_t,
(size+holecount)*sizeof_t - index[lastempty].offs );
// Drop the index
index[lastempty].notempty = false;
holecount--;
// Adjust all the pointers to the subsequent chunks
for (long i = 0; i < size+holecount; i++)
if (index[i].notempty && (index[i].offs > index[lastempty].offs))
index[i].offs -= sizeof_t;
}
if (newsize > maxsize) maxsize = newsize;
while (newsize+holecount > capacity*2/3) {
// Too near to the end?
// double the capacity
capacity *= 2;
rawdata = static_cast(realloc(rawdata, capacity*sizeof_t));
if (!rawdata) {
std::cerr << "XrdClientIdxVector::BufRealloc .... out of memory." << std::endl;
abort();
}
index = static_cast(realloc(index, capacity*sizeof(myindex)));
memset(index+capacity/2, 0, capacity*sizeof(myindex)/2);
}
while ((newsize+holecount < capacity/3) && (capacity > 2*mincap)) {
// Too near to the beginning?
// half the capacity
capacity /= 2;
rawdata = static_cast(realloc(rawdata, capacity*sizeof_t));
if (!rawdata) {
std::cerr << "XrdClientIdxVector::BufRealloc .... out of memory." << std::endl;
abort();
}
index = static_cast(realloc(index, capacity*sizeof(myindex)));
}
return 1;
}
#endif