Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

mmap.cc

Go to the documentation of this file.
00001 
00025 #include "magic/mobject.h"
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <fstream>      // Needed by readStringMap, etc.
00029 #include "magic/mmap.h"
00030 #include "magic/mstream.h"
00031 #include "magic/mtextstream.h"
00032 #include "magic/mdatastream.h"
00033 #include "magic/mclass.h"
00034 
00035 BEGIN_NAMESPACE (MagiC);
00036 
00037 decl_module (map);
00038 
00039 // impl_dynamic (GenHash, {Object});
00040 
00041 
00042 
00044 //                                                                          //
00045 //                    |   |            ----        o                        //
00046 //                    |\ /|  ___   --  |   )  ___    | _                    //
00047 //                    | V |  ___| |  ) |---   ___| | |/                     //
00048 //                    | | | |   | |--  |     |   | | |                      //
00049 //                    |   |  \__| |    |      \__| | |                      //
00050 //                                                                          //
00052 
00053 impl_dynamic (MapPair, {Object});
00054 
00055 MapPair::~MapPair   () {
00056     delete key;
00057     key = NULL;
00058     if (!isref)
00059         delete value;
00060     value = NULL;
00061 }
00062 
00063 DataOStream& MapPair::operator>> (DataOStream& out) const {
00064     if (key)
00065         out.name("key") << *key;
00066     if (value)
00067         out.name("value") << *value;
00068     return out;
00069 }
00070 
00071 void MapPair::check () const {
00072     ASSERT (value!=(void*)0x1);
00073 }
00074 
00075 
00076 
00078 //                                                                          //
00079 //          |   |             |    ----              |                      //
00080 //          |   |  ___   ____ | _  |   )        ___  |    ___   |           //
00081 //          |---|  ___| (     |/ | |---  |   | |   \ | / /   ) -+-          //
00082 //          |   | |   |  \__  |  | |   ) |   | |     |/  |---   |           //
00083 //          |   |  \__| ____) |  | |___   \__! \___/ | \  \__    \          //
00084 //                                                                          //
00086 
00087 impl_dynamic (HashBucket, {Object});
00088 
00089 HashBucket::HashBucket  () {
00090     next=NULL;
00091 }
00092 
00093 HashBucket::~HashBucket () {
00094     delete next;
00095     next = NULL;
00096 }
00097 
00098 DataOStream& HashBucket::operator>> (DataOStream& out) const {
00099     out << pair;
00100     return out;
00101 }
00102 
00103 void HashBucket::check () const {
00104     pair.check ();
00105     if (next)
00106         next->check ();
00107 }
00108 
00109 
00110 
00112 //                                                                          //
00113 //                  ----             |   |             |                    //
00114 //                 |      ___    __  |   |  ___   ____ | _                  //
00115 //                 | --- /   ) |/  | |---|  ___| (     |/ |                 //
00116 //                 |   \ |---  |   | |   | |   |  \__  |  |                 //
00117 //                 |___/  \__  |   | |   |  \__| ____) |  |                 //
00118 //                                                                          //
00120 
00121 impl_dynamic (GenHash, {Object});
00122 
00123 void GenHash::make (HashFunc* hfunc, int hsize, int flags) {
00124     hashsize = hsize;
00125     hash.resize (hashsize);
00126     hashfunc = hfunc;
00127     isref = flags;
00128 }
00129 
00130 void GenHash::set (const Comparable* key, Object* value) {
00131     // Calculate the hash value of the key. This is a feature of
00132     // Comparable-inherited objects.
00133     int hval = key->hashfunc (hashsize);
00134 
00135     // Find the bucket according to the hash value
00136     HashBucket* bucket = hash.getp (hval);
00137 
00138     // If there is a bucket in that hash slot, add into it
00139     if (bucket)
00140         // As long as there is something in the bucket
00141         for (;bucket; bucket=bucket->next) {
00142             // Check if this is the matching bucket
00143             if (bucket->pair.match (*key)) {
00144                 // It existed. Wow.
00145                 delete bucket->pair.value;  // Replace the old value
00146                 delete key;                 // Dispose the excess key
00147                 break;
00148             }
00149     
00150             // That wasn't the right bucket. If there are no more
00151             // buckets, create a new one and exit the search
00152             if (!bucket->next) {
00153                 // Add the item to the new bucket
00154                 bucket->next = new HashBucket;  // Create new bucket
00155                 bucket = bucket->next;          // Move on to the new bucket
00156                 bucket->pair.key = key;         // Set the key
00157                 bucket->pair.isref = isref;     // Clone the global isref setting
00158                 break;
00159             }
00160         }
00161     else {
00162         // Add a new bucket in into the hash array
00163         hash.put (bucket = new HashBucket, hval);
00164         bucket->pair.key = key;
00165     }
00166 
00167     // Finally set the value
00168     bucket->pair.value = value;
00169 }
00170 
00171 const Object* GenHash::get (const Comparable& key) const throw (not_found) {
00172     for (const HashBucket* sanko = hash.getp (key.hashfunc(hashsize)); sanko; sanko=sanko->next) {
00173         ASSERT (sanko->pair.key != (void*)0x1);
00174         ASSERT (sanko->pair.value != (void*)0x1);
00175         if (sanko->pair.match (key))
00176             return sanko->pair.value;
00177     }
00178 
00179     return NULL;
00180 
00181     /*
00182     if (0) {
00183         // String-avaimet kerrotaan...
00184         if (key.is_a ("String")) {
00185             const String& skey = static_cast<const String&> (key);
00186             throw not_found (format ("CMap object not found with key '%s'", (CONSTR) skey));
00187         } else
00188             throw not_found ("CMap object not found with a key");
00189     } else {
00190         // Ilmoitetaan virheestä palauttamalla NULL
00191         return NULL;
00192     }   
00193     */
00194 }
00195 
00196 void GenHash::empty () {
00197     hash.empty ();
00198 }
00199 
00200 void GenHash::remove (const Comparable& key) {
00201     HashBucket* prev = NULL;
00202     int bucket = key.hashfunc (hashsize);
00203     for (HashBucket* sanko = hash.getp (bucket); sanko; sanko=sanko->next) {
00204         if (sanko->pair.match (key)) {
00205             if (prev) {
00206                 // Ei olla ensimmäinen
00207                 prev->next = sanko->next;
00208                 sanko->next = NULL;
00209                 delete sanko;
00210             } else {
00211                 // Ollaan ensimmäinen
00212 
00213                 if (sanko->next) {
00214                     // Perässä on muita
00215                     HashBucket* next = sanko->next;
00216                     sanko->next = NULL;
00217                     hash.put (next, bucket);
00218                     delete sanko;
00219                 } else {
00220                     // Ollaan ainoa
00221                     hash.remove (bucket);
00222                     // hash.empty ();
00223                 }
00224             }
00225             break;
00226         }
00227         prev = sanko;
00228     }
00229 }
00230 
00231 void GenHash::operator+= (const GenHash& other) {
00232     for (GenHashIter i (&other); !i.exhausted(); i.next())
00233         set (static_cast<Comparable*> (i.getkey().clone ()), i.getvalue().clone ());
00234 }
00235 
00236 DataOStream& GenHash::operator>> (DataOStream& out) const {
00237     out.name ("hashsize") << hashsize;
00238     out.name ("isref") << (int)isref;
00239     out.name ("hash") << hash;
00240     return out;
00241 }
00242 
00245 ostream& GenHash::operator>> (ostream& out) const
00246 {
00247     for (GenHashIter iter (this); !iter.exhausted(); iter.next())
00248         out << iter.getkey() << "=" << iter.getvalue() << "\n";
00249     return out;
00250 }
00251 
00254 TextOStream& GenHash::operator>> (TextOStream& out) const
00255 {
00256     for (GenHashIter iter (this); !iter.exhausted(); iter.next())
00257         out << iter.getkey() << "=" << iter.getvalue() << "\n";
00258     return out;
00259 }
00260 
00261 void GenHash::check () const {
00262     for (int i=0; i<hash.size(); i++)
00263         if (hash.getp(i)) // Check only non-null buckets
00264             hash[i].check (); // Check the bucket
00265 }
00266 
00267 
00268 
00269 /*******************************************************************************
00270  **                                                                           **
00271  **          ----            |   |             |    ---                       **
00272  **         |      ___    _  |   |  ___   ____ | _   |   |   ___  | _         **
00273  **         | --- /   ) |/ | |---|  ___| (     |/ |  |  -+- /   ) |/          **
00274  **         |   \ |---  |  | |   | |   |  \__  |  |  |   |  |---  |           **
00275  **         |___/  \__  |  | |   |  \__| ____) |  | _|_   \  \__  |           **
00276  **                                                                           **
00277 **/
00278 
00279 GenHashIter::GenHashIter (const GenHash* ghash) {
00280     hash = ghash;
00281     first ();
00282 }
00283 
00284 void GenHashIter::first () {
00285     bucket = 0;
00286     currbucket = NULL;
00287     exh = 0;
00288     next ();
00289 }
00290 
00291 void GenHashIter::next () {
00292     if (currbucket) {
00293         if ((currbucket = currbucket->next))
00294             return;
00295         else
00296             bucket++;
00297     }
00298     
00299     while (bucket < hash->hash.size() && (currbucket=(HashBucket*)(hash->hash.getp (bucket))) == NULL)
00300         bucket++;
00301 
00302     if (bucket >= hash->hash.size())
00303         exh = 1;
00304 }
00305 
00306 Comparable& GenHashIter::getkeyv () {
00307     if (currbucket)
00308         return const_cast<Comparable&> (*(currbucket->pair.key));
00309     else
00310         return *(Comparable*)NULL;
00311 }
00312 
00313 Object& GenHashIter::getvaluev () {
00314     if (currbucket)
00315         return *(currbucket->pair.value);
00316     else
00317         return *(Object*) NULL;
00318 }
00319 
00320 const Comparable& GenHashIter::getkey () const {
00321     if (currbucket)
00322         return *(currbucket->pair.key);
00323     else
00324         return *(const Comparable*) NULL;
00325 }
00326 
00327 const Object& GenHashIter::getvalue () const {
00328     if (currbucket)
00329         return *(currbucket->pair.value);
00330     else
00331         return *(const Object*) NULL;
00332 }
00333 
00334 
00335 
00337 //                                                                           //
00338 //                                                                           //
00339 //                                                                           //
00340 //                                                                           //
00341 //                                                                           //
00342 //                                                                           //
00343 //                                                                           //
00345 
00346 void splitpairs (CMap<String,String>& trg, const String& source,
00347                  char psep, char rsep) {
00348 
00349     // Tyhjennetään kakat pois
00350     trg.empty ();
00351     
00352     // Halkaistaan ensin kentät erilleen ja laitetaan väliaikaiseen vektoriin
00353     Array<String> tmp;
00354     source.split (tmp, rsep);
00355 
00356     // Käydään parit sisältävät merkkijonot läpi
00357     for (int i=0; i<tmp.size(); i++) {
00358         // Halkaistaan pari kahtia
00359         int pos = tmp[i].find (psep);
00360         String left = tmp[i].left (pos);
00361         String right = tmp[i].mid (pos+1);
00362         trg.set (left, right);
00363     }
00364 }
00365 
00366 String joinpairs (const CMap<String,String>& src, char psep, char rsep) {
00367     Array<String> arr;
00368     forStringMap (src, i)
00369         arr.add (new String (format ("%s%c%s", (CONSTR)i.key(), psep, (CONSTR)i.value())));
00370 
00371     String result;
00372     result.join (arr, rsep);
00373     return result;
00374 }
00375 
00376 // Print operation to string
00377 String toString (const StringMap& map) {
00378     String result = "{";
00379     bool first=true;
00380     forStringMap (map, i) {
00381         if (first)
00382             first = false;
00383         else
00384             result += ", ";
00385         result += i.key() + "=\042" + i.value() + "\042";
00386     }
00387     result += "}";
00388 
00389     return result;
00390 }
00391 
00392 
00393 
00395 //                ----         o             |   |                          //
00396 //               (      |          _         |\ /|  ___   --                //
00397 //                ---  -+- |/\ | |/ \   ___  | V |  ___| |  )               //
00398 //                   )  |  |   | |   | (   \ | | | (   | |--                //
00399 //               ___/    \ |   | |   |  ---/ |   |  \__| |                  //
00400 //                                      __/                                 //
00402 
00403 StringMap readStringMap (const String& filename) {
00404     TextIStream in (new File (filename));
00405     if (!in)
00406         throw file_not_found (strformat ("Could not open file '%s' for reading StringMap",
00407                                          (CONSTR) filename));
00408 
00409     // Determine current path
00410     String path = "./";
00411     if (filename.findRev("/") != -1)
00412         path = filename.mid (0, filename.findRev("/")+1);
00413 
00414     // Call stream reader function
00415     return readStringMap (in, path);
00416 }
00417 
00418 StringMap readStringMap (TextIStream& in, const char* path) {
00419     StringMap result;
00420     String paramStr;
00421     String section;
00422     String buffer;
00423     Array<String> regpar;
00424     Array<String> pair;     // Key-value pair
00425 
00426     while (in.readLine (buffer)) {
00427         buffer.chop(); // Cleanup trailing whitespaces
00428 
00429         // Map definition can be terminated with this special
00430         // row. Case sensitive.
00431         if (buffer == "# end-of-map")
00432             break;
00433 
00434         if (buffer.regmatch ("^INCLUDE\\:? *(.+)", regpar)) {
00435             // Include file directive. Determine path.
00436             String curPath="./";
00437             if (path)
00438                 curPath = path;
00439 
00440             // Read the include file recursively
00441             result += readStringMap (curPath+regpar[1]);
00442 
00443         } else if (buffer.regmatch ("^\\[([a-zA-Z0-9]*)\\]", regpar)) {
00444             // Section name line
00445             section = (regpar[1]=="]")? String():regpar[1];
00446 
00447         } else if (buffer.regmatch ("^[ \t]*\\#")) {
00448             // Comment line, bypass
00449             continue;
00450         } else {
00451             // Check if key=value pair
00452             buffer.split (pair, '=');
00453             if (pair.size() == 2) {
00454                 // Cleanup key and value
00455                 pair[0].chop();
00456                 pair[1].chop();
00457 
00458                 // If neither is empty, add to map
00459                 if (!isempty(pair[0]) && !isempty(pair[1])) {
00460                     // Add section prefix to key
00461                     if (!isempty(section))
00462                         pair[0] = section+"."+pair[0];
00463                     result.set (pair[0], pair[1]); // Add to map
00464                 }
00465             } else {
00466                 // Unknown line
00467             }
00468         }
00469     } // while not EOF
00470     
00471     return result;
00472 }
00473 
00474 void writeStringMap (const StringMap& map, TextOStream& out)
00475 {
00476     // TODO: Handle sectioning correctly
00477     
00478     // Write everything under the default section
00479     out << "[]\n";
00480     
00481     forStringMap (map, mapi)
00482         out << mapi.key() << "=" << mapi.value() << "\n";
00483 }
00484 
00485 
00486 END_NAMESPACE;
00487 

Generated on Thu Feb 10 20:06:42 2005 for LibMagiC by doxygen1.2.18