/* * PROGRAM: JRD Access Method * MODULE: stack.h * DESCRIPTION: Stack. * * The contents of this file are subject to the Initial * Developer's Public License Version 1.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. * * Software distributed under the License is distributed AS IS, * WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the License for the specific language governing rights * and limitations under the License. * * The Original Code was created by Alexander Peshkoff * for the Firebird Open Source RDBMS project. * * Copyright (c) 2004 Alexander Peshkoff * and all contributors signed below. * * All Rights Reserved. * Contributor(s): ______________________________________. * */ #ifndef CLASSES_STACK_H #define CLASSES_STACK_H #include "../common/classes/vector.h" namespace Firebird { template class Stack : public AutoStorage { private: Stack(Stack&); // not implemented class Entry : public Vector { private: typedef Vector inherited; public: Entry* next; Entry(Object e, Entry* stk) : inherited(), next(stk) { add(e); } Entry(Entry* stk) : inherited(), next(stk) { } ~Entry() { delete next; } Entry* push(Object e, MemoryPool& p) { if (inherited::getCount() < this->getCapacity()) { add(e); return this; } Entry* newEntry = FB_NEW(p) Entry(e, this); return newEntry; } Object pop() { fb_assert(inherited::getCount() > 0); return this->data[--this->count]; } Object getObject(size_t pos) const { return this->data[pos]; } void split(size_t elem, Entry* target) { fb_assert(elem > 0 && elem < this->count); fb_assert(target->count == 0); target->count = this->count - elem; memcpy(target->data, &this->data[elem], target->count * sizeof(Object)); this->count = elem; } Entry* dup(MemoryPool& p) { Entry* rc = FB_NEW(p) Entry(next ? next->dup(p) : 0); rc->join(*next); return rc; } bool hasMore(int value) const { fb_assert(value >= 0); if ((size_t) value <= inherited::getCount()) return true; for(const Entry* stk = this; stk && value > 0; stk = stk->next) value -= stk->getCount(); return (value <= 0); } }; Entry* stk; public: explicit Stack(MemoryPool& p) : AutoStorage(p), stk(0) { } Stack() : AutoStorage(), stk(0) { } ~Stack() { delete stk; } void push(Object e) { stk = stk ? stk->push(e, getPool()) : FB_NEW(getPool()) Entry(e, 0); } Object pop() { fb_assert(stk); Object tmp = stk->pop(); if (!stk->getCount()) { Entry *oldEntry = stk; stk = stk->next; oldEntry->next = 0; delete oldEntry; } return tmp; } private: // disable use of default operator= Stack& operator= (const Stack& s); public: void takeOwnership (Stack& s) { fb_assert(&getPool() == &s.getPool()); delete stk; stk = s.stk; s.stk = 0; } class iterator; friend class iterator; class iterator { private: // friend definition here is required to implement // Merge/Split pair of functions friend class ::Firebird::Stack; const Entry* stk; size_t elem; public: explicit iterator(Stack& s) : stk(s.stk), elem(stk ? stk->getCount() : 0) { } iterator(const iterator& i) : stk(i.stk), elem(i.elem) { } iterator() : stk(0), elem(0) { } iterator& operator++() { fb_assert(stk); if (--elem <= 0) { if ((stk = stk->next)) { elem = stk->getCount(); } } return *this; } bool hasMore(int value) const { fb_assert(value >= 0); if (elem) { if ((size_t) value < elem) return true; value -= elem - 1; } if (stk && stk->next) return stk->next->hasMore(value); else return false; } bool hasData() const { return stk; } bool isEmpty() const { return !stk; } Object object() const { fb_assert(stk); return stk->getObject(elem - 1); } bool operator== (const iterator &i) const { return (stk == i.stk) && (elem == i.elem); } bool operator!= (const iterator &i) const { return !(*this == i); } bool operator== (const Stack& s) const { return (this->stk == s.stk) && (s.stk ? this->elem == s.stk->getCount() : true); } bool operator!= (const Stack& s) const { return !(*this == s); } iterator& operator= (iterator& i) { stk = i.stk; elem = i.elem; return *this; } iterator& operator= (Stack& s) { stk = s.stk; elem = stk ? stk->getCount() : 0; return *this; } //friend void class Stack::clear (const iterator &mark); }; // iterator class const_iterator; friend class const_iterator; class const_iterator { private: friend class ::Firebird::Stack; const Entry* stk; size_t elem; public: explicit const_iterator(const Stack& s) : stk(s.stk), elem(stk ? stk->getCount() : 0) { } const_iterator(const iterator& i) : stk(i.stk), elem(i.elem) { } const_iterator(const const_iterator& i) : stk(i.stk), elem(i.elem) { } const_iterator() : stk(0), elem(0) { } const_iterator& operator++() { fb_assert(stk); if (--elem <= 0) { if ((stk = stk->next)) { elem = stk->getCount(); } } return *this; } bool hasMore(int value) const { fb_assert(value >= 0); if (elem) { if (value < elem) return true; value -= elem - 1; } if (stk && stk->next) return stk->next->hasMore(value); else return false; } bool hasData() const { return stk; } bool isEmpty() const { return !stk; } const Object object() const { fb_assert(stk); return stk->getObject(elem - 1); } bool operator== (const iterator &i) const { return (stk == i.stk) && (elem == i.elem); } bool operator== (const const_iterator &i) const { return (stk == i.stk) && (elem == i.elem); } bool operator!= (const iterator &i) const { return !(*this == i); } bool operator!= (const const_iterator &i) const { return !(*this == i); } bool operator== (const Stack& s) const { return (this->stk == s.stk) && (s.stk ? this->elem == s.stk->getCount() : true); } bool operator!= (const Stack& s) const { return !(*this == s); } const_iterator& operator= (const iterator& i) { stk = i.stk; elem = i.elem; return *this; } const_iterator& operator= (const const_iterator& i) { stk = i.stk; elem = i.elem; return *this; } const_iterator& operator= (const Stack& s) { stk = s.stk; elem = stk ? stk->getCount() : 0; return *this; } //friend const const_iterator class Stack::merge(Stack& s); //void class Stack::split (const const_iterator &mark, Stack& s); }; // const_iterator // Merge stack "s" to the end of current one. // Returns - iterator to Split stacks again. // This iterator will be used as "bookmark" for Split later. const const_iterator merge(Stack& s) { fb_assert(&getPool() == &s.getPool()); const const_iterator rc(s); Entry **e = &stk; while (*e) { e = &((*e)->next); } *e = s.stk; s.stk = 0; return rc; } // Split stacks at mark void split (const const_iterator &mark, Stack& s) { fb_assert(&getPool() == &s.getPool()); fb_assert(!s.stk); // if empty stack was merged, there is nothing to do if (!mark.stk) { return; } // find entry to Split Entry **toSplit = &stk; while (*toSplit != mark.stk) { fb_assert(*toSplit); toSplit = &((*toSplit)->next); } // Determine whether some new elements were added // to this stack. Depended on this we must // Split on entries boundary or cut one entry to halfs. fb_assert((*toSplit)->getCount() >= mark.elem); if ((*toSplit)->getCount() == mark.elem) { s.stk = *toSplit; *toSplit = 0; } else { Entry* newEntry = FB_NEW(getPool()) Entry(0); (*toSplit)->split(mark.elem, newEntry); s.stk = *toSplit; *toSplit = newEntry; } } // clear stacks until mark void clear (const iterator &mark) { // for empty mark just clear all stack if (!mark.stk) { clear(); return; } // find entry to clear while (stk != mark.stk) { if (!stk) { return; } Entry *tmp = stk->next; stk->next = 0; delete stk; stk = tmp; } // remove extra elements from Entry fb_assert(stk->getCount() >= mark.elem); if (mark.elem == 0) { Entry *tmp = stk->next; stk->next = 0; delete stk; stk = tmp; } else { stk->shrink(mark.elem); } } size_t getCount() const { size_t rc = 0; for (Entry* entry = stk; entry; entry = entry->next) { rc += entry->getCount(); } return rc; } bool hasMore(int value) const { fb_assert(value >= 0); return (stk && stk->hasMore(value)); } // returns topmost element on the stack Object object() const { fb_assert(stk); return stk->getObject(stk->getCount() - 1); } // returns true if stack is not empty bool hasData() const { return stk; } // returns true if stack is empty bool isEmpty() const { return !stk; } bool operator== (const iterator &i) const { return i == *this; } bool operator!= (const iterator &i) const { return !(i == *this); } bool operator== (const const_iterator &i) const { return i == *this; } bool operator!= (const const_iterator &i) const { return !(i == *this); } void assign(Stack& v) { delete stk; stk = v.stk ? v.stk->dup(getPool()) : 0; } void clear() { delete stk; stk = 0; } MemoryPool& getPool() { return AutoStorage::getPool(); } }; } // namespace Firebird #endif // CLASSES_STACK_H