#ifndef _LSUP_BUFFER_H #define _LSUP_BUFFER_H #include "core.h" /** @brief "NULL" key, a value that is never user-provided. * * Used to mark special values (e.g. deleted records). */ #define NULL_KEY 0 /** @brief General-purpose data buffer. * * The structure is transparently exposed so that the related API only defines * few basic helper methods. Other operations, such as appending, may be * performed by simply using the addr and size attributes. * * A buffer can be initialized once and reused multiple times, e.g. in a loop, * without being freed between iterations, by using #LSUP_buffer_init. */ typedef struct LSUP_Buffer { /*@null@*/ unsigned char *addr; size_t size; } LSUP_Buffer; /** @brief Triple of byte buffers. * * This is a generic data triple. Store implementations should handle this * data type rather than RDF terms and triples. Conversion to/from RDF terms * and triples is done in the term and triple modules. */ typedef struct buffer_triple_t { LSUP_Buffer *s; LSUP_Buffer *p; LSUP_Buffer *o; } LSUP_BufferTriple; typedef enum { TRP_POS_S = 0, TRP_POS_P = 1, TRP_POS_O = 2, } LSUP_TriplePos; /** Initialize or reuse a buffer handle. * * The handle must have been created with #LSUP_buffer_new*(). * * The data block is resized without being freed first. The handle must be * eventually freed with #LSUP_buffer_done() after use. * * @param buf[in] A buffer handle obtained with #LSUP_buffer_new or by manual * allocation. * * @param size[in] New size. * * @param data[in] If not NULL, data to replace the existing ones. The size * of the data to be copied is determined by the size parameter. If NULL, the * existing data are preserved as with a normal realloc(). */ LSUP_rc LSUP_buffer_init ( LSUP_Buffer *buf, const size_t size, const unsigned char *data); /** @brief Create a new buffer and optionally populate it with data. * * To change the buffer size and/or data later call #LSUP_buffer_init. * * To copy a buffer just do buf2 = LSUP_buffer_new (buf1->addr, buf1->size); * * @param size[in] Length of the data. * * @param data[in] Optional data to initially populate the object with. If * NULL, the buffer data are garbage. * * @return LSUP_Buffer pointer. It must be freed with #LSUP_buffer_free. NULL * on error. */ inline LSUP_Buffer * LSUP_buffer_new (const unsigned char *data, const size_t size) { LSUP_Buffer *buf; CALLOC_GUARD (buf, NULL); if (LSUP_buffer_init (buf, size, data) != LSUP_OK) { free (buf->addr); free (buf); return NULL; } return buf; } /** @brief Dummy buffer to be used with #LSUP_buffer_init. */ #define BUF_DUMMY LSUP_buffer_new (NULL, 0) /** @brief Free the content of a buffer. */ void LSUP_buffer_done (LSUP_Buffer *buf); /** @brief Free a buffer. */ void LSUP_buffer_free (LSUP_Buffer *buf); /** @brief Hash a buffer. */ inline LSUP_Key LSUP_buffer_hash (const LSUP_Buffer *buf) { return (buf == NULL) ? NULL_KEY : LSUP_HASH (buf->addr, buf->size, LSUP_HASH_SEED); } /** @brief Print a byte string of a given length in a human-readable format. * * The string is printed in Python style: printable characters are output * literally, and non-printable ones as hex sequences. */ void LSUP_buffer_print (const LSUP_Buffer *buf); /** @brief Format a buffer into anb ASCII string. * * The string has non-printable characters escaped as "\xNN". * * @param buf[in] Buffer to convert. * * @return Formatted string. It must be freed with free(). */ char * LSUP_buffer_as_str (const LSUP_Buffer *buf); /** @brief Compare two buffers. * * The return value is the same as memcmp. */ inline int LSUP_buffer_cmp (const LSUP_Buffer *buf1, const LSUP_Buffer *buf2) { return memcmp ( buf1->addr, buf2->addr, (buf1->size > buf2->size ? buf1->size : buf2->size)); } /** @brief Return whether two buffers are equal. * * This may be faster than #LSUP_buffer_cmp() because it does a size comparison * first. */ inline bool LSUP_buffer_eq (const LSUP_Buffer *buf1, const LSUP_Buffer *buf2) { if (buf1->size != buf2->size) return false; return (LSUP_buffer_cmp (buf1, buf2) == 0) ? true : false; } /* * Buffer triples. */ LSUP_BufferTriple * LSUP_btriple_new(LSUP_Buffer *s, LSUP_Buffer *p, LSUP_Buffer *o); /** @brief Initialize internal term pointers in a heap-allocated buffer triple. * * The triple must be freed with #LSUP_btriple_free(). * * @param sspo[in] Serialized triple pointer to initialize. */ LSUP_rc LSUP_btriple_init ( LSUP_BufferTriple *sspo, LSUP_Buffer *s, LSUP_Buffer *p, LSUP_Buffer *o); /** @brief Free the internal pointers of a buffer triple. * * @param sspo[in] Buffer triple to be freed. */ void LSUP_btriple_done (LSUP_BufferTriple *sspo); /** @brief Free a buffer triple and all its internal pointers. * * NOTE: If the buffer pointers are not to be freed (e.g. they are owned by a * back end), use a simple free(sspo) instead of this. * * @param sspo[in] Buffer triple to be freed. */ void LSUP_btriple_free (LSUP_BufferTriple *sspo); /** @brief Free a buffer triple and its buffer handles but not the buffer data. * * This is useful when freeing a "dummy" triple whose buffers are owned by the * caller but the data the terms point to are owned by the store. * */ void LSUP_btriple_free_shallow (LSUP_BufferTriple *sspo); /** @brief Get serialized triple by term position. * * Useful for looping over all terms. * * @param trp[in] Serialized triple pointer. * * @param n[in] A number between 0รท2. * * @return Corresponding serialized term or NULL if n is out of range. */ inline LSUP_Buffer * LSUP_btriple_pos (const LSUP_BufferTriple *btrp, LSUP_TriplePos n) { if (n == TRP_POS_S) return btrp->s; if (n == TRP_POS_P) return btrp->p; if (n == TRP_POS_O) return btrp->o; return NULL; } /** @brief Hash a buffer triple. * * TODO This doesn't handle blank nodes correctly. */ inline LSUP_Key LSUP_btriple_hash (const LSUP_BufferTriple *strp) { return LSUP_HASH ( strp->s->addr, strp->s->size, LSUP_HASH ( strp->p->addr, strp->p->size, LSUP_HASH (strp->o->addr, strp->o->size, LSUP_HASH_SEED) ) ); } #define BTRP_DUMMY LSUP_btriple_new (NULL, NULL, NULL) #endif