STL.cpp


// Problem definition by Eli Tilevich:

// Well,  I guess I would like to code a simple registration system with a very
// limited functionality which
// would only allow students register for classes, cancel classes, and delete
// students from the system.
// Basically, it would be something very similar to test18e.c; however I would
// like to specifically concentrate on
// handling the many-to-many relation between students and classes. I would
// like to answer the question of which
// facilities in different class libraries help the programmer handle this
// non-trivial software paradigm.
// --------------------------------------------------------------------------

// Program coded by Eli Tilevich, Nov.28/99


#include <stdio.h>
#include <string.h>
#include <time.h>
#include <list>
#include <algorithm>
#include <Vector>

#define EQ_STR(s1, s2) (strcmp(s1, s2) == 0)

using namespace std;

long  starttime;

#define TASK(s)    printf("%s", s);
#define CIN        starttime = clock();
#define COUT       printf("%d\t", clock()-starttime);
#define NL         printf("\n")

class Student;
class Class;
class Takes;

typedef list <Student*> Student_list;
typedef list <Class*>   Class_list;
typedef list <Takes*>   Takes_list;

// School encapsulates your problem
class School {

Student_list	lstStudents;
Class_list		lstClasses;
Takes_list		lstSC;

public:
    
	static char *getName(int i,char *buf);

	Class* add_class(const char * name);
	
	Student * add_student(const char * name);

	Student * find_student(const char * name);

	void list_student_classes(Student * sp);

	Takes* find_student_class(const Student *sp, const char * class_name);
	

	Class* find_class(const char * name);

	void add_student_class(Student * sp, Class * cp);

	void delete_student_class(Takes * tp);

	void delete_student(Student * sp);



};


class Student {
   
char strName[1<<5];
public:
    Student(const char *name){
		strcpy(strName, name);
	
	}
	const char * GetName() const { return strName; }
};

class Class {

char strName[1<<5];
public:
    Class(const char *name){
		strcpy(strName, name);
	
	}
	const char * GetName() const { return strName; }
};

class Takes {
    int mark;
    int absentDays;
	Student *sp;
	Class	*cp;
    
public:
	Takes(Student *s = 0, Class *c = 0) : sp(s), cp(c) {}

    Student * GetStudent() const { return sp; }
	Class * GetClass() const { return cp; }

    int addAbsent(int d){absentDays+=d; return absentDays;} // for d=0 reports
    int getMark(){return mark;}
    void setMark(int m){mark=m;}
};



class same_Student{

Student * sp;
public:
	same_Student(Student * s) : sp(s) {}
	same_Student(const same_Student & other) : sp(other.sp) {}

	inline bool operator () (Takes * tp){
		return EQ_STR(tp->GetStudent()->GetName(),
			   	      sp->GetName());
	}




};


// pick up names including spaces, if i>0 skip the first word
char* School::getName(int i,char *buf){
    char *p;
    for(p=buf; *p!='\n'; p++)continue;
    *p='\0'; // mark the end of the name
    if(i==0)return buf;
    for(p=buf; *p!='\0' && *p!=' '; p++)continue;
    if(*p=='\0')return p;
    for( ;*p==' ' && *p!='\0'; p++);
    return p;
}



Student * School::add_student(const char * name){

	printf("new student=%s\n",name);
    Student * sp=new Student(name);
    lstStudents.push_back(sp);
		
	return sp;
}
	
Class * School::add_class(const char * name){
	
	//printf("... new class\n");
    Class * cp=new Class(name);
    lstClasses.push_back(cp);

	return cp;
	
}


template <class T>
class eq_name{
	
	char strName[1<<5];
	
public:
	eq_name(const char * lpcsName){
		strcpy(strName, lpcsName);
	}

	bool operator () (T * sp){
		return EQ_STR(sp->GetName(), strName);
	}
};

Student * School::find_student(const char * name){
        
	eq_name <Student> en(name);

	Student_list::const_iterator i =
	find_if(lstStudents.begin(), lstStudents.end(), en);

	return (i == lstStudents.end()) ? NULL : *i;
	
}

class Print_Classes{
Student *sp;

public:

Print_Classes(Student *p) : sp(p) {}
inline void operator() (Takes * tp){
  if(EQ_STR(tp->GetStudent()->GetName(), sp->GetName()))
     printf("%s\n", tp->GetClass()->GetName());
}

};

