include/buffer/cc_buf.h (141 lines of code) (raw):
/*
* ccommon - a cache common library.
* Copyright (C) 2013 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* buf: a buffer base for contiguous buffers that can be pooled together
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <cc_bstring.h>
#include <cc_debug.h>
#include <cc_define.h>
#include <cc_metric.h>
#include <cc_option.h>
#include <cc_queue.h>
#include <cc_util.h>
#include <stdbool.h>
#include <sys/param.h>
/* name type default description */
#define BUF_OPTION(ACTION) \
ACTION( buf_init_size, OPTION_TYPE_UINT, BUF_DEFAULT_SIZE, "init buf size incl header" )\
ACTION( buf_poolsize, OPTION_TYPE_UINT, BUF_POOLSIZE, "buf pool size" )
typedef struct {
BUF_OPTION(OPTION_DECLARE)
} buf_options_st;
/* name type description */
#define BUF_METRIC(ACTION) \
ACTION( buf_curr, METRIC_GAUGE, "# buf allocated" )\
ACTION( buf_active, METRIC_GAUGE, "# buf in use/borrowed" )\
ACTION( buf_create, METRIC_COUNTER, "# buf creates" )\
ACTION( buf_create_ex, METRIC_COUNTER, "# buf create exceptions" )\
ACTION( buf_destroy, METRIC_COUNTER, "# buf destroys" )\
ACTION( buf_borrow, METRIC_COUNTER, "# buf borrows" )\
ACTION( buf_borrow_ex, METRIC_COUNTER, "# buf borrow exceptions" )\
ACTION( buf_return, METRIC_COUNTER, "# buf returns" )\
ACTION( buf_memory, METRIC_GAUGE, "memory alloc'd to buf including header" )
typedef struct {
BUF_METRIC(METRIC_DECLARE)
} buf_metrics_st;
struct buf {
STAILQ_ENTRY(buf) next; /* next buf in pool */
char *rpos; /* read marker */
char *wpos; /* write marker */
char *end; /* end of buffer */
bool free; /* is this buf free? */
char begin[]; /* beginning of buffer */
};
#define BUF_HDR_SIZE offsetof(struct buf, begin)
#define BUF_DEFAULT_SIZE 16 * KiB
#define BUF_POOLSIZE 0 /* unlimited */
STAILQ_HEAD(buf_sqh, buf); /* corresponding header type for the STAILQ */
extern uint32_t buf_init_size;
extern buf_metrics_st *buf_metrics;
#define BUF_INIT_SIZE (16 * KiB)
#define BUF_POOLSIZE 0 /* unlimited */
#define BUF_EMTPY(BUF) \
((BUF)->rpos == (BUF)->wpos)
#define BUF_FULL(BUF) \
((BUF)->wpos == (BUF)->end)
/* Setup/teardown buf module */
void buf_setup(buf_options_st *options, buf_metrics_st *metrics);
void buf_teardown(void);
/* Obtain/return a buffer from the pool */
struct buf *buf_borrow(void);
void buf_return(struct buf **buf);
/* Create/destroy a buffer (allocate/deallocate) */
struct buf *buf_create(void);
void buf_destroy(struct buf **buf);
/* Size of data that has yet to be read */
static inline uint32_t
buf_rsize(const struct buf *buf)
{
ASSERT(buf->rpos <= buf->wpos);
return (uint32_t)(buf->wpos - buf->rpos);
}
/* Amount of room left in buffer for writing new data */
static inline uint32_t
buf_wsize(const struct buf *buf)
{
ASSERT(buf->wpos <= buf->end);
return (uint32_t)(buf->end - buf->wpos);
}
/* Total size of given buf, including header */
static inline uint32_t
buf_size(const struct buf *buf)
{
ASSERT(buf->begin < buf->end);
return (uint32_t)(buf->end - (char *)buf);
}
/* Size of given buf, not including header */
static inline uint32_t
buf_capacity(const struct buf *buf)
{
ASSERT(buf->begin < buf->end);
return (uint32_t)(buf->end - buf->begin);
}
/* new capacity needed to write count bytes to the buffer */
static inline uint32_t
buf_new_cap(const struct buf *buf, uint32_t count)
{
ASSERT(buf->begin <= buf->wpos);
return count <= buf_wsize(buf) ? 0 : count - buf_wsize(buf);
}
static inline void
buf_reset(struct buf *buf)
{
STAILQ_NEXT(buf, next) = NULL;
buf->free = 0;
buf->rpos = buf->wpos = buf->begin;
}
static inline uint32_t
buf_read(char *dst, struct buf *src, uint32_t count)
{
ASSERT(dst != NULL && src != NULL);
uint32_t len = MIN(buf_rsize(src), count);
cc_memcpy(dst, src->rpos, len);
src->rpos += len;
return len;
}
static inline uint32_t
buf_write(struct buf *dst, char *src, uint32_t count)
{
if (count == 0) {
return 0;
}
ASSERT(dst != NULL && src != NULL);
uint32_t len = MIN(buf_wsize(dst), count);
cc_memcpy(dst->wpos, src, len);
dst->wpos += len;
return len;
}
static inline void
buf_lshift(struct buf *buf)
{
ASSERT(buf != NULL);
uint32_t size = buf_rsize(buf);
if (size > 0) {
cc_memmove(buf->begin, buf->rpos, size);
}
buf->rpos = buf->begin;
buf->wpos = buf->begin + size;
}
static inline void
buf_rshift(struct buf *buf)
{
ASSERT(buf != NULL);
uint32_t size = buf_rsize(buf);
if (size > 0) {
cc_memmove(buf->end - size, buf->rpos, size);
}
buf->rpos = buf->end - size;
buf->wpos = buf->end;
}
#ifdef __cplusplus
}
#endif