#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 /// Triple position of s, p, o. typedef enum { TRP_POS_S = 0, TRP_POS_P = 1, TRP_POS_O = 2, } LSUP_TriplePos; /// Buffer flags, stored in buffer structure. typedef enum { LSUP_BUF_BORROWED = 1<<0, /**< Borrowed buffer. This indicates that * the memory block pointed to by the * buffer is owned by another function, * and instructs #LSUP_buffer_free() to * only free the buffer handle, but not * the underlying data. */ } LSUP_BufferFlag; /** @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_BufferFlag flags; } 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; /* * Function prototypes. */ /** @brief 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[in] buf A buffer handle obtained with #LSUP_buffer_new or by manual * allocation. * * @param[in] size New size. * * @param[in] data 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[in] size Length of the data. * * @param[in] data Optional data to initially populate the object with. If * NULL, the buffer data are garbage. * * @return LSUP_Buffer handle. 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 Create a borrowed buffer (memory view). * * A borrowed buffer does not own the memory block pointed to and should not * be freed. It can be identified by the LSUP_BUF_BORROWED flag. * * @param[in] data Address of data handled by the buffer. * * @param[in] size Length of the data. * * @return LSUP_Buffer handle. It must be freed with #LSUP_buffer_free, which * will correctly leave the underlying data alone. NULL on error. */ inline LSUP_Buffer * LSUP_buffer_new_borrowed (unsigned char *data, const size_t size) { LSUP_Buffer *buf; MALLOC_GUARD (buf, NULL); buf->addr = data; buf->size = size; buf->flags = LSUP_BUF_BORROWED; 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[in] buf 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. */ /** @brief Create a new buffer triple. * * @important The triple must be freed with #LSUP_btriple_free(). * * @param[in] sspo Serialized triple pointer to initialize. * * @param[in] s Subject as a serialized buffer. * * @param[in] p Predicate as a serialized buffer. * * @param[in] o Object as a serialized buffer. * * @return New triple. */ 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. * * @important The triple must be freed with #LSUP_btriple_free(). * * @param[in] sspo Serialized triple pointer to initialize. * * @param[in] s Subject as a serialized buffer. * * @param[in] p Predicate as a serialized buffer. * * @param[in] o Object as a serialized buffer. * * @return LSUP_OK on success. */ 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[in] sspo Buffer triple to be freed. */ void LSUP_btriple_done (LSUP_BufferTriple *sspo); /** @brief Free a buffer triple and all its internal pointers. * * @important 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[in] sspo Buffer triple to be freed. */ void LSUP_btriple_free (LSUP_BufferTriple *sspo); /** @brief Get serialized triple by term position. * * Useful for looping over all terms. * * @param[in] btrp Serialized triple pointer. * * @param[in] n 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. RDF_Canon should be ported * to this library. * * @param[in] strp Serialized triple to hash. * * @return Hash value. */ 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) ) ); } /** @brief Dummy buffer triple. * * Triple of dummy buffer, with #LSUP_Buffer size space allocated, but no * contents. * * Free with #LSUP_btriple_free(). */ #define BTRP_DUMMY LSUP_btriple_new (BUF_DUMMY, BUF_DUMMY, BUF_DUMMY) #endif