gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

pvariant.cxx (13278B)


      1 /*
      2  *
      3  *  C++ Portable Types Library (PTypes)
      4  *  Version 2.1.1  Released 27-Jun-2007
      5  *
      6  *  Copyright (C) 2001-2007 Hovik Melikyan
      7  *
      8  *  http://www.melikyan.com/ptypes/
      9  *
     10  */
     11 
     12 
     13 #include <stdlib.h>
     14 #include <stdio.h>
     15 #include <limits.h>
     16 
     17 #include "ptypes.h"
     18 
     19 
     20 namespace ptypes {
     21 
     22 
     23 const variant nullvar;
     24 
     25 
     26 struct _varitem
     27 {
     28     string key;
     29     variant var;
     30 
     31     _varitem(const string& ikey, const variant& ivar): key(ikey), var(ivar) {}
     32 };
     33 typedef _varitem* pvaritem;
     34 
     35 
     36 class ptpublic _varray: protected tobjlist<_varitem>
     37 {
     38 protected:
     39     int refcount;
     40 
     41     virtual int compare(const void* key, const void* item) const;
     42 
     43     friend class variant;
     44 
     45 public:
     46     _varray();
     47     _varray(const _varray& a);
     48     virtual ~_varray();
     49 
     50     int get_count()                                     { return tobjlist<_varitem>::get_count(); }
     51     void clear()                                        { tobjlist<_varitem>::clear(); }
     52     void pack()                                         { tobjlist<_varitem>::pack(); }
     53     _varitem* doget(int index) const                    { return tobjlist<_varitem>::doget(index); }
     54     const variant& get(int index) const                 { if (unsigned(index) < unsigned(count)) return doget(index)->var; else return nullvar; }
     55     const string& getkey(int index) const               { if (unsigned(index) < unsigned(count)) return doget(index)->key; else return nullstring; }
     56     const variant& get(const char* key) const;
     57     int put(const string& key, const variant& var);
     58     void put(int index, const variant& var)             { if (unsigned(index) < unsigned(count)) doget(index)->var = var; }
     59     void ins(int index, const variant& var)             { if (unsigned(index) < unsigned(count)) doins(index, new _varitem(nullstring, var)); }
     60     int addvar(const variant& var);
     61     void del(int index)                                 { if (unsigned(index) < unsigned(count)) dodel(index); }
     62     void del(const string& key)                         { put(key, nullstring); }
     63 };
     64 typedef _varray* pvarray;
     65 
     66 
     67 _varray::_varray()
     68     : tobjlist<_varitem>(true), refcount(0)
     69 {
     70     config.sorted = true;
     71     config.casesens = true;
     72 }
     73 
     74 
     75 _varray::_varray(const _varray& a)
     76     : tobjlist<_varitem>(true), refcount(0)
     77 {
     78     config.sorted = true;
     79     config.casesens = true;
     80     set_capacity(a.count);
     81     for (int i = 0; i < a.count; i++)
     82     {
     83         _varitem* v = a.doget(i);
     84         doins(i, new _varitem(v->key, v->var));
     85     }
     86 }
     87 
     88 
     89 _varray::~_varray()
     90 {
     91 }
     92 
     93 
     94 int _varray::compare(const void* key, const void* item) const
     95 {
     96    if (config.casesens)
     97         return strcmp(pconst(key), pvaritem(item)->key);
     98     else
     99         return strcasecmp(pconst(key), pvaritem(item)->key);
    100 }
    101 
    102 
    103 const variant& _varray::get(const char* key) const
    104 {
    105     int index;
    106     if (search(key, index))
    107         return doget(index)->var;
    108     else
    109         return nullvar;
    110 }
    111 
    112 
    113 int _varray::put(const string& key, const variant& var)
    114 {
    115     int index;
    116     if (search(pconst(key), index))
    117     {
    118         if (isnull(var))
    119             dodel(index);
    120         else
    121             doget(index)->var = var;
    122     }
    123     else if (!isnull(var))
    124         doins(index, new _varitem(key, var));
    125     return index;
    126 }
    127 
    128 
    129 int _varray::addvar(const variant& v)
    130 {
    131     int i;
    132     if (count > 0 && isempty(doget(count - 1)->key))
    133         i = count;
    134     else
    135         i = 0;
    136     doins(i, new _varitem(nullstring, v));
    137     return i;
    138 }
    139 
    140 
    141 static void vconverr(large v);
    142 
    143 
    144 static void vfatal()
    145 {
    146     fatal(CRIT_FIRST + 60, "Variant data corrupt");
    147 }
    148 
    149 
    150 evariant::~evariant()
    151 {
    152 }
    153 
    154 
    155 void variant::initialize(_varray* a)
    156 {
    157     tag = VAR_ARRAY;
    158 #ifdef PTYPES_ST
    159     a->refcount++;
    160 #else
    161     pincrement(&a->refcount);
    162 #endif
    163     value.a = a;
    164 }
    165 
    166 
    167 void variant::initialize(component* o)
    168 {
    169     tag = VAR_OBJECT;
    170     value.o = addref(o);
    171 }
    172 
    173 
    174 void variant::initialize(const variant& v)
    175 {
    176     switch (v.tag)
    177     {
    178     case VAR_NULL:
    179         tag = VAR_NULL;
    180         break;
    181     case VAR_INT:
    182     case VAR_BOOL:
    183     case VAR_FLOAT:
    184         tag = v.tag;
    185         value = v.value;
    186         break;
    187     case VAR_STRING:
    188         initialize(PTR_TO_STRING(v.value.s));
    189         break;
    190     case VAR_ARRAY:
    191         initialize(v.value.a);
    192         break;
    193     case VAR_OBJECT:
    194         initialize(v.value.o);
    195         break;
    196     default:
    197         vfatal();
    198     }
    199 }
    200 
    201 
    202 void variant::finalize()
    203 {
    204     if (tag >= VAR_COMPOUND)
    205     {
    206         switch (tag)
    207         {
    208         case VAR_STRING:
    209             ptypes::finalize(PTR_TO_STRING(value.s));
    210             break;
    211         case VAR_ARRAY:
    212 #ifdef PTYPES_ST
    213             if (--value.a->refcount == 0)
    214 #else
    215             if (pdecrement(&value.a->refcount) == 0)
    216 #endif
    217                 delete value.a;
    218             break;
    219         case VAR_OBJECT:
    220             release(value.o);
    221             break;
    222         default:
    223             vfatal();
    224         }
    225     }
    226     tag = VAR_NULL;
    227 }
    228 
    229 
    230 void variant::assign(large v)           { finalize(); initialize(v); }
    231 void variant::assign(bool v)            { finalize(); initialize(v); }
    232 void variant::assign(double v)          { finalize(); initialize(v); }
    233 void variant::assign(const char* v)     { finalize(); initialize(v); }
    234 
    235 
    236 void variant::assign(const string& v)   
    237 { 
    238     if (tag == VAR_STRING)
    239         PTR_TO_STRING(value.s) = v;
    240     else
    241     {
    242         finalize();
    243         initialize(v);
    244     }
    245 }
    246 
    247 
    248 void variant::assign(_varray* a)
    249 {
    250     if (tag == VAR_ARRAY && value.a == a)
    251         return;
    252     finalize();
    253     initialize(a);
    254 }
    255 
    256 
    257 void variant::assign(component* o)
    258 {
    259     if (tag == VAR_OBJECT)
    260     {
    261         if (value.o == o)
    262             return;
    263         else
    264             release(value.o);
    265     }
    266     else
    267         finalize();
    268     initialize(o);
    269 }
    270 
    271 
    272 void variant::assign(const variant& v)
    273 {
    274     switch (v.tag)
    275     {
    276     case VAR_NULL:
    277         finalize();
    278         tag = VAR_NULL;
    279         break;
    280     case VAR_INT:
    281     case VAR_BOOL:
    282     case VAR_FLOAT:
    283         finalize();
    284         tag = v.tag;
    285         value = v.value;
    286         break;
    287     case VAR_STRING:
    288         assign(PTR_TO_STRING(v.value.s));
    289         break;
    290     case VAR_ARRAY:
    291         assign(v.value.a);
    292         break;
    293     case VAR_OBJECT:
    294         assign(v.value.o);
    295         break;
    296     default:
    297         vfatal();
    298     }
    299 }
    300 
    301 
    302 void ptdecl clear(variant& v)
    303 {
    304     v.finalize();
    305     v.initialize();
    306 }
    307 
    308 
    309 variant::operator int() const
    310 {
    311     large t = operator large();
    312     if (t < INT_MIN || t > INT_MAX)
    313         vconverr(t);
    314     return int(t);
    315 }
    316 
    317 
    318 variant::operator unsigned int() const
    319 {
    320     large t = operator large();
    321     if (t < 0 || t > UINT_MAX)
    322         vconverr(t);
    323     return uint(t);
    324 }
    325 
    326 
    327 variant::operator long() const
    328 {
    329     large t = operator large();
    330     if (t < LONG_MIN || t > LONG_MAX)
    331         vconverr(t);
    332     return int(t);
    333 }
    334 
    335 
    336 variant::operator unsigned long() const
    337 {
    338     large t = operator large();
    339     if (t < 0 || t > large(ULONG_MAX))
    340         vconverr(t);
    341     return uint(t);
    342 }
    343 
    344 
    345 variant::operator large() const
    346 {
    347     switch(tag)
    348     {
    349     case VAR_NULL: return 0;
    350     case VAR_INT: return value.i;
    351     case VAR_BOOL: return int(value.b);
    352     case VAR_FLOAT: return int(value.f);
    353     case VAR_STRING: 
    354         {
    355             const char* p = PTR_TO_STRING(value.s);
    356             bool neg = *p == '-';
    357             if (neg)
    358                 p++;
    359             large t = stringtoi(p);
    360             if (t < 0)
    361                 return 0;
    362             else
    363                 return neg ? -t : t;
    364         }
    365     case VAR_ARRAY: return value.a->count != 0;
    366     case VAR_OBJECT: return 0;
    367     default: vfatal();
    368     }
    369     return 0;
    370 }
    371 
    372 
    373 variant::operator bool() const
    374 {
    375     switch(tag)
    376     {
    377     case VAR_NULL: return false;
    378     case VAR_INT: return value.i != 0;
    379     case VAR_BOOL: return value.b;
    380     case VAR_FLOAT: return value.f != 0;
    381     case VAR_STRING: return !isempty((PTR_TO_STRING(value.s)));
    382     case VAR_ARRAY: return value.a->count != 0;
    383     case VAR_OBJECT: return value.o != nil;
    384     default: vfatal();
    385     }
    386     return false;
    387 }
    388 
    389 
    390 variant::operator double() const
    391 {
    392     switch(tag)
    393     {
    394     case VAR_NULL: return 0;
    395     case VAR_INT: return double(value.i);
    396     case VAR_BOOL: return int(value.b);
    397     case VAR_FLOAT: return value.f;
    398     case VAR_STRING: 
    399         {
    400             char* e;
    401             double t = strtod(PTR_TO_STRING(value.s), &e);
    402             if (*e != 0)
    403                 return 0;
    404             else
    405                 return t;
    406         }
    407     case VAR_ARRAY: return int(value.a->count != 0);
    408     case VAR_OBJECT: return 0;
    409     default: vfatal();
    410     }
    411     return 0;
    412 }
    413 
    414 
    415 void string::initialize(const variant& v)
    416 {
    417     switch(v.tag)
    418     {
    419     case VAR_NULL: initialize(); break;
    420     case VAR_INT: initialize(itostring(v.value.i)); break;
    421     case VAR_BOOL: if (v.value.b) initialize('1'); else initialize('0'); break;
    422     case VAR_FLOAT:
    423         {
    424             char buf[256];
    425             sprintf(buf, "%g", v.value.f);
    426             initialize(buf);
    427         }
    428         break;
    429     case VAR_STRING: initialize(PTR_TO_STRING(v.value.s)); break;
    430     case VAR_ARRAY: initialize(); break;
    431     case VAR_OBJECT: initialize(); break;
    432     default: vfatal();
    433     }
    434 }
    435 
    436 
    437 variant::operator string() const
    438 {
    439     // this is a 'dirty' solution to gcc 3.3 typecast problem. most compilers
    440     // handle variant::operator string() pretty well, while gcc 3.3 requires
    441     // to explicitly declare a constructor string::string(const variant&).
    442     // ironically, the presence of both the typecast operator and the constructor
    443     // confuses the MSVC compiler. so the only thing we can do to please all 
    444     // those compilers [that "move towards the c++ standard"] is to conditionally
    445     // exclude the constructor string(const variant&). and this is not the whole
    446     // story. i see you are bored with it and i let you go. nobody would ever care
    447     // about this. it just works, though i'm not happy with what i wrote here:
    448     string t;
    449     t.initialize(*this);
    450     return t;
    451 }
    452 
    453 
    454 variant::operator component*() const
    455 {
    456     if (tag == VAR_OBJECT)
    457         return value.o;
    458     else
    459         return nil;
    460 }
    461 
    462 
    463 bool variant::equal(const variant& v) const
    464 {
    465     if (tag != v.tag)
    466         return false;
    467     switch (tag)
    468     {
    469     case VAR_NULL: return true;
    470     case VAR_INT: return value.i == v.value.i;
    471     case VAR_BOOL: return value.b == v.value.b;
    472     case VAR_FLOAT: return value.f == v.value.f;
    473     case VAR_STRING: return strcmp(value.s, v.value.s) == 0;
    474     case VAR_ARRAY: return value.a == v.value.a;
    475     case VAR_OBJECT: return value.o == v.value.o;
    476     default: vfatal(); return false;
    477     }
    478 }
    479 
    480 
    481 static string numkey(large key)
    482 {
    483     return itostring(key, 16, 16, '0');
    484 }
    485 
    486 
    487 void ptdecl aclear(variant& v)
    488 {
    489     if (v.tag == VAR_ARRAY)
    490         v.value.a->clear();
    491     else
    492     {
    493         v.finalize();
    494         v.initialize(new _varray());
    495     }
    496 }
    497 
    498 
    499 void ptdecl apack(variant& v)
    500 {
    501     if (v.tag == VAR_ARRAY)
    502         v.value.a->pack();
    503 }
    504 
    505 
    506 variant ptdecl aclone(const variant& v)
    507 {
    508     if (v.tag == VAR_ARRAY)
    509         return variant(new _varray(*(v.value.a)));
    510     else
    511         return variant(new _varray());
    512 }
    513 
    514 
    515 int ptdecl alength(const variant& v)
    516 {
    517     if (v.tag == VAR_ARRAY)
    518         return v.value.a->get_count();
    519     else
    520         return 0;
    521 }
    522 
    523 
    524 const variant& ptdecl get(const variant& v, const string& key)
    525 {
    526     if (v.tag == VAR_ARRAY)
    527         return v.value.a->get(key);
    528     else
    529         return nullvar;
    530 }
    531 
    532 
    533 const variant& ptdecl get(const variant& v, large key)
    534 {
    535     return get(v, numkey(key));
    536 }
    537 
    538 
    539 void ptdecl put(variant& v, const string& key, const variant& item)
    540 {
    541     if (v.tag != VAR_ARRAY)
    542         aclear(v);
    543     v.value.a->put(key, item);
    544 }
    545 
    546 
    547 void ptdecl put(variant& v, large key, const variant& item)
    548 {
    549     put(v, numkey(key), item);
    550 }
    551 
    552 
    553 void ptdecl del(variant& v, const string& key)
    554 {
    555     if (v.tag == VAR_ARRAY)
    556         v.value.a->del(key);
    557 }
    558 
    559 
    560 void ptdecl del(variant& v, large key)
    561 {
    562     del(v, numkey(key));
    563 }
    564 
    565 
    566 bool ptdecl anext(const variant& array, int& index, variant& item)
    567 {
    568     string key;
    569     return anext(array, index, item, key);
    570 }
    571 
    572 
    573 bool ptdecl anext(const variant& array, int& index, variant& item, string& key)
    574 {
    575     if (array.tag != VAR_ARRAY)
    576     {
    577         clear(item);
    578         return false;
    579     }
    580     if (index < 0 || index >= array.value.a->get_count())
    581     {
    582         clear(item);
    583         return false;
    584     }
    585     item = array.value.a->doget(index)->var;
    586     key = array.value.a->doget(index)->key;
    587     index++;
    588     return true;
    589 }
    590 
    591 
    592 int ptdecl aadd(variant& array, const variant& item)
    593 {
    594     if (array.tag != VAR_ARRAY)
    595         aclear(array);
    596     return array.value.a->addvar(item);
    597 }
    598 
    599 
    600 const variant& ptdecl aget(const variant& array, int index)
    601 {
    602     if (array.tag == VAR_ARRAY)
    603         return array.value.a->get(index);
    604     else
    605         return nullvar;
    606 }
    607 
    608 
    609 void ptdecl adel(variant& array, int index)
    610 {
    611     if (array.tag == VAR_ARRAY)
    612         array.value.a->del(index);
    613 }
    614 
    615 
    616 void ptdecl aput(variant& array, int index, const variant& item)
    617 {
    618     if (array.tag == VAR_ARRAY)
    619         array.value.a->put(index, item);
    620 }
    621 
    622 
    623 void ptdecl ains(variant& array, int index, const variant& item)
    624 {
    625     if (array.tag == VAR_ARRAY)
    626         array.value.a->ins(index, item);
    627 }
    628 
    629 
    630 #ifdef _MSC_VER
    631 // disable "unreachable code" warning for throw (known compiler bug)
    632 #  pragma warning (disable: 4702)
    633 #endif
    634 
    635 static void vconverr(large v)
    636 {
    637     throw new evariant("Value out of range: " + itostring(v));
    638 }
    639 
    640 
    641 }