/* * Copyright (c) 1987, 1988, 1989 Stanford University * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Stanford not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Stanford makes no representations about * the suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Object tables are implemented by hashing resolved by chaining. */ #include #include /* * Create a new table of (at least) a given size. * * To make hashing faster, the size is rounded up to the next power of 2 and * then decremented so it can be used as a mask. */ ObjectTable::ObjectTable (int n) { nelements = 128; while (nelements < n) { nelements <<= 1; } first = new ObjectTableEntry*[nelements]; memset(first, 0, nelements * sizeof(ObjectTableEntry*)); --nelements; last = &first[nelements]; } ObjectTable::~ObjectTable () { delete first; } unsigned ObjectTable::Hash (Connection* c, ObjectTag t) { return ((((unsigned) c) >> 2) ^ (t >> 2)) & nelements; } ObjectTableEntry* ObjectTable::Start (Connection* c, ObjectTag t) { return first[Hash(c, t)]; } ObjectTableEntry** ObjectTable::StartAddr (Connection* c, ObjectTag t) { return &first[Hash(c, t)]; } bool ObjectTableEntry::Match (Connection* c, ObjectTag t) { return client == c && id == t; } /* * Add an object into the table. */ void ObjectTable::Add (Connection* c, ObjectTag t, ObjectStub* s) { register ObjectTableEntry* e; register ObjectTableEntry** a; e = new ObjectTableEntry; e->client = c; e->id = t; e->ref = s; a = StartAddr(c, t); e->chain = *a; *a = e; } /* * Find an object in the table. * If found return a pointer to the object, otherwise return nil. */ ObjectStub* ObjectTable::Find (Connection* c, ObjectTag t) { register ObjectTableEntry* e; for (e = Start(c, t); e != nil; e = e->chain) { if (e->Match(c, t)) { return e->ref; } } return nil; } /* * Remove an object from the table. */ void ObjectTable::Remove (Connection* c, ObjectTag t) { register ObjectTableEntry* e; register ObjectTableEntry* prev; register ObjectTableEntry** a; a = StartAddr(c, t); e = *a; if (e->Match(c, t)) { *a = e->chain; } else { do { prev = e; e = e->chain; } while (e != nil && !e->Match(c, t)); if (e != nil) { prev->chain = e->chain; delete e; } } } /* * Remove all the objects associated with a given connection. */ void ObjectTable::RemoveAll (Connection* c) { register ObjectTableEntry** i; register ObjectTableEntry* e; register ObjectTableEntry* next; register ObjectTableEntry* prev; for (i = first; i <= last; i++) { prev = nil; for (e = *i; e != nil; e = next) { next = e->chain; if (e->client == c) { if (prev == nil) { *i = e->chain; } else { prev->chain = e->chain; } Unref(e->ref); delete e; } } } }