00001 00002 #include "skype-string-list.h" 00003 #include <stdio.h> 00004 00005 /** \cond INTERNAL */ 00006 class SEStringList::Element 00007 { 00008 public: 00009 Element(); 00010 00011 public: 00012 SEString str; 00013 Element* next; 00014 }; 00015 00016 class SEStringList::Data 00017 { 00018 public: 00019 unsigned int ref; 00020 Element* list; 00021 Element* last; 00022 bool dirty; 00023 Element** quick_list; 00024 size_t size; 00025 SEMutex lock; 00026 }; 00027 00028 SEStringList::Element::Element() 00029 :next(0) 00030 { 00031 00032 } 00033 /** \endcond */ 00034 00035 SEStringList::SEStringList() 00036 :d(0) 00037 { 00038 00039 } 00040 00041 SEStringList::SEStringList(const SEStringList& sl) 00042 :d(0) 00043 { 00044 *this = sl; 00045 } 00046 00047 SEStringList::~SEStringList() 00048 { 00049 d_unref(); 00050 } 00051 00052 /** \cond INTERNAL */ 00053 void SEStringList::init() 00054 { 00055 if (d) 00056 return; 00057 00058 d = new Data(); 00059 d->ref = 1; 00060 d->list = 0; 00061 d->dirty = true; 00062 d->size = 0; 00063 d->quick_list = 0; 00064 } 00065 /** \endcond */ 00066 00067 SEStringList& SEStringList::append(const SEString& str) 00068 { 00069 if (str.isNull()) { 00070 return append("")/**this*/; 00071 } 00072 00073 detach(); 00074 00075 if (0 == d) { 00076 init(); 00077 00078 d->list = new Element(); 00079 d->list->str = str; 00080 d->last = d->list; 00081 } else { 00082 d->dirty = true; 00083 d->last->next = new Element(); 00084 d->last->next->str = str; 00085 d->last = d->last->next; 00086 } 00087 00088 return *this; 00089 } 00090 00091 #if 0 00092 SEStringList& SEStringList::prepend(const SEString& str) 00093 { 00094 if (str.isNull()) 00095 return *this; 00096 00097 detach(); 00098 00099 if (0 == d) { 00100 init(); 00101 00102 d->list = new Element(); 00103 d->list->str = str; 00104 d->last = d->list; 00105 } else { 00106 d->dirty = true; 00107 00108 Element* n = new Element(); 00109 00110 n->str = str; 00111 n->next = d->list; 00112 d->list = n; 00113 } 00114 00115 return *this; 00116 } 00117 #endif 00118 00119 SEString SEStringList::peek() 00120 { 00121 detach(); 00122 00123 if (0 == d) 00124 return SEString(); 00125 00126 d->dirty = true; 00127 00128 SEString ret = d->list->str; 00129 00130 Element* next = d->list->next; 00131 00132 delete d->list; 00133 00134 d->list = next; 00135 00136 if (0 == d->list) { 00137 delete d; 00138 d = 0; 00139 } 00140 00141 return ret; 00142 } 00143 00144 size_t SEStringList::size() const 00145 { 00146 if (0 == d) 00147 return 0; 00148 00149 if (!d->dirty) 00150 return d->size; 00151 00152 if (d->quick_list) 00153 delete[] d->quick_list; 00154 00155 // first pass - count elements 00156 d->size = 0; 00157 00158 Element* e = d->list; 00159 00160 do { 00161 d->size++; 00162 e = e->next; 00163 } while (e); 00164 00165 // second pass - fill quick access vector 00166 d->quick_list = new Element*[d->size]; 00167 00168 e = d->list; 00169 size_t n = 0; 00170 00171 while (e) { 00172 d->quick_list[n++] = e; 00173 00174 e = e->next; 00175 } 00176 00177 d->dirty = false; 00178 00179 return d->size; 00180 } 00181 00182 const SEString &SEStringList::operator[](size_t n) const 00183 { 00184 if ((0 == d) || (n >= size())) 00185 return empty; 00186 00187 return d->quick_list[n]->str; 00188 } 00189 00190 SEString SEStringList::operator[](size_t n) 00191 { 00192 if ((0 == d) || (n >= size())) 00193 return SEString(); 00194 00195 // we have already called size() so we are supposed to be "clean" 00196 00197 return d->quick_list[n]->str; 00198 } 00199 00200 SEStringList& SEStringList::operator=(const SEStringList& sl) 00201 { 00202 const_cast<SEStringList&>(sl).d_ref(); 00203 d_unref(); 00204 00205 d = sl.d; 00206 00207 00208 return *this; 00209 } 00210 00211 /** \cond INTERNAL */ 00212 void SEStringList::d_ref() 00213 { 00214 if (0 == d) 00215 return; 00216 00217 d->lock.Acquire(); 00218 00219 d->ref++; 00220 00221 d->lock.Release(); 00222 } 00223 00224 void SEStringList::d_unref() 00225 { 00226 if (0 == d) 00227 return; 00228 00229 SEMutex* lock = &d->lock; 00230 00231 lock->Acquire(); 00232 00233 if (d->ref > 1) 00234 d->ref--; 00235 else { 00236 Data* tmp_d = d; 00237 d = 0; 00238 lock->Release(); 00239 00240 Element* tmp = tmp_d->list; 00241 00242 while (tmp) { 00243 Element* next = tmp->next; 00244 00245 delete tmp; 00246 00247 tmp = next; 00248 } 00249 00250 if (tmp_d->quick_list) 00251 delete[] tmp_d->quick_list; 00252 00253 delete tmp_d; 00254 return; 00255 } 00256 00257 lock->Release(); 00258 } 00259 00260 void SEStringList::detach() 00261 { 00262 if (0 == d) 00263 return; 00264 00265 d->lock.Acquire(); 00266 00267 if (1 != d->ref) { 00268 00269 Data* d_new = new Data(); 00270 00271 d_new->ref = 1; 00272 d_new->dirty = true; 00273 d_new->quick_list = 0; 00274 00275 d_new->list = new Element; 00276 d_new->list->str = d->list->str; 00277 00278 Element* from = d->list->next; 00279 Element* to = d_new->list; 00280 00281 while (from) { 00282 to->next = new Element; 00283 to->next->str = from->str; 00284 00285 to = to->next; 00286 from = from->next; 00287 } 00288 00289 d_new->last = to; 00290 00291 d->lock.Release(); 00292 00293 d_unref(); 00294 00295 d = d_new; 00296 00297 return; 00298 } 00299 00300 d->lock.Release(); 00301 } 00302 /** \endcond */ 00303 00304 SEString SEStringList::join(const SEString& sep, bool escape_args) const 00305 { 00306 SEString ret; 00307 00308 if (!size()) 00309 return ret; 00310 00311 ret += escape_args ? operator[](0).escape() : operator[](0); 00312 00313 for (size_t n = 1; n < size(); n++) 00314 ret += sep + (escape_args ? operator[](n).escape() : operator[](n)); 00315 00316 return ret; 00317 } 00318 00319 SEStringList SEStringList::split(const SEString& str, char sep, char esc) 00320 { 00321 SEStringList ret; 00322 int from = 0; 00323 int cur = 0; 00324 int* quotes = NULL; 00325 00326 const size_t len = str.length(); 00327 00328 if (len == 0) 00329 return ret; 00330 00331 if (esc) { 00332 int q = ('"' == str[0]) ? 1 : 0; 00333 if ((q) && ('"' == str[1])) 00334 return ret; 00335 00336 // we can initialize quotes only here because it's never used if esc == null 00337 quotes = new int[len]; 00338 00339 quotes[0] = q; 00340 00341 for (size_t n = 1; n < len; n++) { 00342 if (str[n] == '"') { 00343 if (str[n - 1] != esc) // " is not escaped 00344 quotes[n] = ++q; 00345 else { // " is escaped 00346 size_t i = n - 1; 00347 // to detect the case where we have some escaped \ just before the " 00348 while (i && (str[i] == esc)) i--; 00349 if ((n - i) % 2) // even number of /, " is not escaped 00350 quotes[n] = ++q; 00351 else // odd number of /, " is escaped 00352 quotes[n] = q; 00353 } 00354 00355 } else 00356 quotes[n] = q; 00357 } 00358 } 00359 00360 // skip trailing separators 00361 while (str[cur] == sep) { 00362 from++; 00363 cur++; 00364 } 00365 00366 cur++; 00367 00368 while (cur <= (int)len) { 00369 // the case when we go out of bounds is when we have escaped separator 00370 // before end of the string 00371 if (cur == (int)len) { 00372 ret.append(str.substr(from, cur - 1)); 00373 00374 break; 00375 } 00376 00377 if ((str[cur] == sep)) { 00378 // here we may go out of bounds (handled above) 00379 if (esc && ((str[cur - 1] == esc) || (quotes[cur] % 2))) { 00380 cur++; 00381 00382 continue; 00383 } 00384 00385 ret.append(str.substr(from, cur - 1)); 00386 00387 while ((str[cur] == sep) && (cur < (int)len)) 00388 cur++; 00389 00390 if (cur >= (int)len) 00391 break; 00392 00393 from = cur++; 00394 00395 continue; 00396 } 00397 00398 if (cur == (int)len - 1) { 00399 ret.append(str.substr(from, cur)); 00400 00401 break; 00402 } 00403 00404 cur++; 00405 } 00406 00407 if (esc) 00408 delete[] quotes; 00409 00410 return ret; 00411 } 00412 00413 00414 void SEStringList::resize(const unsigned int new_size) 00415 { 00416 if (size() == new_size) return; 00417 if (new_size == 0) { 00418 clear(); 00419 return; 00420 } 00421 00422 detach(); 00423 unsigned int cursize = size(); //updates quick_list 00424 00425 if (cursize > new_size) { //shrink 00426 00427 Element* elem_last = d->quick_list[new_size-1]; 00428 elem_last->next = 0; 00429 d->last = elem_last; 00430 00431 for (unsigned int n = new_size; n < cursize; n++) { 00432 delete d->quick_list[n]; 00433 } 00434 00435 } else { //grow 00436 00437 while (cursize < new_size) { 00438 if (0 == d) { 00439 init(); 00440 d->list = new Element(); 00441 d->list->str = ""; 00442 d->last = d->list; 00443 } else { 00444 d->last->next = new Element(); 00445 d->last->next->str = ""; 00446 d->last = d->last->next; 00447 } 00448 00449 cursize++; 00450 } 00451 } 00452 00453 d->dirty = true; 00454 } 00455 00456 int SEStringList::find_pos(const SEString& val) 00457 { 00458 int len = size(); 00459 for (int n = 0; n < len; n++) { 00460 if (d->quick_list[n]->str == val) { 00461 return n; 00462 } 00463 } 00464 00465 return -1; 00466 } 00467 00468 bool SEStringList::contains(const SEString& val) 00469 { 00470 return (find_pos(val) >= 0); 00471 } 00472 00473 bool SEStringList::remove_val(const SEString& val) 00474 { 00475 int pos = find_pos(val); 00476 if (pos >= 0) return remove_pos(pos); 00477 00478 return false; 00479 } 00480 00481 bool SEStringList::remove_pos(const unsigned int pos) 00482 { 00483 if (0 == d || pos >= size()) return false; 00484 00485 detach(); 00486 unsigned int cursize = size();//updates quick_list 00487 00488 Element* elem_del = d->quick_list[pos]; 00489 Element* elem_next = elem_del->next; 00490 Element* elem_prev = pos == 0 ? 0 : d->quick_list[pos-1]; 00491 00492 if (pos == 0) {//first 00493 delete elem_del; 00494 d->list = elem_next; 00495 } else if (pos == cursize -1) { //last 00496 delete elem_del; 00497 elem_prev->next = 0; 00498 d->last = elem_prev; 00499 } else { 00500 delete elem_del; 00501 elem_prev->next = elem_next; 00502 } 00503 00504 d->dirty = true; 00505 if (0 == d->list) { 00506 delete d; 00507 d = 0; 00508 } 00509 00510 return true; 00511 } 00512 00513 void SEStringList::clear() 00514 { 00515 if (0 == d) { 00516 return; 00517 } 00518 00519 detach(); 00520 00521 for (unsigned int n = 0; n < size(); n++) { 00522 delete d->quick_list[n]; 00523 } 00524 00525 if (d->quick_list) 00526 delete[] d->quick_list; 00527 00528 delete d; 00529 00530 d = 0; 00531 } 00532
(c) Skype Technologies S.A. Confidential/Proprietary
Last updated: Fri Mar 16 2012