Files
secondo/Tools/ListsAndTables/CTable.h
2026-01-23 17:03:45 +08:00

860 lines
17 KiB
C++

/*
----
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
----
//paragraph [10] title: [{\Large \bf ] [}]
//paragraph [21] table1column: [\begin{quote}\begin{tabular}{l}] [\end{tabular}\end{quote}]
//paragraph [22] table2columns: [\begin{quote}\begin{tabular}{ll}] [\end{tabular}\end{quote}]
//paragraph [23] table3columns: [\begin{quote}\begin{tabular}{lll}] [\end{tabular}\end{quote}]
//paragraph [24] table4columns: [\begin{quote}\begin{tabular}{llll}] [\end{tabular}\end{quote}]
//[--------] [\hline]
//characters [1] verbatim: [$] [$]
//characters [2] formula: [$] [$]
//characters [3] capital: [\textsc{] [}]
//characters [4] teletype: [\texttt{] [}]
//[ae] [\"a]
//[oe] [\"o]
//[ue] [\"u]
//[ss] [{\ss}]
//[<=] [\leq]
//[#] [\neq]
//[tilde] [\verb|~|]
//[star] [\verb|*|]
//[cppref] [\verb|[]|]
1 Header File: Compact Table
February 1994 Gerd Westerman
November 1996 RHG, Revision.
January 2002 Ulrich Telle, Port to C++.
November 2002 M. Spiekermann, method reportVectorSizes added.
Jan - May 2003 M. Spiekermann, ~CTable~ alternative implemented on top of
the ~PArray~ template.
July 2004 M. Spiekermann. Some simple functions implemented inside the class
declaration. There is also an alternative header file called MemCTable.h which
includes this file and renames the class into MemCTable. This is useful to have
a class which is based on a implementation using class vector ignoring the
macro CTABLE\_PERSITENT. This is useful because only the code in nested list
module has been revised to guarantee that it runs with both ~CTable~
implementations.
1.1 Concept
A compact table is a sequence of elements of equal size indexed by natural
numbers starting from 1. Whereas a list offers only sequential access, a
table offers random access to all its elements.
Figure 1: Concept of a compact table [CompactTable.eps]
A compact table also provides the storage for its elements.
It can be used in several ways:
The first is like an array in programming languages by selecting a component
by index or assigning a value to a component. The second way of using it is as
a container for a set of elements retrievable by index. In that case it doesn't
matter under which index an element is kept. For the latter purpose, the table
maintains a record of which of its slots are filled or empty, respectively, and
is also able to extend its size automatically when all slots are filled. The
third way is writing and reading it sequentially, like a list.
[24] Creation/Removal & Size info & Element access & Managing a set \\
[--------]
CTable & Size & [cppref] const & IsValid \\
[tilde]CTable & NoEntries & [cppref] & EmptySlot \\
& & & Add \\
& & & Remove \\
[23] Iterator & Scanning & Persistence \\
[--------]
Iterator & ++ & Load (not implemented yet) \\
Begin & EndOfScan & Save (not implemented yet) \\
End & GetIndex & \\
operator== & operator[star] & \\
operator!= & operator= & \\
The CTable has two implementations. The first is on top of the standard vector
template and the second is build up with the PArray template class, an array
implementation which uses a variable length SmiRecord to store the elements.
You can request the persistence version with use of the preprocessor directive
\#define CTABLE\_PERSISTENT before \#include "CTable.h". But there are some
inevitable limitations:
* operator[star] can be used only in an rvalue.
* [cppref] can also be used only in an rvalue.
For example if 'it' is an iterator for an CTable<int> object, then [star]it = 5
will cause a compiler error message. The same holds for [cppref] at the left
side of an assignment. You have to substitute those expressions by code
fragments like this:
---- int elem = Expression; myTable.Put(pos, elem);
----
In order to write code that is independent from the CTABLE\_PERSISTENT switch
don't use the [star] and [cppref] operations as lvalue.
The in-memory version will have some dummy functions, because some methods only
make sense for the persistence version. The Code is organized in three files.
This file contains all declarations and the implementation of code which is
independent from the vector or PArray classes. The file CTable.cpp is included
for the vector based implementation and the file PCTable.cpp contains code for
the PArray version.
Open Problems: The ~put~ and ~add~ methods should use a const T parameter, but
this is only possible if we make a copy of the paramater inside the functions
since other interfaces used below this are not suitable for passing a const
parameter.
1.2 Imports, Types
*/
#ifndef CTABLE_H
#define CTABLE_H
#include <assert.h>
#include <sstream>
#include <iostream>
#include <string>
#include <typeinfo>
#include <stdint.h>
#ifdef THREAD_SAFE
#include <boost/thread.hpp>
#endif
#ifdef CTABLE_PERSISTENT
#include "PagedArray.h"
#else
#include <vector>
typedef unsigned long Cardinal;
#endif
/**************************************************************************
1.3 Class "CTable"[1]
*/
template <typename T>
class CTable
{
public:
/**************************************************************************
3.1.1 Construction and destruction
*/
CTable( Cardinal const count );
~CTable();
std::string MemoryModel();
/*
~CTable~ Creates a table with ~count~ slots. In the persistent
version count indicates the number of record buffers. Hence it should
be smaller e.g. count/ (pagesize/sizeof(T)).
MemoryModel returns the values "PERSISTENT" or "NON-PERSISTENT".
*/
/************************************
3.2.1 Size Info
*/
Cardinal Size();
void TotalMemory(Cardinal &mem, Cardinal &pageChanges, Cardinal &slotAccess );
/*
Size() returns the size (number of slots) of the table. The method
totalMemory() calculates the allocated memory via pointer arithmetic.
The number of page changes and slot accesses are interesting when using
the persistent implementation.
*/
Cardinal NoEntries();
/*
Returns the highest valid index (the largest index of a filled slot).
In particular useful when the table is filled sequentially.
*/
/************************************
3.3.1 Accessing Elements
The following ~Select~ operations get the address of a slot for
reading, or writing its contents. After writing into a slot it is
considered valid and changed. If used as a lvalue the slot is marked
valid.
*/
void Get( Cardinal const n, T& elem );
void Put( Cardinal const n, T& elem );
#ifdef CTABLE_PERSISTENT
const T& operator[]( Cardinal n );
#else
const T& operator[]( Cardinal n ) const;
T& operator[]( Cardinal n );
#endif
/*
``Select for reading''. Returns the address of the slot with index ~index~.
*Precondition*: "1 [<=] index [<=] Size(Table)"[1] and slot ~index~ must be
valid.
``Select for writing''. Returns the address of the slot with index ~index~.
Makes slot ~index~ valid and marks it as changed. In the persistent
implementation only the Put method can be used to write a value into a slot.
Warning: If you want to write code that can be used with both implementations
you must always use the following sequence of operations, to ~write~ values
into a slot:
index = EmptySlot()
Get(index, Record)
change Record values
Put(index, Record)
Be careful: references to Records are invalid after the next call of the
Get method.
*Precondition*: "1 [<=] Index [<=] Size (Table)".
*/
/************************************
3.4.1 Managing a Set
*/
bool IsValid( Cardinal const index );
/*
Determines whether slot ~index~ is valid.
*Precondition*: "1 [<=] index [<=] Size(CTable)".
*/
const Cardinal EmptySlot();
/*
Returns the index of an empty slot. If necessary (because the table is
full) the table is made larger before returning the index.
*NOTE*: An initial sequence of ~EmptySlot~ operations (before any ~Remove~
operations) returns always the empty slot with the lowest index. Hence,
one can fill a table sequentially by a sequence of operations of the form
---- i := Empty Slot (t); t[i] := p; ... <fill entry>
----
After ~Remove~ operations this is not guaranteed any more (in contrast to
earlier definitions of compact tables!).
*/
const Cardinal Add( T& element );
/*
Copies the element referenced by ~element~ into some empty slot of ~Table~,
which may be automatically extended for this purpose, and returns the index
where the element was put.
Provided for convenience; is the same as:
---- i := EmptySlot (Table); Table\[i\] := element; RETURN i;
----
An initial sequence of ~Add~ operations (before any ~Remove~ operations
and without ~Remove~ or ~EmptySlot~ in between) is guaranteed to fill the
table sequentially and hence maintains the order of insertions.
*/
void Remove( Cardinal const index );
/*
Makes slot ~Index~ empty (no more valid).
*Precondition*: "1 [<=] Index [<=] Size (Table)".
*/
/***************
1.1 Scan Operations
Iterators allow to scan through this ~CTable~ by enumerating
only the valid slots in increasing order.
*/
class Iterator; // Declaration required
friend class Iterator; // Make it a friend
class Iterator // Definition
{
public:
Iterator();
/*
Creates a default iterator. The iterator can't be used before an initialized
iterator is assigned.
*/
Iterator( const Iterator& other );
/*
Creates a copy of iterator ~other~.
*/
// Iterator( const Iterator& other, bool );
Iterator& operator++(); // Prefix ++
const Iterator operator++(int); // Postfix ++
/*
Advances the scan to the next element. No effect if ~EndOfScan~ holds
before. ~EndOfScan~ may become true.
*/
#ifdef CTABLE_PERSISTENT
const T& operator*() const;
#else
T& operator*() const;
#endif
/*
Dereferencing of an iterator in the persistent implementation yields an
const reference to T. So use as lvalue is not supported.
*/
Iterator& operator=( const Iterator& other );
bool operator==( const Iterator& other ) const;
/*
Copy Constructor and Comparison. The second
compares two iterators and returns ~true~ if they are equal.
*/
bool operator!=( const Iterator& other ) const;
/*
Compares two iterators and returns ~true~ if they are not equal.
*/
Cardinal GetIndex() const;
/*
Returns the index in the table of the current scan element.
The element may then be accessed by the table operations.
*/
bool EndOfScan() const;
/*
True if the scan is at position ~end~ (no more elements present).
*/
private:
Iterator( CTable<T>* ctPtr );
#ifdef CTABLE_PERSISTENT
mutable T returnelem; // speed up of operator*
#endif
/*
Creates an iterator for the CTable referenced by ~ctPtr~ pointing to the
first valid slot.
*/
Iterator( CTable<T>* ctPtr, bool );
/*
Creates an iterator for the CTable referenced by ~ctPtr~ pointing beyond the
highest valid slot. Such an iterator can be used to mark the end of a scan.
*/
CTable<T>* ct; // referenced Compact Table
Cardinal current; // current iterator position
friend class CTable<T>;
};
Iterator Begin();
/*
Creates an iterator for this ~CTable~, pointing to the first valid slot.
*/
Iterator End();
/*
Creates an iterator for this ~CTable~, pointing beyond the last valid slot.
*/
/*********************************************************************
1.7.0 Object State
*/
const std::string StateToStr();
intptr_t GetSlotSize() { return slotSize; }
/*
1.7.1 Private Members
*/
private:
#ifdef THREAD_SAFE
boost::recursive_mutex mtx;
#endif
#ifdef THREAD_SAFE
static boost::recursive_mutex smtx;
#endif
inline bool OutOfRange(Cardinal const n) { // check if a valid slot is used
#ifdef THREAD_SAFE
boost::lock_guard<boost::recursive_mutex> guard(mtx);
#endif
if ( !(n > 0 && n <= elemCount) ) {
std::cerr << "CTable<" << typeid(T).name() << "> "
<< "slot n=" << n << " is out of range [0.."
<< elemCount <<"]." << std::endl;
return true;
}
return false;
}
void CalcSlotSize() { // Calculate the slot size
#ifdef THREAD_SAFE
boost::lock_guard<boost::recursive_mutex> guard(mtx);
#endif
T* ptrT = 0;
bool* ptrb = 0; // vector<bool> may have a special implementation
// which uses memory more efficiently
// calculation of allocated memory
intptr_t dT = ((intptr_t)++ptrT);
intptr_t db = ((intptr_t)++ptrb);
slotSize = dT + db;
}
void UpdateSlotCounters(Cardinal const n); // used by Add and
#ifdef CTABLE_PERSISTENT
bool setFALSE; // Reference Values needed for the
bool setTRUE; // PArray.Put(int index, T& elem) method
T* dummyElem;
T lastAccessedElem; // For speed up of []operator implementation
Cardinal lastAccessedIndex;
PagedArray<T>* table; // Array of table elements
PagedArray<bool>* valid; // Array of table element states
#else
std::vector<T> table; // Array of table elements
std::vector<bool> valid; // Array of table element states
#endif // common member variables
intptr_t slotSize;
bool isPersistent; // Flag indicating the implemented model
Cardinal elemCount; // Size of compact table
Cardinal leastFree; // Position of free slot
Cardinal highestValid; // Position of highest valid slot
Cardinal last;
static size_t noInstances; // instance counter
size_t instanceID;
};
/*
1.1.1 implementation of common parts
*/
/*
1.1 Size of a CTable
*/
template<typename T>
Cardinal
CTable<T>::Size() {
#ifdef THREAD_SAFE
boost::lock_guard<boost::recursive_mutex> guard(mtx);
#endif
return elemCount;
}
/*
1.1 Number of entries in a CTable
*/
template<typename T>
Cardinal
CTable<T>::NoEntries() {
#ifdef THREAD_SAFE
boost::lock_guard<boost::recursive_mutex> guard(mtx);
#endif
return highestValid;
}
template<typename T>
std::string
CTable<T>::MemoryModel() {
#ifdef THREAD_SAFE
boost::lock_guard<boost::recursive_mutex> guard(mtx);
#endif
if ( !isPersistent) {
return "NON-PERSISTENT";
} else {
return "PERSISTENT";
}
}
template<typename T>
const std::string
CTable<T>::StateToStr() {
#ifdef THREAD_SAFE
boost::lock_guard<boost::recursive_mutex> guard(mtx);
#endif
std::stringstream st;
st << "( elemCount=" << elemCount
<< ", leastFree=" << leastFree
<< ", highestValid= " << highestValid << std::ends;
return st.str();
}
/*
1.1 Creation of a Begin iterator
*/
template<typename T>
typename CTable<T>::Iterator
CTable<T>::Begin() {
#ifdef THREAD_SAFE
boost::lock_guard<boost::recursive_mutex> guard(mtx);
#endif
return typename CTable<T>::Iterator( this );
}
/*
1.1 Creation of an End iterator
*/
template<typename T>
typename CTable<T>::Iterator
CTable<T>::End() {
#ifdef THREAD_SAFE
boost::lock_guard<boost::recursive_mutex> guard(mtx);
#endif
return typename CTable<T>::Iterator( this, false );
}
/*
1.1 Default constructor for iterator
*/
template<typename T>
CTable<T>::Iterator::Iterator() : ct(0), current(0)
{
}
template<typename T>
CTable<T>::Iterator::Iterator( CTable<T>* ctPtr, bool ) {
ct = ctPtr;
current = ct->highestValid;
}
template<typename T>
CTable<T>::Iterator::Iterator( Iterator const &other ) {
ct = other.ct;
current = other.current;
}
/*
1.1 Iterator assignment
*/
template<typename T>
typename CTable<T>::Iterator&
CTable<T>::Iterator::operator=( CTable<T>::Iterator const &other ) {
ct = other.ct;
current = other.current;
return *this;
}
/*
1.1 Iterator comparison (equality and inequality)
*/
template<typename T>
bool
CTable<T>::Iterator::operator==( const Iterator& other ) const {
return (ct == other.ct) && (current == other.current);
}
template<typename T>
bool
CTable<T>::Iterator::operator!=( const Iterator& other ) const {
return (ct != other.ct) || (current != other.current);
}
/*
1.1 Index of element iterator is pointing to
*/
template<typename T>
Cardinal
CTable<T>::Iterator::GetIndex() const {
assert( ct != 0 );
return current+1;
}
/*
1.1 Test for end of scan
*/
template<typename T>
bool
CTable<T>::Iterator::EndOfScan() const {
assert( ct != 0 );
return current >= ct->highestValid;
}
/*
1.1 Inclusion of variant implementations
*/
#ifdef CTABLE_PERSISTENT
#include "PCTable.cpp"
#else
#include "CTable.cpp"
#endif
#endif