Files
secondo/Algebras/GeneralTree/GTree/GTree_Tree.h

664 lines
15 KiB
C
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
\newpage
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO 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.
SECONDO 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 SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//[_] [\_]
//characters [1] verbatim: [$] [$]
//characters [2] formula: [$] [$]
//characters [3] capital: [\textsc{] [}]
//characters [4] teletype: [\texttt{] [}]
1.1 Headerfile "GTree[_]Tree.h"[4]
January-May 2008, Mirko Dibbert
*/
#ifndef __GTREE_TREE_H__
#define __GTREE_TREE_H__
#include <stack>
#include "GTree_Header.h"
#include "GTree_FileNode.h"
#include "GTree_TreeManager.h"
namespace gtree
{
/*
Class ~Tree~
This is the base class for trees.
*/
template <class THeader = Header, class TTreeManager = TreeManager>
class Tree : public ObjCounter<generalTrees>
{
public:
/*
Default constructor.
*/
Tree(bool temporary = false);
/*
Constructor (reads a previously stored tree from file).
*/
Tree(SmiFileId fileId);
/*
Default copy constructor.
*/
Tree(const Tree& tree);
/*
Destructor.
*/
~Tree();
/*
Deletes the tree file.
*/
inline void deleteFile();
/*
Returns the file id of the "SmiRecordFile"[4], that contains the tree.
*/
inline SmiFileId fileId();
/*
Returns the count of all Internal nodes.
*/
inline unsigned internalCount();
/*
Returns the count of all leafes.
*/
inline unsigned leafCount();
/*
Returns the count of all entries, stored in the tree.
*/
inline unsigned entryCount();
/*
Returns the height of the tree.
*/
inline unsigned height();
/*
Returns the count of open general trees.
*/
inline unsigned openTrees();
/*
Returns the count of open general tree nodes.
*/
inline unsigned openNodes();
/*
Returns the count of open general tree entries.
*/
inline unsigned openEntries();
protected:
/*
Adds a new protoype node.
*/
inline void addNodePrototype(NodeBase* node);
/*
Creates a new node.
*/
inline NodePtr createNode(NodeTypeId type, unsigned level = 0);
/*
Creates a new node on the same level as "treeMngr->curNode()"[4].
*/
inline NodePtr createNeighbourNode(NodeTypeId type);
/*
Creates a new node on root level.
*/
inline NodePtr createRoot(NodeTypeId type);
/*
Creates a new node on root level and inserts the given entries.
*/
inline NodePtr createRoot(
NodeTypeId type, InternalEntry *e1, InternalEntry *e2);
/*
Reads the specified node from file.
*/
inline NodePtr getNode(
SmiRecordId nodeId, unsigned level = 0) const;
/*
Method initPath (initiates a new tree manager path from root)
*/
inline void initPath(SmiRecordId root, int level);
/*
Method initPath (initiates a new tree manager path from header.root)
*/
inline void initPath();
private:
/*
Reads the header from "file"[4].
*/
void readHeader();
/*
Writes the header to "file"[4].
*/
void writeHeader();
protected:
THeader header; // contains the header of the tree file
SmiRecordFile file; // contais the tree file
private:
bool temporary; /* true, if the file should be dropped
when the tree is deleted. */
unsigned headerPageCount; // count of header pages
protected:
NodeManager* nodeMngr; /* reference to the tree file and the
node prototypes */
TTreeManager* treeMngr; // reference to the tree manager
}; // class Tree
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/*
Tree constructor (new file):
*/
template <class THeader, class TTreeManager>
gtree::Tree<THeader, TTreeManager>::Tree(bool _temporary)
: header(), file(true, PAGESIZE), temporary(_temporary),
nodeMngr(new NodeManager(&file)),
treeMngr(new TTreeManager(nodeMngr))
{
#ifdef __GTREE_DEBUG
Msg::showDbgMsg();
#endif
file.Create();
// create header page(s), compute headerPageCount
SmiRecordId headerId;
SmiRecord headerRecord;
headerPageCount = 0;
while (sizeof(THeader) > headerPageCount*PAGESIZE)
{
++headerPageCount;
file.AppendRecord(headerId, headerRecord);
assert(headerId == headerPageCount);
}
}
/*
Tree constructor (reads from file):
*/
template <class THeader, class TTreeManager>
gtree::Tree<THeader, TTreeManager>::Tree(SmiFileId fileId)
: header(), file(true), temporary(false),
nodeMngr(new NodeManager(&file)),
treeMngr(new TTreeManager(nodeMngr))
{
#ifdef __GTREE_DEBUG
Msg::showDbgMsg();
#endif
bool t1 = file.Open(fileId);
assert(t1);
// compute headerPageCount
headerPageCount = 0;
while (sizeof(THeader) > headerPageCount*PAGESIZE)
++headerPageCount;
readHeader();
}
/*
Tree copy constructor:
*/
template <class THeader, class TTreeManager>
gtree::Tree<THeader, TTreeManager>::Tree(
const Tree<THeader, TTreeManager>& tree)
: file(true, PAGESIZE), temporary(tree.temporary),
nodeMngr(new NodeManager(&file)),
treeMngr(new TTreeManager(nodeMngr))
{
#ifdef __GTREE_DEBUG
Msg::showDbgMsg();
#endif
file.Create();
// create header page(s), compute headerPageCount
SmiRecordId headerId;
SmiRecord headerRecord;
headerPageCount = 0;
while (sizeof(THeader) > headerPageCount*PAGESIZE)
{
++headerPageCount;
file.AppendRecord(headerId, headerRecord);
assert(headerId == headerPageCount);
}
// copy header
memcpy((void*)&header, &tree.header, sizeof(THeader));
nodeMngr->copyPrototypes(tree.nodeMngr);
// disable node cache, while copying the tree structure
treeMngr->disableCache();
std::stack<std::pair<NodePtr, NodePtr> > remaining;
std::stack<unsigned> indizes;
unsigned curIndex = 0;
// read tree root and create new root
NodePtr source = tree.getNode(tree.header.root);
NodePtr target = createNode(source->typeId());
header.root = target->getNodeId();
// copy tree structure (copies the tree node by node and updates
// the chield node pointers, needs enough memory to hold
// header.height nodes open at one time)
if (source->isLeaf())
{
for (unsigned i = 0; i < source->entryCount(); ++i)
target->insertCopy(source->baseEntry(i));
}
else
{
NodePtr chield = tree.getNode(source->chield(curIndex));
NodePtr newChield = createNode(chield->typeId());
target->insertCopy(source->baseEntry(curIndex));
static_cast<InternalEntry*>(target->baseEntry(curIndex))->
setChield(newChield);
// push current node to stack, if
// further entries are remaining
if (++curIndex < source->entryCount())
{
remaining.push(std::pair<NodePtr, NodePtr>(source, target));
indizes.push(curIndex);
}
// push chield node to stack
remaining.push(std::pair<NodePtr, NodePtr>(chield, newChield));
indizes.push(0);
}
while (!remaining.empty())
{
source = remaining.top().first;
target = remaining.top().second;
curIndex = indizes.top();
remaining.pop();
indizes.pop();
if (source->isLeaf())
{
for (unsigned i = 0; i < source->entryCount(); ++i)
target->insertCopy(source->baseEntry(i));
}
else
{
NodePtr chield = tree.getNode(source->chield(curIndex));
NodePtr newChield = createNode(chield->typeId());
target->insertCopy(source->baseEntry(curIndex));
static_cast<InternalEntry*>(target->
baseEntry(curIndex))->setChield(newChield);
// push current node to stack, if
// further entries are remaining
if (++curIndex < source->entryCount())
{
remaining.push(
std::pair<NodePtr, NodePtr>(source, target));
indizes.push(curIndex);
}
// push chield node to stack
remaining.push(
std::pair<NodePtr, NodePtr>(chield, newChield));
indizes.push(0);
}
}
treeMngr->enableCache();
} // tree copy constructor
/*
Tree destructor:
*/
template <class THeader, class TTreeManager>
gtree::Tree<THeader, TTreeManager>::~Tree()
{
delete treeMngr;
delete nodeMngr;
if (temporary)
deleteFile();
if (file.IsOpen())
{
writeHeader();
file.Close();
}
#ifdef __GTREE_DEBUG
/* print count of open objects only for the last remaining tree
(otherwhise the warning message would appear allways, if more
than one tree exists, e.g. when calling the copy constructor)*/
if (openTrees() == 1)
{
if (openNodes())
Msg::memoryLeak_Warning(openNodes(), "nodes");
if (openEntries())
Msg::memoryLeak_Warning(openEntries(), "entries");
}
#endif
} // Tree destructor
/*
Method ~readHeader~:
*/
template <class THeader, class TTreeManager>
void gtree::Tree<THeader, TTreeManager>::readHeader()
{
// create buffer
char buffer[headerPageCount*PAGESIZE];
memset(buffer, 0, headerPageCount*PAGESIZE);
// read header-data from file
SmiRecord record;
SmiRecordId curPage = 1;
for (unsigned i = 0; i < headerPageCount; ++i)
{
file.SelectRecord(curPage, record, SmiFile::ReadOnly);
record.Read(buffer + (i*PAGESIZE), PAGESIZE, 0);
++curPage;
}
// copy buffer to header
memcpy((void*)&header, buffer, sizeof(THeader));
} // Tree::readHeader
/*
Method ~writeHeader~:
*/
template <class THeader, class TTreeManager>
void gtree::Tree<THeader, TTreeManager>::writeHeader()
{
// create buffer and copy header to buffer
char buffer[headerPageCount*PAGESIZE];
memset(buffer, 0, headerPageCount*PAGESIZE);
memcpy(buffer, &header, sizeof(THeader));
// write header-data to file
SmiRecord record;
SmiRecordId curPage = 1;
for (unsigned i = 0; i < headerPageCount; ++i)
{
file.SelectRecord(curPage, record, SmiFile::Update);
record.Write(buffer + (i*PAGESIZE), PAGESIZE, 0);
++curPage;
}
} // Tree::writeHeader
/*
Method ~deleteFile~:
*/
template <class THeader, class TTreeManager>
void gtree::Tree<THeader, TTreeManager>::deleteFile()
{
if (file.IsOpen())
file.Close();
file.Drop();
}
/*
Method ~fileId~:
*/
template <class THeader, class TTreeManager>
SmiFileId gtree::Tree<THeader, TTreeManager>::fileId()
{ return file.GetFileId(); }
/*
Method ~internalCount~:
*/
template <class THeader, class TTreeManager>
unsigned gtree::Tree<THeader, TTreeManager>::internalCount()
{ return header.internalCount; }
/*
Method ~leafCount~:
*/
template <class THeader, class TTreeManager>
unsigned gtree::Tree<THeader, TTreeManager>::leafCount()
{ return header.leafCount; }
/*
Method ~entryCount~:
*/
template <class THeader, class TTreeManager>
unsigned gtree::Tree<THeader, TTreeManager>::entryCount()
{ return header.entryCount; }
/*
Method ~height~:
*/
template <class THeader, class TTreeManager>
unsigned gtree::Tree<THeader, TTreeManager>::height()
{ return header.height; }
/*
Method ~openTrees~:
*/
template <class THeader, class TTreeManager>
unsigned gtree::Tree<THeader, TTreeManager>::openTrees()
{ return ObjCounter<generalTrees>::openObjects(); }
/*
Method ~openNodes~:
*/
template <class THeader, class TTreeManager>
unsigned gtree::Tree<THeader, TTreeManager>::openNodes()
{ return ObjCounter<generalTreeNodes>::openObjects(); }
/*
Method ~openEntries~:
*/
template <class THeader, class TTreeManager>
unsigned gtree::Tree<THeader, TTreeManager>::openEntries()
{ return ObjCounter<generalTreeEntries>::openObjects(); }
/*
Method ~addNodePrototype~:
*/
template <class THeader, class TTreeManager>
void gtree::Tree<THeader, TTreeManager>::addNodePrototype(
NodeBase* node)
{ nodeMngr->addPrototype(node); }
/*
Method ~createNode~:
*/
template <class THeader, class TTreeManager>
NodePtr gtree::Tree<THeader, TTreeManager>::
createNode(NodeTypeId type, unsigned level /* = 0 */)
{
if (level == 0)
++header.leafCount;
else
++header.internalCount;
return treeMngr->createNode(type, level);
}
/*
Method ~createNeighbourNode~:
*/
template <class THeader, class TTreeManager>
NodePtr gtree::Tree<THeader, TTreeManager>::
createNeighbourNode(NodeTypeId type)
{
if (treeMngr->curNode()->isLeaf())
++header.leafCount;
else
++header.internalCount;
return treeMngr->createNeighbourNode(type);
}
/*
Method ~createRoot~:
*/
template <class THeader, class TTreeManager>
NodePtr gtree::Tree<THeader, TTreeManager>::createRoot(
NodeTypeId type)
{
NodePtr root(treeMngr->createNode(type, header.height));
header.root = root->getNodeId();
if (header.height == 0)
{
++header.leafCount;
}
else
{
++header.internalCount;
}
++header.height;
return root;
}
/*
Method ~createRoot~:
*/
template <class THeader, class TTreeManager>
NodePtr gtree::Tree<THeader, TTreeManager>::createRoot(
NodeTypeId type, InternalEntry *e1, InternalEntry *e2)
{
NodePtr root(treeMngr->createNode(type, header.height));
treeMngr->insert(root, e1);
treeMngr->insert(root, e2);
header.root = root->getNodeId();
++header.height;
++header.internalCount;
return root;
}
/*
Method ~getNode~:
*/
template <class THeader, class TTreeManager>
NodePtr gtree::Tree<THeader, TTreeManager>:: getNode(
SmiRecordId nodeId, unsigned level) const
{ return treeMngr->getNode(nodeId, level); }
/*
Method initPath:
*/
template <class THeader, class TTreeManager>
void gtree::Tree<THeader, TTreeManager>::initPath(
SmiRecordId root, int level)
{
treeMngr->initPath(root, level);
}
/*
Method initPath:
*/
template <class THeader, class TTreeManager>
void gtree::Tree<THeader, TTreeManager>::initPath()
{
treeMngr->initPath(header.root, header.height-1);
}
} // namespace gtree
#endif // #define __GTREE_TREE_H__