Relation
A. Second Edition
This is the second edition of my Relation class and it has been lingering in my mind for a long time.
B.Idea of program
1¡£ Basic idea:
I delete class Elements and changed logicSets to have two internal list---one is set list and the other is data list. Data
now is pure data, set is pure subsets. I also changed the implementation of "call-back" functions, such as forEach to be
separate as "forEachSet" and "forEachData". I believe in this way it gives more flexibility for programmer's purpose.
2¡£ Program design:
I used so many "call-back" global functions that I even feel hopeless to go on. It is a pain that I cannot use member function
as call back function, which in Delphi is a possible. (I think, but now memory is blurred.)
3¡£ Major function
A. void forEachSet(void (*checkEach)(LogicSets* each, void* method, void* userData1, void* userData2), void* method=NULL, void* userData1=NULL, void* userData2=NULL);The reason that I insert so many parameters is that when Relation is construct, it need so many data to pass on.And for simple job, programmer can use a simple form of forEachSet which only require the call-back functionpointer as parameter.B. void forEachData(void (*checkData)(void* data, void* method, void* userData1, void* userData2), void* method=NULL, void* userData1=NULL, void* userData2=NULL);This is quite similar to forEachSet, except that it is a special method for you to handle each data and forEachSetcan do more general job. And for simple job you can use a simple form forEachData with one parameter.C. void Relation::construct(LogicSets* A, LogicSets* B, bool(*condition)(void* first, void* second))This function originally is constructor of Relation, and only for debug that I make it an independent method.it first call set A's forEachData method and pass A's data itself as a parameter and Relation pointer. Then in Call-backfunction, it use B's forEachData method and call the user-defined condition method pointer to make the condition-checking.D. bool condition(void* x, void* y)this should be defined by user.E. void forEachY(void* y, void* checkMethod, void* x, void* relation)void forEachX(void* each, void* method, void* userData1, void* userData2)these are internal call-back functions and user should not modify them.
4¡£ Further improvement£º
A. This is actually not like a class!!! What have I done???
#include <iostream>
#include <iomanip>
using namespace std;
/////////////////////////////////////////////////////////////////////////////////
//This is what I thought when I wrote first edition:
//actually sets and elements are just like problem of "egg" and "chicken", we do
//know who comes first, they should always comes together, except the emptySets who has
//no elements at all
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//Now I think that set is element and element is set:
//chicken is egg, and egg is chicken!!!
//////////////////////////////////////////////////////////////////////////////
template<class T>
class mylist
{
private:
T *flist;
int LENGTH;
int SIZE;
int counter;
protected:
void uninitialize();
void initialize();
bool checksize();
void expand();
int locate(T ptr);
public:
mylist();
~mylist();
void add(T ptr);
bool find(T ptr);
void display();
int count();
T& items(int index);
void insert(int index, T ptr);
};
class LogicSets
{
private:
mylist<LogicSets*> setlst;
mylist<void*> datalst;
long ID; //plan to use address to represent as ID
char* name;
LogicSets* parent;
public:
LogicSets* belongTo() { return parent; }
int setCount(){ return setlst.count();}
int dataCount(){ return datalst.count();}
void setParent(LogicSets* father) { parent = father;}
LogicSets* getParent() { return parent;}
void addData(void* newData){ datalst.add(newData); }
LogicSets* setItems(int index){ return setlst.items(index);}
void* dataItems(int index) { return datalst.items(index);}
char* getName() { return name;}
void setName(const char* givenName);
bool include(LogicSets* pSets);
void add(LogicSets* pSets);
//call back function "for all"
bool forAll( bool (*checkEach)(void* each));
//call back function "exist"
bool exists( bool (*checkEach)(void* each));
//call back function for general purpose
void forEachSet( void (*checkSet)(LogicSets* each));
void forEachData(void (*checkData)(void* data));
//a more powerful call-back function for inputting user data
void forEachSet(void (*checkEach)(LogicSets* each, void* method, void* userData1,
void* userData2), void* method=NULL, void* userData1=NULL, void* userData2=NULL);
void forEachData(void (*checkData)(void* data, void* method, void* userData1,
void* userData2), void* method=NULL, void* userData1=NULL, void* userData2=NULL);
~LogicSets();
LogicSets();
};
struct Pair
{
void* first;
void* second;
};
class Relation: public LogicSets
{
private:
public:
void construct(LogicSets* A, LogicSets* B, bool (*condition)(void* first, void* second));
~Relation();
};
////////////////////////////////////////////////////////////////
//these following call-back function are all programmer-defined
//which will be passed as parameter to forall, exist method of
//logicsets. it is like delphi "even" method
////////////////////////////////////////////////////////////////
//to check all if all are string like "this is no.5"
bool allCheck(LogicSets* each)
{
//this function should be user or programme defined
return strcmp(each->getName(), "this is no.5") == 0;
}
bool existCheck(LogicSets* each)
{
//this function should be user or programme defined
return strcmp(each->getName(), "this is no.5") == 0;
}
void showEach(LogicSets* each)
{
//this function should be user or programme defined
cout<<"\nSet name is '"<<each->getName()<<"' and data is: ";
for (int i=0; i< each->dataCount(); i++)
{
cout<<"data no "<<i<<" is "<<*((int*)(each->dataItems(i)))<<endl;
}
}
void forEachY(void* y, void* checkMethod, void* x, void* relation)
{
bool (*check)(void* x, void* y);
Pair* pair = new Pair;
check = (bool (*)(void* , void* ))(checkMethod);
if (check(x, y))
{
pair->first = x;
pair->second = y;
((Relation*)(relation))->addData((void*)(pair));
}
}
void forEachX(void* each, void* method, void* userData1, void* userData2)
{
((LogicSets*)(userData1))->forEachData(forEachY, method, each, userData2);
}
bool condition(void* x, void* y)
{
return *((int*)x)> *((int*)y);
}
int main()
{
const int Number =10;
char buffer[4];
char str[20];
LogicSets aSets[Number];
LogicSets A, B;
int aNum[Number];
for (int i=0; i<Number; i++)
{
itoa(i, buffer, 10);
strcpy(str, "this is ");
strcat(str, buffer);
aNum[i] = rand()%90;
aSets[i].addData((void*)(aNum+i));
aSets[i].setName(str);
if (i <7)
{
A.add(aSets + i);
}
else
{
B.add(aSets + i);
}
}
for (i=0; i<Number; i++)
{
(aSets+i)->forEachSet(showEach);
}
A.setName("this is set A");
B.setName("this is set B");
cout<<"\nNow show Set A\n";
A.forEachSet(showEach);
cout<<"\nNow show Set B\n";
B.forEachSet(showEach);
cout<<endl;
Relation C;
C.setName("A relation of AXB");
C.construct(&A, &B, condition);
int *x, * y;
Pair* pair;
for (int j =0; j < C.dataCount(); j++)
{
cout<<"pair no."<<j<<" is \n";
pair = (Pair*)(C.dataItems(j));
x = (int*)(pair->first);
y = (int*)(pair->second);
cout<<" x is "<<*x<<endl;
cout<<" y is "<<*y<<endl;
}
return 0;
}
Relation::~Relation()
{
for (int i=0; i< dataCount(); i++)
{
delete dataItems(i);
}
}
void Relation::construct(LogicSets* A, LogicSets* B, bool(*condition)(void* first, void* second))
{
A->forEachData(forEachX, (void*)condition, (void*)B, (void*)this);
}
void LogicSets::forEachData(void (*checkData)(void* data, void* method, void* userData1,
void* userData2), void* method, void* userData1, void* userData2)
{
for (int i=0; i<setCount(); i++)
{
setItems(i)->forEachData(checkData, method, userData1, userData2);
}
for (i=0; i<dataCount(); i++)
{
checkData(dataItems(i), method, userData1, userData2);
}
}
LogicSets::LogicSets()
{
name = NULL;
ID =0;
parent = NULL;
}
void LogicSets::forEachSet(void (*checkEach)(LogicSets* each, void* method, void* userData1,
void* userData2), void* method, void* userData1, void* userData2)
{
for (int i=0; i< setCount(); i++)
{
setItems(i)->forEachSet(checkEach, method, userData1, userData2);
}
checkEach(this, method, userData1, userData2);
}
bool LogicSets::include(LogicSets* pSets)
{
return setlst.find(pSets);
}
LogicSets::~LogicSets()
{
if (name!=NULL)
{
free(name);
}
}
void LogicSets::forEachData(void (*checkData)(void* data))
{
for (int i=0; i<setCount(); i++)
{
setItems(i)->forEachData(checkData);
}
for ( i=0; i< dataCount(); i++)
{
checkData(dataItems(i));
}
}
void LogicSets::forEachSet(void (*checkSet)(LogicSets* each))
{
checkSet(this);
for (int i = 0; i< setCount(); i++)
{
setItems(i)->forEachSet(checkSet);
}
}
void LogicSets::setName(const char* givenName)
{
if (name==NULL)
{
name = (char*)malloc(strlen(givenName)+1);
strcpy(name, givenName);
}
else
{
name = (char*)realloc((void*)name, strlen(givenName)+1);
strcpy(name, givenName);
}
}
void LogicSets::add(LogicSets* pSets)
{
setlst.add(pSets);
pSets->setParent(this);
}
bool LogicSets::forAll(bool (*checkEach)(void* each))
{
for (int i=0; i< setCount(); i++)
{
if (!setItems(i)->forAll(checkEach))
{
return false;
}
}
for (i=0; i< dataCount(); i++)
{
if (!checkEach(dataItems(i)))
{
return false;
}
}
return true;
}
bool LogicSets::exists(bool (*checkEach)(void* each))
{
for (int i=0; i< setCount(); i++)
{
if (setItems(i)->exists(checkEach))
{
return true;
}
}
for (i=0; i< dataCount(); i++)
{
if (checkEach(dataItems(i)))
{
return true;
}
}
return false;
}
template<class T>
void mylist<T>::insert(int index, T ptr)
{
if (!checksize())
expand();
if (counter == 0)
{
items(0) = ptr;
counter++;
}
else
{
if (index>=0&& index<=counter)
{
int i=index;
T hold1 = items(index), hold2= items(index+1);
while (i<counter)
{
hold2 = items(i+1);
items(i+1) = hold1;
hold1 = hold2;
i++;
}
items(index) = ptr; //any exception trap???
counter++;
}
}
}
template<class T>
int mylist<T>::locate(T ptr)
{
int index = 0;
while (items(index) <ptr &&index <counter)
{
index++;
}
return index;
}
template<class T>
bool mylist<T>::find(T ptr)
{
int index = 0;
index = locate(ptr);
if (index == counter)
{
return false;
}
else
{
return (items(index) == ptr);
}
}
template<class T>
int mylist<T>::count()
{
return counter;
}
template<class T>
T& mylist<T>::items(int index)
{
return flist[index];
}
template<class T>
void mylist<T>::display()
{
cout<<setiosflags(ios::showpoint|ios::fixed);
for (int i = 0; i < counter; i ++)
{
cout<<"Number "<<i<<" item is:"<<flist[i]<<endl;
}
}
template<class T>
void mylist<T>::uninitialize()
{
free(flist);
}
template<class T>
mylist<T>::~mylist()
{
uninitialize();
}
template<class T>
void mylist<T>::add(T ptr)
{
int index;
index = locate(ptr);
if (items(index)!=ptr)
{
insert(index, ptr);
}
}
template<class T>
void mylist<T>::initialize()
{
LENGTH = 10;
SIZE = LENGTH;
if ((flist =(T*)(malloc(sizeof(T) * SIZE)))==NULL)
cout<<"Unable malloc memory for size of "<<SIZE<<endl; //exception need to be handled here!!
counter = 0;
}
template<class T>
bool mylist<T>::checksize()
{
return (counter < SIZE);
}
template<class T>
void mylist<T>::expand()
{
SIZE += LENGTH;
if ((flist = (T*)(realloc(flist, sizeof(T) * SIZE)))== NULL)
cout<<"Unable realloc memory for mylist of size "<<SIZE<<endl;
}
template<class T>
mylist<T>::mylist()
{
initialize();
}
This simple output result demonstrate the relation actually choose all elements from A as first
element in each pair, and elements from B as second in each pair by condition that first element
is bigger that second element:
Set name is 'this is 0' and data is: data no 0 is 41 Set name is 'this is 1' and data is: data no 0 is 17 Set name is 'this is 2' and data is: data no 0 is 34 Set name is 'this is 3' and data is: data no 0 is 40 Set name is 'this is 4' and data is: data no 0 is 89 Set name is 'this is 5' and data is: data no 0 is 64 Set name is 'this is 6' and data is: data no 0 is 48 Set name is 'this is 7' and data is: data no 0 is 18 Set name is 'this is 8' and data is: data no 0 is 52 Set name is 'this is 9' and data is: data no 0 is 74 Now show Set A Set name is 'this is set A' and data is: Set name is 'this is 0' and data is: data no 0 is 41 Set name is 'this is 1' and data is: data no 0 is 17 Set name is 'this is 2' and data is: data no 0 is 34 Set name is 'this is 3' and data is: data no 0 is 40 Set name is 'this is 4' and data is: data no 0 is 89 Set name is 'this is 5' and data is: data no 0 is 64 Set name is 'this is 6' and data is: data no 0 is 48 Now show Set B Set name is 'this is set B' and data is: Set name is 'this is 7' and data is: data no 0 is 18 Set name is 'this is 8' and data is: data no 0 is 52 Set name is 'this is 9' and data is: data no 0 is 74 pair no.0 is x is 89 y is 18 pair no.1 is x is 40 y is 18 pair no.2 is x is 34 y is 18 pair no.3 is x is 41 y is 18 pair no.4 is x is 48 y is 18 pair no.5 is x is 64 y is 52 pair no.6 is x is 64 y is 18 pair no.7 is x is 89 y is 74 pair no.8 is x is 89 y is 52
¡¡