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