Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

Dictionary.cc

Go to the documentation of this file.
00001 /*
00002  * Dictionary.cc
00003  *
00004  * Smalltalk like class library for C++
00005  * Growable collection of key-value pairs, not index-accessible.
00006  *
00007  * Copyright (c) 2003 Milan Cermak
00008  */
00009 /*
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  */
00024 #include <stlib/Dictionary.h>
00025 #include <stlib/Association.h>
00026 #include <stlib/Array.h>
00027 #include <stlib/KAVIterator.h>
00028 #include <stlib/String.h>
00029 #include <stlib/Visitor.h>
00030 
00031 #include <stlib/KeyNotFoundError.h>
00032 #include <stlib/ValueNotFoundError.h>
00033 #include <stlib/SOOBoundsError.h>
00034 
00035 Dictionary::Dictionary(int length)
00036   : Set(length)
00037 {
00038 }
00039 
00040 /* Class-accessing protocol */
00041 String *Dictionary::className(void) const
00042 {
00043     return new String("Dictionary");
00044 }
00045 
00046 /* Accessing protocol */
00047 Object *Dictionary::at(Object *key)
00048 {
00049     long index;
00050     Association *obj;
00051 
00052     index = findKeyOrNil(key);
00053     obj = (Association *) content->at(index);
00054     if (obj == nil)
00055         (new KeyNotFoundError(__PRETTY_FUNCTION__, key))->raiseFrom(this);
00056     return obj->value();
00057 }
00058 
00059 Object *Dictionary::at(Object *key, Object *ifAbsentValue)
00060 {
00061     long index;
00062     Association *obj;
00063 
00064     index = findKeyOrNil(key);
00065     obj = (Association *) content->at(index);
00066     if (obj == nil)
00067         return ifAbsentValue;
00068     return obj->value();
00069 }
00070 
00071 Object *Dictionary::at(const char *key) {
00072     return at(new String(key));
00073 }
00074 
00075 Object *Dictionary::at(const char* key, const char *ifAbsentValue) {
00076     return at(new String(key), (ifAbsentValue == nil ? nil : new String(ifAbsentValue)));
00077 }
00078 
00079 void Dictionary::put(Object *key, Object *value)
00080 {
00081     long index;
00082     Association *element;
00083 
00084     if (key == nil)
00085         (new SubscriptOutOfBoundsError(__PRETTY_FUNCTION__, 0))->raiseFrom(this);
00086     index = findKeyOrNil(key);
00087     element = (Association *) content->at(index);
00088     if (element == nil) atNewIndexPut(index, new Association(key, value));
00089                    else element->value(value);
00090 }
00091 
00092 void Dictionary::put(const char* key, Object* value) {
00093     put(new String(key), value);
00094 }
00095 
00096 void Dictionary::put(const char* key, const char* value) {
00097     put(new String(key), new String(value));
00098 }
00099 
00100 Object *Dictionary::keyAtValue(Object *value)
00101 {
00102     for (KeysAndValuesIterator i(this); !i.finished(); i.next()) {
00103         if (i.value()->isEqual(value))
00104             return i.key();
00105     }
00106     (new ValueNotFoundError(__PRETTY_FUNCTION__, value))->raiseFrom(this);
00107 }
00108 
00109 Object *Dictionary::keyAtValue(Object *value, Object *ifAbsentKey)
00110 {
00111     Object *obj;
00112 
00113     try {
00114         obj = keyAtValue(value);
00115     }
00116     catch (ValueNotFoundError *ex) {
00117         obj = ifAbsentKey;
00118     }
00119     return obj;
00120 }
00121 
00122 /* Adding protocol */
00123 void Dictionary::add(Object *assoc)
00124 {
00125     long index;
00126     Object *assocKey;
00127     Association *element;
00128 
00129     if (!assoc->isAssociation() ||
00130         (assocKey = ((Association *) assoc)->key()) == nil)
00131         (new SubscriptOutOfBoundsError(__PRETTY_FUNCTION__, 0))->raiseFrom(this);
00132     index = findKeyOrNil(assocKey);
00133     element = (Association *) content->at(index);
00134     if (element == nil) atNewIndexPut(index, assoc);
00135                    else element->value(((Association *)assoc)->value());
00136 }
00137 
00138 /* Copying protocol */
00139 Object *Dictionary::copy(void)
00140 {
00141     return new Dictionary(*this);
00142 }
00143 
00144 Object *Dictionary::copyEmpty(long size)
00145 {
00146     return new Dictionary(size);
00147 }
00148 
00149 /* Enumeration protocol */
00150 KeysAndValuesIterator *Dictionary::keysAndValuesIterator(void) const
00151 {
00152     return new KeysAndValuesIterator(this);
00153 }
00154 
00155 /* Removing protocol */
00156 Object *Dictionary::remove(Object *)
00157 {
00158     shouldNotImplement(new String(__PRETTY_FUNCTION__));
00159     return nil;
00160 }
00161 
00162 Object *Dictionary::removeKey(Object *key)
00163 {
00164     long index;
00165     Association *element;
00166 
00167     index = findKey(key);
00168     element = (Association *) content->at(index);
00169     content->put(index, nil);
00170     tally = tally - 1;
00171     fixCollisionsFrom(index);
00172     return element->value();
00173 }
00174 
00175 /* Testing protocol */
00176 bool Dictionary::includes(Object *obj)
00177 {
00178     return Collection::includes(obj);
00179 }
00180 
00181 bool Dictionary::includesKey(Object *key)
00182 {
00183     return content->at(findKeyOrNil(key)) != nil;
00184 }
00185 
00186 /* Visiting protocol */
00187 void Dictionary::visitBy(Visitor *visitor)
00188 {
00189     visitor->visitDictionary(this);
00190 }
00191 
00192 /* Private protocol */
00193 void Dictionary::changeCapacity(long newCapacity)
00194 {
00195     Array *oldContent;
00196     Iterator *i;
00197 
00198     oldContent = content;
00199     content = new Array(newCapacity);
00200     tally = 0;
00201     for (i = oldContent->iterator(); !i->finished(); i->next()) {
00202         if (i->value() != nil)
00203             noCheckAdd((Association *) i->value());
00204     }
00205     delete i;
00206     delete oldContent;
00207 }
00208 
00209 int Dictionary::findKey(Object *key)
00210 {
00211     int index;
00212 
00213     index = findKeyOrNil(key);
00214     if (content->at(index) == nil)
00215         (new KeyNotFoundError(__PRETTY_FUNCTION__, key))->raiseFrom(this);
00216     return index;
00217 }
00218 
00219 int Dictionary::findKeyOrNil(Object *key)
00220 {
00221     int pass, length = capacity();
00222     Association *elem;
00223     int index;
00224 
00225     index = key->hash() % length;
00226     /* Unfortunately, result of modulo can be negative */
00227     if (index < 0) index = length + index;
00228     pass = 1;
00229     while ((elem = (Association *) content->at(index)) != nil &&
00230            !elem->key()->isEqual(key)) {
00231         index++;
00232         if (index >= length) {
00233             index = 0;
00234             pass++;
00235             if (pass > 2) {
00236                 grow();
00237                 return findKeyOrNil(key);
00238             }
00239         }
00240     }
00241     return index;
00242 }
00243 
00244 void Dictionary::fixCollisionsFrom(int oldIndex)
00245 {
00246     int length, nextIndex;
00247     Association *nextObject = nil;
00248 
00249     length = capacity();
00250     nextIndex = oldIndex;
00251     do {
00252         if (nextIndex != oldIndex) {
00253             content->put(nextIndex, nextObject);
00254             content->put(oldIndex, nil);
00255         }
00256         oldIndex = (oldIndex + 1) % length;
00257         nextObject = (Association *) content->at(oldIndex);
00258         if (nextObject != nil)
00259             nextIndex = findKeyOrNil(nextObject->key());
00260     } while (nextObject != nil);
00261 }
00262 
00263 void Dictionary::noCheckAdd(Association *object)
00264 {
00265     content->put(findKeyOrNil(object->key()), object);
00266     tally = tally + 1;
00267 }

Generated on Mon Nov 27 09:47:55 2006 for Smalltalk like C++ Class Library by  doxygen 1.4.2