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
¡¡