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);
}