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 <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 }
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;
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)
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 }
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