8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 19:23:03 +01:00
firebird-mirror/src/common/classes/stack.h

594 lines
11 KiB
C
Raw Normal View History

/*
* PROGRAM: JRD Access Method
* MODULE: stack.h
* DESCRIPTION: Stack.
*
2004-04-19 15:40:30 +02:00
* 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.
*
2004-04-19 15:40:30 +02:00
* 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.
*
2004-04-19 15:40:30 +02:00
* The Original Code was created by Alexander Peshkoff
* for the Firebird Open Source RDBMS project.
*
2004-04-19 15:40:30 +02:00
* Copyright (c) 2004 Alexander Peshkoff <peshkoff@mail.ru>
* and all contributors signed below.
*
2004-04-19 15:40:30 +02:00
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#ifndef CLASSES_STACK_H
#define CLASSES_STACK_H
#include "../common/classes/vector.h"
namespace Firebird {
template <typename Object, size_t Capacity = 16>
class Stack : public AutoStorage
{
private:
Stack<Object, Capacity>(Stack<Object, Capacity>&); // not implemented
class Entry : public Vector<Object, Capacity>
{
private:
typedef Vector<Object, Capacity> 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)
{
2004-05-03 06:25:06 +02:00
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);
2004-05-03 06:25:06 +02:00
return this->data[--this->count];
}
Object getObject(size_t pos) const
{
2004-05-03 06:25:06 +02:00
return this->data[pos];
}
void split(size_t elem, Entry* target)
{
2004-06-13 05:08:13 +02:00
fb_assert(elem > 0 && elem < this->count);
2004-05-06 10:42:56 +02:00
fb_assert(target->count == 0);
2004-06-13 05:08:13 +02:00
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(size_t value) const
{
2007-03-01 14:07:08 +01:00
for (const Entry* stk = this; stk; stk = stk->next)
{
size_t c = static_cast<const inherited*>(stk)->getCount();
if (value < c)
{
return true;
}
value -= c;
}
2007-03-01 14:07:08 +01:00
return false;
}
2004-11-08 03:57:23 +01:00
}; // class Entry
Entry* stk;
Entry* stk_cache;
public:
explicit Stack<Object, Capacity>(MemoryPool& p)
: AutoStorage(p), stk(0), stk_cache(0) { }
Stack<Object, Capacity>() : AutoStorage(), stk(0), stk_cache(0) { }
~Stack()
{
delete stk;
delete stk_cache;
}
void push(Object e)
{
if (!stk && stk_cache)
{
stk = stk_cache;
stk_cache = 0;
}
stk = stk ? stk->push(e, getPool())
: FB_NEW(getPool()) Entry(e, 0);
}
Object pop()
{
fb_assert(stk);
Object tmp = stk->pop();
if (!stk->getCount())
{
fb_assert(!stk_cache);
stk_cache = stk;
stk = stk->next;
stk_cache->next = 0;
// don't delete last empty Entry
if (stk)
{
delete stk_cache;
stk_cache = 0;
}
}
return tmp;
}
2004-04-19 15:40:30 +02:00
private:
// disable use of default operator=
2004-05-09 07:48:33 +02:00
Stack<Object, Capacity>& operator= (const Stack<Object, Capacity>& s);
2004-04-19 15:40:30 +02:00
public:
void takeOwnership (Stack<Object, Capacity>& s)
{
fb_assert(&getPool() == &s.getPool());
delete stk;
stk = s.stk;
s.stk = 0;
if (stk)
{
delete stk_cache;
stk_cache = 0;
}
}
2004-05-09 07:48:33 +02:00
class iterator;
friend class iterator;
class iterator
{
private:
2004-05-06 10:42:56 +02:00
// friend definition here is required to implement
// Merge/Split pair of functions
friend class ::Firebird::Stack<Object, Capacity>;
const Entry* stk;
size_t elem;
public:
2004-05-09 07:48:33 +02:00
explicit iterator(Stack<Object, Capacity>& s)
: stk(s.stk), elem(stk ? stk->getCount() : 0) { }
2004-05-03 06:25:06 +02:00
iterator(const iterator& i)
: stk(i.stk), elem(i.elem) { }
iterator() : stk(0), elem(0) { }
iterator& operator++()
{
fb_assert(stk);
fb_assert(elem);
if (--elem == 0)
{
2004-04-19 15:40:30 +02:00
if ((stk = stk->next))
{
elem = stk->getCount();
}
}
return *this;
}
bool hasMore(size_t value) const
{
if (elem)
{
if (value < elem)
return true;
value -= elem;
}
2004-05-09 07:48:33 +02:00
if (stk && stk->next)
return stk->next->hasMore(value);
2008-04-19 13:11:10 +02:00
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<Object, Capacity>& s) const
{
2008-04-19 13:11:10 +02:00
return (this->stk == s.stk) &&
(s.stk ? this->elem == s.stk->getCount() : true);
}
bool operator!= (const Stack<Object, Capacity>& s) const
{
return !(*this == s);
}
iterator& operator= (iterator& i)
{
stk = i.stk;
elem = i.elem;
return *this;
}
iterator& operator= (Stack<Object, Capacity>& s)
{
stk = s.stk;
elem = stk ? stk->getCount() : 0;
return *this;
}
2004-05-09 07:48:33 +02:00
//friend void class Stack<Object, Capacity>::clear (const iterator& mark);
2004-05-09 07:48:33 +02:00
}; // iterator
class const_iterator;
friend class const_iterator;
class const_iterator
{
2004-05-09 07:48:33 +02:00
private:
friend class ::Firebird::Stack<Object, Capacity>;
const Entry* stk;
size_t elem;
2004-05-09 07:48:33 +02:00
public:
explicit const_iterator(const Stack<Object, Capacity>& 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);
2004-11-29 10:59:19 +01:00
fb_assert(elem);
if (--elem == 0)
{
2004-05-09 07:48:33 +02:00
if ((stk = stk->next))
{
elem = stk->getCount();
}
}
return *this;
}
bool hasMore(size_t value) const
2004-05-09 07:48:33 +02:00
{
if (elem)
{
if (value < elem)
return true;
value -= elem;
2004-05-09 07:48:33 +02:00
}
if (stk && stk->next)
return stk->next->hasMore(value);
2008-04-19 13:11:10 +02:00
return false;
2004-05-09 07:48:33 +02:00
}
bool hasData() const
2004-05-09 07:48:33 +02:00
{
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
2004-05-09 07:48:33 +02:00
{
return (stk == i.stk) && (elem == i.elem);
}
bool operator== (const const_iterator& i) const
2004-05-09 07:48:33 +02:00
{
return (stk == i.stk) && (elem == i.elem);
}
bool operator!= (const iterator& i) const
2004-05-09 07:48:33 +02:00
{
return !(*this == i);
}
bool operator!= (const const_iterator& i) const
2004-05-09 07:48:33 +02:00
{
return !(*this == i);
}
bool operator== (const Stack<Object, Capacity>& s) const
{
return (this->stk == s.stk) &&
2004-05-09 07:48:33 +02:00
(s.stk ? this->elem == s.stk->getCount() : true);
}
bool operator!= (const Stack<Object, Capacity>& s) const
{
return !(*this == s);
}
const_iterator& operator= (const iterator& i)
{
2004-05-09 07:48:33 +02:00
stk = i.stk;
elem = i.elem;
return *this;
}
const_iterator& operator= (const const_iterator& i)
{
2004-05-09 07:48:33 +02:00
stk = i.stk;
elem = i.elem;
return *this;
}
const_iterator& operator= (const Stack<Object, Capacity>& s)
{
2004-05-09 07:48:33 +02:00
stk = s.stk;
elem = stk ? stk->getCount() : 0;
return *this;
}
//friend const const_iterator class Stack<Object, Capacity>::merge(Stack<Object, Capacity>& s);
//void class Stack<Object, Capacity>::split (const const_iterator& mark, Stack<Object, Capacity>& s);
2004-05-09 07:48:33 +02:00
}; // const_iterator
// Merge stack "s" to the end of current one.
2004-05-06 10:42:56 +02:00
// Returns - iterator to Split stacks again.
// This iterator will be used as "bookmark" for Split later.
2004-05-09 07:48:33 +02:00
const const_iterator merge(Stack<Object, Capacity>& s)
{
fb_assert(&getPool() == &s.getPool());
2004-05-09 07:48:33 +02:00
const const_iterator rc(s);
Entry **e = &stk;
while (*e)
{
e = &((*e)->next);
}
*e = s.stk;
s.stk = 0;
if (stk)
{
delete stk_cache;
stk_cache = 0;
}
return rc;
}
2004-05-06 10:42:56 +02:00
// Split stacks at mark
void split (const const_iterator& mark, Stack<Object, Capacity>& s)
{
fb_assert(&getPool() == &s.getPool());
fb_assert(!s.stk);
// if empty stack was merged, there is nothing to do
if (!mark.stk)
{
return;
}
2004-05-06 10:42:56 +02:00
// 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
2004-05-06 10:42:56 +02:00
// 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);
2004-05-06 10:42:56 +02:00
s.stk = *toSplit;
*toSplit = newEntry;
}
if (s.stk)
{
delete s.stk_cache;
s.stk_cache = 0;
}
}
// 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(size_t value) const
{
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
{
2004-05-09 07:48:33 +02:00
return i == *this;
}
bool operator!= (const iterator& i) const
{
2004-05-09 07:48:33 +02:00
return !(i == *this);
}
bool operator== (const const_iterator& i) const
2004-05-09 07:48:33 +02:00
{
return i == *this;
}
bool operator!= (const const_iterator& i) const
2004-05-09 07:48:33 +02:00
{
return !(i == *this);
}
void assign(Stack<Object, Capacity>& v)
{
delete stk;
stk = v.stk ? v.stk->dup(getPool()) : 0;
if (stk)
{
delete stk_cache;
stk_cache = 0;
}
}
void clear()
{
delete stk;
stk = 0;
}
MemoryPool& getPool()
{
return AutoStorage::getPool();
}
2004-11-08 03:57:23 +01:00
}; // class Stack
} // namespace Firebird
#endif // CLASSES_STACK_H
2004-05-09 07:48:33 +02:00