cannam@130: /* cannam@130: Copyright 2011-2016 David Robillard cannam@130: cannam@130: Permission to use, copy, modify, and/or distribute this software for any cannam@130: purpose with or without fee is hereby granted, provided that the above cannam@130: copyright notice and this permission notice appear in all copies. cannam@130: cannam@130: THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES cannam@130: WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF cannam@130: MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR cannam@130: ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES cannam@130: WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN cannam@130: ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF cannam@130: OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. cannam@130: */ cannam@130: cannam@130: /** cannam@130: @file sord.h API for Sord, a lightweight RDF model library. cannam@130: */ cannam@130: cannam@130: #ifndef SORD_SORD_H cannam@130: #define SORD_SORD_H cannam@130: cannam@130: #include cannam@130: #include cannam@130: #include cannam@130: cannam@130: #include "serd/serd.h" cannam@130: cannam@130: #ifdef SORD_SHARED cannam@130: # ifdef _WIN32 cannam@130: # define SORD_LIB_IMPORT __declspec(dllimport) cannam@130: # define SORD_LIB_EXPORT __declspec(dllexport) cannam@130: # else cannam@130: # define SORD_LIB_IMPORT __attribute__((visibility("default"))) cannam@130: # define SORD_LIB_EXPORT __attribute__((visibility("default"))) cannam@130: # endif cannam@130: # ifdef SORD_INTERNAL cannam@130: # define SORD_API SORD_LIB_EXPORT cannam@130: # else cannam@130: # define SORD_API SORD_LIB_IMPORT cannam@130: # endif cannam@130: #else cannam@130: # define SORD_API cannam@130: #endif cannam@130: cannam@130: #ifdef __cplusplus cannam@130: extern "C" { cannam@130: #else cannam@130: # include cannam@130: #endif cannam@130: cannam@130: /** cannam@130: @defgroup sord Sord cannam@130: A lightweight RDF model library. cannam@130: cannam@130: Sord stores RDF (subject object predicate context) quads, where the context cannam@130: may be omitted (to represent triples in the default graph). cannam@130: @{ cannam@130: */ cannam@130: cannam@130: /** cannam@130: Sord World. cannam@130: The World represents all library state, including interned strings. cannam@130: */ cannam@130: typedef struct SordWorldImpl SordWorld; cannam@130: cannam@130: /** cannam@130: Sord Model. cannam@130: cannam@130: A model is an indexed set of Quads (i.e. it can contain several RDF cannam@130: graphs). It may be searched using various patterns depending on which cannam@130: indices are enabled. cannam@130: */ cannam@130: typedef struct SordModelImpl SordModel; cannam@130: cannam@130: /** cannam@130: Model Inserter. cannam@130: cannam@130: An inserter is used for writing statements to a model using the Serd sink cannam@130: interface. This makes it simple to write to a model directly using a cannam@130: SerdReader, or any other code that writes statements to a SerdStatementSink. cannam@130: */ cannam@130: typedef struct SordInserterImpl SordInserter; cannam@130: cannam@130: /** cannam@130: Model Iterator. cannam@130: */ cannam@130: typedef struct SordIterImpl SordIter; cannam@130: cannam@130: /** cannam@130: RDF Node. cannam@130: A Node is a component of a Quad. Nodes may be URIs, blank nodes, or cannam@130: (in the case of quad objects only) string literals. Literal nodes may cannam@130: have an associate language or datatype (but not both). cannam@130: */ cannam@130: typedef struct SordNodeImpl SordNode; cannam@130: cannam@130: /** cannam@130: Quad of nodes (a statement), or a quad pattern. cannam@130: cannam@130: Nodes are ordered (S P O G). The ID of the default graph is 0. cannam@130: */ cannam@130: typedef const SordNode* SordQuad[4]; cannam@130: cannam@130: /** cannam@130: Index into a SordQuad. cannam@130: */ cannam@130: typedef enum { cannam@130: SORD_SUBJECT = 0, /**< Subject */ cannam@130: SORD_PREDICATE = 1, /**< Predicate ("key") */ cannam@130: SORD_OBJECT = 2, /**< Object ("value") */ cannam@130: SORD_GRAPH = 3 /**< Graph ("context") */ cannam@130: } SordQuadIndex; cannam@130: cannam@130: /** cannam@130: Type of a node. cannam@130: */ cannam@130: typedef enum { cannam@130: SORD_URI = 1, /**< URI */ cannam@130: SORD_BLANK = 2, /**< Blank node identifier */ cannam@130: SORD_LITERAL = 3 /**< Literal (string with optional lang or datatype) */ cannam@130: } SordNodeType; cannam@130: cannam@130: /** cannam@130: Indexing option. cannam@130: */ cannam@130: typedef enum { cannam@130: SORD_SPO = 1, /**< Subject, Predicate, Object */ cannam@130: SORD_SOP = 1 << 1, /**< Subject, Object, Predicate */ cannam@130: SORD_OPS = 1 << 2, /**< Object, Predicate, Subject */ cannam@130: SORD_OSP = 1 << 3, /**< Object, Subject, Predicate */ cannam@130: SORD_PSO = 1 << 4, /**< Predicate, Subject, Object */ cannam@130: SORD_POS = 1 << 5 /**< Predicate, Object, Subject */ cannam@130: } SordIndexOption; cannam@130: cannam@130: /** cannam@130: @name World cannam@130: @{ cannam@130: */ cannam@130: cannam@130: /** cannam@130: Create a new Sord World. cannam@130: It is safe to use multiple worlds in one process, though no data cannam@130: (e.g. nodes) can be shared between worlds, and this should be avoided if cannam@130: possible for performance reasons. cannam@130: */ cannam@130: SORD_API cannam@130: SordWorld* cannam@130: sord_world_new(void); cannam@130: cannam@130: /** cannam@130: Free `world`. cannam@130: */ cannam@130: SORD_API cannam@130: void cannam@130: sord_world_free(SordWorld* world); cannam@130: cannam@130: /** cannam@130: Set a function to be called when errors occur. cannam@130: cannam@130: The `error_sink` will be called with `handle` as its first argument. If cannam@130: no error function is set, errors are printed to stderr. cannam@130: */ cannam@130: SORD_API cannam@130: void cannam@130: sord_world_set_error_sink(SordWorld* world, cannam@130: SerdErrorSink error_sink, cannam@130: void* handle); cannam@130: cannam@130: /** cannam@130: @} cannam@130: @name Node cannam@130: @{ cannam@130: */ cannam@130: cannam@130: /** cannam@130: Get a URI node from a string. cannam@130: cannam@130: Note this function measures `str`, which is a common bottleneck. cannam@130: Use sord_node_from_serd_node() instead if `str` is already measured. cannam@130: */ cannam@130: SORD_API cannam@130: SordNode* cannam@130: sord_new_uri(SordWorld* world, const uint8_t* uri); cannam@130: cannam@130: /** cannam@130: Get a URI node from a relative URI string. cannam@130: */ cannam@130: SORD_API cannam@130: SordNode* cannam@130: sord_new_relative_uri(SordWorld* world, cannam@130: const uint8_t* str, cannam@130: const uint8_t* base_uri); cannam@130: cannam@130: /** cannam@130: Get a blank node from a string. cannam@130: cannam@130: Note this function measures `str`, which is a common bottleneck. cannam@130: Use sord_node_from_serd_node() instead if `str` is already measured. cannam@130: */ cannam@130: SORD_API cannam@130: SordNode* cannam@130: sord_new_blank(SordWorld* world, const uint8_t* str); cannam@130: cannam@130: /** cannam@130: Get a literal node from a string. cannam@130: cannam@130: Note this function measures `str`, which is a common bottleneck. cannam@130: Use sord_node_from_serd_node() instead if `str` is already measured. cannam@130: */ cannam@130: SORD_API cannam@130: SordNode* cannam@130: sord_new_literal(SordWorld* world, cannam@130: SordNode* datatype, cannam@130: const uint8_t* str, cannam@130: const char* lang); cannam@130: cannam@130: /** cannam@130: Copy a node (obtain a reference). cannam@130: cannam@130: Node that since nodes are interned and reference counted, this does not cannam@130: actually create a deep copy of `node`. cannam@130: */ cannam@130: SORD_API cannam@130: SordNode* cannam@130: sord_node_copy(const SordNode* node); cannam@130: cannam@130: /** cannam@130: Free a node (drop a reference). cannam@130: */ cannam@130: SORD_API cannam@130: void cannam@130: sord_node_free(SordWorld* world, SordNode* node); cannam@130: cannam@130: /** cannam@130: Return the type of a node (SORD_URI, SORD_BLANK, or SORD_LITERAL). cannam@130: */ cannam@130: SORD_API cannam@130: SordNodeType cannam@130: sord_node_get_type(const SordNode* node); cannam@130: cannam@130: /** cannam@130: Return the string value of a node. cannam@130: */ cannam@130: SORD_API cannam@130: const uint8_t* cannam@130: sord_node_get_string(const SordNode* node); cannam@130: cannam@130: /** cannam@130: Return the string value of a node, and set `bytes` to its length in bytes. cannam@130: */ cannam@130: SORD_API cannam@130: const uint8_t* cannam@130: sord_node_get_string_counted(const SordNode* node, size_t* bytes); cannam@130: cannam@130: /** cannam@130: Return the string value of a node, and set `bytes` to its length in bytes, cannam@130: and `count` to its length in characters. cannam@130: */ cannam@130: SORD_API cannam@130: const uint8_t* cannam@130: sord_node_get_string_measured(const SordNode* node, cannam@130: size_t* bytes, cannam@130: size_t* chars); cannam@130: cannam@130: /** cannam@130: Return the language of a literal node (or NULL). cannam@130: */ cannam@130: SORD_API cannam@130: const char* cannam@130: sord_node_get_language(const SordNode* node); cannam@130: cannam@130: /** cannam@130: Return the datatype URI of a literal node (or NULL). cannam@130: */ cannam@130: SORD_API cannam@130: SordNode* cannam@130: sord_node_get_datatype(const SordNode* node); cannam@130: cannam@130: /** cannam@130: Return the flags (string attributes) of a node. cannam@130: */ cannam@130: SORD_API cannam@130: SerdNodeFlags cannam@130: sord_node_get_flags(const SordNode* node); cannam@130: cannam@130: /** cannam@130: Return true iff node can be serialised as an inline object. cannam@130: cannam@130: More specifically, this returns true iff the node is the object field cannam@130: of exactly one statement, and therefore can be inlined since it needn't cannam@130: be referred to by name. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_node_is_inline_object(const SordNode* node); cannam@130: cannam@130: /** cannam@130: Return true iff `a` is equal to `b`. cannam@130: cannam@130: Note this is much faster than comparing the node's strings. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_node_equals(const SordNode* a, cannam@130: const SordNode* b); cannam@130: cannam@130: /** cannam@130: Return a SordNode as a SerdNode. cannam@130: cannam@130: The returned node is shared and must not be freed or modified. cannam@130: */ cannam@130: SORD_API cannam@130: const SerdNode* cannam@130: sord_node_to_serd_node(const SordNode* node); cannam@130: cannam@130: /** cannam@130: Create a new SordNode from a SerdNode. cannam@130: cannam@130: The returned node must be freed using sord_node_free(). cannam@130: */ cannam@130: SORD_API cannam@130: SordNode* cannam@130: sord_node_from_serd_node(SordWorld* world, cannam@130: SerdEnv* env, cannam@130: const SerdNode* node, cannam@130: const SerdNode* datatype, cannam@130: const SerdNode* lang); cannam@130: cannam@130: /** cannam@130: @} cannam@130: @name Model cannam@130: @{ cannam@130: */ cannam@130: cannam@130: /** cannam@130: Create a new model. cannam@130: cannam@130: @param world The world in which to make this model. cannam@130: cannam@130: @param indices SordIndexOption flags (e.g. SORD_SPO|SORD_OPS). Be sure to cannam@130: enable an index where the most significant node(s) are not variables in your cannam@130: queries (e.g. to make (? P O) queries, enable either SORD_OPS or SORD_POS). cannam@130: cannam@130: @param graphs If true, store (and index) graph contexts. cannam@130: */ cannam@130: SORD_API cannam@130: SordModel* cannam@130: sord_new(SordWorld* world, cannam@130: unsigned indices, cannam@130: bool graphs); cannam@130: cannam@130: /** cannam@130: Close and free `model`. cannam@130: */ cannam@130: SORD_API cannam@130: void cannam@130: sord_free(SordModel* model); cannam@130: cannam@130: /** cannam@130: Get the world associated with `model`. cannam@130: */ cannam@130: SORD_API cannam@130: SordWorld* cannam@130: sord_get_world(SordModel* model); cannam@130: cannam@130: /** cannam@130: Return the number of nodes stored in `world`. cannam@130: cannam@130: Nodes are included in this count iff they are a part of a quad in `world`. cannam@130: */ cannam@130: SORD_API cannam@130: size_t cannam@130: sord_num_nodes(const SordWorld* world); cannam@130: cannam@130: /** cannam@130: Return the number of quads stored in `model`. cannam@130: */ cannam@130: SORD_API cannam@130: size_t cannam@130: sord_num_quads(const SordModel* model); cannam@130: cannam@130: /** cannam@130: Return an iterator to the start of `model`. cannam@130: */ cannam@130: SORD_API cannam@130: SordIter* cannam@130: sord_begin(const SordModel* model); cannam@130: cannam@130: /** cannam@130: Search for statements by a quad pattern. cannam@130: @return an iterator to the first match, or NULL if no matches found. cannam@130: */ cannam@130: SORD_API cannam@130: SordIter* cannam@130: sord_find(SordModel* model, const SordQuad pat); cannam@130: cannam@130: /** cannam@130: Search for statements by nodes. cannam@130: @return an iterator to the first match, or NULL if no matches found. cannam@130: */ cannam@130: SORD_API cannam@130: SordIter* cannam@130: sord_search(SordModel* model, cannam@130: const SordNode* s, cannam@130: const SordNode* p, cannam@130: const SordNode* o, cannam@130: const SordNode* g); cannam@130: /** cannam@130: Search for a single node that matches a pattern. cannam@130: Exactly one of `s`, `p`, `o` must be NULL. cannam@130: This function is mainly useful for predicates that only have one value. cannam@130: The returned node must be freed using sord_node_free(). cannam@130: @return the first matching node, or NULL if no matches are found. cannam@130: */ cannam@130: SORD_API cannam@130: SordNode* cannam@130: sord_get(SordModel* model, cannam@130: const SordNode* s, cannam@130: const SordNode* p, cannam@130: const SordNode* o, cannam@130: const SordNode* g); cannam@130: cannam@130: /** cannam@130: Return true iff a statement exists. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_ask(SordModel* model, cannam@130: const SordNode* s, cannam@130: const SordNode* p, cannam@130: const SordNode* o, cannam@130: const SordNode* g); cannam@130: cannam@130: /** cannam@130: Return the number of matching statements. cannam@130: */ cannam@130: SORD_API cannam@130: uint64_t cannam@130: sord_count(SordModel* model, cannam@130: const SordNode* s, cannam@130: const SordNode* p, cannam@130: const SordNode* o, cannam@130: const SordNode* g); cannam@130: cannam@130: /** cannam@130: Check if `model` contains a triple pattern. cannam@130: cannam@130: @return true if `model` contains a match for `pat`, otherwise false. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_contains(SordModel* model, const SordQuad pat); cannam@130: cannam@130: /** cannam@130: Add a quad to a model. cannam@130: cannam@130: Calling this function invalidates all iterators on `model`. cannam@130: cannam@130: @return true on success, false, on error. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_add(SordModel* model, const SordQuad quad); cannam@130: cannam@130: /** cannam@130: Remove a quad from a model. cannam@130: cannam@130: Calling this function invalidates all iterators on `model`. To remove quads cannam@130: while iterating, use sord_erase() instead. cannam@130: */ cannam@130: SORD_API cannam@130: void cannam@130: sord_remove(SordModel* model, const SordQuad quad); cannam@130: cannam@130: /** cannam@130: Remove a quad from a model via an iterator. cannam@130: cannam@130: Calling this function invalidates all iterators on `model` except `iter`. cannam@130: cannam@130: @param model The model which `iter` points to. cannam@130: @param iter Iterator to the element to erase, which is incremented to the cannam@130: next value on return. cannam@130: */ cannam@130: SORD_API cannam@130: SerdStatus cannam@130: sord_erase(SordModel* model, SordIter* iter); cannam@130: cannam@130: /** cannam@130: @} cannam@130: @name Inserter cannam@130: @{ cannam@130: */ cannam@130: cannam@130: /** cannam@130: Create an inserter for writing statements to a model. cannam@130: */ cannam@130: SORD_API cannam@130: SordInserter* cannam@130: sord_inserter_new(SordModel* model, cannam@130: SerdEnv* env); cannam@130: cannam@130: /** cannam@130: Free an inserter. cannam@130: */ cannam@130: SORD_API cannam@130: void cannam@130: sord_inserter_free(SordInserter* inserter); cannam@130: cannam@130: /** cannam@130: Set the current base URI for writing to the model. cannam@130: cannam@130: Note this function can be safely casted to SerdBaseSink. cannam@130: */ cannam@130: SORD_API cannam@130: SerdStatus cannam@130: sord_inserter_set_base_uri(SordInserter* inserter, cannam@130: const SerdNode* uri); cannam@130: cannam@130: /** cannam@130: Set a namespace prefix for writing to the model. cannam@130: cannam@130: Note this function can be safely casted to SerdPrefixSink. cannam@130: */ cannam@130: SORD_API cannam@130: SerdStatus cannam@130: sord_inserter_set_prefix(SordInserter* inserter, cannam@130: const SerdNode* name, cannam@130: const SerdNode* uri); cannam@130: cannam@130: /** cannam@130: Write a statement to the model. cannam@130: cannam@130: Note this function can be safely casted to SerdStatementSink. cannam@130: */ cannam@130: SORD_API cannam@130: SerdStatus cannam@130: sord_inserter_write_statement(SordInserter* inserter, cannam@130: SerdStatementFlags flags, cannam@130: const SerdNode* graph, cannam@130: const SerdNode* subject, cannam@130: const SerdNode* predicate, cannam@130: const SerdNode* object, cannam@130: const SerdNode* object_datatype, cannam@130: const SerdNode* object_lang); cannam@130: cannam@130: /** cannam@130: @} cannam@130: @name Iteration cannam@130: @{ cannam@130: */ cannam@130: cannam@130: /** cannam@130: Set `quad` to the quad pointed to by `iter`. cannam@130: */ cannam@130: SORD_API cannam@130: void cannam@130: sord_iter_get(const SordIter* iter, SordQuad quad); cannam@130: cannam@130: /** cannam@130: Return a field of the quad pointed to by `iter`. cannam@130: cannam@130: Returns NULL if `iter` is NULL or is at the end. cannam@130: */ cannam@130: SORD_API cannam@130: const SordNode* cannam@130: sord_iter_get_node(const SordIter* iter, SordQuadIndex index); cannam@130: cannam@130: /** cannam@130: Return the store pointed to by `iter`. cannam@130: */ cannam@130: SORD_API cannam@130: const SordModel* cannam@130: sord_iter_get_model(SordIter* iter); cannam@130: cannam@130: /** cannam@130: Increment `iter` to point to the next statement. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_iter_next(SordIter* iter); cannam@130: cannam@130: /** cannam@130: Return true iff `iter` is at the end of its range. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_iter_end(const SordIter* iter); cannam@130: cannam@130: /** cannam@130: Free `iter`. cannam@130: */ cannam@130: SORD_API cannam@130: void cannam@130: sord_iter_free(SordIter* iter); cannam@130: cannam@130: /** cannam@130: @} cannam@130: @name Utilities cannam@130: @{ cannam@130: */ cannam@130: cannam@130: /** cannam@130: Match two quads (using ID comparison only). cannam@130: cannam@130: This function is a straightforward and fast equivalence match with wildcard cannam@130: support (ID 0 is a wildcard). It does not actually read node data. cannam@130: @return true iff `x` and `y` match. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_quad_match(const SordQuad x, const SordQuad y); cannam@130: cannam@130: /** cannam@130: @} cannam@130: @name Serialisation cannam@130: @{ cannam@130: */ cannam@130: cannam@130: /** cannam@130: Return a reader that will read into `model`. cannam@130: */ cannam@130: SORD_API cannam@130: SerdReader* cannam@130: sord_new_reader(SordModel* model, cannam@130: SerdEnv* env, cannam@130: SerdSyntax syntax, cannam@130: SordNode* graph); cannam@130: cannam@130: /** cannam@130: Write a model to a writer. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_write(SordModel* model, cannam@130: SerdWriter* writer, cannam@130: SordNode* graph); cannam@130: cannam@130: /** cannam@130: Write a range to a writer. cannam@130: cannam@130: This increments `iter` to its end, then frees it. cannam@130: */ cannam@130: SORD_API cannam@130: bool cannam@130: sord_write_iter(SordIter* iter, cannam@130: SerdWriter* writer); cannam@130: cannam@130: /** cannam@130: @} cannam@130: @} cannam@130: */ cannam@130: cannam@130: #ifdef __cplusplus cannam@130: } /* extern "C" */ cannam@130: #endif cannam@130: cannam@130: #endif /* SORD_SORD_H */