Main Page   Class Hierarchy   Compound List   File List   Compound Members  

mmap.cc

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

Generated at Tue Dec 4 19:53:26 2001 for MagiC++ by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001