<tt.rantala@gmail.com>
namespace rantala {
template <typename T, unsigned Initial = 16>
struct vector_bagwell
{
typedef T value_type;
typedef std::vector<T*> index_block_type;
void push_back(const T& t)
{
if (__builtin_expect(current_block_full(), false)) {
_left_in_block = Initial << _index_block.size();
_insertpos = static_cast<T*>(
malloc(_left_in_block*sizeof(T)));
_index_block.push_back(_insertpos);
}
*_insertpos++ = t;
--_left_in_block;
}
bool current_block_full() const { return _left_in_block == 0; }
T operator[](size_t index) const
{
assert(index < size());
BOOST_STATIC_ASSERT(Initial==16);
BOOST_STATIC_ASSERT(sizeof(size_t) <= sizeof(unsigned long));
const unsigned long fixed = index+16;
const unsigned long msb_diff =
(sizeof(unsigned long)*8-4-1) - __builtin_clzl(fixed);
const unsigned long msbit = 1 <<
((sizeof(unsigned long)*8-1) - __builtin_clzl(fixed));
const unsigned long fixed2 = fixed & ~msbit;
return _index_block[msb_diff][fixed2];
}
void clear()
{
for (unsigned i=0; i < _index_block.size(); ++i) {
free(_index_block[i]);
}
_index_block.clear();
_insertpos = 0;
_left_in_block = 0;
}
size_t size() const
{
BOOST_STATIC_ASSERT(Initial==16);
if (empty()) return 0;
return (1<<(3+_index_block.size()))-1-15
+ _insertpos-_index_block.back();
}
bool empty() const { return _insertpos==0; }
~vector_bagwell()
{
for (unsigned i=0; i < _index_block.size(); ++i)
free(_index_block[i]);
}
vector_bagwell() : _index_block(), _insertpos(0), _left_in_block(0) {}
index_block_type _index_block;
T* _insertpos;
size_t _left_in_block;
};
template <typename T, unsigned InitialSize, typename OutputIterator>
static inline void
copy(const vector_bagwell<T, InitialSize>& v, OutputIterator dst)
{
size_t bufsize = InitialSize;
for (size_t i=1; i < v._index_block.size(); ++i) {
std::copy(v._index_block[i-1],
v._index_block[i-1]+bufsize,
dst);
dst += bufsize;
bufsize *= 2;
}
std::copy(v._index_block.back(), v._insertpos, dst);
}
}