RAUL
0.8.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 <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