Mercurial > hg > sv-dependency-builds
comparison osx/include/sord/sordmm.hpp @ 28:a988521943bc
sord-0 -> sord and serd-0 -> serd
author | Chris Cannam |
---|---|
date | Thu, 09 Jan 2014 21:21:48 +0000 |
parents | osx/include/sord-0/sord/sordmm.hpp@cc5d363db385 |
children |
comparison
equal
deleted
inserted
replaced
27:fffb975dc0b1 | 28:a988521943bc |
---|---|
1 /* | |
2 Copyright 2011-2013 David Robillard <http://drobilla.net> | |
3 | |
4 Permission to use, copy, modify, and/or distribute this software for any | |
5 purpose with or without fee is hereby granted, provided that the above | |
6 copyright notice and this permission notice appear in all copies. | |
7 | |
8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 */ | |
16 | |
17 /** | |
18 @file sordmm.hpp | |
19 Public Sord C++ API. | |
20 */ | |
21 | |
22 #ifndef SORD_SORDMM_HPP | |
23 #define SORD_SORDMM_HPP | |
24 | |
25 #include <cassert> | |
26 #include <cstring> | |
27 #include <cstdlib> | |
28 #include <iostream> | |
29 #include <set> | |
30 #include <string> | |
31 #include <sstream> | |
32 | |
33 #include "serd/serd.h" | |
34 #include "sord/sord.h" | |
35 | |
36 #define SORD_NS_XSD "http://www.w3.org/2001/XMLSchema#" | |
37 | |
38 namespace Sord { | |
39 | |
40 /** Utility base class to prevent copying. */ | |
41 class Noncopyable { | |
42 protected: | |
43 Noncopyable() {} | |
44 ~Noncopyable() {} | |
45 private: | |
46 Noncopyable(const Noncopyable&); | |
47 const Noncopyable& operator=(const Noncopyable&); | |
48 }; | |
49 | |
50 /** C++ wrapper for a Sord object. */ | |
51 template <typename T> | |
52 class Wrapper { | |
53 public: | |
54 inline Wrapper(T c_obj = NULL) : _c_obj(c_obj) {} | |
55 | |
56 inline T c_obj() { return _c_obj; } | |
57 inline const T c_obj() const { return _c_obj; } | |
58 | |
59 protected: | |
60 T _c_obj; | |
61 }; | |
62 | |
63 /** Collection of RDF namespaces with prefixes. */ | |
64 class Namespaces : public Wrapper<SerdEnv*> { | |
65 public: | |
66 Namespaces() : Wrapper<SerdEnv*>(serd_env_new(NULL)) {} | |
67 ~Namespaces() { serd_env_free(_c_obj); } | |
68 | |
69 static inline SerdNode string_to_node(SerdType type, const std::string& s) { | |
70 SerdNode ret = { | |
71 (const uint8_t*)s.c_str(), s.length(), s.length(), 0, type }; | |
72 return ret; | |
73 } | |
74 | |
75 inline void add(const std::string& name, | |
76 const std::string& uri) { | |
77 const SerdNode name_node = string_to_node(SERD_LITERAL, name); | |
78 const SerdNode uri_node = string_to_node(SERD_URI, uri); | |
79 serd_env_set_prefix(_c_obj, &name_node, &uri_node); | |
80 } | |
81 | |
82 inline std::string qualify(std::string uri) const { | |
83 const SerdNode uri_node = string_to_node(SERD_URI, uri); | |
84 SerdNode prefix; | |
85 SerdChunk suffix; | |
86 if (serd_env_qualify(_c_obj, &uri_node, &prefix, &suffix)) { | |
87 std::string ret((const char*)prefix.buf, prefix.n_bytes); | |
88 ret.append(":").append((const char*)suffix.buf, suffix.len); | |
89 return ret; | |
90 } | |
91 return uri; | |
92 } | |
93 | |
94 inline std::string expand(const std::string& curie) const { | |
95 assert(curie.find(":") != std::string::npos); | |
96 SerdNode curie_node = string_to_node(SERD_CURIE, curie); | |
97 SerdChunk uri_prefix; | |
98 SerdChunk uri_suffix; | |
99 if (!serd_env_expand(_c_obj, &curie_node, &uri_prefix, &uri_suffix)) { | |
100 std::string ret((const char*)uri_prefix.buf, uri_prefix.len); | |
101 ret.append((const char*)uri_suffix.buf, uri_suffix.len); | |
102 return ret; | |
103 } | |
104 std::cerr << "CURIE `" << curie << "' has unknown prefix." << std::endl; | |
105 return curie; | |
106 } | |
107 }; | |
108 | |
109 /** Sord library state. */ | |
110 class World : public Noncopyable, public Wrapper<SordWorld*> { | |
111 public: | |
112 inline World() | |
113 : _next_blank_id(0) | |
114 { | |
115 _c_obj = sord_world_new(); | |
116 } | |
117 | |
118 inline ~World() { | |
119 sord_world_free(_c_obj); | |
120 } | |
121 | |
122 inline uint64_t blank_id() { return _next_blank_id++; } | |
123 | |
124 inline void add_prefix(const std::string& prefix, const std::string& uri) { | |
125 _prefixes.add(prefix, uri); | |
126 } | |
127 | |
128 inline const Namespaces& prefixes() const { return _prefixes; } | |
129 inline SordWorld* world() { return _c_obj; } | |
130 | |
131 private: | |
132 Namespaces _prefixes; | |
133 std::set<std::string> _blank_ids; | |
134 uint64_t _next_blank_id; | |
135 }; | |
136 | |
137 /** An RDF Node (resource, literal, etc) | |
138 */ | |
139 class Node : public Wrapper<SordNode*> { | |
140 public: | |
141 enum Type { | |
142 UNKNOWN = 0, | |
143 URI = SORD_URI, | |
144 BLANK = SORD_BLANK, | |
145 LITERAL = SORD_LITERAL | |
146 }; | |
147 | |
148 inline Node() : Wrapper<SordNode*>(NULL), _world(NULL) {} | |
149 | |
150 inline Node(World& world, Type t, const std::string& s); | |
151 inline Node(World& world); | |
152 inline Node(World& world, const SordNode* node); | |
153 inline Node(World& world, SordNode* node, bool copy=false); | |
154 inline Node(const Node& other); | |
155 inline ~Node(); | |
156 | |
157 inline Type type() const { | |
158 return _c_obj ? (Type)sord_node_get_type(_c_obj) : UNKNOWN; | |
159 } | |
160 | |
161 inline const SordNode* get_node() const { return _c_obj; } | |
162 inline SordNode* get_node() { return _c_obj; } | |
163 | |
164 const SerdNode* to_serd_node() { | |
165 return sord_node_to_serd_node(_c_obj); | |
166 } | |
167 | |
168 inline bool is_valid() const { return type() != UNKNOWN; } | |
169 | |
170 inline bool operator<(const Node& other) const { | |
171 if (type() != other.type()) { | |
172 return type() < other.type(); | |
173 } else { | |
174 return to_string() < other.to_string(); | |
175 } | |
176 } | |
177 | |
178 Node& operator=(const Node& other) { | |
179 if (&other != this) { | |
180 if (_c_obj) { | |
181 sord_node_free(_world->c_obj(), _c_obj); | |
182 } | |
183 _world = other._world; | |
184 _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL; | |
185 } | |
186 return *this; | |
187 } | |
188 | |
189 inline bool operator==(const Node& other) const { | |
190 return sord_node_equals(_c_obj, other._c_obj); | |
191 } | |
192 | |
193 inline const uint8_t* to_u_string() const; | |
194 inline const char* to_c_string() const; | |
195 inline std::string to_string() const; | |
196 | |
197 inline bool is_literal_type(const char* type_uri) const; | |
198 | |
199 inline bool is_uri() const { return _c_obj && type() == URI; } | |
200 inline bool is_blank() const { return _c_obj && type() == BLANK; } | |
201 inline bool is_int() const { return is_literal_type(SORD_NS_XSD "integer"); } | |
202 inline bool is_float() const { return is_literal_type(SORD_NS_XSD "decimal"); } | |
203 inline bool is_bool() const { return is_literal_type(SORD_NS_XSD "boolean"); } | |
204 | |
205 inline int to_int() const; | |
206 inline float to_float() const; | |
207 inline bool to_bool() const; | |
208 | |
209 inline static Node blank_id(World& world, const std::string base="b") { | |
210 const uint64_t num = world.blank_id(); | |
211 std::ostringstream ss; | |
212 ss << base << num; | |
213 return Node(world, Node::BLANK, ss.str()); | |
214 } | |
215 | |
216 private: | |
217 World* _world; | |
218 }; | |
219 | |
220 inline std::ostream& | |
221 operator<<(std::ostream& os, const Node& node) | |
222 { | |
223 return os << node.to_string(); | |
224 } | |
225 | |
226 class URI : public Node { | |
227 public: | |
228 inline URI(World& world, const std::string& s) | |
229 : Node(world, Node::URI, s) {} | |
230 inline URI(World& world, const std::string& s, const std::string& base) | |
231 : Node(world, sord_new_relative_uri(world.world(), | |
232 (const uint8_t*)s.c_str(), | |
233 (const uint8_t*)base.c_str())) | |
234 {} | |
235 }; | |
236 | |
237 class Curie : public Node { | |
238 public: | |
239 inline Curie(World& world, const std::string& s) | |
240 : Node(world, Node::URI, world.prefixes().expand(s)) {} | |
241 }; | |
242 | |
243 class Literal : public Node { | |
244 public: | |
245 inline Literal(World& world, const std::string& s) | |
246 : Node(world, Node::LITERAL, s) {} | |
247 | |
248 static inline Node decimal(World& world, double d, unsigned frac_digits) { | |
249 const SerdNode val = serd_node_new_decimal(d, 7); | |
250 const SerdNode type = serd_node_from_string( | |
251 SERD_URI, (const uint8_t*)SORD_NS_XSD "decimal"); | |
252 | |
253 return Node( | |
254 world, | |
255 sord_node_from_serd_node( | |
256 world.c_obj(), world.prefixes().c_obj(), &val, &type, NULL), | |
257 false); | |
258 } | |
259 | |
260 static inline Node integer(World& world, int64_t i) { | |
261 const SerdNode val = serd_node_new_integer(i); | |
262 const SerdNode type = serd_node_from_string( | |
263 SERD_URI, (const uint8_t*)SORD_NS_XSD "integer"); | |
264 | |
265 return Node( | |
266 world, | |
267 sord_node_from_serd_node( | |
268 world.c_obj(), world.prefixes().c_obj(), &val, &type, NULL), | |
269 false); | |
270 } | |
271 }; | |
272 | |
273 inline | |
274 Node::Node(World& world, Type type, const std::string& s) | |
275 : _world(&world) | |
276 { | |
277 switch (type) { | |
278 case URI: | |
279 _c_obj = sord_new_uri( | |
280 world.world(), (const unsigned char*)s.c_str()); | |
281 break; | |
282 case LITERAL: | |
283 _c_obj = sord_new_literal( | |
284 world.world(), NULL, (const unsigned char*)s.c_str(), NULL); | |
285 break; | |
286 case BLANK: | |
287 _c_obj = sord_new_blank( | |
288 world.world(), (const unsigned char*)s.c_str()); | |
289 break; | |
290 default: | |
291 _c_obj = NULL; | |
292 } | |
293 | |
294 assert(this->type() == type); | |
295 } | |
296 | |
297 inline | |
298 Node::Node(World& world) | |
299 : _world(&world) | |
300 { | |
301 Node me = blank_id(world); | |
302 *this = me; | |
303 } | |
304 | |
305 inline | |
306 Node::Node(World& world, const SordNode* node) | |
307 : _world(&world) | |
308 { | |
309 _c_obj = sord_node_copy(node); | |
310 } | |
311 | |
312 inline | |
313 Node::Node(World& world, SordNode* node, bool copy) | |
314 : _world(&world) | |
315 { | |
316 _c_obj = copy ? sord_node_copy(node) : node; | |
317 } | |
318 | |
319 inline | |
320 Node::Node(const Node& other) | |
321 : Wrapper<SordNode*>() | |
322 , _world(other._world) | |
323 { | |
324 if (_world) { | |
325 _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL; | |
326 } | |
327 | |
328 assert((!_c_obj && !other._c_obj) || to_string() == other.to_string()); | |
329 } | |
330 | |
331 inline | |
332 Node::~Node() | |
333 { | |
334 if (_world) { | |
335 sord_node_free(_world->c_obj(), _c_obj); | |
336 } | |
337 } | |
338 | |
339 inline std::string | |
340 Node::to_string() const | |
341 { | |
342 return _c_obj ? (const char*)sord_node_get_string(_c_obj) : ""; | |
343 } | |
344 | |
345 inline const char* | |
346 Node::to_c_string() const | |
347 { | |
348 return (const char*)sord_node_get_string(_c_obj); | |
349 } | |
350 | |
351 inline const uint8_t* | |
352 Node::to_u_string() const | |
353 { | |
354 return sord_node_get_string(_c_obj); | |
355 } | |
356 | |
357 inline bool | |
358 Node::is_literal_type(const char* type_uri) const | |
359 { | |
360 if (_c_obj && sord_node_get_type(_c_obj) == SORD_LITERAL) { | |
361 const SordNode* datatype = sord_node_get_datatype(_c_obj); | |
362 if (datatype && !strcmp((const char*)sord_node_get_string(datatype), | |
363 type_uri)) | |
364 return true; | |
365 } | |
366 return false; | |
367 } | |
368 | |
369 inline int | |
370 Node::to_int() const | |
371 { | |
372 assert(is_int()); | |
373 char* endptr; | |
374 return strtol((const char*)sord_node_get_string(_c_obj), &endptr, 10); | |
375 } | |
376 | |
377 inline float | |
378 Node::to_float() const | |
379 { | |
380 assert(is_float()); | |
381 char* endptr; | |
382 return serd_strtod((const char*)sord_node_get_string(_c_obj), &endptr); | |
383 } | |
384 | |
385 inline bool | |
386 Node::to_bool() const | |
387 { | |
388 assert(is_bool()); | |
389 return !strcmp((const char*)sord_node_get_string(_c_obj), "true"); | |
390 } | |
391 | |
392 struct Iter : public Wrapper<SordIter*> { | |
393 inline Iter(World& world, SordIter* c_obj) | |
394 : Wrapper<SordIter*>(c_obj), _world(world) {} | |
395 inline ~Iter() { sord_iter_free(_c_obj); } | |
396 inline bool end() const { return sord_iter_end(_c_obj); } | |
397 inline bool next() const { return sord_iter_next(_c_obj); } | |
398 inline Iter& operator++() { | |
399 assert(!end()); | |
400 next(); | |
401 return *this; | |
402 } | |
403 inline const Node get_subject() const { | |
404 SordQuad quad; | |
405 sord_iter_get(_c_obj, quad); | |
406 return Node(_world, quad[SORD_SUBJECT]); | |
407 } | |
408 inline const Node get_predicate() const { | |
409 SordQuad quad; | |
410 sord_iter_get(_c_obj, quad); | |
411 return Node(_world, quad[SORD_PREDICATE]); | |
412 } | |
413 inline const Node get_object() const { | |
414 SordQuad quad; | |
415 sord_iter_get(_c_obj, quad); | |
416 return Node(_world, quad[SORD_OBJECT]); | |
417 } | |
418 World& _world; | |
419 }; | |
420 | |
421 /** An RDF Model (collection of triples). | |
422 */ | |
423 class Model : public Noncopyable, public Wrapper<SordModel*> { | |
424 public: | |
425 inline Model(World& world, | |
426 const std::string& base_uri, | |
427 unsigned indices = (SORD_SPO | SORD_OPS), | |
428 bool graphs = true); | |
429 | |
430 inline ~Model(); | |
431 | |
432 inline const Node& base_uri() const { return _base; } | |
433 | |
434 size_t num_quads() const { return sord_num_quads(_c_obj); } | |
435 | |
436 inline void load_file(SerdEnv* env, | |
437 SerdSyntax syntax, | |
438 const std::string& uri, | |
439 const std::string& base_uri=""); | |
440 | |
441 inline void load_string(SerdEnv* env, | |
442 SerdSyntax syntax, | |
443 const char* str, | |
444 size_t len, | |
445 const std::string& base_uri); | |
446 | |
447 inline SerdStatus write_to_file( | |
448 const std::string& uri, | |
449 SerdSyntax syntax = SERD_TURTLE, | |
450 SerdStyle style = (SerdStyle)(SERD_STYLE_ABBREVIATED | |
451 |SERD_STYLE_CURIED | |
452 |SERD_STYLE_RESOLVED)); | |
453 | |
454 inline std::string write_to_string( | |
455 const std::string& base_uri, | |
456 SerdSyntax syntax = SERD_TURTLE, | |
457 SerdStyle style = (SerdStyle)(SERD_STYLE_ABBREVIATED | |
458 |SERD_STYLE_CURIED | |
459 |SERD_STYLE_RESOLVED)); | |
460 | |
461 inline void add_statement(const Node& subject, | |
462 const Node& predicate, | |
463 const Node& object); | |
464 | |
465 inline Iter find(const Node& subject, | |
466 const Node& predicate, | |
467 const Node& object); | |
468 | |
469 inline Node get(const Node& subject, | |
470 const Node& predicate, | |
471 const Node& object); | |
472 | |
473 inline World& world() const { return _world; } | |
474 | |
475 private: | |
476 World& _world; | |
477 Node _base; | |
478 SerdWriter* _writer; | |
479 size_t _next_blank_id; | |
480 }; | |
481 | |
482 /** Create an empty in-memory RDF model. | |
483 */ | |
484 inline | |
485 Model::Model(World& world, | |
486 const std::string& base_uri, | |
487 unsigned indices, | |
488 bool graphs) | |
489 : _world(world) | |
490 , _base(world, Node::URI, base_uri) | |
491 , _writer(NULL) | |
492 { | |
493 _c_obj = sord_new(_world.world(), indices, graphs); | |
494 } | |
495 | |
496 inline void | |
497 Model::load_string(SerdEnv* env, | |
498 SerdSyntax syntax, | |
499 const char* str, | |
500 size_t len, | |
501 const std::string& base_uri) | |
502 { | |
503 SerdReader* reader = sord_new_reader(_c_obj, env, syntax, NULL); | |
504 serd_reader_read_string(reader, (const uint8_t*)str); | |
505 serd_reader_free(reader); | |
506 } | |
507 | |
508 inline Model::~Model() | |
509 { | |
510 sord_free(_c_obj); | |
511 } | |
512 | |
513 inline void | |
514 Model::load_file(SerdEnv* env, | |
515 SerdSyntax syntax, | |
516 const std::string& data_uri, | |
517 const std::string& base_uri) | |
518 { | |
519 uint8_t* path = serd_file_uri_parse((const uint8_t*)data_uri.c_str(), NULL); | |
520 if (!path) { | |
521 fprintf(stderr, "Failed to parse file URI <%s>\n", data_uri.c_str()); | |
522 return; | |
523 } | |
524 | |
525 // FIXME: blank prefix parameter? | |
526 SerdReader* reader = sord_new_reader(_c_obj, env, syntax, NULL); | |
527 serd_reader_read_file(reader, path); | |
528 serd_reader_free(reader); | |
529 free(path); | |
530 } | |
531 | |
532 inline SerdStatus | |
533 Model::write_to_file(const std::string& uri, SerdSyntax syntax, SerdStyle style) | |
534 { | |
535 uint8_t* path = serd_file_uri_parse((const uint8_t*)uri.c_str(), NULL); | |
536 if (!path) { | |
537 fprintf(stderr, "Failed to parse file URI <%s>\n", uri.c_str()); | |
538 return SERD_ERR_BAD_ARG; | |
539 } | |
540 | |
541 FILE* const fd = fopen((const char*)path, "w"); | |
542 if (!fd) { | |
543 fprintf(stderr, "Failed to open file %s\n", path); | |
544 free(path); | |
545 return SERD_ERR_UNKNOWN; | |
546 } | |
547 free(path); | |
548 | |
549 SerdURI base_uri = SERD_URI_NULL; | |
550 if (serd_uri_parse((const uint8_t*)uri.c_str(), &base_uri)) { | |
551 fprintf(stderr, "Invalid base URI <%s>\n", uri.c_str()); | |
552 fclose(fd); | |
553 return SERD_ERR_BAD_ARG; | |
554 } | |
555 | |
556 SerdWriter* writer = serd_writer_new(syntax, | |
557 style, | |
558 _world.prefixes().c_obj(), | |
559 &base_uri, | |
560 serd_file_sink, | |
561 fd); | |
562 | |
563 serd_env_foreach(_world.prefixes().c_obj(), | |
564 (SerdPrefixSink)serd_writer_set_prefix, | |
565 writer); | |
566 | |
567 sord_write(_c_obj, writer, 0); | |
568 serd_writer_free(writer); | |
569 fclose(fd); | |
570 | |
571 return SERD_SUCCESS; | |
572 } | |
573 | |
574 static size_t | |
575 string_sink(const void* buf, size_t len, void* stream) | |
576 { | |
577 std::string* str = (std::string*)stream; | |
578 str->append((const char*)buf, len); | |
579 return len; | |
580 } | |
581 | |
582 inline std::string | |
583 Model::write_to_string(const std::string& base_uri_str, | |
584 SerdSyntax syntax, | |
585 SerdStyle style) | |
586 { | |
587 SerdURI base_uri = SERD_URI_NULL; | |
588 if (serd_uri_parse((const uint8_t*)base_uri_str.c_str(), &base_uri)) { | |
589 fprintf(stderr, "Invalid base URI <%s>\n", base_uri_str.c_str()); | |
590 return ""; | |
591 } | |
592 | |
593 std::string ret; | |
594 | |
595 SerdWriter* writer = serd_writer_new(syntax, | |
596 style, | |
597 _world.prefixes().c_obj(), | |
598 &base_uri, | |
599 string_sink, | |
600 &ret); | |
601 | |
602 serd_env_foreach(_world.prefixes().c_obj(), | |
603 (SerdPrefixSink)serd_writer_set_prefix, | |
604 writer); | |
605 | |
606 sord_write(_c_obj, writer, 0); | |
607 | |
608 serd_writer_free(writer); | |
609 return ret; | |
610 } | |
611 | |
612 inline void | |
613 Model::add_statement(const Node& subject, | |
614 const Node& predicate, | |
615 const Node& object) | |
616 { | |
617 SordQuad quad = { subject.c_obj(), | |
618 predicate.c_obj(), | |
619 object.c_obj(), | |
620 NULL }; | |
621 | |
622 sord_add(_c_obj, quad); | |
623 } | |
624 | |
625 inline Iter | |
626 Model::find(const Node& subject, | |
627 const Node& predicate, | |
628 const Node& object) | |
629 { | |
630 SordQuad quad = { subject.c_obj(), | |
631 predicate.c_obj(), | |
632 object.c_obj(), | |
633 NULL }; | |
634 | |
635 return Iter(_world, sord_find(_c_obj, quad)); | |
636 } | |
637 | |
638 inline Node | |
639 Model::get(const Node& subject, | |
640 const Node& predicate, | |
641 const Node& object) | |
642 { | |
643 SordNode* c_node = sord_get( | |
644 _c_obj, subject.c_obj(), predicate.c_obj(), object.c_obj(), NULL); | |
645 Node node(_world, c_node); | |
646 sord_node_free(_world.c_obj(), c_node); | |
647 return node; | |
648 } | |
649 | |
650 } // namespace Sord | |
651 | |
652 #endif // SORD_SORDMM_HPP | |
653 |