libStatGen Software  1
StringMap.cpp
00001 /*
00002  *  Copyright (C) 2010  Regents of the University of Michigan
00003  *
00004  *   This program is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #include "StringMap.h"
00019 
00020 int StringMap::alloc = 8;
00021 
00022 StringMap::StringMap(int startsize)
00023 {
00024     count = 0;
00025     size = (startsize + alloc) / alloc * alloc;
00026     strings = new ::String * [size];
00027     objects = new void * [size];
00028 };
00029 
00030 StringMap::~StringMap()
00031 {
00032     for (int i = 0; i < count; i++)
00033         delete strings[i];
00034     delete [] strings;
00035     delete [] objects;
00036 }
00037 
00038 void StringMap::Grow(int newsize)
00039 {
00040     if (newsize >= size)
00041     {
00042         if ((newsize >> 1) >= size)
00043             size = (newsize + alloc) / alloc * alloc;
00044         else
00045         {
00046             size = alloc;
00047             while (size <= newsize)
00048                 size *= 2;
00049         }
00050 
00051         size = (newsize + alloc) / alloc * alloc;
00052 
00053         ::String ** newStrings = new ::String * [size];
00054         void     ** newObjects = new void * [size];
00055 
00056         for (int i = 0; i < count; i++)
00057         {
00058             newStrings[i] = strings[i];
00059             newObjects[i] = objects[i];
00060         }
00061 
00062         delete [] strings;
00063         delete [] objects;
00064 
00065         strings = newStrings;
00066         objects = newObjects;
00067     }
00068 }
00069 
00070 int StringMap::Add(const ::String & key, void * object)
00071 {
00072     if (count == 0)
00073     {
00074         Grow(1);
00075         strings[0] = new ::String(key);
00076         objects[0] = object;
00077         return count++;
00078     }
00079 
00080     int left = 0;
00081     int right = count - 1;
00082 
00083     while (right > left)
00084     {
00085         int probe = (left + right) / 2;
00086         int test  = key.SlowCompare(*(strings[probe]));
00087 
00088         if (test == 0)
00089         {
00090             objects[probe] = object;
00091             return probe;
00092         }
00093 
00094         if (test < 0)
00095             right = probe - 1;
00096         else
00097             left  = probe + 1;
00098     }
00099 
00100     int insertAt = left;
00101     int test = key.SlowCompare(*(strings[insertAt]));
00102 
00103     if (test == 0)
00104     {
00105         objects[insertAt] = object;
00106         return insertAt;
00107     }
00108 
00109     if (test > 0) insertAt++;
00110 
00111     Grow(count + 1);
00112 
00113     if (insertAt < count)
00114     {
00115         for (int i = count; i > insertAt; i--)
00116         {
00117             strings[i] = strings[i - 1];
00118             objects[i] = objects[i - 1];
00119         }
00120     }
00121 
00122     strings[insertAt] = new ::String(key);
00123     objects[insertAt] = object;
00124     count++;
00125 
00126     return insertAt;
00127 }
00128 
00129 int StringMap::Find(const ::String & s,  void *(*create_object)())
00130 {
00131     if (!count)
00132         return create_object == NULL ? -1 : Add(s, create_object());
00133 
00134     int left = 0;
00135     int right = count - 1;
00136 
00137     while (right > left)
00138     {
00139         int probe = (left + right) / 2;
00140         int test  = s.SlowCompare(*(strings[probe]));
00141 
00142         if (test == 0)
00143             return probe;
00144 
00145         if (test < 0)
00146             right = probe - 1;
00147         else
00148             left  = probe + 1;
00149     }
00150 
00151     int position = left;
00152     int test = s.SlowCompare(*(strings[left]));
00153 
00154     if (test == 0)
00155         return position;
00156 
00157     if (create_object == NULL)
00158         return -1;
00159 
00160     if (test > 0)
00161         position++;
00162 
00163     Grow(count + 1);
00164 
00165     if (position < count)
00166     {
00167         for (int i = count; i > position; i--)
00168         {
00169             strings[i] = strings[i - 1];
00170             objects[i] = objects[i - 1];
00171         }
00172     }
00173 
00174     strings[position] = new ::String(s);
00175     objects[position] = create_object();
00176     count++;
00177 
00178     return position;
00179 }
00180 
00181 int StringMap::Find(const ::String & s) const
00182 {
00183     if (!count) return -1;
00184 
00185     int left = 0;
00186     int right = count - 1;
00187 
00188     while (right > left)
00189     {
00190         int probe = (left + right) / 2;
00191         int test  = s.SlowCompare(*(strings[probe]));
00192 
00193         if (test == 0)
00194             return probe;
00195 
00196         if (test < 0)
00197             right = probe - 1;
00198         else
00199             left  = probe + 1;
00200     }
00201 
00202     int position = left;
00203     int test = s.SlowCompare(*(strings[left]));
00204 
00205     if (test == 0)
00206         return position;
00207 
00208     return -1;
00209 }
00210 
00211 int StringMap::FindStem(const ::String & stem) const
00212 {
00213     if (!count) return -1;
00214 
00215     int left = 0;
00216     int right = count - 1;
00217 
00218     while (right > left)
00219     {
00220         int probe = (left + right) / 2;
00221         int test  = strings[probe]->SlowCompareToStem(stem);
00222 
00223         if (test == 0)
00224         {
00225             if ((left  < probe && strings[probe-1]->SlowCompareToStem(stem) == 0) ||
00226                     (right > probe && strings[probe+1]->SlowCompareToStem(stem) == 0))
00227                 return -2;
00228 
00229             return probe;
00230         }
00231 
00232         if (test > 0)
00233             right = probe - 1;
00234         else
00235             left  = probe + 1;
00236     }
00237 
00238     if (strings[left]->SlowCompareToStem(stem) == 0)
00239         return left;
00240 
00241     return -1;
00242 }
00243 
00244 int StringMap::FindFirstStem(const ::String & stem) const
00245 {
00246     if (!count) return -1;
00247 
00248     int left = 0;
00249     int right = count - 1;
00250 
00251     while (right > left)
00252     {
00253         int probe = (left + right) / 2;
00254         int test  = strings[probe]->SlowCompareToStem(stem);
00255 
00256         if (test == 0)
00257         {
00258             while (left < probe && strings[probe-1]->SlowCompareToStem(stem) == 0)
00259                 probe--;
00260 
00261             return probe;
00262         }
00263 
00264         if (test > 0)
00265             right = probe - 1;
00266         else
00267             left  = probe + 1;
00268     }
00269 
00270     if (strings[left]->SlowCompareToStem(stem) == 0)
00271         return left;
00272 
00273     return -1;
00274 }
00275 
00276 void * StringMap::CreateMap()
00277 {
00278     return (void *) new StringMap();
00279 }
00280 
00281 void StringMap::Clear()
00282 {
00283     for (int i = 0; i < count; i++)
00284         delete strings[i];
00285     count = 0;
00286 }
00287 
00288 void StringMap::Delete(int index)
00289 {
00290     count--;
00291 
00292     delete strings[index];
00293 
00294     for (int i = index; i < count; i++)
00295     {
00296         strings[i] = strings[i+1];
00297         objects[i] = objects[i+1];
00298     }
00299 }
00300 
00301 // StringIntMap class
00302 //
00303 
00304 int StringIntMap::alloc = 8;
00305 
00306 StringIntMap::StringIntMap(int startsize)
00307 {
00308     count = 0;
00309     size = (startsize + alloc) / alloc * alloc;
00310     strings = new ::String * [size];
00311     integers = new int[size];
00312 };
00313 
00314 StringIntMap::~StringIntMap()
00315 {
00316     for (int i = 0; i < count; i++)
00317         delete strings[i];
00318     delete [] strings;
00319     delete [] integers;
00320 }
00321 
00322 void StringIntMap::Grow(int newsize)
00323 {
00324     if (newsize >= size)
00325     {
00326         if ((newsize >> 1) >= size)
00327             size = (newsize + alloc) / alloc * alloc;
00328         else
00329         {
00330             size = alloc;
00331             while (size <= newsize)
00332                 size *= 2;
00333         }
00334 
00335         ::String ** newStrings = new ::String * [size];
00336         int       * newIntegers = new int [size];
00337 
00338         for (int i = 0; i < count; i++)
00339         {
00340             newStrings[i] = strings[i];
00341             newIntegers[i] = integers[i];
00342         }
00343 
00344         delete [] strings;
00345         delete [] integers;
00346 
00347         strings = newStrings;
00348         integers = newIntegers;
00349     }
00350 }
00351 
00352 int StringIntMap::Add(const ::String & key, int integer)
00353 {
00354     if (count == 0)
00355     {
00356         Grow(1);
00357         strings[0] = new ::String(key);
00358         integers[0] = integer;
00359         return count++;
00360     }
00361 
00362     int left = 0;
00363     int right = count - 1;
00364 
00365     while (right > left)
00366     {
00367         int probe = (left + right) / 2;
00368         int test  = key.SlowCompare(*(strings[probe]));
00369 
00370         if (test == 0)
00371         {
00372             integers[probe] = integer;
00373             return probe;
00374         }
00375 
00376         if (test < 0)
00377             right = probe - 1;
00378         else
00379             left  = probe + 1;
00380     }
00381 
00382     int insertAt = left;
00383     int test = key.SlowCompare(*(strings[insertAt]));
00384 
00385     if (test == 0)
00386     {
00387         integers[insertAt] = integer;
00388         return insertAt;
00389     }
00390 
00391     if (test > 0) insertAt++;
00392 
00393     Grow(count + 1);
00394 
00395     if (insertAt < count)
00396     {
00397         for (int i = count; i > insertAt; i--)
00398         {
00399             strings[i] = strings[i - 1];
00400             integers[i] = integers[i - 1];
00401         }
00402     }
00403 
00404     strings[insertAt] = new ::String(key);
00405     integers[insertAt] = integer;
00406     count++;
00407 
00408     return insertAt;
00409 }
00410 
00411 int StringIntMap::Find(const ::String & s, int defaultValue)
00412 {
00413     if (!count)
00414         return Add(s, defaultValue);
00415 
00416     int left = 0;
00417     int right = count - 1;
00418 
00419     while (right > left)
00420     {
00421         int probe = (left + right) / 2;
00422         int test  = s.SlowCompare(*(strings[probe]));
00423 
00424         if (test == 0)
00425             return probe;
00426 
00427         if (test < 0)
00428             right = probe - 1;
00429         else
00430             left  = probe + 1;
00431     }
00432 
00433     int position = left;
00434     int test = s.SlowCompare(*(strings[left]));
00435 
00436     if (test == 0)
00437         return position;
00438 
00439     if (test > 0)
00440         position++;
00441 
00442     Grow(count + 1);
00443 
00444     if (position < count)
00445     {
00446         for (int i = count; i > position; i--)
00447         {
00448             strings[i] = strings[i - 1];
00449             integers[i] = integers[i - 1];
00450         }
00451     }
00452 
00453     strings[position] = new ::String(s);
00454     integers[position] = defaultValue;
00455     count++;
00456 
00457     return position;
00458 }
00459 
00460 int StringIntMap::Find(const ::String & s) const
00461 {
00462     if (!count) return -1;
00463 
00464     int left = 0;
00465     int right = count - 1;
00466 
00467     while (right > left)
00468     {
00469         int probe = (left + right) / 2;
00470         int test  = s.SlowCompare(*(strings[probe]));
00471 
00472         if (test == 0)
00473             return probe;
00474 
00475         if (test < 0)
00476             right = probe - 1;
00477         else
00478             left  = probe + 1;
00479     }
00480 
00481     int position = left;
00482     int test = s.SlowCompare(*(strings[left]));
00483 
00484     if (test == 0)
00485         return position;
00486 
00487     return -1;
00488 }
00489 
00490 int StringIntMap::FindStem(const ::String & stem) const
00491 {
00492     if (!count) return -1;
00493 
00494     int left = 0;
00495     int right = count - 1;
00496 
00497     while (right > left)
00498     {
00499         int probe = (left + right) / 2;
00500         int test  = strings[probe]->SlowCompareToStem(stem);
00501 
00502         if (test == 0)
00503         {
00504             if ((left  < probe && strings[probe-1]->SlowCompareToStem(stem) == 0) ||
00505                     (right > probe && strings[probe+1]->SlowCompareToStem(stem) == 0))
00506                 return -2;
00507 
00508             return probe;
00509         }
00510 
00511         if (test > 0)
00512             right = probe - 1;
00513         else
00514             left  = probe + 1;
00515     }
00516 
00517     if (strings[left]->SlowCompareToStem(stem) == 0)
00518         return left;
00519 
00520     return -1;
00521 }
00522 
00523 void StringIntMap::Clear()
00524 {
00525     for (int i = 0; i < count; i++)
00526         delete strings[i];
00527     count = 0;
00528 }
00529 
00530 int StringIntMap::GetCount(const ::String & key) const
00531 {
00532     int index = Find(key);
00533     return index == -1 ?  0 : integers[index];
00534 }
00535 
00536 int StringIntMap::IncrementCount(const ::String & key)
00537 {
00538     int index = Find(key);
00539 
00540     if (index != -1)
00541         return ++(integers[index]);
00542 
00543     SetInteger(key, 1);
00544     return 1;
00545 }
00546 
00547 int StringIntMap::DecrementCount(const ::String & key)
00548 {
00549     int index = Find(key);
00550 
00551     if (index != -1)
00552         return --(integers[index]);
00553 
00554     SetInteger(key, -1);
00555     return -1;
00556 }
00557 
00558 void StringIntMap::Delete(int index)
00559 {
00560     count--;
00561 
00562     delete strings[index];
00563 
00564     for (int i = index; i < count; i++)
00565     {
00566         strings[i] = strings[i+1];
00567         integers[i] = integers[i+1];
00568     }
00569 }
00570 
00571 
00572 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends