00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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 }
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;
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)
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 }
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