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 function 
pointer 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 forEachSet
can 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-back
function, 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

¡¡

                                                        back.gif (341 bytes)       up.gif (335 bytes)         next.gif (337 bytes)

Hosted by www.Geocities.ws

1