Add initial bits for Qt6 support
[carla.git] / source / modules / lilv / sord-0.16.0 / sord / sordmm.hpp
blob83281c8b482d7167b217672586ba16ee8d637e54
1 /*
2 Copyright 2011-2013 David Robillard <http://drobilla.net>
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.
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.
17 /**
18 @file sordmm.hpp
19 Public Sord C++ API.
22 #ifndef SORD_SORDMM_HPP
23 #define SORD_SORDMM_HPP
25 #include <cassert>
26 #include <cstring>
27 #include <cstdlib>
28 #include <iostream>
29 #include <set>
30 #include <string>
31 #include <sstream>
33 #include "serd/serd.h"
34 #include "sord/sord.h"
36 #define SORD_NS_XSD "http://www.w3.org/2001/XMLSchema#"
38 namespace Sord {
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&);
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) {}
56 inline T c_obj() { return _c_obj; }
57 inline const T c_obj() const { return _c_obj; }
59 protected:
60 T _c_obj;
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); }
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;
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);
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;
91 return uri;
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;
104 std::cerr << "CURIE `" << curie << "' has unknown prefix." << std::endl;
105 return curie;
109 /** Sord library state. */
110 class World : public Noncopyable, public Wrapper<SordWorld*> {
111 public:
112 inline World()
113 : _next_blank_id(0)
115 _c_obj = sord_world_new();
118 inline ~World() {
119 sord_world_free(_c_obj);
122 inline uint64_t blank_id() { return _next_blank_id++; }
124 inline void add_prefix(const std::string& prefix, const std::string& uri) {
125 _prefixes.add(prefix, uri);
128 inline const Namespaces& prefixes() const { return _prefixes; }
129 inline SordWorld* world() { return _c_obj; }
131 private:
132 Namespaces _prefixes;
133 std::set<std::string> _blank_ids;
134 uint64_t _next_blank_id;
137 /** An RDF Node (resource, literal, etc)
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
148 inline Node() : Wrapper<SordNode*>(NULL), _world(NULL) {}
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();
157 inline Type type() const {
158 return _c_obj ? (Type)sord_node_get_type(_c_obj) : UNKNOWN;
161 inline const SordNode* get_node() const { return _c_obj; }
162 inline SordNode* get_node() { return _c_obj; }
164 const SerdNode* to_serd_node() {
165 return sord_node_to_serd_node(_c_obj);
168 inline bool is_valid() const { return type() != UNKNOWN; }
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();
178 Node& operator=(const Node& other) {
179 if (&other != this) {
180 if (_c_obj) {
181 sord_node_free(_world->c_obj(), _c_obj);
183 _world = other._world;
184 _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL;
186 return *this;
189 inline bool operator==(const Node& other) const {
190 return sord_node_equals(_c_obj, other._c_obj);
193 inline const uint8_t* to_u_string() const;
194 inline const char* to_c_string() const;
195 inline std::string to_string() const;
197 inline bool is_literal_type(const char* type_uri) const;
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"); }
205 inline int to_int() const;
206 inline float to_float() const;
207 inline bool to_bool() const;
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());
216 private:
217 World* _world;
220 inline std::ostream&
221 operator<<(std::ostream& os, const Node& node)
223 return os << node.to_string();
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()))
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)) {}
243 class Literal : public Node {
244 public:
245 inline Literal(World& world, const std::string& s)
246 : Node(world, Node::LITERAL, s) {}
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");
253 return Node(
254 world,
255 sord_node_from_serd_node(
256 world.c_obj(), world.prefixes().c_obj(), &val, &type, NULL),
257 false);
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");
265 return Node(
266 world,
267 sord_node_from_serd_node(
268 world.c_obj(), world.prefixes().c_obj(), &val, &type, NULL),
269 false);
273 inline
274 Node::Node(World& world, Type type, const std::string& s)
275 : _world(&world)
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;
294 assert(this->type() == type);
297 inline
298 Node::Node(World& world)
299 : _world(&world)
301 Node me = blank_id(world);
302 *this = me;
305 inline
306 Node::Node(World& world, const SordNode* node)
307 : _world(&world)
309 _c_obj = sord_node_copy(node);
312 inline
313 Node::Node(World& world, SordNode* node, bool copy)
314 : _world(&world)
316 _c_obj = copy ? sord_node_copy(node) : node;
319 inline
320 Node::Node(const Node& other)
321 : Wrapper<SordNode*>()
322 , _world(other._world)
324 if (_world) {
325 _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL;
328 assert((!_c_obj && !other._c_obj) || to_string() == other.to_string());
331 inline
332 Node::~Node()
334 if (_world) {
335 sord_node_free(_world->c_obj(), _c_obj);
339 inline std::string
340 Node::to_string() const
342 return _c_obj ? (const char*)sord_node_get_string(_c_obj) : "";
345 inline const char*
346 Node::to_c_string() const
348 return (const char*)sord_node_get_string(_c_obj);
351 inline const uint8_t*
352 Node::to_u_string() const
354 return sord_node_get_string(_c_obj);
357 inline bool
358 Node::is_literal_type(const char* type_uri) const
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;
366 return false;
369 inline int
370 Node::to_int() const
372 assert(is_int());
373 char* endptr;
374 return strtol((const char*)sord_node_get_string(_c_obj), &endptr, 10);
377 inline float
378 Node::to_float() const
380 assert(is_float());
381 return serd_strtod((const char*)sord_node_get_string(_c_obj), NULL);
384 inline bool
385 Node::to_bool() const
387 assert(is_bool());
388 return !strcmp((const char*)sord_node_get_string(_c_obj), "true");
391 struct Iter : public Wrapper<SordIter*> {
392 inline Iter(World& world, SordIter* c_obj)
393 : Wrapper<SordIter*>(c_obj), _world(world) {}
394 inline ~Iter() { sord_iter_free(_c_obj); }
395 inline bool end() const { return sord_iter_end(_c_obj); }
396 inline bool next() const { return sord_iter_next(_c_obj); }
397 inline Iter& operator++() {
398 assert(!end());
399 next();
400 return *this;
402 inline const Node get_subject() const {
403 SordQuad quad;
404 sord_iter_get(_c_obj, quad);
405 return Node(_world, quad[SORD_SUBJECT]);
407 inline const Node get_predicate() const {
408 SordQuad quad;
409 sord_iter_get(_c_obj, quad);
410 return Node(_world, quad[SORD_PREDICATE]);
412 inline const Node get_object() const {
413 SordQuad quad;
414 sord_iter_get(_c_obj, quad);
415 return Node(_world, quad[SORD_OBJECT]);
417 World& _world;
420 /** An RDF Model (collection of triples).
422 class Model : public Noncopyable, public Wrapper<SordModel*> {
423 public:
424 inline Model(World& world,
425 const std::string& base_uri,
426 unsigned indices = (SORD_SPO | SORD_OPS),
427 bool graphs = true);
429 inline ~Model();
431 inline const Node& base_uri() const { return _base; }
433 size_t num_quads() const { return sord_num_quads(_c_obj); }
435 inline void load_file(SerdEnv* env,
436 SerdSyntax syntax,
437 const std::string& uri,
438 const std::string& base_uri="");
440 inline void load_string(SerdEnv* env,
441 SerdSyntax syntax,
442 const char* str,
443 size_t len,
444 const std::string& base_uri);
446 inline SerdStatus write_to_file(
447 const std::string& uri,
448 SerdSyntax syntax = SERD_TURTLE,
449 SerdStyle style = (SerdStyle)(SERD_STYLE_ABBREVIATED
450 |SERD_STYLE_CURIED
451 |SERD_STYLE_RESOLVED));
453 inline std::string write_to_string(
454 const std::string& base_uri,
455 SerdSyntax syntax = SERD_TURTLE,
456 SerdStyle style = (SerdStyle)(SERD_STYLE_ABBREVIATED
457 |SERD_STYLE_CURIED
458 |SERD_STYLE_RESOLVED));
460 inline void add_statement(const Node& subject,
461 const Node& predicate,
462 const Node& object);
464 inline Iter find(const Node& subject,
465 const Node& predicate,
466 const Node& object);
468 inline Node get(const Node& subject,
469 const Node& predicate,
470 const Node& object);
472 inline World& world() const { return _world; }
474 private:
475 World& _world;
476 Node _base;
479 /** Create an empty in-memory RDF model.
481 inline
482 Model::Model(World& world,
483 const std::string& base_uri,
484 unsigned indices,
485 bool graphs)
486 : _world(world)
487 , _base(world, Node::URI, base_uri)
489 _c_obj = sord_new(_world.world(), indices, graphs);
492 inline void
493 Model::load_string(SerdEnv* env,
494 SerdSyntax syntax,
495 const char* str,
496 size_t len,
497 const std::string& base_uri)
499 SerdReader* reader = sord_new_reader(_c_obj, env, syntax, NULL);
500 serd_reader_read_string(reader, (const uint8_t*)str);
501 serd_reader_free(reader);
504 inline Model::~Model()
506 sord_free(_c_obj);
509 inline void
510 Model::load_file(SerdEnv* env,
511 SerdSyntax syntax,
512 const std::string& data_uri,
513 const std::string& base_uri)
515 uint8_t* path = serd_file_uri_parse((const uint8_t*)data_uri.c_str(), NULL);
516 if (!path) {
517 fprintf(stderr, "Failed to parse file URI <%s>\n", data_uri.c_str());
518 return;
521 // FIXME: blank prefix parameter?
522 SerdReader* reader = sord_new_reader(_c_obj, env, syntax, NULL);
523 serd_reader_read_file(reader, path);
524 serd_reader_free(reader);
525 free(path);
528 inline SerdStatus
529 Model::write_to_file(const std::string& uri, SerdSyntax syntax, SerdStyle style)
531 uint8_t* path = serd_file_uri_parse((const uint8_t*)uri.c_str(), NULL);
532 if (!path) {
533 fprintf(stderr, "Failed to parse file URI <%s>\n", uri.c_str());
534 return SERD_ERR_BAD_ARG;
537 FILE* const fd = fopen((const char*)path, "w");
538 if (!fd) {
539 fprintf(stderr, "Failed to open file %s\n", path);
540 free(path);
541 return SERD_ERR_UNKNOWN;
543 free(path);
545 SerdURI base_uri = SERD_URI_NULL;
546 if (serd_uri_parse((const uint8_t*)uri.c_str(), &base_uri)) {
547 fprintf(stderr, "Invalid base URI <%s>\n", uri.c_str());
548 fclose(fd);
549 return SERD_ERR_BAD_ARG;
552 SerdWriter* writer = serd_writer_new(syntax,
553 style,
554 _world.prefixes().c_obj(),
555 &base_uri,
556 serd_file_sink,
557 fd);
559 serd_env_foreach(_world.prefixes().c_obj(),
560 (SerdPrefixSink)serd_writer_set_prefix,
561 writer);
563 sord_write(_c_obj, writer, 0);
564 serd_writer_free(writer);
565 fclose(fd);
567 return SERD_SUCCESS;
570 static size_t
571 string_sink(const void* buf, size_t len, void* stream)
573 std::string* str = (std::string*)stream;
574 str->append((const char*)buf, len);
575 return len;
578 inline std::string
579 Model::write_to_string(const std::string& base_uri_str,
580 SerdSyntax syntax,
581 SerdStyle style)
583 SerdURI base_uri = SERD_URI_NULL;
584 if (serd_uri_parse((const uint8_t*)base_uri_str.c_str(), &base_uri)) {
585 fprintf(stderr, "Invalid base URI <%s>\n", base_uri_str.c_str());
586 return "";
589 std::string ret;
591 SerdWriter* writer = serd_writer_new(syntax,
592 style,
593 _world.prefixes().c_obj(),
594 &base_uri,
595 string_sink,
596 &ret);
598 const SerdNode base_uri_node = serd_node_from_string(
599 SERD_URI, (const uint8_t*)base_uri_str.c_str());
600 serd_writer_set_base_uri(writer, &base_uri_node);
602 serd_env_foreach(_world.prefixes().c_obj(),
603 (SerdPrefixSink)serd_writer_set_prefix,
604 writer);
606 sord_write(_c_obj, writer, 0);
608 serd_writer_free(writer);
609 return ret;
612 inline void
613 Model::add_statement(const Node& subject,
614 const Node& predicate,
615 const Node& object)
617 SordQuad quad = { subject.c_obj(),
618 predicate.c_obj(),
619 object.c_obj(),
620 NULL };
622 sord_add(_c_obj, quad);
625 inline Iter
626 Model::find(const Node& subject,
627 const Node& predicate,
628 const Node& object)
630 SordQuad quad = { subject.c_obj(),
631 predicate.c_obj(),
632 object.c_obj(),
633 NULL };
635 return Iter(_world, sord_find(_c_obj, quad));
638 inline Node
639 Model::get(const Node& subject,
640 const Node& predicate,
641 const Node& object)
643 SordNode* c_node = sord_get(
644 _c_obj, subject.c_obj(), predicate.c_obj(), object.c_obj(), NULL);
645 return Node(_world, c_node, false);
648 } // namespace Sord
650 #endif // SORD_SORDMM_HPP