00001 00002 #include "skype-int-dict.h" 00003 #include "skype-string.h" 00004 00005 #define SIZE 17 00006 00007 /** \cond INTERNAL */ 00008 class SEIntDict::Element 00009 { 00010 public: 00011 Element(const int k, const SEString& v); 00012 00013 public: 00014 Element* next; 00015 int key; 00016 SEString value; 00017 }; 00018 00019 class SEIntDict::Data 00020 { 00021 public: 00022 Data(); 00023 00024 public: 00025 Element* dict[SIZE]; 00026 unsigned int ref; 00027 size_t size; 00028 Element** quick_list; 00029 bool dirty; 00030 SEMutex lock; 00031 }; 00032 00033 SEIntDict::Data::Data() 00034 :quick_list(false), 00035 dirty(true) 00036 { 00037 00038 } 00039 00040 SEIntDict::Element::Element(const int k, const SEString& v) 00041 :next(0), 00042 key(k), 00043 value(v) 00044 { 00045 00046 } 00047 /** \endcond */ 00048 00049 SEIntDict::SEIntDict() 00050 :d(0) 00051 { 00052 } 00053 00054 SEIntDict::SEIntDict(const SEIntDict& dict) 00055 :d(0) 00056 { 00057 *this = dict; 00058 } 00059 00060 SEIntDict::~SEIntDict() 00061 { 00062 d_unref(); 00063 } 00064 00065 void SEIntDict::insert(const int key, const SEString& new_value, bool replace_only) 00066 { 00067 detach(); 00068 00069 if (0 == d) { 00070 d = new Data(); 00071 00072 d->ref = 1; 00073 00074 for (size_t n = 0; n < SIZE; n++) 00075 d->dict[n] = 0; 00076 } 00077 00078 d->dirty = true; 00079 00080 unsigned int h = (unsigned int)key % SIZE; 00081 00082 Element** e = &(d->dict[h]); 00083 00084 while (*e && ((*e)->key != key)) { 00085 e = &((*e)->next); 00086 } 00087 00088 if (0 == *e) { 00089 if (replace_only) 00090 return; 00091 else 00092 *e = new Element(key, new_value); 00093 } else 00094 (*e)->value = new_value; 00095 } 00096 00097 SEString SEIntDict::find(const int key) const 00098 { 00099 if (0 == d) 00100 return SEString(); 00101 00102 unsigned int h = (unsigned int)key % SIZE; 00103 00104 Element** e = &(d->dict[h]); 00105 00106 while (*e) { 00107 if ((*e)->key == key) 00108 return (*e)->value; 00109 00110 e = &((*e)->next); 00111 } 00112 00113 return SEString(); 00114 } 00115 00116 /** \cond INTERNAL */ 00117 // TODO can save many mallocs if SEString has sprintf() 00118 SEString SEIntDict::format() const 00119 { 00120 if (0 == d) 00121 return SEString(); 00122 00123 SEString ret; 00124 00125 for (size_t n = 0; n < SIZE; n++) { 00126 Element** e = &(d->dict[n]); 00127 00128 while (*e) { 00129 ret+= SEString::from((*e)->key) + "=\"" + (*e)->value + "\" "; 00130 00131 e = &((*e)->next); 00132 } 00133 } 00134 00135 return ret.substr(0, -1); 00136 } 00137 /** \endcond */ 00138 00139 SEIntDict& SEIntDict::operator=(const SEIntDict& dict) 00140 { 00141 const_cast<SEIntDict&>(dict).d_ref(); 00142 00143 d_unref(); 00144 00145 d = dict.d; 00146 00147 return *this; 00148 } 00149 00150 /** \cond INTERNAL */ 00151 void SEIntDict::d_ref() 00152 { 00153 if (0 == d) 00154 return; 00155 00156 d->lock.Acquire(); 00157 00158 d->ref++; 00159 00160 d->lock.Release(); 00161 } 00162 00163 void SEIntDict::d_unref() 00164 { 00165 if (0 == d) 00166 return; 00167 00168 SEMutex* lock = &d->lock; 00169 00170 lock->Acquire(); 00171 00172 if (d->ref > 1) 00173 d->ref--; 00174 else { 00175 Data* tmp_d = d; 00176 00177 d = 0; 00178 00179 lock->Release(); 00180 00181 for (size_t n = 0; n < SIZE; n++) { 00182 while (tmp_d->dict[n]) { 00183 Element* tmp = tmp_d->dict[n]->next; 00184 00185 delete tmp_d->dict[n]; 00186 00187 tmp_d->dict[n] = tmp; 00188 } 00189 } 00190 00191 if (tmp_d->quick_list) 00192 delete[] tmp_d->quick_list; 00193 00194 delete tmp_d; 00195 00196 return; 00197 } 00198 00199 lock->Release(); 00200 } 00201 00202 void SEIntDict::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 /** \endcond */ 00243 00244 size_t SEIntDict::size() const 00245 { 00246 if (0 == d) 00247 return 0; 00248 00249 if (d->dirty) { 00250 if (d->quick_list) 00251 delete[] d->quick_list; 00252 00253 d->size = 0; 00254 00255 size_t n; 00256 for (n = 0; n < SIZE; n++) { 00257 Element** e = &(d->dict[n]); 00258 00259 while (*e) { 00260 d->size++; 00261 00262 e = &((*e)->next); 00263 } 00264 } 00265 00266 d->quick_list = new Element*[d->size]; 00267 00268 size_t c = 0; 00269 00270 for (n = 0; n < SIZE; n++) { 00271 Element** e = &(d->dict[n]); 00272 00273 while (*e) { 00274 d->quick_list[c++] = *e; 00275 00276 e = &((*e)->next); 00277 } 00278 } 00279 00280 d->dirty = false; 00281 } 00282 00283 return d->size; 00284 } 00285 00286 SEString SEIntDict::operator[](size_t i) const 00287 { 00288 if (0 == d) 00289 return SEString(); 00290 00291 if (i >= size()) 00292 return SEString(); 00293 00294 // we have already called size() so we are supposed to be "clean" 00295 return d->quick_list[i]->value; 00296 } 00297 00298 int SEIntDict::keyAt(size_t i) const 00299 { 00300 if (0 == d) 00301 return -1; 00302 00303 if (i >= size()) 00304 return 0; 00305 00306 // we have already called size() so we are supposed to be "clean" 00307 return d->quick_list[i]->key; 00308 } 00309 00310 SEString SEIntDict::value(const int key) 00311 { 00312 return find(key); 00313 }
(c) Skype Technologies S.A. Confidential/Proprietary
Last updated: Fri Mar 16 2012