00001
00025 #include "magic/mobject.h"
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <fstream>
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
00040
00041
00042
00044
00045
00046
00047
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
00132
00133 int hval = key->hashfunc (hashsize);
00134
00135
00136 HashBucket* bucket = hash.getp (hval);
00137
00138
00139 if (bucket)
00140
00141 for (;bucket; bucket=bucket->next) {
00142
00143 if (bucket->pair.match (*key)) {
00144
00145 delete bucket->pair.value;
00146 delete key;
00147 break;
00148 }
00149
00150
00151
00152 if (!bucket->next) {
00153
00154 bucket->next = new HashBucket;
00155 bucket = bucket->next;
00156 bucket->pair.key = key;
00157 bucket->pair.isref = isref;
00158 break;
00159 }
00160 }
00161 else {
00162
00163 hash.put (bucket = new HashBucket, hval);
00164 bucket->pair.key = key;
00165 }
00166
00167
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
00183
00184
00185
00186
00187
00188
00189
00190
00191
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
00207 prev->next = sanko->next;
00208 sanko->next = NULL;
00209 delete sanko;
00210 } else {
00211
00212
00213 if (sanko->next) {
00214
00215 HashBucket* next = sanko->next;
00216 sanko->next = NULL;
00217 hash.put (next, bucket);
00218 delete sanko;
00219 } else {
00220
00221 hash.remove (bucket);
00222
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))
00264 hash[i].check ();
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
00350 trg.empty ();
00351
00352
00353 Array<String> tmp;
00354 source.split (tmp, rsep);
00355
00356
00357 for (int i=0; i<tmp.size(); i++) {
00358
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
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
00396
00397
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
00410 String path = "./";
00411 if (filename.findRev("/") != -1)
00412 path = filename.mid (0, filename.findRev("/")+1);
00413
00414
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;
00425
00426 while (in.readLine (buffer)) {
00427 buffer.chop();
00428
00429
00430
00431 if (buffer == "# end-of-map")
00432 break;
00433
00434 if (buffer.regmatch ("^INCLUDE\\:? *(.+)", regpar)) {
00435
00436 String curPath="./";
00437 if (path)
00438 curPath = path;
00439
00440
00441 result += readStringMap (curPath+regpar[1]);
00442
00443 } else if (buffer.regmatch ("^\\[([a-zA-Z0-9]*)\\]", regpar)) {
00444
00445 section = (regpar[1]=="]")? String():regpar[1];
00446
00447 } else if (buffer.regmatch ("^[ \t]*\\#")) {
00448
00449 continue;
00450 } else {
00451
00452 buffer.split (pair, '=');
00453 if (pair.size() == 2) {
00454
00455 pair[0].chop();
00456 pair[1].chop();
00457
00458
00459 if (!isempty(pair[0]) && !isempty(pair[1])) {
00460
00461 if (!isempty(section))
00462 pair[0] = section+"."+pair[0];
00463 result.set (pair[0], pair[1]);
00464 }
00465 } else {
00466
00467 }
00468 }
00469 }
00470
00471 return result;
00472 }
00473
00474 void writeStringMap (const StringMap& map, TextOStream& out)
00475 {
00476
00477
00478
00479 out << "[]\n";
00480
00481 forStringMap (map, mapi)
00482 out << mapi.key() << "=" << mapi.value() << "\n";
00483 }
00484
00485
00486 END_NAMESPACE;
00487