• 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 <cstdlib>
00023 #include <cassert>
00024 #include <cstring>
00025 #include <string>
00026 #include <map>
00027 #include <ostream>
00028 #include <glib.h>
00029 
00030 namespace Raul {
00031 
00032 class URI;
00033 
00042 class Atom {
00043 public:
00044     enum Type {
00045         NIL,
00046         INT,
00047         FLOAT,
00048         BOOL,
00049         URI,
00050         STRING,
00051         BLOB,
00052         DICT
00053     };
00054 
00055     Atom()                : _type(NIL),    _blob_val(0)             {}
00056     Atom(int32_t val)     : _type(INT),    _int_val(val)            {}
00057     Atom(float val)       : _type(FLOAT),  _float_val(val)          {}
00058     Atom(bool val)        : _type(BOOL),   _bool_val(val)           {}
00059     Atom(const char* val) : _type(STRING), _string_val(strdup(val)) {}
00060 
00061     Atom(const std::string& val) : _type(STRING), _string_val(strdup(val.c_str())) {}
00062 
00064     Atom(Type t, const std::string& val) : _type(t), _string_val(g_intern_string(val.c_str())) {
00065         assert(t == URI);
00066     }
00067 
00068     Atom(const char* type_uri, size_t size, void* val)
00069         : _type(BLOB), _blob_val(new BlobValue(type_uri, size, val)) {}
00070 
00071     typedef std::map<Raul::Atom, Raul::Atom> DictValue;
00072     Atom(const DictValue& dict) : _type(DICT), _dict_val(new DictValue(dict)) {}
00073 
00074     ~Atom() { dealloc(); }
00075 
00076     Atom(const Atom& copy)
00077         : _type(copy._type)
00078     {
00079         switch (_type) {
00080         case NIL:    _blob_val   = 0;                              break;
00081         case INT:    _int_val    = copy._int_val;                  break;
00082         case FLOAT:  _float_val  = copy._float_val;                break;
00083         case BOOL:   _bool_val   = copy._bool_val;                 break;
00084         case URI:    _string_val = copy._string_val;               break;
00085         case STRING: _string_val = strdup(copy._string_val);       break;
00086         case BLOB:   _blob_val   = new BlobValue(*copy._blob_val); break;
00087         case DICT:   _dict_val   = new DictValue(*copy._dict_val); break;
00088         }
00089     }
00090 
00091     Atom& operator=(const Atom& other) {
00092         dealloc();
00093         _type = other._type;
00094 
00095         switch (_type) {
00096         case NIL:    _blob_val   = 0;                               break;
00097         case INT:    _int_val    = other._int_val;                  break;
00098         case FLOAT:  _float_val  = other._float_val;                break;
00099         case BOOL:   _bool_val   = other._bool_val;                 break;
00100         case URI:    _string_val = other._string_val;               break;
00101         case STRING: _string_val = strdup(other._string_val);       break;
00102         case BLOB:   _blob_val   = new BlobValue(*other._blob_val); break;
00103         case DICT:   _dict_val   = new DictValue(*other._dict_val); break;
00104         }
00105         return *this;
00106     }
00107 
00108     inline bool operator==(const Atom& other) const {
00109         if (_type == other.type()) {
00110             switch (_type) {
00111             case NIL:    return true;
00112             case INT:    return _int_val    == other._int_val;
00113             case FLOAT:  return _float_val  == other._float_val;
00114             case BOOL:   return _bool_val   == other._bool_val;
00115             case URI:    return _string_val == other._string_val;
00116             case STRING: return strcmp(_string_val, other._string_val) == 0;
00117             case BLOB:   return _blob_val == other._blob_val;
00118             case DICT:   return *_dict_val == *other._dict_val;
00119             }
00120         }
00121         return false;
00122     }
00123 
00124     inline bool operator!=(const Atom& other) const { return ! operator==(other); }
00125 
00126     inline bool operator<(const Atom& other) const {
00127         if (_type == other.type()) {
00128             switch (_type) {
00129             case NIL:    return true;
00130             case INT:    return _int_val    < other._int_val;
00131             case FLOAT:  return _float_val  < other._float_val;
00132             case BOOL:   return _bool_val   < other._bool_val;
00133             case URI:
00134                 if (_string_val == other._string_val) {
00135                     return false;
00136                 } // else fall through to STRING
00137             case STRING: return strcmp(_string_val, other._string_val) < 0;
00138             case BLOB:   return _blob_val   < other._blob_val;
00139             case DICT:   return *_dict_val  < *other._dict_val;
00140             }
00141         }
00142         return _type < other.type();
00143     }
00144 
00145     inline size_t data_size() const {
00146         switch (_type) {
00147         case NIL:    return 0;
00148         case INT:    return sizeof(uint32_t);
00149         case FLOAT:  return sizeof(float);
00150         case BOOL:   return sizeof(bool);
00151         case URI:
00152         case STRING: return strlen(_string_val);
00153         case BLOB:   return _blob_val->size();
00154         case DICT:   return 0; // FIXME ?
00155         }
00156         return 0;
00157     }
00158 
00159     inline bool is_valid() const { return (_type != NIL); }
00160 
00164     Type type() const { return _type; }
00165 
00166     inline int32_t     get_int32()  const { assert(_type == INT);    return _int_val; }
00167     inline float       get_float()  const { assert(_type == FLOAT);  return _float_val; }
00168     inline bool        get_bool()   const { assert(_type == BOOL);   return _bool_val; }
00169     inline const char* get_string() const { assert(_type == STRING); return _string_val; }
00170     inline const char* get_uri()    const { assert(_type == URI);    return _string_val; }
00171 
00172     inline const char* get_blob_type() const { assert(_type == BLOB); return _blob_val->type(); }
00173     inline const void* get_blob()      const { assert(_type == BLOB); return _blob_val->data(); }
00174 
00175     inline const DictValue& get_dict() const { assert(_type == DICT); return *_dict_val; }
00176 
00177 private:
00178     Type _type;
00179 
00180     friend class Raul::URI;
00181     Atom(const char* str, uint32_t magic) : _type(URI), _string_val(str) {
00182         assert(magic == 12345);
00183         assert(g_intern_string(str) == str);
00184     }
00185 
00186     inline void dealloc() {
00187         switch (_type) {
00188         case STRING:
00189             free(const_cast<char*>(_string_val));
00190             break;
00191         case BLOB:
00192             delete _blob_val;
00193         default:
00194             break;
00195         }
00196     }
00197 
00198     class BlobValue {
00199     public:
00200         BlobValue(const char* type, size_t size, void* data)
00201             : _type_length(strlen(type) + 1) // + 1 for \0
00202             , _size(size)
00203             , _buf(malloc(_type_length + _size))
00204         {
00205             memcpy(_buf, type, _type_length);
00206             memcpy(static_cast<char*>(_buf) + _type_length, data, size);
00207         }
00208 
00209         BlobValue(const BlobValue& copy)
00210             : _type_length(copy._type_length)
00211             , _size(copy._size)
00212             , _buf(malloc(_type_length + _size))
00213         {
00214             _type_length = copy._type_length;
00215             memcpy(_buf, copy._buf, _type_length + _size);
00216         }
00217 
00218         ~BlobValue() { free(_buf); }
00219 
00220         inline const char* type() const { return static_cast<const char*>(_buf); }
00221         inline const void* data() const { return static_cast<const char*>(_buf) + _type_length; }
00222         inline size_t      size() const { return _size; }
00223     private:
00224         size_t _type_length; 
00225         size_t _size;        
00226         void*  _buf;         
00227     };
00228 
00229     union {
00230         int32_t          _int_val;
00231         float            _float_val;
00232         bool             _bool_val;
00233         const char*      _string_val;
00234         BlobValue*       _blob_val;
00235         const DictValue* _dict_val;
00236     };
00237 };
00238 
00239 
00240 } // namespace Raul
00241 
00242 static inline std::ostream& operator<<(std::ostream& os, const Raul::Atom& atom)
00243 {
00244     switch (atom.type()) {
00245     case Raul::Atom::NIL:    return os << "(nil)";
00246     case Raul::Atom::INT:    return os << atom.get_int32();
00247     case Raul::Atom::FLOAT:  return os << atom.get_float();
00248     case Raul::Atom::BOOL:   return os << (atom.get_bool() ? "true" : "false");
00249     case Raul::Atom::URI:    return os << "<" << atom.get_uri() << ">";
00250     case Raul::Atom::STRING: return os << atom.get_string();
00251     case Raul::Atom::BLOB:   return os << atom.get_blob();
00252     case Raul::Atom::DICT:
00253         os << "{";
00254         for (Raul::Atom::DictValue::const_iterator i = atom.get_dict().begin();
00255                 i != atom.get_dict().end(); ++i) {
00256             os << " " << i->first << " " << i->second << ";";
00257         }
00258         os << " }";
00259         return os;
00260     }
00261     return os;
00262 }
00263 
00264 static inline std::ostream& operator<<(std::ostream& os, Raul::Atom::Type type)
00265 {
00266     switch (type) {
00267     case Raul::Atom::NIL:    return os << "Nil";
00268     case Raul::Atom::INT:    return os << "Int";
00269     case Raul::Atom::FLOAT:  return os << "Float";
00270     case Raul::Atom::BOOL:   return os << "Bool";
00271     case Raul::Atom::URI:    return os << "URI";
00272     case Raul::Atom::STRING: return os << "String";
00273     case Raul::Atom::BLOB:   return os << "Blob";
00274     case Raul::Atom::DICT:   return os << "Dict";
00275     }
00276     return os;
00277 }
00278 
00279 #endif // RAUL_ATOM_HPP

Generated on Sun Sep 12 2010 for RAUL by  doxygen 1.7.1