RAUL  0.8.0
Atom.hpp
1 /* This file is part of Raul.
2  * Copyright (C) 2007-2009 David Robillard <http://drobilla.net>
3  *
4  * Raul is free software; you can redistribute it and/or modify it under the
5  * terms of the GNU General Public License as published by the Free Software
6  * Foundation; either version 2 of the License, or (at your option) any later
7  * version.
8  *
9  * Raul is distributed in the hope that it will be useful, but WITHOUT ANY
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16  */
17 
18 #ifndef RAUL_ATOM_HPP
19 #define RAUL_ATOM_HPP
20 
21 #include <stdint.h>
22 #include <glib.h>
23 
24 #include <cassert>
25 #include <cstdlib>
26 #include <cstring>
27 #include <map>
28 #include <ostream>
29 #include <string>
30 
31 namespace Raul {
32 
33 class URI;
34 
43 class Atom {
44 public:
45  enum Type {
46  NIL,
47  INT,
48  FLOAT,
49  BOOL,
50  URI,
51  STRING,
52  BLOB,
53  DICT
54  };
55 
56  Atom() : _type(NIL), _blob_val(0) {}
57  Atom(int32_t val) : _type(INT), _int_val(val) {}
58  Atom(float val) : _type(FLOAT), _float_val(val) {}
59  Atom(bool val) : _type(BOOL), _bool_val(val) {}
60  Atom(const char* val) : _type(STRING), _string_val(strdup(val)) {}
61 
62  Atom(const std::string& val) : _type(STRING), _string_val(strdup(val.c_str())) {}
63 
65  Atom(Type t, const std::string& val) : _type(t), _string_val(g_intern_string(val.c_str())) {
66  assert(t == URI);
67  }
68 
69  Atom(const char* type_uri, size_t size, void* val)
70  : _type(BLOB), _blob_val(new BlobValue(type_uri, size, val)) {}
71 
72  typedef std::map<Raul::Atom, Raul::Atom> DictValue;
73  Atom(const DictValue& dict) : _type(DICT), _dict_val(new DictValue(dict)) {}
74 
75  ~Atom() { dealloc(); }
76 
77  Atom(const Atom& copy)
78  : _type(copy._type)
79  {
80  switch (_type) {
81  case NIL: _blob_val = 0; break;
82  case INT: _int_val = copy._int_val; break;
83  case FLOAT: _float_val = copy._float_val; break;
84  case BOOL: _bool_val = copy._bool_val; break;
85  case URI: _string_val = copy._string_val; break;
86  case STRING: _string_val = strdup(copy._string_val); break;
87  case BLOB: _blob_val = new BlobValue(*copy._blob_val); break;
88  case DICT: _dict_val = new DictValue(*copy._dict_val); break;
89  }
90  }
91 
92  Atom& operator=(const Atom& other) {
93  dealloc();
94  _type = other._type;
95 
96  switch (_type) {
97  case NIL: _blob_val = 0; break;
98  case INT: _int_val = other._int_val; break;
99  case FLOAT: _float_val = other._float_val; break;
100  case BOOL: _bool_val = other._bool_val; break;
101  case URI: _string_val = other._string_val; break;
102  case STRING: _string_val = strdup(other._string_val); break;
103  case BLOB: _blob_val = new BlobValue(*other._blob_val); break;
104  case DICT: _dict_val = new DictValue(*other._dict_val); break;
105  }
106  return *this;
107  }
108 
109  inline bool operator==(const Atom& other) const {
110  if (_type == other.type()) {
111  switch (_type) {
112  case NIL: return true;
113  case INT: return _int_val == other._int_val;
114  case FLOAT: return _float_val == other._float_val;
115  case BOOL: return _bool_val == other._bool_val;
116  case URI: return _string_val == other._string_val;
117  case STRING: return strcmp(_string_val, other._string_val) == 0;
118  case BLOB: return _blob_val == other._blob_val;
119  case DICT: return *_dict_val == *other._dict_val;
120  }
121  }
122  return false;
123  }
124 
125  inline bool operator!=(const Atom& other) const { return ! operator==(other); }
126 
127  inline bool operator<(const Atom& other) const {
128  if (_type == other.type()) {
129  switch (_type) {
130  case NIL: return true;
131  case INT: return _int_val < other._int_val;
132  case FLOAT: return _float_val < other._float_val;
133  case BOOL: return _bool_val < other._bool_val;
134  case URI:
135  if (_string_val == other._string_val) {
136  return false;
137  } // else fall through to STRING
138  case STRING: return strcmp(_string_val, other._string_val) < 0;
139  case BLOB: return _blob_val < other._blob_val;
140  case DICT: return *_dict_val < *other._dict_val;
141  }
142  }
143  return _type < other.type();
144  }
145 
146  inline size_t data_size() const {
147  switch (_type) {
148  case NIL: return 0;
149  case INT: return sizeof(uint32_t);
150  case FLOAT: return sizeof(float);
151  case BOOL: return sizeof(bool);
152  case URI:
153  case STRING: return strlen(_string_val) + 1;
154  case BLOB: return _blob_val->size();
155  case DICT: return 0; // FIXME ?
156  }
157  return 0;
158  }
159 
160  inline bool is_valid() const { return (_type != NIL); }
161 
165  Type type() const { return _type; }
166 
167  inline int32_t get_int32() const { assert(_type == INT); return _int_val; }
168  inline float get_float() const { assert(_type == FLOAT); return _float_val; }
169  inline bool get_bool() const { assert(_type == BOOL); return _bool_val; }
170  inline const char* get_string() const { assert(_type == STRING); return _string_val; }
171  inline const char* get_uri() const { assert(_type == URI); return _string_val; }
172 
173  inline const char* get_blob_type() const { assert(_type == BLOB); return _blob_val->type(); }
174  inline const void* get_blob() const { assert(_type == BLOB); return _blob_val->data(); }
175 
176  inline const DictValue& get_dict() const { assert(_type == DICT); return *_dict_val; }
177 
178 private:
179  Type _type;
180 
181  friend class Raul::URI;
182  Atom(const char* str, uint32_t magic) : _type(URI), _string_val(str) {
183  assert(magic == 12345);
184  assert(g_intern_string(str) == str);
185  }
186 
187  inline void dealloc() {
188  switch (_type) {
189  case STRING:
190  free(const_cast<char*>(_string_val));
191  break;
192  case BLOB:
193  delete _blob_val;
194  default:
195  break;
196  }
197  }
198 
199  class BlobValue {
200  public:
201  BlobValue(const char* type, size_t size, void* data)
202  : _type_length(strlen(type) + 1) // + 1 for \0
203  , _size(size)
204  , _buf(malloc(_type_length + _size))
205  {
206  memcpy(_buf, type, _type_length);
207  memcpy(static_cast<char*>(_buf) + _type_length, data, size);
208  }
209 
210  BlobValue(const BlobValue& copy)
211  : _type_length(copy._type_length)
212  , _size(copy._size)
213  , _buf(malloc(_type_length + _size))
214  {
215  _type_length = copy._type_length;
216  memcpy(_buf, copy._buf, _type_length + _size);
217  }
218 
219  ~BlobValue() { free(_buf); }
220 
221  inline const char* type() const { return static_cast<const char*>(_buf); }
222  inline const void* data() const { return static_cast<const char*>(_buf) + _type_length; }
223  inline size_t size() const { return _size; }
224  private:
225  size_t _type_length;
226  size_t _size;
227  void* _buf;
228  };
229 
230  union {
231  int32_t _int_val;
232  float _float_val;
233  bool _bool_val;
234  const char* _string_val;
235  BlobValue* _blob_val;
236  const DictValue* _dict_val;
237  };
238 };
239 
240 
241 } // namespace Raul
242 
243 static inline std::ostream& operator<<(std::ostream& os, const Raul::Atom& atom)
244 {
245  switch (atom.type()) {
246  case Raul::Atom::NIL: return os << "(nil)";
247  case Raul::Atom::INT: return os << atom.get_int32();
248  case Raul::Atom::FLOAT: return os << atom.get_float();
249  case Raul::Atom::BOOL: return os << (atom.get_bool() ? "true" : "false");
250  case Raul::Atom::URI: return os << "<" << atom.get_uri() << ">";
251  case Raul::Atom::STRING: return os << atom.get_string();
252  case Raul::Atom::BLOB: return os << atom.get_blob();
253  case Raul::Atom::DICT:
254  os << "{";
255  for (Raul::Atom::DictValue::const_iterator i = atom.get_dict().begin();
256  i != atom.get_dict().end(); ++i) {
257  os << " " << i->first << " " << i->second << ";";
258  }
259  os << " }";
260  return os;
261  }
262  return os;
263 }
264 
265 static inline std::ostream& operator<<(std::ostream& os, Raul::Atom::Type type)
266 {
267  switch (type) {
268  case Raul::Atom::NIL: return os << "Nil";
269  case Raul::Atom::INT: return os << "Int";
270  case Raul::Atom::FLOAT: return os << "Float";
271  case Raul::Atom::BOOL: return os << "Bool";
272  case Raul::Atom::URI: return os << "URI";
273  case Raul::Atom::STRING: return os << "String";
274  case Raul::Atom::BLOB: return os << "Blob";
275  case Raul::Atom::DICT: return os << "Dict";
276  }
277  return os;
278 }
279 
280 #endif // RAUL_ATOM_HPP
A piece of data with some type.
Definition: Atom.hpp:43
Atom(Type t, const std::string &val)
URI constructor (t must be URI)
Definition: Atom.hpp:65
Type type() const
Type of this atom.
Definition: Atom.hpp:165
Simple wrapper around standard string with useful URI-specific methods.
Definition: URI.hpp:37
URI(const std::basic_string< char > &uri="nil:0")
Construct a URI from an std::string.
Definition: URI.hpp:53