void School::list_student_classes(Student * sp){

	
	printf("%s is enrolled in:\n", sp->GetName());
	Print_Classes pc(sp);
	for_each(lstSC.begin(), lstSC.end(), pc);
}


class same_Class{

const Student * sp;
char class_name[1<<5];

public:
same_Class(const Student *s, const char* name) : sp(s) {
	strcpy(class_name, name);
}

bool operator() (Takes * tp){
return 	(EQ_STR(tp->GetStudent()->GetName(), sp->GetName()) &&
		 EQ_STR(tp->GetClass()->GetName(), class_name));

}

};

Takes* School::find_student_class(const Student *sp, const char * class_name){
   same_Class sc(sp, class_name);
   Takes_list::iterator i = find_if(lstSC.begin(), lstSC.end(), sc);    

    return (i == lstSC.end()) ? NULL : *i;

}



Class * School::find_class(const char * name){

	eq_name <Class> en(name);
	
	Class_list::const_iterator i =
	find_if(lstClasses.begin(), lstClasses.end(), en);

	return (i == lstClasses.end()) ? NULL : *i;

}


void School::add_student_class(Student * sp, Class * cp){
	
	Takes * tp = new Takes(sp, cp);

	lstSC.push_back(tp);


}


void School::delete_student_class(Takes * tp){
	
	lstSC.remove(tp);
	delete tp;
}




template <class Cont>
class erase_elem{

	Cont & cont;
public:
	erase_elem(Cont& c) : cont(c) {}
	
	inline void operator () (Cont::iterator it){
		cont.erase(it);
		delete *it;
	
	} 

};


template <class FwdIt, class Pred, class Pred1>
void real_remove_if(FwdIt first, FwdIt last, Pred pr, Pred1 destroy_pr){

FwdIt i = remove_if(first, last, pr);

while(i != last){

    FwdIt del = i ;
    i++; 
    
	destroy_pr(del);
	
}


}



void pr(Takes * tp){
printf("%s - %s\n", tp->GetStudent()->GetName(), tp->GetClass()->GetName());

}

void School::delete_student(Student * sp){

TASK("Timing School::delete_student() STL implementation\n");
CIN;
	
	// delete all class links of this student
    erase_elem <Takes_list> ee(lstSC);
    same_Student ss(sp);
	real_remove_if(lstSC.begin(), lstSC.end(), ss, ee);
			
	//delete student
	lstStudents.remove(sp);
	delete sp;

COUT;
NL;

}



#define BSIZE 80
char buff[BSIZE];

main(int argc,char **argv) {
    
	School *school; Student *sp; Takes *tp; Class *cp;
    char *name,cc;

    school=new School;
    
	for(;;){
        printf("type your name:\n");
        fgets(buff,BSIZE,stdin);
        name=school->getName(0,buff);
        if(!strcmp(name,"STOP"))break;
		
		sp = school->find_student(name);
        
        if(sp){
           
			if(strcmp(name, "eli") != 0)
				school->list_student_classes(sp);
		
		}
        else {
            sp = school->add_student(name);
	
			//Generate test data for timing
			if(strcmp(name, "eli") == 0){
				
				char class_name[1<<5];               
                for(int cl = 0; cl < 100000; cl ++){
					sprintf(class_name, "CS%d", cl);
				    cp = school->add_class(class_name);
                    school->add_student_class(sp, cp);
									
				}
            			
			}
       
        }
        for(;;){
            printf("menu(A className,D className,R=remove student,E=exit):\n");
            fgets(buff,BSIZE,stdin);
            sscanf(buff,"%c",&cc);
            name = school->getName(1,buff);
            if(cc=='A'){
                // first check that this student isn't already registered there
                tp = school->find_student_class(sp, name);
				if(tp){ printf("... you are already registered\n"); continue;}

                // find the class
                cp = school->find_class(name);
				if(!cp){
                    cp = school->add_class(name);
                }
                school->add_student_class(sp, cp);
            }
            else if(cc=='D'){
                tp = school->find_student_class(sp, name);
                if(!tp){
                    printf(" you are not registered for this class\n");
                    continue;
                }
                school->delete_student_class(tp);
            }
            else if(cc=='R'){
				school->delete_student(sp);
                break;
            }
            else if(cc=='E')break;
            else printf("unknown command=%c\n",cc);
        }
    }

    return(0);
}