blob: 3d8be58d6aa809b8ae0aa4cc00ed5d195b56319e [file] [log] [blame]
/*
vectorbuffer.cpp
yet another circle buffer
Markus Mertama
*/
#ifndef __VECTORBUFFER_H__
#define __VECTORBUFFER_H__
#include<e32std.h>
#define VLOG(x)
#define VECPANIC(x) VectorPanic(x, __LINE__)
void VectorPanic(TInt, TInt);
//int DEBUG_INT;
NONSHARABLE_CLASS(TNodeBuffer)
{
public:
protected:
NONSHARABLE_CLASS(TNode)
{
public:
static TNode* Empty(TUint8* iBuffer);
static TNode* New(TNode* aPrev, const TDesC8& aData);
const TUint8* Ptr() const;
TInt Size() const;
inline TNode* Succ();
static void SetSucc(TNode*& aNode);
void Terminator(TNode* aNode);
private:
TNode* iSucc;
};
};
inline TNodeBuffer::TNode* TNodeBuffer::TNode::Succ()
{
return iSucc;
}
template <TInt C>
NONSHARABLE_CLASS(TVectorBuffer) : public TNodeBuffer
{
public:
TVectorBuffer();
TInt Append(const TDesC8& aData);
// TInt AppendOverwrite(const TDesC8& aData);
TPtrC8 Shift();
TPtrC8 operator[](TInt aIndex) const;
TInt Size() const;
private:
TInt GetRoom(TInt aSize) const;
TInt Unreserved() const;
private:
TNode* iTop;
TNode* iBottom;
TInt iSize;
TUint8 iBuffer[C];
};
template <TInt C>
TVectorBuffer<C>::TVectorBuffer() : iSize(0)
{
Mem::FillZ(iBuffer, C);
iTop = TNode::Empty(iBuffer); //these points to buffer
iBottom = TNode::Empty(iBuffer);
}
template<TInt C >
TInt TVectorBuffer<C>::Unreserved() const
{
__ASSERT_DEBUG(iBottom < iBottom->Succ(), VECPANIC(KErrCorrupt));
const TInt bytesbetween =
reinterpret_cast<const TUint8*>(iBottom->Succ()) -
reinterpret_cast<const TUint8*>(iTop);
const TInt topsize = sizeof(TNode);
if(bytesbetween > 0) //bytesbetween is room between bottom and top
{ //therefore free room is subracted from free space
const TInt room = C - bytesbetween - topsize;
return room;
}
if(bytesbetween == 0)
{
if(Size() > 0)
return 0;
else
return C - topsize;
}
const TInt room = -bytesbetween - topsize; //free is space between pointers
return room;
}
template <TInt C>
TInt TVectorBuffer<C>::GetRoom(TInt aSize) const
{
const TInt bytesnew = sizeof(TNode) + aSize;
const TInt room = Unreserved() - bytesnew;
return room;
}
template <TInt C>
TInt TVectorBuffer<C>::Append(const TDesC8& aData) //ei ole ok!
{
const TInt len = aData.Length();
if(GetRoom(len) < 0)
{
return KErrOverflow;
}
if(iBottom->Succ()->Ptr() - iBuffer > (C - (len + TInt(sizeof(TNode)))))
{
VLOG("rc");
// RDebug::Print(_L("vector: append"));
TNode* p = TNode::Empty(iBuffer);
iBottom->Terminator(p);
iBottom = p;
return Append(aData);
// Append();
// iBottom = TNode::New(p, aData); //just append something into end
}
//DEBUG_INT++;
iBottom = TNode::New(iBottom, aData);
iSize += len;
return KErrNone;
}
/*
template <TInt C>
TInt TVectorBuffer<C>::AppendOverwrite(const TDesC8& aData) //ei ole ok!
{
while(Append(aData) == KErrOverflow)
{
if(iTop->Succ() == NULL)
{
return KErrUnderflow;
}
//Shift(); //data is lost
}
return KErrNone;
}
*/
template <TInt C>
TPtrC8 TVectorBuffer<C>::Shift()
{
__ASSERT_ALWAYS(iTop->Succ() != NULL, VECPANIC(KErrUnderflow)); //can never pass-by bottom
TNode* node = iTop;
iTop = iTop->Succ();
if(iTop > node)
{
// DEBUG_INT--;
iSize -= node->Size();
return TPtrC8(node->Ptr(), node->Size());
}
else
{
// RDebug::Print(_L("vector: shift"));
return Shift(); //this happens when buffer is terminated, and data lies in next
}
}
template <TInt C>
TInt TVectorBuffer<C>::Size() const
{
return iSize;
}
template <TInt C>
TPtrC8 TVectorBuffer<C>::operator[](TInt aIndex) const
{
TInt index = 0;
TNode* t = iTop->Size() > 0 ? iTop : iTop->Succ(); //eliminate terminator
while(index < aIndex)
{
TNode* nt = t->Succ();
if(nt < t)
{
nt = nt->Succ();
}
t = nt;
if(t->Size() > 0)
index++;
__ASSERT_ALWAYS(t->Succ() != NULL, VECPANIC(KErrUnderflow)); //can never pass-by bottom
}
return t->Ptr();
}
template <class T, TInt C>
NONSHARABLE_CLASS(TVector) : public TVectorBuffer<C * sizeof(T)>
{
public:
TVector();
TInt Append(const T& aData);
const T& Shift();
TInt Size() const;
const T& operator[](TInt aIndex) const;
};
template <class T, TInt C>
TVector<T, C>::TVector() : TVectorBuffer<C * sizeof(T)>()
{
}
template <class T, TInt C>
TInt TVector<T, C>::Append(const T& aData)
{
const TPckgC<T> data(aData);
return TVectorBuffer<C * sizeof(T)>::Append(data);
}
template <class T, TInt C>
const T& TVector<T, C>::Shift()
{
const TPtrC8 ptr = TVectorBuffer<C * sizeof(T)>::Shift();
return *(reinterpret_cast<const T*>(ptr.Ptr()));
}
template <class T, TInt C>
TInt TVector<T, C>::Size() const
{
return TVectorBuffer<C * sizeof(T)>::Size() / sizeof(T);
}
template <class T, TInt C>
const T& TVector<T, C>::operator[](TInt aIndex) const
{
const TPtrC8 ptr = TVectorBuffer<C * sizeof(T)>::operator[](aIndex);
return *(reinterpret_cast<const T*>(ptr.Ptr()));
}
#endif