RAUL 0.7.0
|
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