diff options
Diffstat (limited to 'serd')
-rw-r--r-- | serd/serd.hpp | 1111 |
1 files changed, 1111 insertions, 0 deletions
diff --git a/serd/serd.hpp b/serd/serd.hpp new file mode 100644 index 00000000..e7632212 --- /dev/null +++ b/serd/serd.hpp @@ -0,0 +1,1111 @@ +/* + Copyright 2018 David Robillard <http://drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/// @file serd.hpp C++ API for Serd, a lightweight RDF syntax library + +#ifndef SERD_SERD_HPP +#define SERD_SERD_HPP + +#include <serd/serd.h> + +#include <cassert> +#include <memory> +#include <ostream> +#include <type_traits> +#include <utility> + +/** + @defgroup serdxx Serdxx + C++ bindings for Serd, a lightweight RDF syntax library. + @{ +*/ + +namespace serd { +namespace detail { + +template <typename T> +using FreeFunc = void (*)(T*); + +template <typename T> +using CopyFunc = T* (*)(const T*); + +template <typename T> +void +no_free(T*) +{ +} + +template <typename T> +struct Deleter +{ + Deleter(FreeFunc<T> free_func) : _free_func(free_func) {} + + void operator()(T* ptr) + { + if (_free_func) { + _free_func(ptr); + } + } + + FreeFunc<T> _free_func; +}; + +/// C++ wrapper for a C object +template <typename T, void FreeFunc(T*)> +class Wrapper +{ +public: + using CType = T; + + Wrapper(T* ptr) : _ptr(ptr, Deleter<T>(FreeFunc)) {} + + Wrapper(const T* ptr) : _ptr(const_cast<T*>(ptr), nullptr) {} + + Wrapper(Wrapper&& wrapper) = default; + Wrapper& operator=(Wrapper&& wrapper) = default; + + Wrapper(const Wrapper&) = delete; + Wrapper& operator=(const Wrapper&) = delete; + + bool operator==(const Wrapper&) = delete; + bool operator!=(const Wrapper&) = delete; + + operator const T*() const { return _ptr.get(); } + + inline T* c_obj() { return _ptr.get(); } + inline const T* c_obj() const { return _ptr.get(); } + +protected: + Wrapper(std::nullptr_t) : _ptr(nullptr, nullptr) {} + + std::unique_ptr<T, Deleter<T>> _ptr; +}; + +template <typename T, T* CopyFunc(const T*), void FreeFunc(T*)> +class Copyable : public Wrapper<T, FreeFunc> +{ +public: + Copyable(T* ptr) : Wrapper<T, FreeFunc>(ptr) {} + + Copyable(const T* ptr) : Wrapper<T, FreeFunc>(ptr) {} + + Copyable(const Copyable& wrapper) + : Wrapper<T, FreeFunc>(CopyFunc(wrapper.c_obj())) + { + } + + Copyable(Copyable&&) = default; + Copyable& operator=(Copyable&&) = default; + + Copyable& operator=(const Copyable& wrapper) + { + this->_ptr = std::unique_ptr<T, Deleter<T>>(CopyFunc(wrapper.c_obj()), + FreeFunc); + return *this; + } + +protected: + Copyable(std::nullptr_t) : Wrapper<T, FreeFunc>(nullptr) {} +}; + +static inline size_t +stream_sink(const void* buf, size_t size, size_t nmemb, void* stream) +{ + try { + std::ostream* const s = static_cast<std::ostream*>(stream); + s->write(static_cast<const char*>(buf), std::streamsize(size * nmemb)); + if (s->good()) { + return nmemb; + } + } catch (...) { + } + return 0; +} + +/// Type-safe bit flags +template <typename Flag> +class Flags +{ +public: + static_assert(std::is_enum<Flag>::value, ""); + + using FlagUnderlyingType = typename std::underlying_type<Flag>::type; + using Value = typename std::make_unsigned<FlagUnderlyingType>::type; + + Flags() : _value(0) {} + Flags(const Flag f) : _value(static_cast<Value>(f)) {} + explicit Flags(const Value value) : _value{value} {} + + Flags operator|(const Flag rhs) const + { + return Flags{_value | static_cast<Value>(rhs)}; + } + + Flags operator|(const Flags rhs) const + { + return Flags{_value | rhs._value}; + } + + operator Value() const { return _value; } + +private: + Value _value{}; +}; + +} // namespace detail + +template <typename Flag> +inline typename std::enable_if<std::is_enum<Flag>::value, + detail::Flags<Flag>>::type +operator|(const Flag lhs, const Flag rhs) +{ + return detail::Flags<Flag>{lhs} | rhs; +} + +/// Return status code +enum class Status { + success = SERD_SUCCESS, ///< No error + failure = SERD_FAILURE, ///< Non-fatal failure + err_unknown = SERD_ERR_UNKNOWN, ///< Unknown error + err_bad_syntax = SERD_ERR_BAD_SYNTAX, ///< Invalid syntax + err_bad_arg = SERD_ERR_BAD_ARG, ///< Invalid argument + err_bad_iter = SERD_ERR_BAD_ITER, ///< Use of invalidated iterator + err_not_found = SERD_ERR_NOT_FOUND, ///< Not found + err_id_clash = SERD_ERR_ID_CLASH, ///< Clashing blank node IDs + err_bad_curie = SERD_ERR_BAD_CURIE, ///< Invalid CURIE + err_internal = SERD_ERR_INTERNAL, ///< Unexpected internal error + err_overflow = SERD_ERR_OVERFLOW, ///< Stack overflow + err_invalid = SERD_ERR_INVALID ///< Invalid data +}; + +/// RDF syntax type +enum class Syntax { + Turtle = SERD_TURTLE, ///< Terse RDF Triple Language + NTriples = SERD_NTRIPLES, ///< Line-based RDF triples + NQuads = SERD_NQUADS, ///< Line-based RDF quads (NTriples with graphs) + TriG = SERD_TRIG ///< Terse RDF quads (Turtle with graphs) +}; + +/// Flags indicating inline abbreviation information for a statement +enum class StatementFlag { + empty_S = SERD_EMPTY_S, ///< Empty blank node subject + anon_S = SERD_ANON_S, ///< Start of anonymous subject + anon_O = SERD_ANON_O, ///< Start of anonymous object + list_S = SERD_LIST_S, ///< Start of list subject + list_O = SERD_LIST_O ///< Start of list object +}; + +using StatementFlags = detail::Flags<StatementFlag>; + +/// Flags that control style for a model serialisation +enum class SerialisationFlag { + no_inline_objects = + SERD_NO_INLINE_OBJECTS, ///< Do not inline objects where possible +}; + +using SerialisationFlags = detail::Flags<SerialisationFlag>; + +/** + Type of a syntactic RDF node + + This is more precise than the type of an abstract RDF node. An abstract + node is either a resource, literal, or blank. In syntax there are two ways + to refer to a resource (by URI or CURIE) and two ways to refer to a blank + (by ID or anonymously). Anonymous (inline) blank nodes are expressed using + SerdStatementFlags rather than this type. +*/ +enum class NodeType { + /** + The type of a nonexistent node + + This type is useful as a sentinel, but is never emitted by the reader. + */ + nothing = SERD_NOTHING, + + /** + Literal value + + A literal optionally has either a language, or a datatype (not both). + */ + literal = SERD_LITERAL, + + /** + URI (absolute or relative) + + Value is an unquoted URI string, which is either a relative reference + with respect to the current base URI (e.g. "foo/bar"), or an absolute + URI (e.g. "http://example.org/foo"). + @see <a href="http://tools.ietf.org/html/rfc3986">RFC3986</a>. + */ + URI = SERD_URI, + + /** + CURIE, a shortened URI + + Value is an unquoted CURIE string relative to the current environment, + e.g. "rdf:type". + @see <a href="http://www.w3.org/TR/curie">CURIE Syntax 1.0</a> + */ + CURIE = SERD_CURIE, + + /** + A blank node + + Value is a blank node ID, e.g. "id3", which is meaningful only within + this serialisation. + @see <a href="http://www.w3.org/TeamSubmission/turtle#nodeID">Turtle + <tt>nodeID</tt></a> + */ + blank = SERD_BLANK +}; + +/// Flags indicating certain string properties relevant to serialisation +enum class NodeFlag { + has_newline = SERD_HAS_NEWLINE, ///< Contains line breaks + has_quote = SERD_HAS_QUOTE, ///< Contains quotes + has_datatype = SERD_HAS_DATATYPE, ///< Literal node has datatype + has_language = SERD_HAS_LANGUAGE ///< Literal node has language +}; + +using NodeFlags = detail::Flags<NodeFlag>; + +/// Field in a statement +enum class Field { + subject = SERD_SUBJECT, ///< Subject + predicate = SERD_PREDICATE, ///< Predicate ("key") + object = SERD_OBJECT, ///< Object ("value") + graph = SERD_GRAPH ///< Graph ("context") +}; + +/** + Syntax style options + + The style of the writer output can be controlled by ORing together + values from this enumeration. Note that some options are only supported + for some syntaxes (e.g. NTriples does not support abbreviation and is + always ASCII). +*/ +enum class WriterFlag { + ascii = SERD_STYLE_ASCII, ///< Escape all non-ASCII characters +}; + +using WriterFlags = detail::Flags<WriterFlag>; + +/// Indexing option +enum class ModelFlag { + index_SPO = SERD_INDEX_SPO, ///< Subject, Predicate, Object + index_SOP = SERD_INDEX_SOP, ///< Subject, Object, Predicate + index_OPS = SERD_INDEX_OPS, ///< Object, Predicate, Subject + index_OSP = SERD_INDEX_OSP, ///< Object, Subject, Predicate + index_PSO = SERD_INDEX_PSO, ///< Predicate, Subject, Object + index_POS = SERD_INDEX_POS, ///< Predicate, Object, Subject + index_graphs = SERD_INDEX_GRAPHS ///< Support multiple graphs in model +}; + +using ModelFlags = detail::Flags<ModelFlag>; + +/** + A simple optional wrapper around a wrapped type with a pointer-like API + + This works like a typical optional type, but only works with Wrapper types, + and exploits the fact that these are interally just pointers to avoid adding + space overhead for an "is_set" flag, like a generic optional class would. +*/ +template <typename T> +class Optional +{ +public: + using CType = typename T::CType; + + Optional() : _value() {} + Optional(std::nullptr_t) : _value() {} + Optional(const T& value) : _value(value) {} + Optional(T&& value) : _value(std::move(value)) {} + + Optional(const Optional&) = default; + Optional(Optional&&) = default; + Optional& operator=(const Optional&) = default; + Optional& operator=(Optional&&) = default; + + void reset() { *this = nullptr; } + + const T& operator*() const + { + assert(_value.c_obj()); + return _value; + } + + T& operator*() + { + assert(_value.c_obj()); + return _value; + } + + const T* operator->() const + { + assert(_value.c_obj()); + return &_value; + } + + T* operator->() + { + assert(_value.c_obj()); + return &_value; + } + + bool operator==(const Optional& optional) + { + return (!*this && !optional) || + (*this && optional && _value == optional._value); + } + + bool operator!=(const Optional& optional) { return !operator==(optional); } + + explicit operator bool() const { return _value.c_obj(); } + + bool operator!() const { return !_value.c_obj(); } + + inline CType* ptr() { return _value.c_obj(); } + inline const CType* ptr() const { return _value.c_obj(); } + +private: + T _value; +}; + +/** + A temporary reference to a string + + This is used as a function parameter type to allow passing either + `std::string` or `const char*` without requiring multiple wrapper + definitions or the copying overhead of `std::string`. +*/ +struct StringRef +{ + StringRef(const char* str) : _ptr(str) {} + StringRef(const std::string& str) : _ptr(str.c_str()) {} + + StringRef(const StringRef&) = delete; + StringRef& operator=(const StringRef&) = delete; + + operator const char*() const { return _ptr; } + +private: + const char* const _ptr; +}; + +/** + @name String Utilities + @{ +*/ + +inline const char* +strerror(const Status status) +{ + return serd_strerror(static_cast<SerdStatus>(status)); +} + +/** + @} + @name URI + @{ +*/ + +inline std::string +file_uri_parse(const StringRef& uri, std::string* hostname = nullptr) +{ + char* c_hostname = nullptr; + char* c_path = serd_file_uri_parse(uri, &c_hostname); + if (hostname && c_hostname) { + *hostname = c_hostname; + } + const std::string path(c_path); + free(c_hostname); + free(c_path); + return path; +} + +/** + @} + @name Node + @{ +*/ + +class Node : public detail::Copyable<SerdNode, serd_node_copy, serd_node_free> +{ +public: + explicit Node(SerdNode* ptr) : Copyable(ptr) {} + explicit Node(const SerdNode* ptr) : Copyable(ptr) {} + + NodeType type() const { return NodeType(serd_node_get_type(c_obj())); } + const char* c_str() const { return serd_node_get_string(c_obj()); } + std::string str() const { return c_str(); } + size_t size() const { return serd_node_get_length(c_obj()); } + size_t length() const { return serd_node_get_length(c_obj()); } + NodeFlags flags() const { return NodeFlags(serd_node_get_flags(c_obj())); } + + Optional<Node> datatype() const + { + return Node(serd_node_get_datatype(c_obj())); + } + + Optional<Node> language() const + { + return Node(serd_node_get_language(c_obj())); + } + + Node resolve(const Node& base) const + { + return Node(serd_node_resolve(c_obj(), base.c_obj())); + } + + bool operator==(const Node& node) const + { + return serd_node_equals(c_obj(), node.c_obj()); + } + + bool operator!=(const Node& node) const + { + return !serd_node_equals(c_obj(), node.c_obj()); + } + + bool operator<(const Node& node) const + { + return serd_node_compare(c_obj(), node.c_obj()) < 0; + } + + operator std::string() const + { + return std::string(serd_node_get_string(c_obj()), + serd_node_get_length(c_obj())); + } + +private: + friend class Optional<Node>; + Node() : Copyable(nullptr) {} +}; + +inline std::ostream& +operator<<(std::ostream& os, const Node& node) +{ + return os << node.c_str(); +} + +inline Node +make_string(const StringRef& str) +{ + return Node(serd_new_string(str)); +} + +inline Node +make_plain_literal(const StringRef& str, const StringRef& lang) +{ + return Node(serd_new_plain_literal(str, lang)); +} + +inline Node +make_typed_literal(const StringRef& str, const Node& datatype) +{ + return Node(serd_new_typed_literal(str, datatype.c_obj())); +} + +inline Node +make_blank(const StringRef& str) +{ + return Node(serd_new_blank(str)); +} + +inline Node +make_curie(const StringRef& str) +{ + return Node(serd_new_curie(str)); +} + +inline Node +make_uri(const StringRef& str) +{ + return Node(serd_new_uri(str)); +} + +inline Node +make_resolved_uri(const StringRef& str, const Node& base) +{ + return Node(serd_new_resolved_uri(str, base.c_obj())); +} + +inline Node +make_file_uri(const StringRef& path) +{ + return Node(serd_new_file_uri(path, nullptr)); +} + +inline Node +make_file_uri(const StringRef& path, const StringRef& hostname) +{ + return Node(serd_new_file_uri(path, hostname)); +} + +inline Node +make_relative_uri(const StringRef& str, + const Node& base, + const Optional<Node>& root = {}) +{ + return Node(serd_new_relative_uri(str, base.c_obj(), root.ptr())); +} + +inline Node +make_decimal(double d, + unsigned frac_digits, + const Optional<Node>& datatype = {}) +{ + return Node(serd_new_decimal(d, frac_digits, datatype.ptr())); +} + +inline Node +make_integer(int64_t i, const Optional<Node>& datatype = {}) +{ + return Node(serd_new_integer(i, datatype.ptr())); +} + +inline Node +make_blob(const void* buf, + size_t size, + bool wrap_lines, + const Optional<Node>& datatype = {}) +{ + return Node(serd_new_blob(buf, size, wrap_lines, datatype.ptr())); +} + +/** + @} + @name World + @{ +*/ + +class World : public detail::Wrapper<SerdWorld, serd_world_free> +{ +public: + World() : Wrapper(serd_world_new()) {} + + explicit World(SerdWorld* ptr) : Wrapper(ptr) {} + + Node get_blank() { return Node(serd_world_get_blank(c_obj())); } + + void set_message_sink(SerdMessageSink msg_sink, void* handle) + { + serd_world_set_message_sink(c_obj(), msg_sink, handle); + } +}; + +/** + @} + @name Statement + @{ +*/ + +class Statement : public detail::Wrapper<SerdStatement, detail::no_free> +{ +public: + Statement(const SerdStatement* statement) : Wrapper(statement) {} + + Node node(Field field) + { + return Node(serd_statement_get_node(c_obj(), + static_cast<SerdField>(field))); + } + + Node subject() const { return Node(serd_statement_get_subject(c_obj())); } + + Node predicate() const + { + return Node(serd_statement_get_predicate(c_obj())); + } + + Node object() const { return Node(serd_statement_get_object(c_obj())); } + + Node graph() const { return Node(serd_statement_get_graph(c_obj())); } +}; + +/** + @} + @name Sink + @{ +*/ + +class Sink +{ +public: + Sink() + : _sink(serd_sink_new(this, NULL), + detail::Deleter<SerdSink>(serd_sink_free)) + , _is_user(true) + { + serd_sink_set_base_func(_sink.get(), s_base); + serd_sink_set_prefix_func(_sink.get(), s_prefix); + serd_sink_set_statement_func(_sink.get(), s_statement); + serd_sink_set_end_func(_sink.get(), s_end); + } + + explicit Sink(const SerdSink* ptr) + : _sink(const_cast<SerdSink*>(ptr), detail::Deleter<SerdSink>(nullptr)) + , _is_user(false) + { + } + + virtual ~Sink() = default; + + virtual Status base(const Node& uri) + { + return _is_user ? Status::success + : Status(serd_sink_set_base(_sink.get(), uri.c_obj())); + } + + virtual Status prefix(const Node& name, const Node& uri) + { + return _is_user ? Status::success + : Status(serd_sink_set_prefix( + _sink.get(), name.c_obj(), uri.c_obj())); + } + + virtual Status statement(StatementFlags flags, const Statement& statement) + { + return _is_user ? Status::success + : Status(serd_sink_write_statement( + _sink.get(), flags, statement.c_obj())); + } + + virtual Status write(StatementFlags flags, + const Node& subject, + const Node& predicate, + const Node& object, + const Optional<Node>& graph = {}) + { + return _is_user ? Status::success + : Status(serd_sink_write(_sink.get(), + flags, + subject.c_obj(), + predicate.c_obj(), + object.c_obj(), + graph.ptr())); + } + + virtual Status end(const Node& node) + { + return _is_user ? Status::success + : Status(serd_sink_end(_sink.get(), node.c_obj())); + } + + const SerdSink* c_sink() const { return _sink.get(); } + SerdSink* c_sink() { return _sink.get(); } + +private: + static SerdStatus s_base(void* handle, const SerdNode* uri) + { + Sink* const sink = static_cast<Sink*>(handle); + return static_cast<SerdStatus>(sink->base(Node(uri))); + } + + static SerdStatus + s_prefix(void* handle, const SerdNode* name, const SerdNode* uri) + { + Sink* const sink = static_cast<Sink*>(handle); + return static_cast<SerdStatus>(sink->prefix(Node(name), Node(uri))); + } + + static SerdStatus s_statement(void* handle, + SerdStatementFlags flags, + const SerdStatement* statement) + { + Sink* const sink = static_cast<Sink*>(handle); + return static_cast<SerdStatus>( + sink->statement(StatementFlags(flags), statement)); + } + + static SerdStatus s_end(void* handle, const SerdNode* node) + { + Sink* const sink = static_cast<Sink*>(handle); + return static_cast<SerdStatus>(sink->end(Node(node))); + } + + std::unique_ptr<SerdSink, detail::Deleter<SerdSink>> _sink; + bool _is_user; +}; + +/** + @} + @name Environment + @{ +*/ + +class Env : public detail::Copyable<SerdEnv, serd_env_copy, serd_env_free> +{ +public: + explicit Env(const Optional<Node>& base = {}) + : Copyable(serd_env_new(base.ptr())) + { + } + + /// Return the base URI + Node base_uri() const { return Node(serd_env_get_base_uri(c_obj())); } + + /// Set the base URI + Status set_base_uri(const Node& uri) + { + return Status(serd_env_set_base_uri(c_obj(), uri.c_obj())); + } + + /// Set a namespace prefix + Status set_prefix(const Node& name, const Node& uri) + { + return Status(serd_env_set_prefix(c_obj(), name.c_obj(), uri.c_obj())); + } + + /// Set a namespace prefix + Status set_prefix(const StringRef& name, const StringRef& uri) + { + return Status(serd_env_set_prefix_from_strings(c_obj(), name, uri)); + } + + /// Qualify `uri` into a CURIE if possible + Optional<Node> qualify(const Node& uri) const + { + return Node(serd_env_qualify(c_obj(), uri.c_obj())); + } + + /// Expand `node` into an absolute URI if possible + Optional<Node> expand(const Node& node) const + { + return Node(serd_env_expand(c_obj(), node.c_obj())); + } + + /// Send all prefixes to `sink` + void send_prefixes(Sink& sink) const + { + serd_env_send_prefixes(c_obj(), sink.c_sink()); + } + + bool operator==(const Env& env) + { + return serd_env_equals(c_obj(), env.c_obj()); + } + + bool operator!=(const Env& env) { return !operator==(env); } +}; + +/** + @} + @name Reader + @{ +*/ + +class Reader : public detail::Wrapper<SerdReader, serd_reader_free> +{ +public: + Reader(World& world, Syntax syntax, const Sink& sink, size_t stack_size) + : Wrapper(serd_reader_new(world.c_obj(), + SerdSyntax(syntax), + sink.c_sink(), + stack_size)) + { + } + + void set_strict(bool strict) { serd_reader_set_strict(c_obj(), strict); } + + void add_blank_prefix(const StringRef& prefix) + { + serd_reader_add_blank_prefix(c_obj(), prefix); + } + + SerdStatus start_file(const StringRef& uri, bool bulk = true) + { + return serd_reader_start_file(c_obj(), uri, bulk); + } + + SerdStatus start_stream(SerdReadFunc read_func, + SerdStreamErrorFunc error_func, + void* stream, + const Node& name, + size_t page_size) + { + return serd_reader_start_stream(c_obj(), + read_func, + error_func, + stream, + name.c_obj(), + page_size); + } + + SerdStatus + start_string(const StringRef& utf8, const Optional<Node>& name = {}) + { + return serd_reader_start_string(c_obj(), utf8, name.ptr()); + } + + SerdStatus read_chunk() { return serd_reader_read_chunk(c_obj()); } + + SerdStatus read_document() { return serd_reader_read_document(c_obj()); } + + SerdStatus finish() { return serd_reader_finish(c_obj()); } +}; + +/** + @} + @name Writer + @{ +*/ + +class ByteSink : public detail::Wrapper<SerdByteSink, serd_byte_sink_free> +{ +public: + ByteSink(SerdWriteFunc sink, void* stream, size_t block_size) + : Wrapper(serd_byte_sink_new(sink, stream, block_size)) + { + } + + ByteSink(std::ostream& stream) + : Wrapper(serd_byte_sink_new(detail::stream_sink, &stream, 1)) + { + } +}; + +class Writer : public detail::Wrapper<SerdWriter, serd_writer_free>, public Sink +{ +public: + Writer(World& world, + const Syntax syntax, + const WriterFlags writer_flags, + Env& env, + ByteSink& sink) + : Wrapper(serd_writer_new( + world.c_obj(), + SerdSyntax(syntax), + writer_flags, + env.c_obj(), + reinterpret_cast<SerdWriteFunc>(serd_byte_sink_write), + sink.c_obj())) + , Sink(serd_writer_get_sink(c_obj())) + { + } + + Writer(World& world, + const Syntax syntax, + const WriterFlags writer_flags, + Env& env, + SerdWriteFunc write_func, + void* stream) + : Wrapper(serd_writer_new(world.c_obj(), + SerdSyntax(syntax), + writer_flags, + env.c_obj(), + write_func, + stream)) + , Sink(serd_writer_get_sink(c_obj())) + { + } + + Writer(World& world, + const Syntax syntax, + const WriterFlags writer_flags, + Env& env, + std::ostream& stream) + : Wrapper(serd_writer_new(world.c_obj(), + SerdSyntax(syntax), + writer_flags, + env.c_obj(), + detail::stream_sink, + &stream)) + , Sink(serd_writer_get_sink(c_obj())) + { + } + + Status set_root_uri(const Node& uri) + { + return Status(serd_writer_set_root_uri(c_obj(), uri.c_obj())); + } + + SerdStatus finish() { return serd_writer_finish(c_obj()); } +}; + +/** + @} +*/ + +class Iter : public detail::Copyable<SerdIter, serd_iter_copy, serd_iter_free> +{ +public: + Iter(SerdIter* i) : Copyable(i) {} + Iter(const SerdIter* i) : Copyable(i) {} + + Iter& operator++() + { + serd_iter_next(c_obj()); + return *this; + } + + Statement operator*() const { return Statement(serd_iter_get(c_obj())); } + + bool operator==(const Iter& i) const + { + return serd_iter_equals(c_obj(), i.c_obj()); + } + + bool operator!=(const Iter& i) const + { + return !serd_iter_equals(c_obj(), i.c_obj()); + } +}; + +class Range + : public detail::Copyable<SerdRange, serd_range_copy, serd_range_free> +{ +public: + Range(SerdRange* r) : Copyable(r) {} + Range(const SerdRange* r) : Copyable(r) {} + + Iter begin() const { return Iter(serd_range_begin(c_obj())); } + Iter end() const { return Iter(serd_range_end(c_obj())); } + + bool operator==(const Range& i) const + { + return serd_range_equals(c_obj(), i.c_obj()); + } + + bool operator!=(const Range& i) const + { + return !serd_range_equals(c_obj(), i.c_obj()); + } +}; + +class Model + : public detail::Copyable<SerdModel, serd_model_copy, serd_model_free> +{ +public: + using value_type = Statement; + using iterator = Iter; + using const_iterator = Iter; + + Model(World& world, ModelFlags flags) + : Copyable(serd_model_new(world.c_obj(), flags)) + { + } + + Model(World& world, ModelFlag flag) + : Copyable(serd_model_new(world.c_obj(), ModelFlags(flag))) + { + } + + size_t size() const { return serd_model_size(c_obj()); } + + bool empty() const { return serd_model_empty(c_obj()); } + + void insert(const Statement& s) { serd_model_insert(c_obj(), s.c_obj()); } + + void insert(const Node& s, + const Node& p, + const Node& o, + const Optional<Node>& g = {}) + { + serd_model_add(c_obj(), s.c_obj(), p.c_obj(), o.c_obj(), g.ptr()); + } + + Iter find(const Optional<Node>& s, + const Optional<Node>& p, + const Optional<Node>& o, + const Optional<Node>& g = {}) const + { + return Iter( + serd_model_find(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr())); + } + + Range range(const Optional<Node>& s, + const Optional<Node>& p, + const Optional<Node>& o, + const Optional<Node>& g = {}) const + { + return Range( + serd_model_range(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr())); + } + + Optional<Node> get(const Optional<Node>& s, + const Optional<Node>& p, + const Optional<Node>& o, + const Optional<Node>& g = {}) const + { + return Node( + serd_model_get(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr())); + } + + Optional<Statement> get_statement(const Optional<Node>& s, + const Optional<Node>& p, + const Optional<Node>& o, + const Optional<Node>& g = {}) const + { + return Statement(serd_model_get_statement( + c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr())); + } + + bool ask(const Optional<Node>& s, + const Optional<Node>& p, + const Optional<Node>& o, + const Optional<Node>& g = {}) const + { + return serd_model_ask(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr()); + } + + size_t count(const Optional<Node>& s, + const Optional<Node>& p, + const Optional<Node>& o, + const Optional<Node>& g = {}) const + { + return serd_model_count(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr()); + } + + bool operator==(const Model& model) const + { + return serd_model_equals(c_obj(), model.c_obj()); + } + + bool operator!=(const Model& model) const + { + return !serd_model_equals(c_obj(), model.c_obj()); + } + + Range all() const { return Range(serd_model_all(c_obj())); } + + iterator begin() const { return iterator(serd_model_begin(c_obj())); } + + iterator end() const { return iterator(serd_model_end(c_obj())); } +}; + +class Inserter : public detail::Wrapper<SerdInserter, serd_inserter_free>, + public Sink +{ +public: + Inserter(Model& model, Env& env, const Optional<Node>& default_graph = {}) + : Wrapper(serd_inserter_new(model.c_obj(), + env.c_obj(), + default_graph.ptr())) + , Sink(serd_inserter_get_sink(c_obj())) + { + } +}; + +} // namespace serd + +/** + @} +*/ + +#endif /* SERD_SERD_HPP */ |