您的位置:首页 > 理论基础 > 数据结构算法

高性能流媒体服务器-nebula之数据结构(4)--动态数组NBAArray

2016-09-01 13:09 447 查看
NBAArray是一个不使用realloc分配内存的动态数组,当数组动态增长时,我们使用bucket指数级的分配内存,将动态数组的内存分配分散到各个bucket,避免了数组内存分配时的数据复制,使用场景:数据push很频繁的时候。经与stl中的vector比较测试,push时nbaarray比vector高出近5倍的性能,get时比vector慢3倍左右。在服务器系统中,有着非常均衡的稳定性。

//
//  NBAArray.h
//  nebula
//
//  Created by yi.cheng on 16/5/10.
//  Copyright © 2016年 kanshansoft. All rights reserved.
//

#ifndef NBAArray_h
#define NBAArray_h
#include
#include
#include

/******************************************************************************/
/* array */

/**
* Initial and minimal size of the array expressed as a power of 2.
* The initial size is 2^NBA_ARRAYOF_BIT.
*/
#define NBA_ARRAYOF_BIT     6

/** \internal
* Max number of elements as a power of 2.
*/
#define NBA_ARRAYOF_BIT_MAX 32

/**
* Array container type.
* \note Don't use internal fields directly, but access the container only using functions.
*/
template class NBAArray {
NBAArray(const NBAArray&);
NBAArray& operator = (const NBAArray&);
public:
NBAArray(lfalloctor& alloctor);

const T& operator [](uint32_t index) const;
T& editItemAt(uint32_t index);
void push(const T& item);
void push(T&& item);
const T& begin() const;
const T& last() const;
INLINE uint32_t size() const  {
return mCount;
}
INLINE bool isEmpty() const {
return (mCount == 0);
}
void clear();
~NBAArray();
private:
void*           mBucket[NBA_ARRAYOF_BIT_MAX]; /**< Dynamic array of buckets. */
size_t          mElementSize;                 /**< Size of the stored element in bytes. */
uint32_t        mBucketBit;                   /**< Bits used in the bit mask. */
uint32_t        mBucketMax;                   /**< Number of buckets. */
uint32_t        mCount;                       /**< Number of initialized elements in the array. */
uint32_t        mDefaultBucketNum;
lfalloctor&     mAlloctor;

void            _grow(uint32_t  count);
void*           getItem(uint32_t pos);
const           void* getItem() const;
void*           _itemRef(uint32_t pos);
const void*     _itemRef(uint32_t pos) const;
};

template NBAArray::NBAArray(lfalloctor& alloctor) :
mAlloctor(alloctor),
mElementSize(sizeof(T)),
mBucketBit(NBA_ARRAYOF_BIT),
mBucketMax(1 << NBA_ARRAYOF_BIT) {

mBucket[0] = mAlloctor.malloc(mBucketMax*mElementSize);
mCount = 0;
mDefaultBucketNum = mBucketMax;
for (uint32_t i = 1; i < mBucketBit; ++i) {
mBucket[i] = mBucket[0];
}
}

template INLINE void NBAArray::_grow(uint32_t count)
{
mCount = count;
while (count > mBucketMax) {
uint8_t* segment = (uint8_t*)mAlloctor.malloc(mBucketMax * mElementSize);
/* store it adjusting the offset */
/* cast to ptrdiff_t to ensure to get a negative value */
mBucket[mBucketBit] = segment - (ptrdiff_t)mBucketMax * mElementSize;
++mBucketBit;
mBucketMax = 1 << mBucketBit;
}
}

template INLINE void* NBAArray::_itemRef(uint32_t pos)
{
unsigned char* ptr;
uint32_t bsr;

/* get the highest bit set, in case of all 0, return 0 */
bsr = ilog2_u32(pos | 1);

ptr = (unsigned char*)mBucket[bsr];

return ptr + pos * mElementSize;
}

template INLINE const void* NBAArray::_itemRef(uint32_t pos) const
{
unsigned char* ptr;
uint32_t bsr;

/* get the highest bit set, in case of all 0, return 0 */
bsr = ilog2_u32(pos | 1);

ptr = (unsigned char*)mBucket[bsr];

return ptr + pos * mElementSize;
}

template INLINE void NBAArray::push(const T& item) {
uint32_t pos = mCount;
_grow(pos + 1);
void* ptr = _itemRef(pos);
copy_type(static_cast(ptr), &item, 1);
}

template INLINE void NBAArray::push(T&& item) {
uint32_t pos = mCount;
_grow(pos + 1);
void* ptr = _itemRef(pos);
copy_type(static_cast(ptr), std::forward(item));
}

template  INLINE const T& NBAArray::begin() const {
const T* e = static_cast(_itemRef(0));
return *e;
}

template  INLINE const T& NBAArray::last() const {
const T* e = static_cast(_itemRef(mCount-1));
return *e;
}

template INLINE const T& NBAArray::operator[](uint32_t index) const
{
const T* e = static_cast(_itemRef(index));
return *e;
}

template INLINE T& NBAArray::editItemAt(uint32_t index)
{
T* e = static_cast(_itemRef(index));
return *e;
}

template NBAArray::~NBAArray() {
uint32_t i =0;
uint32_t destructItems;
if(!traits::has_trivial_dtor && mCount > 0) {
destructItems = (mCount >= mDefaultBucketNum) ? mDefaultBucketNum : mCount;
destroy_type(static_cast(mBucket[0]), destructItems);
mCount -= destructItems;
}
mAlloctor.free(mBucket[0]);
for (i = NBA_ARRAYOF_BIT; i < mBucketBit; ++i) {
unsigned char* segment = (unsigned char*)mBucket[i];
ptrdiff_t  fft = (((ptrdiff_t)1) << i);
if(!traits::has_trivial_dtor && mCount > 0) {
void* storePtr = segment + fft * mElementSize;
destructItems = (mCount >= fft) ? (uint32_t)fft : mCount;
destroy_type(static_cast(storePtr), destructItems);
mCount -= destructItems;
}
mAlloctor.free(segment + fft * mElementSize);
}
}

template void NBAArray::clear()
{
uint32_t i =0;
uint32_t destructItems;
if(!traits::has_trivial_dtor && mCount > 0) {
destructItems = (mCount >= mDefaultBucketNum) ? mDefaultBucketNum : mCount;
destroy_type(static_cast(mBucket[0]), destructItems);
mCount -= destructItems;
}
for (i = NBA_ARRAYOF_BIT; i < mBucketBit; ++i) {
unsigned char* segment = (unsigned char*)mBucket[i];
ptrdiff_t  fft = (((ptrdiff_t)1) << i);
if(!traits::has_trivial_dtor && mCount > 0) {
void* storePtr = segment + fft * mElementSize;
destructItems = (mCount >= fft) ? (uint32_t)fft : mCount;
destroy_type(static_cast(storePtr), destructItems);
mCount -= destructItems;
}
}
}

#endif /* NBAArray_h */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息