- Main Page
- Related Pages
- Classes
- Files
- Examples

- File List
- File Members

# skype-string-dict.cpp

Go to the documentation of this file.

    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 }

All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

(c) Skype Technologies S.A. Confidential/Proprietary

Last updated: Fri Jan 27 2012