Files
secondo/Algebras/PointRectangle/PointRectangleAlgebra.cpp
2026-01-23 17:03:45 +08:00

1055 lines
29 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 [1] title: [{\Large \bf ] [}]
//characters [2] verbatim: [\verb@] [@]
//[ue] [\"{u}]
//[toc] [\tableofcontents]
""[2]
[1] PointRectangle Algebra
July 2002, R. H. G[ue]ting
2003 - 2006, V. Almeida. Code changes due to interface changes.
Oct. 2006, M. Spiekermann. Introduction of a namespace, string constants and
usage of the "static_cast<>" templates. Additionally, more comments and hints
were given.
Sept. 2007, M. Spiekermann. Many code changes to demonstrate new programming interfaces.
Oct. 2007 RHG Revision of text.
[toc]
0 Overview
This little example algebra provides two type constructors ~xpoint~ and
~xrectangle~ and two operators:
1. ~inside~, which checks whether either a point or a rectangle is
within a rectangle, and
2. ~intersects~, which checks two rectangles for intersection.
1 Preliminaries
1.1 Includes
*/
#include "Algebra.h"
#include "NestedList.h"
#include "ListUtils.h"
#include "NList.h"
#include "LogMsg.h"
#include "QueryProcessor.h"
#include "ConstructorTemplates.h"
#include "StandardTypes.h"
/*
The file "Algebra.h" is included, since the new algebra must be a subclass of
class Algebra. All of the data available in Secondo has a nested list
representation. Therefore, conversion functions have to be written for this
algebra, too, and "NestedList.h" is needed for this purpose. The result of an
operation is passed directly to the query processor. An instance of
"QueryProcessor" serves for this. Secondo provides some standard data types, e.g.
"CcInt", "CcReal", "CcString", "CcBool", which is needed as the result type of the
implemented operations. To use them "StandardTypes.h" needs to be included.
*/
extern NestedList* nl;
extern QueryProcessor *qp;
/*
The variables above define some global references to unique system-wide
instances of the query processor and the nested list storage.
1.2 Auxiliaries
Within this algebra module implementation, we have to handle values of
four different types defined in namespace ~symbols~: ~INT~ and ~REAL~, ~BOOL~ and
~STRING~. They are constant values of the C++-string class.
Moreover, for type mappings some auxiliary helper functions are defined in the
file "TypeMapUtils.h" which defines a namespace ~mappings~.
*/
#include "TypeMapUtils.h"
#include "Symbols.h"
#include <string>
using namespace std;
/*
The implementation of the algebra is embedded into
a namespace ~prt~ in order to avoid name conflicts with other modules.
*/
namespace prt {
/*
2 Type Constructor ~xpoint~
In this section we describe what is needed to implement the Secondo type
~xpoint~. Here the more traditional programming interfaces are shown. Some more
recent alternatives are presented in the next section.
2.1 Data Structure - Class ~XPoint~
*/
class XPoint
{
public:
/*
Constructors and destructor:
*/
XPoint( int x, int y );
XPoint(const XPoint& rhs);
~XPoint();
int GetX() const;
int GetY() const;
void SetX( int x );
void SetY( int y );
XPoint* Clone();
/*
Below the mandatory set of algebra support functions is declared.
Note that these functions need to be static member functions of the class.
Their implementations do nothing which depends on the state of an instance.
*/
static Word In( const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo,
bool& correct );
static ListExpr Out( ListExpr typeInfo, Word value );
static Word Create( const ListExpr typeInfo );
static void Delete( const ListExpr typeInfo, Word& w );
static void Close( const ListExpr typeInfo, Word& w );
static Word Clone( const ListExpr typeInfo, const Word& w );
static bool KindCheck( ListExpr type, ListExpr& errorInfo );
static int SizeOfObj();
static ListExpr Property();
/*
The following function defines the name of the type constructor, resp. the name
Secondo uses for this type.
*/
static const string BasicType() { return "xpoint"; }
static const bool checkType(const ListExpr type){
return listutils::isSymbol(type, BasicType());
}
private:
inline XPoint() {}
/*
Warning: Never do initializations in the default constructor!
It will be used in a special way in the cast function which is needed
for making a class persistent when acting as an attribute in a tuple.
In order to guarantee this, we make this constructor private.
One always needs to provide at least a second constructor, here
"XPoint( int x, int y )" in order to construct an instance.
Moreover,
avoid declarations like "XPoint p1;" since these will create an uninitialized
class instance. Instead you should use only properly initialized variables
like "XPoint(0,0) p1;"
*/
int x;
int y;
};
/*
We recommend to separate class declarations from their implementations.
This makes life easier if you want to use the type provided in one algebra in
another algebra. Only for the sake of a compact presentation, we did not move
the declarations to special header files in this example algebra.
*/
XPoint::XPoint(int X, int Y) : x(X), y(Y) {}
XPoint::XPoint(const XPoint& rhs) : x(rhs.x), y(rhs.y) {}
XPoint::~XPoint() {}
int XPoint::GetX() const { return x; }
int XPoint::GetY() const { return y; }
void XPoint::SetX(int X) { x = X; }
void XPoint::SetY(int Y) { y = Y; }
/*
2.2 List Representation
The list representation of an xpoint is
---- (x y)
----
2.3 ~In~ and ~Out~ Functions
The ~In~-function gets a nested list representation of an ~xpoint~ value passed
in the variable "instance". It is represented by the C++ type "ListExpr".
Moreover, there is a global pointer variable "nl" which points to the (single)
instance of class ~NestedList~. This class provides a set of functions which
can investigate and manipulate nested lists. For details refer to the file
"NestedList.h".
The parameter "errorInfo" can be used to return specific
error information if the retrieved list is not correct. In the latter case,
the boolean parameter "correct" needs to be set to false.
The return value of the function is of type ~Word~ which can simply be
regarded as a pointer. The query processor operates with this type-less
abstraction for objects. If all integrity checks are correct we will return
a pointer to a new instance of class ~XPoint~.
*/
Word
XPoint::In( const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct )
{
Word w = SetWord(Address(0));
if ( nl->ListLength( instance ) == 2 )
{
ListExpr First = nl->First(instance);
ListExpr Second = nl->Second(instance);
if ( nl->IsAtom(First) && nl->AtomType(First) == IntType
&& nl->IsAtom(Second) && nl->AtomType(Second) == IntType )
{
correct = true;
w.addr = new XPoint(nl->IntValue(First), nl->IntValue(Second));
return w;
}
}
correct = false;
cmsg.inFunError("Expecting a list of two integer atoms!");
return w;
}
/*
The ~Out~-function will get a pointer to an ~XPoint~ representation.
Before we can use a member function of class ~XPoint~, we need to do
a type cast in order to tell the compiler about the object's type.
Note: At this point we can be sure that it is a pointer to type ~XPoint~, hence
it is safe to do it. But in general, type casts can be a source for ~strange~
errors, e.g. segmentation faults, if you cast to a type which is not compatible
to the object that the pointer belongs to.
*/
ListExpr
XPoint::Out( ListExpr typeInfo, Word value )
{
XPoint* point = static_cast<XPoint*>( value.addr );
return nl->TwoElemList(nl->IntAtom(point->GetX()),
nl->IntAtom(point->GetY()));
}
/*
2.4 Support Functions for Persistent Sorage
*/
Word
XPoint::Create( const ListExpr typeInfo )
{
return (SetWord( new XPoint( 0, 0 ) ));
}
void
XPoint::Delete( const ListExpr typeInfo, Word& w )
{
delete static_cast<XPoint*>( w.addr );
w.addr = 0;
}
void
XPoint::Close( const ListExpr typeInfo, Word& w )
{
delete static_cast<XPoint*>( w.addr );
w.addr = 0;
}
Word
XPoint::Clone( const ListExpr typeInfo, const Word& w )
{
XPoint* p = static_cast<XPoint*>( w.addr );
return SetWord( new XPoint(*p) );
}
/*
Here, a clone simply calls the copy constructor, but for other
types, which may have also a disk part, some code for copying
the disk parts would be needed also. Often this is implemented
in a special member function "Clone()".
*/
int
XPoint::SizeOfObj()
{
return sizeof(XPoint);
}
/*
2.4 Type Description
At the user interface, the command ~list type constructors~ lists all type
constructors of all currently linked algebra modules. The information listed is
generated by the algebra module itself, to be more precise it is generated by
the ~property~-functions.
Generally, a property list consists of two sublists providing labels and contents.
Currently a structure like the one below has been established to
be the standard.
*/
ListExpr
XPoint::Property()
{
return (nl->TwoElemList(
nl->FiveElemList(nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List"),
nl->StringAtom("Remarks")),
nl->FiveElemList(nl->StringAtom("-> DATA"),
nl->StringAtom(XPoint::BasicType()),
nl->StringAtom("(<x> <y>)"),
nl->StringAtom("(-3 15)"),
nl->StringAtom("x- and y-coordinates must be "
"of type int."))));
}
/*
This is an older technique for creating property lists. A more recent technique
is shown below for type ~XRectangle~.
2.5 Kind Checking Function
This function checks whether the type constructor is applied correctly. Since
type constructor ~xpoint~ does not have arguments, this is trivial.
*/
bool
XPoint::KindCheck( ListExpr type, ListExpr& errorInfo )
{
return (nl->IsEqual( type, XPoint::BasicType() ));
}
/*
2.6 Creation of the Type Constructor Instance
*/
TypeConstructor xpointTC(
XPoint::BasicType(), // name of the type in SECONDO
XPoint::Property, // property function describing signature
XPoint::Out, XPoint::In, // Out and In functions
0, 0, // SaveToList, RestoreFromList functions
XPoint::Create, XPoint::Delete, // object creation and deletion
0, 0, // object open, save
XPoint::Close, XPoint::Clone, // close, and clone
0, // cast function
XPoint::SizeOfObj, // sizeof function
XPoint::KindCheck ); // kind checking function
/*
3 Type Constructor ~xrectangle~
To define the Secondo type ~xrectangle~, we need to (i) define a data
structure, that is a class, to (ii) decide about a nested list representation,
and (iii) write conversion functions from and to nested list representation.
The function for converting from the list representation is the most involved
one, since it has to check that the given list structure is entirely correct.
After we have described the traditional programming interface in the previous
section, here in some places we use more recent alternative programming
interfaces for implementing a type.
3.1 Data Structure - Class ~XRectangle~
*/
class XRectangle
{
public:
XRectangle( int XLeft, int XRight, int YBottom, int YTop );
XRectangle( const XRectangle& rhs );
~XRectangle() {}
int GetXLeft() const;
int GetXRight() const;
int GetYBottom() const;
int GetYTop() const;
bool intersects( const XRectangle& r) const;
/*
Here we will only implement the following three support functions, since the others
have default implementations which can be generated at compile time using C++ template
functionality.
*/
static Word In( const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct );
static ListExpr Out( ListExpr typeInfo, Word value );
static Word Create( const ListExpr typeInfo );
/*
In contrast to the example above, we will implement specific ~open~ and ~save~
functions instead of using the generic persistent mechanism.
*/
static bool Open( SmiRecord& valueRecord,
size_t& offset, const ListExpr typeInfo,
Word& value );
static bool Save( SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& w );
/*
The following function defines the name of the type constructor, resp. the name
Secondo uses for this type.
*/
static const string BasicType() { return "xrectangle"; }
static const bool checkType(const ListExpr type){
return listutils::isSymbol(type, BasicType());
}
private:
XRectangle() {}
// Since we want to use some default implementations we need
// to allow access to private members for the class below.
friend struct ConstructorFunctions<XRectangle>;
int xl;
int xr;
int yb;
int yt;
};
XRectangle::XRectangle( int XLeft, int XRight, int YBottom, int YTop )
{
xl = XLeft; xr = XRight; yb = YBottom; yt = YTop;
}
XRectangle::XRectangle( const XRectangle& rhs )
{
xl = rhs.xl; xr = rhs.xr; yb = rhs.yb; yt = rhs.yt;
}
int XRectangle::GetXLeft() const { return xl; }
int XRectangle::GetXRight() const { return xr; }
int XRectangle::GetYBottom() const { return yb; }
int XRectangle::GetYTop() const { return yt; }
/*
3.2 Auxiliary Functions for Operations
To implement rectangle intersection, we first introduce an auxiliary function which
tests if two intervals overlap.
*/
bool overlap ( int low1, int high1, int low2, int high2 )
{
if ( high1 < low2 || high2 < low1 )
return false;
else
return true;
}
bool
XRectangle::intersects( const XRectangle& r ) const
{
return ( overlap(xl, xr, r.GetXLeft(), r.GetXRight())
&& overlap(yb, yt, r.GetYBottom(), r.GetYTop()) );
}
/*
3.3 List Representation and ~In~/~Out~ Functions
The list representation of an xrectangle is
---- (XLeft XRight YBottom YTop)
----
In contrast to the code examples above, we use here the class
~NList~ instead of the static functions "nl->f(...)". Its interface is described
in file "NList.h". It is a simple wrapper for calls like "nl->f(...)" and provides
a more object-oriented access to a nested list.
This class was implemented more recently; hence there is a lot of code which uses
the older interface. But as you can observe, the code based on ~NList~ is more
compact, easier to read, understand, and maintain. Thus we recommend to use this
interface.
*/
Word
XRectangle::In( const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct )
{
correct = false;
Word result = SetWord(Address(0));
const string errMsg = "Expecting a list of four integer atoms!";
NList list(instance);
// When you check list structures it will be a good advice to detect
// errors as early as possible to avoid deep nestings of if statements.
if ( list.length() != 4 ) {
cmsg.inFunError(errMsg);
return result;
}
NList First = list.first();
NList Second = list.second();
NList Third = list.third();
NList Fourth = list.fourth();
if ( First.isInt() && Second.isInt()
&& Third.isInt() && Fourth.isInt() )
{
int xl = First.intval();
int xr = Second.intval();
int yb = Third.intval();
int yt = Fourth.intval();
if ( xl < xr && yb < yt )
{
correct = true;
XRectangle* r = new XRectangle(xl, xr, yb, yt);
result.addr = r;
}
}
else
{
cmsg.inFunError(errMsg);
}
return result;
}
ListExpr
XRectangle::Out( ListExpr typeInfo, Word value )
{
XRectangle* rectangle = static_cast<XRectangle*>( value.addr );
NList fourElems(
NList( rectangle->GetXLeft() ),
NList( rectangle->GetXRight() ),
NList( rectangle->GetYBottom() ),
NList( rectangle->GetYTop() ) );
return fourElems.listExpr();
}
/*
4.4 Storage Management: ~Open~, ~Save~, and ~Create~
The ~open~ and ~save~ functions need an ~SmiRecord~ as argument which contains the
binary representation of the type, starting at the position indicated by ~offset~. The
implementor has to read out or write in data there and adjust the offset. The argument
~typeinfo~ is needed only for complex types whose constructors can be parameterized,
e.g. rel(tuple(...)).
*/
bool
XRectangle::Open( SmiRecord& valueRecord,
size_t& offset, const ListExpr typeInfo,
Word& value )
{
//cerr << "OPEN XRectangle" << endl;
size_t size = sizeof(int);
int xl = 0, xr = 0, yb = 0, yt = 0;
bool ok = true;
ok = ok && valueRecord.Read( &xl, size, offset );
offset += size;
ok = ok && valueRecord.Read( &xr, size, offset );
offset += size;
ok = ok && valueRecord.Read( &yb, size, offset );
offset += size;
ok = ok && valueRecord.Read( &yt, size, offset );
offset += size;
value.addr = new XRectangle(xl, xr, yb, yt);
return ok;
}
bool
XRectangle::Save( SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& value )
{
//cerr << "SAVE XRectangle" << endl;
XRectangle* r = static_cast<XRectangle*>( value.addr );
size_t size = sizeof(int);
bool ok = true;
ok = ok && valueRecord.Write( &r->xl, size, offset );
offset += size;
ok = ok && valueRecord.Write( &r->xr, size, offset );
offset += size;
ok = ok && valueRecord.Write( &r->yb, size, offset );
offset += size;
ok = ok && valueRecord.Write( &r->yt, size, offset );
offset += size;
return ok;
}
Word
XRectangle::Create( const ListExpr typeInfo )
{
return (SetWord( new XRectangle( 0, 0, 0, 0 ) ));
}
/*
4.5 Type Description
The property function is deprecated. Instead
this is done by implementing a subclass of ~ConstructorInfo~.
*/
struct xrectangleInfo : ConstructorInfo {
xrectangleInfo() {
name = XRectangle::BasicType();
signature = "-> " + Kind::SIMPLE();
typeExample = XRectangle::BasicType();
listRep = "(<xleft> <xright> <ybottom> <ytop>)";
valueExample = "(4 12 2 8)";
remarks = "all coordinates must be of type int.";
}
};
/*
4.6 Creation of the Type Constructor Instance
Here we also use a new programming interface. As you may have observed, most
implementations of the support functions needed for registering a Secondo type
are trivial to implement. Hence, we offer a template class
~ConstructorFunctions~ which will create many default implementations of
functions used by a Secondo type. For details refer to
"ConstructorFunctions.h". However, some functions need to be implemented since
the default may not be sufficient. The default kind check function assumes that
the type constructor does not have any arguments.
*/
struct xrectangleFunctions : ConstructorFunctions<XRectangle> {
xrectangleFunctions()
{
// re-assign some function pointers
create = XRectangle::Create;
in = XRectangle::In;
out = XRectangle::Out;
// the default implementations for open and save are only
// suitable for a class which is derived from class ~Attribute~, hence
// open and save functions must be overwritten here.
open = XRectangle::Open;
save = XRectangle::Save;
}
};
xrectangleInfo xri;
xrectangleFunctions xrf;
TypeConstructor xrectangleTC( xri, xrf );
/*
5 Creating Operators
5.1 Type Mapping Functions
A type mapping function checks whether the correct argument types are supplied
for an operator; if so, it returns a list expression for the result type,
otherwise the symbol ~typeerror~. Again we use interface ~NList.h~ for
manipulating list expressions.
*/
ListExpr
RectRectBool( ListExpr args )
{
NList type(args);
if ( type != NList(XRectangle::BasicType(), XRectangle::BasicType()) ) {
return NList::typeError("Expecting two rectangles");
}
return NList(CcBool::BasicType()).listExpr();
}
ListExpr
insideTypeMap( ListExpr args )
{
NList type(args);
const string errMsg = "Expecting two rectangles "
"or a point and a rectangle";
// first alternative: xpoint x xrectangle -> bool
if ( type == NList(XPoint::BasicType(), XRectangle::BasicType()) ) {
return NList(CcBool::BasicType()).listExpr();
}
// second alternative: xrectangle x xrectangle -> bool
if ( type == NList(XRectangle::BasicType(), XRectangle::BasicType()) ) {
return NList(CcBool::BasicType()).listExpr();
}
return NList::typeError(errMsg);
}
/*
5.2 Selection Function
A selection function is quite similar to a type mapping function. The only
difference is that it doesn't return a type but the index of a value
mapping function being able to deal with the respective combination of
input parameter types.
Note that a selection function does not need to check the correctness of
argument types; this has already been checked by the type mapping function.
A selection function is only called if the type mapping was successful. This
makes programming easier as one can rely on a correct structure of the list
~args~.
*/
int
insideSelect( ListExpr args )
{
NList type(args);
if ( type.first().isSymbol( XRectangle::BasicType() ) )
return 1;
else
return 0;
}
/*
5.3 Value Mapping Functions
5.3.1 The ~intersects~ predicate for two rectangles
*/
int
intersectsFun (Word* args, Word& result, int message,
Word& local, Supplier s)
{
XRectangle *r1 = static_cast<XRectangle*>( args[0].addr );
XRectangle *r2 = static_cast<XRectangle*>( args[1].addr );
result = qp->ResultStorage(s);
//query processor has provided
//a CcBool instance for the result
CcBool* b = static_cast<CcBool*>( result.addr );
b->Set(true, r1->intersects(*r2));
//the first argument says the boolean
//value is defined, the second is the
//real boolean value)
return 0;
}
/*
4.3.2 The ~inside~ predicate for a point and a rectangle
*/
int
insideFun_PR (Word* args, Word& result, int message,
Word& local, Supplier s)
{
//cout << "insideFun_PR" << endl;
XPoint* p = static_cast<XPoint*>( args[0].addr );
XRectangle* r = static_cast<XRectangle*>( args[1].addr );
result = qp->ResultStorage(s);
//query processor has provided
//a CcBool instance for the result
CcBool* b = static_cast<CcBool*>( result.addr );
bool res = ( p->GetX() >= r->GetXLeft()
&& p->GetX() <= r->GetXRight()
&& p->GetY() >= r->GetYBottom()
&& p->GetY() <= r->GetYTop() );
b->Set(true, res); //the first argument says the boolean
//value is defined, the second is the
//real boolean value)
return 0;
}
/*
4.3.3 The ~inside~ predicate for two rectangles
*/
int
insideFun_RR (Word* args, Word& result, int message,
Word& local, Supplier s)
{
//cout << "insideFun_RR" << endl;
XRectangle* r1 = static_cast<XRectangle*>( args[0].addr );
XRectangle* r2 = static_cast<XRectangle*>( args[1].addr );
result = qp->ResultStorage(s);
//query processor has provided
//a CcBool instance for the result
CcBool* b = static_cast<CcBool*>( result.addr );
bool res = true;
res = res && r1->GetXLeft() >= r2->GetXLeft();
res = res && r1->GetXLeft() <= r2->GetXRight();
res = res && r1->GetXRight() >= r2->GetXLeft();
res = res && r1->GetXRight() <= r2->GetXRight();
res = res && r1->GetYBottom() >= r2->GetYBottom();
res = res && r1->GetYBottom() <= r2->GetYTop();
res = res && r1->GetYTop() >= r2->GetYBottom();
res = res && r1->GetYTop() <= r2->GetYTop();
b->Set(true, res); //the first argument says the boolean
//value is defined, the second is the
//real boolean value)
return 0;
}
/*
4.4 Operator Descriptions
Similar to the ~property~ function of a type constructor, an operator needs to
be described, e.g. for the ~list operators~ command. This is now done by
creating a subclass of class ~OperatorInfo~.
*/
struct intersectsInfo : OperatorInfo {
intersectsInfo()
{
name = "intersects";
signature = XRectangle::BasicType() + " x " + XRectangle::BasicType()
+ " -> " + CcBool::BasicType();
syntax = "_ intersects _";
meaning = "Intersection predicate for two xrectangles.";
}
}; // Don't forget the semicolon here. Otherwise the compiler
// returns strange error messages
struct insideInfo : OperatorInfo {
insideInfo()
{
name = "inside";
signature = XPoint::BasicType() + " x " + XRectangle::BasicType() + " -> "
+ CcBool::BasicType();
// since this is an overloaded operator we append
// an alternative signature here
appendSignature( XRectangle::BasicType() + " x " + XRectangle::BasicType()
+ " -> " + CcBool::BasicType() );
syntax = "_ inside _";
meaning = "Inside predicate.";
}
};
/*
5 Implementation of the Algebra Class
*/
class PointRectangleAlgebra : public Algebra
{
public:
PointRectangleAlgebra() : Algebra()
{
/*
5.2 Registration of Types
*/
AddTypeConstructor( &xpointTC );
AddTypeConstructor( &xrectangleTC );
//the lines below define that xpoint and xrectangle
//can be used in places where types of kind SIMPLE are expected
xpointTC.AssociateKind( Kind::SIMPLE() );
xrectangleTC.AssociateKind( Kind::SIMPLE() );
/*
5.3 Registration of Operators
*/
AddOperator( intersectsInfo(), intersectsFun, RectRectBool );
// the overloaded inside operator needs an array of function pointers
// which must be null terminated!
ValueMapping insideFuns[] = { insideFun_PR, insideFun_RR, 0 };
AddOperator( insideInfo(), insideFuns, insideSelect, insideTypeMap );
}
~PointRectangleAlgebra() {};
};
/*
6 Initialization
Each algebra module needs an initialization function. The algebra manager
has a reference to this function if this algebra is included in the list
of required algebras, thus forcing the linker to include this module.
The algebra manager invokes this function to get a reference to the instance
of the algebra class and to provide references to the global nested list
container (used to store constructor, type, operator and object information)
and to the query processor.
The function has a C interface to make it possible to load the algebra
dynamically at runtime (if it is built as a dynamic link library). The name
of the initialization function defines the name of the algebra module. By
convention it must start with "Initialize<AlgebraName>".
To link the algebra together with the system you must create an
entry in the file "makefile.algebra" and to define an algebra ID in the
file "Algebras/Management/AlgebraList.i.cfg".
*/
} // end of namespace ~prt~
extern "C"
Algebra*
InitializePointRectangleAlgebra( NestedList* nlRef,
QueryProcessor* qpRef )
{
// The C++ scope-operator :: must be used to qualify the full name
return new prt::PointRectangleAlgebra;
}
/*
7 Examples and Tests
The file "PointRectangle.examples" contains for every operator one example.
This allows one to verify that the examples are running and to provide a coarse
regression test for all algebra modules. The command "Selftest <file>" will
execute the examples. Without any arguments, the examples for all active
algebras are executed. This helps to detect side effects, if you have touched
central parts of Secondo or existing types and operators.
In order to setup more comprehensive automated test procedures one can write a
test specification for the ~TestRunner~ application. You will find the file
"example.test" in directory "bin" and others in the directory "Tests/Testspecs".
There is also one for this algebra.
Accurate testing is often treated as an unpopular daunting task. But it is
absolutely inevitable if you want to provide a reliable algebra module.
Try to write tests covering every signature of your operators and consider
special cases, as undefined arguments, illegal argument values and critical
argument value combinations, etc.
*/