• Main Page
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List

Atom.hpp

00001 /* This file is part of Raul.
00002  * Copyright (C) 2007-2009 David Robillard <http://drobilla.net>
00003  *
00004  * Raul is free software; you can redistribute it and/or modify it under the
00005  * terms of the GNU General Public License as published by the Free Software
00006  * Foundation; either version 2 of the License, or (at your option) any later
00007  * version.
00008  *
00009  * Raul is distributed in the hope that it will be useful, but WITHOUT ANY
00010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
00012  *
00013  * You should have received a copy of the GNU General Public License along
00014  * with this program; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00016  */
00017 
00018 #ifndef RAUL_ATOM_HPP
00019 #define RAUL_ATOM_HPP
00020 
00021 #include <stdint.h>
00022 #include <glib.h>
00023 
00024 #include <cassert>
00025 #include <cstdlib>
00026 #include <cstring>
00027 #include <map>
00028 #include <ostream>
00029 #include <string>
00030 
00031 namespace Raul {
00032 
00033 class URI;
00034 
00043 class Atom {
00044 public:
00045     enum Type {
00046         NIL,
00047         INT,
00048         FLOAT,
00049         BOOL,
00050         URI,
00051         STRING,
00052         BLOB,
00053         DICT
00054     };
00055 
00056     Atom()                : _type(NIL),    _blob_val(0)             {}
00057     Atom(int32_t val)     : _type(INT),    _int_val(val)            {}
00058     Atom(float val)       : _type(FLOAT),  _float_val(val)          {}
00059     Atom(bool val)        : _type(BOOL),   _bool_val(val)           {}
00060     Atom(const char* val) : _type(STRING), _string_val(strdup(val)) {}
00061 
00062     Atom(const std::string& val) : _type(STRING), _string_val(strdup(val.c_str())) {}
00063 
00065     Atom(Type t, const std::string& val) : _type(t), _string_val(g_intern_string(val.c_str())) {
00066         assert(t == URI);
00067     }
00068 
00069     Atom(const char* type_uri, size_t size, void* val)
00070         : _type(BLOB), _blob_val(new BlobValue(type_uri, size, val)) {}
00071 
00072     typedef std::map<Raul::Atom, Raul::Atom> DictValue;
00073     Atom(const DictValue& dict) : _type(DICT), _dict_val(new DictValue(dict)) {}
00074 
00075     ~Atom() { dealloc(); }
00076 
00077     Atom(const Atom& copy)
00078         : _type(copy._type)
00079     {
00080         switch (_type) {
00081         case NIL:    _blob_val   = 0;                              break;
00082         case INT:    _int_val    = copy._int_val;                  break;
00083         case FLOAT:  _float_val  = copy._float_val;                break;
00084         case BOOL:   _bool_val   = copy._bool_val;                 break;
00085         case URI:    _string_val = copy._string_val;               break;
00086         case STRING: _string_val = strdup(copy._string_val);       break;
00087         case BLOB:   _blob_val   = new BlobValue(*copy._blob_val); break;
00088         case DICT:   _dict_val   = new DictValue(*copy._dict_val); break;
00089         }
00090     }
00091 
00092     Atom& operator=(const Atom& other) {
00093         dealloc();
00094         _type = other._type;
00095 
00096         switch (_type) {
00097         case NIL:    _blob_val   = 0;                               break;
00098         case INT:    _int_val    = other._int_val;                  break;
00099         case FLOAT:  _float_val  = other._float_val;                break;
00100         case BOOL:   _bool_val   = other._bool_val;                 break;
00101         case URI:    _string_val = other._string_val;               break;
00102         case STRING: _string_val = strdup(other._string_val);       break;
00103         case BLOB:   _blob_val   = new BlobValue(*other._blob_val); break;
00104         case DICT:   _dict_val   = new DictValue(*other._dict_val); break;
00105         }
00106         return *this;
00107     }
00108 
00109     inline bool operator==(const Atom& other) const {
00110         if (_type == other.type()) {
00111             switch (_type) {
00112             case NIL:    return true;
00113             case INT:    return _int_val    == other._int_val;
00114             case FLOAT:  return _float_val  == other._float_val;
00115             case BOOL:   return _bool_val   == other._bool_val;
00116             case URI:    return _string_val == other._string_val;
00117             case STRING: return strcmp(_string_val, other._string_val) == 0;
00118             case BLOB:   return _blob_val == other._blob_val;
00119             case DICT:   return *_dict_val == *other._dict_val;
00120             }
00121         }
00122         return false;
00123     }
00124 
00125     inline bool operator!=(const Atom& other) const { return ! operator==(other); }
00126 
00127     inline bool operator<(const Atom& other) const {
00128         if (_type == other.type()) {
00129             switch (_type) {
00130             case NIL:    return true;
00131             case INT:    return _int_val    < other._int_val;
00132             case FLOAT:  return _float_val  < other._float_val;
00133             case BOOL:   return _bool_val   < other._bool_val;
00134             case URI:
00135                 if (_string_val == other._string_val) {
00136                     return false;
00137                 } // else fall through to STRING
00138             case STRING: return strcmp(_string_val, other._string_val) < 0;
00139             case BLOB:   return _blob_val   < other._blob_val;
00140             case DICT:   return *_dict_val  < *other._dict_val;
00141             }
00142         }
00143         return _type < other.type();
00144     }
00145 
00146     inline size_t data_size() const {
00147         switch (_type) {
00148         case NIL:    return 0;
00149         case INT:    return sizeof(uint32_t);
00150         case FLOAT:  return sizeof(float);
00151         case BOOL:   return sizeof(bool);
00152         case URI:
00153         case STRING: return strlen(_string_val) + 1;
00154         case BLOB:   return _blob_val->size();
00155         case DICT:   return 0; // FIXME ?
00156         }
00157         return 0;
00158     }
00159 
00160     inline bool is_valid() const { return (_type != NIL); }
00161 
00165     Type type() const { return _type; }
00166 
00167     inline int32_t     get_int32()  const { assert(_type == INT);    return _int_val; }
00168     inline float       get_float()  const { assert(_type == FLOAT);  return _float_val; }
00169     inline bool        get_bool()   const { assert(_type == BOOL);   return _bool_val; }
00170     inline const char* get_string() const { assert(_type == STRING); return _string_val; }
00171     inline const char* get_uri()    const { assert(_type == URI);    return _string_val; }
00172 
00173     inline const char* get_blob_type() const { assert(_type == BLOB); return _blob_val->type(); }
00174     inline const void* get_blob()      const { assert(_type == BLOB); return _blob_val->data(); }
00175 
00176     inline const DictValue& get_dict() const { assert(_type == DICT); return *_dict_val; }
00177 
00178 private:
00179     Type _type;
00180 
00181     friend class Raul::URI;
00182     Atom(const char* str, uint32_t magic) : _type(URI), _string_val(str) {
00183         assert(magic == 12345);
00184         assert(g_intern_string(str) == str);
00185     }
00186 
00187     inline void dealloc() {
00188         switch (_type) {
00189         case STRING:
00190             free(const_cast<char*>(_string_val));
00191             break;
00192         case BLOB:
00193             delete _blob_val;
00194         default:
00195             break;
00196         }
00197     }
00198 
00199     class BlobValue {
00200     public:
00201         BlobValue(const char* type, size_t size, void* data)
00202             : _type_length(strlen(type) + 1) // + 1 for \0
00203             , _size(size)
00204             , _buf(malloc(_type_length + _size))
00205         {
00206             memcpy(_buf, type, _type_length);
00207             memcpy(static_cast<char*>(_buf) + _type_length, data, size);
00208         }
00209 
00210         BlobValue(const BlobValue& copy)
00211             : _type_length(copy._type_length)
00212             , _size(copy._size)
00213             , _buf(malloc(_type_length + _size))
00214         {
00215             _type_length = copy._type_length;
00216             memcpy(_buf, copy._buf, _type_length + _size);
00217         }
00218 
00219         ~BlobValue() { free(_buf); }
00220 
00221         inline const char* type() const { return static_cast<const char*>(_buf); }
00222         inline const void* data() const { return static_cast<const char*>(_buf) + _type_length; }
00223         inline size_t      size() const { return _size; }
00224     private:
00225         size_t _type_length; 
00226         size_t _size;        
00227         void*  _buf;         
00228     };
00229 
00230     union {
00231         int32_t          _int_val;
00232         float            _float_val;
00233         bool             _bool_val;
00234         const char*      _string_val;
00235         BlobValue*       _blob_val;
00236         const DictValue* _dict_val;
00237     };
00238 };
00239 
00240 
00241 } // namespace Raul
00242 
00243 static inline std::ostream& operator<<(std::ostream& os, const Raul::Atom& atom)
00244 {
00245     switch (atom.type()) {
00246     case Raul::Atom::NIL:    return os << "(nil)";
00247     case Raul::Atom::INT:    return os << atom.get_int32();
00248     case Raul::Atom::FLOAT:  return os << atom.get_float();
00249     case Raul::Atom::BOOL:   return os << (atom.get_bool() ? "true" : "false");
00250     case Raul::Atom::URI:    return os << "<" << atom.get_uri() << ">";
00251     case Raul::Atom::STRING: return os << atom.get_string();
00252     case Raul::Atom::BLOB:   return os << atom.get_blob();
00253     case Raul::Atom::DICT:
00254         os << "{";
00255         for (Raul::Atom::DictValue::const_iterator i = atom.get_dict().begin();
00256                 i != atom.get_dict().end(); ++i) {
00257             os << " " << i->first << " " << i->second << ";";
00258         }
00259         os << " }";
00260         return os;
00261     }
00262     return os;
00263 }
00264 
00265 static inline std::ostream& operator<<(std::ostream& os, Raul::Atom::Type type)
00266 {
00267     switch (type) {
00268     case Raul::Atom::NIL:    return os << "Nil";
00269     case Raul::Atom::INT:    return os << "Int";
00270     case Raul::Atom::FLOAT:  return os << "Float";
00271     case Raul::Atom::BOOL:   return os << "Bool";
00272     case Raul::Atom::URI:    return os << "URI";
00273     case Raul::Atom::STRING: return os << "String";
00274     case Raul::Atom::BLOB:   return os << "Blob";
00275     case Raul::Atom::DICT:   return os << "Dict";
00276     }
00277     return os;
00278 }
00279 
00280 #endif // RAUL_ATOM_HPP

Generated on Tue Jan 11 2011 18:26:17 for RAUL by  doxygen 1.7.1