/* vectorbuffer.cpp yet another circle buffer Markus Mertama */ #ifndef __VECTORBUFFER_H__ #define __VECTORBUFFER_H__ #include #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 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 TVectorBuffer::TVectorBuffer() : iSize(0) { Mem::FillZ(iBuffer, C); iTop = TNode::Empty(iBuffer); //these points to buffer iBottom = TNode::Empty(iBuffer); } template TInt TVectorBuffer::Unreserved() const { __ASSERT_DEBUG(iBottom < iBottom->Succ(), VECPANIC(KErrCorrupt)); const TInt bytesbetween = reinterpret_cast(iBottom->Succ()) - reinterpret_cast(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 TVectorBuffer::GetRoom(TInt aSize) const { const TInt bytesnew = sizeof(TNode) + aSize; const TInt room = Unreserved() - bytesnew; return room; } template TInt TVectorBuffer::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 TVectorBuffer::AppendOverwrite(const TDesC8& aData) //ei ole ok! { while(Append(aData) == KErrOverflow) { if(iTop->Succ() == NULL) { return KErrUnderflow; } //Shift(); //data is lost } return KErrNone; } */ template TPtrC8 TVectorBuffer::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 TVectorBuffer::Size() const { return iSize; } template TPtrC8 TVectorBuffer::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 NONSHARABLE_CLASS(TVector) : public TVectorBuffer { public: TVector(); TInt Append(const T& aData); const T& Shift(); TInt Size() const; const T& operator[](TInt aIndex) const; }; template TVector::TVector() : TVectorBuffer() { } template TInt TVector::Append(const T& aData) { const TPckgC data(aData); return TVectorBuffer::Append(data); } template const T& TVector::Shift() { const TPtrC8 ptr = TVectorBuffer::Shift(); return *(reinterpret_cast(ptr.Ptr())); } template TInt TVector::Size() const { return TVectorBuffer::Size() / sizeof(T); } template const T& TVector::operator[](TInt aIndex) const { const TPtrC8 ptr = TVectorBuffer::operator[](aIndex); return *(reinterpret_cast(ptr.Ptr())); } #endif