00001 00002 #include "skype-ref-list.h" 00003 #include "skype-object.h" 00004 00005 SEReference empty; 00006 00007 /** \cond INTERNAL */ 00008 class SERefList::Element 00009 { 00010 public: 00011 Element(); 00012 00013 public: 00014 SEReference reference; 00015 Element* next; 00016 }; 00017 00018 class SERefList::Data 00019 { 00020 public: 00021 unsigned int ref; 00022 Element* list; 00023 Element* last; 00024 bool dirty; 00025 Element** quick_list; 00026 size_t size; 00027 SEMutex lock; 00028 }; 00029 00030 SERefList::Element::Element() 00031 :next(0) 00032 { 00033 00034 } 00035 /** \endcond */ 00036 00037 SERefList::SERefList() 00038 :d(0) 00039 { 00040 } 00041 00042 SERefList::SERefList(const SERefList& sl) 00043 :d(0) 00044 { 00045 *this = sl; 00046 } 00047 00048 SERefList::~SERefList() 00049 { 00050 d_unref(); 00051 } 00052 00053 /** \cond INTERNAL */ 00054 void SERefList::init() 00055 { 00056 if (d) 00057 return; 00058 00059 d = new Data(); 00060 d->ref = 1; 00061 d->list = 0; 00062 d->dirty = true; 00063 d->size = 0; 00064 d->quick_list = 0; 00065 } 00066 /** \endcond */ 00067 00068 SERefList& SERefList::append(const SEReference& ref) 00069 { 00070 detach(); 00071 00072 if (0 == d) { 00073 init(); 00074 00075 d->list = new Element(); 00076 d->list->reference = ref; 00077 d->last = d->list; 00078 } else { 00079 d->dirty = true; 00080 d->last->next = new Element(); 00081 d->last->next->reference = ref; 00082 d->last = d->last->next; 00083 } 00084 00085 return *this; 00086 } 00087 00088 SEReference& SERefList::peek() 00089 { 00090 detach(); 00091 00092 if (0 == d) 00093 return empty; 00094 00095 d->dirty = true; 00096 00097 SEReference& ret = d->list->reference; 00098 00099 Element* next = d->list->next; 00100 00101 delete d->list; 00102 00103 d->list = next; 00104 00105 if (0 == d->list) { 00106 delete d; 00107 d = 0; 00108 } 00109 00110 return ret; 00111 } 00112 00113 size_t SERefList::size() const 00114 { 00115 if (0 == d) 00116 return 0; 00117 00118 if (!d->dirty) 00119 return d->size; 00120 00121 if (d->quick_list) 00122 delete[] d->quick_list; 00123 00124 // first pass - count elements 00125 d->size = 0; 00126 00127 Element* e = d->list; 00128 00129 do { 00130 d->size++; 00131 e = e->next; 00132 } while (e); 00133 00134 // second pass - fill quick access vector 00135 d->quick_list = new Element*[d->size]; 00136 00137 e = d->list; 00138 size_t n = 0; 00139 00140 while (e) { 00141 d->quick_list[n++] = e; 00142 00143 e = e->next; 00144 } 00145 00146 d->dirty = false; 00147 00148 return d->size; 00149 } 00150 00151 SEReference &SERefList::operator[](size_t n) const 00152 { 00153 if ((0 == d) || (n >= size())) 00154 return const_cast<SEReference &>(empty); 00155 00156 return d->quick_list[n]->reference; 00157 } 00158 00159 SERefList& SERefList::operator=(const SERefList& sl) 00160 { 00161 d_unref(); 00162 00163 d = sl.d; 00164 00165 d_ref(); 00166 00167 return *this; 00168 } 00169 00170 /** \cond INTERNAL */ 00171 void SERefList::d_ref() 00172 { 00173 if (0 == d) 00174 return; 00175 00176 d->lock.Acquire(); 00177 00178 d->ref++; 00179 00180 d->lock.Release(); 00181 } 00182 00183 void SERefList::d_unref() 00184 { 00185 if (0 == d) 00186 return; 00187 00188 SEMutex* lock = &d->lock; 00189 00190 lock->Acquire(); 00191 00192 if (d->ref > 1) 00193 d->ref--; 00194 else { 00195 Element* tmp = d->list; 00196 00197 while (tmp) { 00198 Element* next = tmp->next; 00199 00200 delete tmp; 00201 00202 tmp = next; 00203 } 00204 00205 if (d->quick_list) 00206 delete[] d->quick_list; 00207 00208 Data* keep = d; 00209 d = 0; 00210 lock->Release(); 00211 delete keep; 00212 00213 00214 00215 return; 00216 } 00217 00218 lock->Release(); 00219 } 00220 00221 void SERefList::detach() 00222 { 00223 if (0 == d) 00224 return; 00225 00226 d->lock.Acquire(); 00227 00228 if (1 != d->ref) { 00229 00230 Data* d_new = new Data(); 00231 00232 d_new->ref = 1; 00233 d_new->dirty = true; 00234 d_new->quick_list = 0; 00235 00236 d_new->list = new Element; 00237 d_new->list->reference = d->list->reference; 00238 00239 Element* from = d->list->next; 00240 Element* to = d_new->list; 00241 00242 while (from) { 00243 to->next = new Element; 00244 to->next->reference = from->reference; 00245 00246 to = to->next; 00247 from = from->next; 00248 } 00249 00250 d_new->last = to; 00251 00252 d->lock.Release(); 00253 00254 d_unref(); 00255 00256 d = d_new; 00257 00258 return; 00259 } 00260 00261 d->lock.Release(); 00262 } 00263 /** \endcond */ 00264 00265 void SERefList::resize(const unsigned int new_size) 00266 { 00267 if (size() == new_size) return; 00268 if (new_size == 0) { 00269 clear(); 00270 return; 00271 } 00272 00273 detach(); 00274 uint cursize = size(); //updates quick_list 00275 00276 if (cursize > new_size) { //shrink 00277 00278 Element* elem_last = d->quick_list[new_size-1]; 00279 elem_last->next = 0; 00280 d->last = elem_last; 00281 00282 for (uint n = new_size; n < cursize; n++) { 00283 delete d->quick_list[n]; 00284 } 00285 00286 } else { //grow 00287 00288 while (cursize < new_size) { 00289 if (0 == d) { 00290 init(); 00291 d->list = new Element(); 00292 d->list->reference = SEReference(); 00293 d->last = d->list; 00294 } else { 00295 d->last->next = new Element(); 00296 d->last->next->reference = SEReference(); 00297 d->last = d->last->next; 00298 } 00299 00300 cursize++; 00301 } 00302 } 00303 00304 d->dirty = true; 00305 } 00306 00307 int SERefList::find_pos(const SEReference & val) 00308 { 00309 int len = size(); 00310 for (int n = 0; n < len; n++) { 00311 if (d->quick_list[n]->reference == val) { 00312 return n; 00313 } 00314 } 00315 00316 return -1; 00317 } 00318 00319 bool SERefList::contains(const SEReference & val) 00320 { 00321 return (find_pos(val) >= 0); 00322 } 00323 00324 bool SERefList::remove_val(const SEReference & val) 00325 { 00326 int pos = find_pos(val); 00327 if (pos >= 0) 00328 return remove_pos(pos); 00329 00330 return false; 00331 } 00332 00333 bool SERefList::remove_pos(const unsigned int pos) 00334 { 00335 if (0 == d || pos >= size()) return false; 00336 00337 detach(); 00338 uint cursize = size();//updates quick_list 00339 00340 Element* elem_del = d->quick_list[pos]; 00341 Element* elem_next = elem_del->next; 00342 Element* elem_prev = pos == 0 ? 0 : d->quick_list[pos-1]; 00343 00344 if (pos == 0) {//first 00345 delete elem_del; 00346 d->list = elem_next; 00347 } else if (pos == cursize -1) { //last 00348 delete elem_del; 00349 elem_prev->next = 0; 00350 d->last = elem_prev; 00351 } else { 00352 delete elem_del; 00353 elem_prev->next = elem_next; 00354 } 00355 00356 d->dirty = true; 00357 if (0 == d->list) { 00358 delete d; 00359 d = 0; 00360 } 00361 00362 return true; 00363 } 00364 00365 void SERefList::clear() 00366 { 00367 if (0 == d) { 00368 return; 00369 } 00370 00371 detach(); 00372 00373 for (uint n = 0; n < size(); n++) { 00374 delete d->quick_list[n]; 00375 } 00376 00377 if (d->quick_list) 00378 delete[] d->quick_list; 00379 00380 delete d; 00381 00382 d = 0; 00383 }
(c) Skype Technologies S.A. Confidential/Proprietary
Last updated: Fri Jan 27 2012