00001 00002 #include "skype-string-dict.h" 00003 #include "skype-string.h" 00004 #include "skype-string-list.h" 00005 00006 #include <stdio.h> 00007 00008 #define SIZE 17 00009 00010 /** \cond INTERNAL */ 00011 class SEStringDict::Element 00012 { 00013 public: 00014 Element(const SEString& k, const SEString& v); 00015 00016 public: 00017 Element* next; 00018 SEString key; 00019 SEString value; 00020 }; 00021 00022 class SEStringDict::Data 00023 { 00024 public: 00025 Data(); 00026 00027 public: 00028 Element* dict[SIZE]; 00029 unsigned int ref; 00030 size_t size; 00031 bool dirty; 00032 Element** quick_list; 00033 SEMutex lock; 00034 }; 00035 00036 SEStringDict::Element::Element(const SEString& k, const SEString& v) 00037 :next(0), 00038 key(k), 00039 value(v) 00040 { 00041 00042 } 00043 00044 SEStringDict::Data::Data() 00045 :dirty(true), 00046 quick_list(0) 00047 { 00048 00049 } 00050 /** \endcond */ 00051 00052 SEStringDict::SEStringDict() 00053 :d(0) 00054 { 00055 00056 } 00057 00058 SEStringDict::SEStringDict(const SEStringDict& dict) 00059 :d(0) 00060 { 00061 *this = dict; 00062 } 00063 00064 SEStringDict::~SEStringDict() 00065 { 00066 d_unref(); 00067 } 00068 00069 void SEStringDict::insert(const SEString& key, const SEString& new_value) 00070 { 00071 if (key.isNull()) 00072 return; 00073 00074 detach(); 00075 00076 if (0 == d) { 00077 d = new Data(); 00078 00079 d->ref = 1; 00080 00081 for (size_t n = 0; n < SIZE; n++) 00082 d->dict[n] = 0; 00083 } 00084 00085 d->dirty = true; 00086 00087 unsigned int h = key.hash(SIZE); 00088 00089 Element** e = &(d->dict[h]); 00090 00091 while (*e) 00092 e = &((*e)->next); 00093 00094 *e = new Element(key, new_value); 00095 } 00096 00097 SEString SEStringDict::find(const SEString& key, unsigned int offset) const 00098 { 00099 if (0 == d) 00100 return SEString(); 00101 00102 unsigned int h = key.hash(SIZE); 00103 00104 Element** e = &(d->dict[h]); 00105 00106 while (*e) { 00107 if ((*e)->key == key) { 00108 if (0 == offset) 00109 return (*e)->value; 00110 else 00111 offset--; 00112 } 00113 00114 e = &((*e)->next); 00115 } 00116 00117 return SEString(); 00118 } 00119 00120 /** \cond INTERNAL */ 00121 SEString SEStringDict::format(bool escape_args) const 00122 { 00123 if (0 == d) 00124 return SEString(); 00125 00126 SEString ret; 00127 00128 for (size_t n = 0; n < SIZE; n++) { 00129 Element** e = &(d->dict[n]); 00130 00131 while (*e) { 00132 // we save a bunch of malloc with this one 00133 // For binary, escaping has already been done 00134 ret += SEString::keyValue((*e)->key, (!escape_args || (*e)->value.isBinary()) ? (*e)->value : (*e)->value.escape()); 00135 00136 e = &((*e)->next); 00137 } 00138 } 00139 00140 return ret.substr(0, -1); 00141 } 00142 /** \endcond */ 00143 00144 SEStringDict& SEStringDict::operator=(const SEStringDict& dict) 00145 { 00146 const_cast<SEStringDict&>(dict).d_ref(); 00147 d_unref(); 00148 d = dict.d; 00149 00150 return *this; 00151 } 00152 00153 /** \cond INTERNAL */ 00154 void SEStringDict::d_ref() 00155 { 00156 if (0 == d) 00157 return; 00158 00159 d->lock.Acquire(); 00160 00161 d->ref++; 00162 00163 d->lock.Release(); 00164 } 00165 00166 void SEStringDict::d_unref() 00167 { 00168 if (0 == d) 00169 return; 00170 00171 SEMutex* lock = &d->lock; 00172 00173 lock->Acquire(); 00174 00175 if (d->ref > 1) 00176 d->ref--; 00177 else { 00178 Data* tmp_d = d; 00179 d = 0; 00180 lock->Release(); 00181 00182 for (size_t n = 0; n < SIZE; n++) { 00183 while (tmp_d->dict[n]) { 00184 Element* tmp = tmp_d->dict[n]->next; 00185 00186 delete tmp_d->dict[n]; 00187 00188 tmp_d->dict[n] = tmp; 00189 } 00190 } 00191 00192 if (tmp_d->quick_list) 00193 delete[] tmp_d->quick_list; 00194 00195 delete tmp_d; 00196 return; 00197 } 00198 00199 lock->Release(); 00200 } 00201 00202 void SEStringDict::detach() 00203 { 00204 if (0 == d) 00205 return; 00206 00207 d->lock.Acquire(); 00208 00209 if (1 != d->ref) { 00210 00211 Data* d_new = new Data(); 00212 00213 d_new->ref = 1; 00214 00215 size_t n; 00216 for (n = 0; n < SIZE; n++) 00217 d_new->dict[n] = 0; 00218 00219 for (n = 0; n < SIZE; n++) { 00220 Element** from = &(d->dict[n]); 00221 Element** to = &(d_new->dict[n]); 00222 00223 while (*from) { 00224 *to = new Element((*from)->key, (*from)->value); 00225 00226 from = &((*from)->next); 00227 to = &((*to)->next); 00228 } 00229 } 00230 00231 d->lock.Release(); 00232 00233 d_unref(); 00234 00235 d = d_new; 00236 00237 return; 00238 } 00239 00240 d->lock.Release(); 00241 } 00242 00243 SEStringDict SEStringDict::parse(const SEString& str) 00244 { 00245 // we assume very strict formatting here 00246 SEStringList sl = SEStringList::split(str, ' '); 00247 00248 return parse(sl); 00249 } 00250 00251 SEStringDict SEStringDict::parse(const SEStringList& str) 00252 { 00253 // we assume very strict formatting here 00254 SEStringList sl = str; 00255 00256 SEString cur; 00257 SEStringDict ret; 00258 00259 while (!(cur = sl.peek()).isNull()) { 00260 int eq = cur.find('='); 00261 00262 if (-1 == eq) 00263 continue; 00264 00265 SEString key = cur.substr(0, eq - 1); 00266 SEString value; 00267 00268 if ((cur[eq + 1] == 'r') && (cur[eq + 2] == '"')) { // binary are identified with =r"" 00269 value = cur.substr(eq + 3, -1); 00270 value.markAsBinary(); 00271 } else 00272 value = cur.substr(eq + 2, -1); 00273 00274 // Empty string (done before unescaping, otherwise "" is ignored) 00275 if (('"' == value[0]) && ('"' == value[1])) 00276 value = SEString(); 00277 00278 // For binary, don't unescape now, will do it later 00279 if (!value.isBinary()) 00280 value = value.unescape(); 00281 00282 ret.insert(key, value); 00283 } 00284 00285 return ret; 00286 } 00287 /** \endcond */ 00288 00289 size_t SEStringDict::size() const 00290 { 00291 if (0 == d) 00292 return 0; 00293 00294 if (d->dirty) { 00295 if (d->quick_list) 00296 delete[] d->quick_list; 00297 00298 d->size = 0; 00299 00300 size_t n; 00301 for (n = 0; n < SIZE; n++) { 00302 Element** e = &(d->dict[n]); 00303 00304 while (*e) { 00305 d->size++; 00306 00307 e = &((*e)->next); 00308 } 00309 } 00310 00311 d->quick_list = new Element*[d->size]; 00312 00313 size_t c = 0; 00314 00315 for (n = 0; n < SIZE; n++) { 00316 Element** e = &(d->dict[n]); 00317 00318 while (*e) { 00319 d->quick_list[c++] = *e; 00320 00321 e = &((*e)->next); 00322 } 00323 } 00324 00325 d->dirty = false; 00326 } 00327 00328 return d->size; 00329 } 00330 00331 SEString SEStringDict::operator[](size_t i) const 00332 { 00333 if (0 == d) 00334 return SEString(); 00335 00336 if (i >= size()) 00337 return SEString(); 00338 00339 // we have already called size() so we are supposed to be "clean" 00340 return d->quick_list[i]->value; 00341 } 00342 00343 SEString SEStringDict::keyAt(size_t i) const 00344 { 00345 if (0 == d) 00346 return SEString(); 00347 00348 if (i >= size()) 00349 return SEString(); 00350 00351 // we have already called size() so we are supposed to be "clean" 00352 return d->quick_list[i]->key; 00353 }
(c) Skype Technologies S.A. Confidential/Proprietary
Last updated: Fri Mar 16 2012