📄 databuffer.hpp
字号:
/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#ifndef DATA_BUFFER_HPP#define DATA_BUFFER_HPP#include "ArrayPool.hpp"/** * @class DataBuffer * @brief Buffer of data words * * @note The buffer is divided into segments (of size sz) */template <Uint32 sz>class DataBuffer {public: struct Segment { Uint32 nextPool; Uint32 data[sz]; NdbOut& print(NdbOut& out){ out << "[DataBuffer<" << sz << ">::Segment this=" << this << dec << " nextPool= " << nextPool << " ]"; return out; } };public: typedef ArrayPool<Segment> DataBufferPool; /** * Head/anchor for data buffer */ struct Head { Head() ; Uint32 used; // Words used Uint32 firstItem; // First segment (or RNIL) Uint32 lastItem; // Last segment (or RNIL) /** * Get size of databuffer, in words */ Uint32 getSize() const { return used;} /** * Get segment size in words (template argument) */ static Uint32 getSegmentSize() { return sz;} }; /** Constructor */ DataBuffer(DataBufferPool &); /** Seize <b>n</b> words, Release */ bool seize(Uint32 n); void release(); /** * Get size of databuffer, in words */ Uint32 getSize() const; /** * Check if buffer is empty */ bool isEmpty() const; /** * Get segment size in words (template argument) */ static Uint32 getSegmentSize(); void print(FILE*) const; /* ----------------------------------------------------------------------- */ struct DataBufferIterator { Ptr<Segment> curr; // Ptr to current segment Uint32* data; // Pointer to current data (word) Uint32 ind; // Word index within a segment Uint32 pos; // Absolute word position within DataBuffer void print(FILE* out) { fprintf(out, "[DataBufferIterator curr.i=%d, data=%p, ind=%d, pos=%d]\n", curr.i, (void*) data, ind, pos); }; inline bool isNull() const { return curr.isNull();} inline void setNull() { curr.setNull(); data = 0; ind = pos = RNIL;} }; struct ConstDataBufferIterator { ConstPtr<Segment> curr; const Uint32 * data; Uint32 ind; Uint32 pos; inline bool isNull() const { return curr.isNull();} inline void setNull() { curr.setNull(); data = 0; ind = pos = RNIL;} }; /** * Iterator * @parameter hops Number of words to jump forward * @note DataBuffer::next returns false if applied to last word. */ bool first(DataBufferIterator &); bool next(DataBufferIterator &); bool next(DataBufferIterator &, Uint32 hops); bool nextPool(DataBufferIterator &); /** * Set iterator to position */ bool position(DataBufferIterator& it, Uint32 pos); /** Iterator */ bool first(ConstDataBufferIterator &) const; bool next(ConstDataBufferIterator &) const; bool next(ConstDataBufferIterator &, Uint32 hops) const; bool nextPool(ConstDataBufferIterator &) const; /** * Returns true if it is possible to store <em>len</em> * no of words at position given in iterator. */ bool importable(const DataBufferIterator, Uint32 len); /** * Stores <em>len</em> no of words starting at location <em>src</em> in * databuffer at position given in iterator. * * @return true if success, false otherwise. * @note Iterator is not advanced. */ bool import(const DataBufferIterator &, const Uint32* src, Uint32 len); /** * Increases size with appends <em>len</em> words * @return true if success, false otherwise. */ bool append(const Uint32* src, Uint32 len);protected: Head head; DataBufferPool & thePool;private: /** * This is NOT a public method, since the intension is that the import * method using iterators will be more effective in the future */ bool import(Uint32 pos, const Uint32* src, Uint32 len);};template<Uint32 sz>class LocalDataBuffer : public DataBuffer<sz> {public: LocalDataBuffer(typename DataBuffer<sz>::DataBufferPool & thePool, typename DataBuffer<sz>::Head & _src) : DataBuffer<sz>(thePool), src(_src) { this->head = src; } ~LocalDataBuffer(){ src = this->head; }private: typename DataBuffer<sz>::Head & src;};template<Uint32 sz>inlineDataBuffer<sz>::Head::Head(){ used = 0; firstItem = RNIL; lastItem = RNIL;}template<Uint32 sz>inlinebool DataBuffer<sz>::importable(const DataBufferIterator it, Uint32 len){ return (it.pos + len < head.used);}template<Uint32 sz>inlinebool DataBuffer<sz>::position(DataBufferIterator& it, Uint32 p){ // TODO: The current implementation is not the most effective one. // A more effective implementation would start at the current // position of the iterator. if(!first(it)){ return false; } return next(it, p);} template<Uint32 sz>inlinebool DataBuffer<sz>::import(const DataBufferIterator & it, const Uint32* src, Uint32 len){#if 0 DataBufferIterator it; position(it, _it.pos); for(; len > 0; len--){ Uint32 s = * src; * it.data = s; next(it); src++; } return true;#else Uint32 ind = (it.pos % sz); Uint32 left = sz - ind; Segment * p = it.curr.p; while(len > left){ memcpy(&p->data[ind], src, 4 * left); src += left; len -= left; ind = 0; left = sz; p = thePool.getPtr(p->nextPool); } memcpy(&p->data[ind], src, 4 * len); return true;#endif}template<Uint32 sz>inlinebool DataBuffer<sz>::append(const Uint32* src, Uint32 len){ if(len == 0) return true; Uint32 pos = head.used; if(!seize(len)){ return false; } DataBufferIterator it; if(position(it, pos) && import(it, src, len)){ return true; } abort(); return false;}template<Uint32 sz>inlinevoid DataBuffer<sz>::print(FILE* out) const { fprintf(out, "[DataBuffer used=%d words, segmentsize=%d words", head.used, sz); if (head.firstItem == RNIL) { fprintf(out, ": No segments seized.]\n"); return; } else { fprintf(out, "\n"); } Ptr<Segment> ptr; ptr.i = head.firstItem; Uint32 acc = 0; for(; ptr.i != RNIL; ){ thePool.getPtr(ptr); const Uint32 * rest = ptr.p->data; for(Uint32 i = 0; i<sz; i++){ fprintf(out, " H'%.8x", rest[i]); if(acc++ == 6){ acc = 0; fprintf(out, "\n"); } } ptr.i = ptr.p->nextPool; } fprintf(out, " ]\n");}template<Uint32 sz>inlineDataBuffer<sz>::DataBuffer(DataBufferPool & p) : thePool(p){}template<Uint32 sz>inlineboolDataBuffer<sz>::seize(Uint32 n){ Uint32 rest; // Free space in last segment (currently) Segment* prevPtr; if(head.firstItem == RNIL){ rest = 0; prevPtr = (Segment*)&head.firstItem; } else { rest = (sz - (head.used % sz)) % sz; prevPtr = thePool.getPtr(head.lastItem); } /** * Check for space */ Uint32 free = thePool.getNoOfFree() * sz + rest; if(n > free){ release(); return false; } Uint32 used = head.used + n; Ptr<Segment> currPtr; currPtr.i = head.lastItem; while(n >= sz){ if(0) ndbout_c("n(%d) %c sz(%d)", n, (n>sz?'>':(n<sz?'<':'=')), sz); thePool.seize(currPtr); assert(currPtr.i != RNIL); prevPtr->nextPool = currPtr.i; prevPtr = currPtr.p; prevPtr->nextPool = RNIL; n -= sz; } if(0){ Uint32 pos = rest + n; ndbout_c("rest(%d), n(%d) pos=%d %c sz(%d)", rest, n, pos, (pos>sz?'>':(pos<sz?'<':'=')), sz); } if(n > rest){ thePool.seize(currPtr); assert(currPtr.i != RNIL); prevPtr->nextPool = currPtr.i; currPtr.p->nextPool = RNIL; } head.used = used; head.lastItem = currPtr.i; #if 0 { ndbout_c("Before validate - %d", head.used); if(head.used == 0){ assert(head.firstItem == RNIL); assert(head.lastItem == RNIL); } else { Ptr<Segment> tmp; tmp.i = head.firstItem; for(Uint32 i = head.used; i > sz; i -= sz){ ndbout << tmp.i << " "; tmp.p = thePool.getPtr(tmp.i); tmp.i = tmp.p->nextPool; } ndbout_c("%d", tmp.i); assert(head.lastItem == tmp.i); } ndbout_c("After validate"); }#endif return true;}template<Uint32 sz>inlinevoidDataBuffer<sz>::release(){ Uint32 used = head.used + sz - 1; if(head.firstItem != RNIL){ thePool.releaseList(used / sz, head.firstItem, head.lastItem); head.used = 0; head.firstItem = RNIL; head.lastItem = RNIL; }}template<Uint32 sz>inlineUint32DataBuffer<sz>::getSegmentSize(){ return sz;}template<Uint32 sz>inlineboolDataBuffer<sz>::first(DataBufferIterator & it){ return first((ConstDataBufferIterator&)it);}template<Uint32 sz>inlineboolDataBuffer<sz>::next(DataBufferIterator & it){ return next((ConstDataBufferIterator&)it);}template<Uint32 sz>inlineboolDataBuffer<sz>::next(DataBufferIterator & it, Uint32 hops){ return next((ConstDataBufferIterator&)it, hops);}template<Uint32 sz>inlineboolDataBuffer<sz>::first(ConstDataBufferIterator & it) const { it.curr.i = head.firstItem; if(it.curr.i == RNIL){ it.setNull(); return false; } thePool.getPtr(it.curr); it.data = &it.curr.p->data[0]; it.ind = 0; it.pos = 0; return true;}template<Uint32 sz>inlineboolDataBuffer<sz>::next(ConstDataBufferIterator & it) const { it.ind ++; it.data ++; it.pos ++; if(it.ind < sz && it.pos < head.used){ return true; } if(it.pos < head.used){ it.curr.i = it.curr.p->nextPool;#ifdef ARRAY_GUARD if(it.curr.i == RNIL){ /** * This is actually "internal error" * pos can't be less than head.used and at the same time we can't * find next segment * * Note this must not "really" be checked since thePool.getPtr will * abort when trying to get RNIL. That's why the check is within * ARRAY_GUARD */ ErrorReporter::handleAssert("DataBuffer<sz>::next", __FILE__, __LINE__); }#endif thePool.getPtr(it.curr); it.data = &it.curr.p->data[0]; it.ind = 0; return true; } it.setNull(); return false;}template<Uint32 sz>inlineboolDataBuffer<sz>::next(ConstDataBufferIterator & it, Uint32 hops) const {#if 0 for (Uint32 i=0; i<hops; i++) { if (!this->next(it)) return false; } return true;#else if(it.pos + hops < head.used){ while(hops >= sz){ it.curr.i = it.curr.p->nextPool; thePool.getPtr(it.curr); hops -= sz; it.pos += sz; } it.ind += hops; it.pos += hops; if(it.ind < sz){ it.data = &it.curr.p->data[it.ind]; return true; } it.curr.i = it.curr.p->nextPool; thePool.getPtr(it.curr); it.ind -= sz; it.data = &it.curr.p->data[it.ind]; return true; } it.setNull(); return false;#endif}template<Uint32 sz>inlineUint32DataBuffer<sz>::getSize() const { return head.used;}template<Uint32 sz>inlineboolDataBuffer<sz>::isEmpty() const { return (head.used == 0);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -