// ASSOCIATION Class Template // -------------------------- // // This is a class template for implemeting many-to-many associations. // For an association between two arbitrary classes C1 and C2, it stores // the links (obj1, obj2) and attributes with each link for the association, // where obj1 and obj2 are pointers to objects of C1 and C2, respectively. // To instantiate a association class for the association between // class X and class Y with class A as the attributes class, declare // typedef ASSOCIATION Association; // (Note that this is actually an aggregate of an association.) // Then declare // Association assoc; // in order to create an object (of the aggregate of the association). // The template provides the following functions: // // void add_link( C1 *, C2 *, ATTRIBUTES ); // void add_link( C1 *, C2 * ); // void update_attributes(C1 *, C2 *, ATTRIBUTES ); // void remove_link( C1 * o1, C2 * o2 ); remove the link (o1, o2) // void remove_links1( C1 * o1 ); remove all links to o1 // void remove_links2( C2 * o2 ); remove all links to o2 // int is_link( C1 * o1, C2 * o2 ); is (o1, o2) a link? // int how_many_links1( C1 * o1 ); return the # of links to o1 // int how_many_links2( C2 * o2 ); return the # of links to o2 // C2 * the_ith_link1( C1 * o1, int i ); return the ith object linked to o1 // C1 * the_ith_link2( C2 * o2, int i ); return the ith object linked to o2 // ATTRIBUTES attributes( C1 *, C2 * ); return the attributes of the link // If you add a line // #define TEST // before the inclusion of this file, the template also provide the function // void print_all(); // for testing purpose. However, if you use this print function, you have // to make sure that all the substituting classes, e.g., X, Y, and A, should // have a public member function "print()". // For a sample usage, see "assoc_test.C". // --------------------------------------------------------------------------- // Author: S. Yu // Last modified: Jan 31, 1997 at 2:30am #define FALSE 0 #define TRUE 1 #define null 0 // This is the class template for a LINK // template class LINK { public: C1 * p_object1; // pointer to the first object of the link C2 * p_object2; // pointer to the second object of the link ATTRIBUTES attributes; // attributes of the link }; // This is the class template for an item in a set of LINKs // template class ASSOC_ITEM : public LINK { public: ASSOC_ITEM * next; ASSOC_ITEM * pre; ASSOC_ITEM(C1 *, C2 *, ATTRIBUTES ); // constructor ASSOC_ITEM(C1 *, C2 * ); // constructor ASSOC_ITEM(); // constructor }; // This is the class template for a many-to-many association // (an aggregate of links from the association, more precisely). // template class ASSOCIATION { ASSOC_ITEM * head; ASSOC_ITEM * tail; ASSOC_ITEM * search( C1 *, C2 * ); public: ASSOCIATION(); // constructor ~ASSOCIATION(); // destructor void add_link( C1 *, C2 *, ATTRIBUTES ); void add_link( C1 *, C2 * ); void update_attributes(C1 *, C2 *, ATTRIBUTES ); void remove_link( C1 *, C2 * ); void remove_links1( C1 * ); // remove all links to a C1 object void remove_links2( C2 * ); // remove all links to a C2 object int is_link( C1 *, C2 * ); int how_many_links1( C1 * ); // return the # of links to a C1 object int how_many_links2( C2 * ); // return the # of links to a C2 object C2 * the_ith_link1( C1 *, int i ); // return the ith C2 object linked to // the given C1 object C1 * the_ith_link2( C2 *, int i ); // return the ith C1 object linked to // the given C2 object ATTRIBUTES attributes( C1 *, C2 * );// return the attributes of the link #ifdef TEST void print_all(); // print all links #endif }; // Member function definitions for the class template ASSOC_ITEM // ------------------------------------------------------------- template // the first constructor ASSOC_ITEM:: ASSOC_ITEM(C1 * p1, C2 * p2, ATTRIBUTES attrs) { p_object1 = p1; p_object2 = p2; attributes = attrs; } template // the second constructor ASSOC_ITEM:: ASSOC_ITEM(C1 * p1, C2 * p2) { p_object1 = p1; p_object2 = p2; } template // the third constructor ASSOC_ITEM::ASSOC_ITEM() { p_object1 = null; p_object2 = null; } // Member function definitions for the class template ASSOCIATION // -------------------------------------------------------------- template // constructor ASSOCIATION::ASSOCIATION() { head = new ASSOC_ITEM; tail = new ASSOC_ITEM; head->next = tail; tail->pre = head; head->pre = tail->next = null; } template // destructor ASSOCIATION::~ASSOCIATION() { ASSOC_ITEM * current, * next; current = head->next; next = current->next; while (current != tail) { delete current; current = next; next = next->next; } } template ASSOC_ITEM * ASSOCIATION::search( C1 * p_obj1, C2 * p_obj2 ) { ASSOC_ITEM * p; int found = FALSE; for (p = head->next; (p != tail) && (found==FALSE); p = p->next) found = (p->p_object1 == p_obj1) && (p->p_object2 == p_obj2 ); if (found) return p->pre; else return null; } template void ASSOCIATION:: add_link( C1 * obj1, C2 * obj2, ATTRIBUTES attrs ) { ASSOC_ITEM * p; p = search( obj1, obj2 ); if (p == null) { p = new ASSOC_ITEM(obj1,obj2,attrs); p->pre = tail->pre; p->next = tail; tail->pre->next = p; tail->pre = p; } else cerr << "Link already exists. Addition fails.\n"; } template void ASSOCIATION:: add_link( C1 * obj1, C2 * obj2 ) { ASSOC_ITEM * p; p = search( obj1, obj2 ); if (p == null) { p = new ASSOC_ITEM(obj1,obj2); p->pre = tail->pre; p->next = tail; tail->pre->next = p; tail->pre = p; } else cerr << "Link already exists. Addition fails.\n"; } template void ASSOCIATION:: update_attributes( C1 * obj1, C2 * obj2, ATTRIBUTES attrs ) { ASSOC_ITEM * p; p = search( obj1, obj2 ); if (p != null) { p->attributes = attrs; } else cerr << "Link does not exist. \n"; } template // remove the link (obj1, obj2) void ASSOCIATION:: remove_link( C1 * obj1, C2 * obj2 ) { ASSOC_ITEM * p; p = search( obj1, obj2 ); if (p != null) { p->next->pre = p->pre; p->pre->next = p->next; delete p; } else cerr << "Link does not exits!\n"; } template // remove all links (obj1, *) void ASSOCIATION:: remove_links1( C1 * obj1 ) { ASSOC_ITEM * p, * temp; for (p = head->next; (p != tail); p = p->next) if (obj1 == p->p_object1) { temp = p; p = p->pre; temp->next->pre = p; p->next = temp->next; delete temp; } } template // remove all links (*, obj2) void ASSOCIATION:: remove_links2( C2 * obj2 ) { ASSOC_ITEM * p, * temp; for (p = head->next; (p != tail); p = p->next) if (obj2 == p->p_object2) { temp = p; p = p->pre; temp->next->pre = p; p->next = temp->next; delete temp; } } template // is (obj1, obj2) a link? int ASSOCIATION:: is_link( C1 * obj1, C2 * obj2 ) { return (search( obj1, obj2 ) != null); } template // # of links with obj1 int ASSOCIATION:: how_many_links1( C1 * obj1 ) { int how_many = 0; ASSOC_ITEM * p; for (p = head->next; (p != tail); p = p->next) if (obj1 == p->p_object1) how_many++; return how_many; } template // # of links with obj2 int ASSOCIATION:: how_many_links2( C2 * obj2 ) { int how_many = 0; ASSOC_ITEM * p; for (p = head->next; (p != tail); p = p->next) if (obj2 == p->p_object2) how_many++; return how_many; } template // return the ith C2 object C2 * ASSOCIATION:: // that linked to obj1 the_ith_link1( C1 * obj1, int i ) { int j = 0; ASSOC_ITEM * p; for (p = head->next; (p != tail); p = p->next) if (obj1 == p->p_object1) if (++j == i) return p->p_object2; cerr << "The " << i <<"th link does not exists!\n"; return null; } template // return the ith C1 object C1 * ASSOCIATION:: // that linked to obj2 the_ith_link2( C2 * obj2, int i ) { int j = 0; ASSOC_ITEM * p; for (p = head->next; (p != tail); p = p->next) if (obj2 == p->p_object2) if (++j == i) return p->p_object1; cerr << "The " << i <<"th link does not exists!\n"; return null; } template // return the attributes of ATTRIBUTES ASSOCIATION:: // the link (obj1, obj2) attributes( C1 * obj1, C2 * obj2 ) { ASSOC_ITEM * p; p = search( obj1, obj2 ); if (p != null) return p->attributes; else cerr << "Link does not exists! \n"; } #ifdef TEST template void ASSOCIATION::print_all() { ASSOC_ITEM * p; for (p = head->next; p != tail; p = p->next) { p->p_object1->print(); cout << " <-> "; p->p_object2->print(); cout << " <-attribute-> "; p->attributes.print(); cout << '\n'; cout.flush(); } } #endif