diff options
Diffstat (limited to 'inc/sbuf.h')
-rw-r--r-- | inc/sbuf.h | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/inc/sbuf.h b/inc/sbuf.h new file mode 100644 index 0000000..96775c8 --- /dev/null +++ b/inc/sbuf.h @@ -0,0 +1,175 @@ +/** + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SBUF_H +#define SBUF_H + +#include <string.h> +#include <stdint.h> +#include "AEEstd.h" + +/** + * lightweight serialize/deserialize buffer. + + For example + + struct sbuf; + //initialize empty buffer; + sbuf_init(&sbuf, 0, 0, 0); + + //fill it with data + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr1, 10); + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr2, 20); + + //allocate the memory needed + mem = malloc(sbuf_needed(&sbuf)); + + //initialize with the data + sbuf_init(&sbuf, 0, mem, sbuf_needed(&sbuf)); + + //fill it with data, since it has memory, it will actually copy + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr1, 10); + sbuf_align(&sbuf, 8); + sbuf_write(&sbuf, ptr2, 20); + + See sbuf_q.c for more examples + */ + + +struct sbuf { + uintptr_t buf; //! start of valid memory + uintptr_t bufEnd; //! end of valid memory + uintptr_t bufStart; //! start with optinal offset from valid mem + uintptr_t bufCur; //! current position, could be outside of valid range +}; + +/** + * @param buf, the buffer structure instance + * @param offset, this value indicates how far ahead the data buffer is + * start = data - offset + * @param data, the valid memory + * @param dataLen, the length ov valid memory + */ +static __inline void sbuf_init(struct sbuf* buf, int offset, void* data, int dataLen) { + buf->buf = (uintptr_t)data; + buf->bufStart = buf->bufCur = (uintptr_t)data - offset; + buf->bufEnd = (uintptr_t)data + dataLen; +} + +//! move the current pointer by len +static __inline void sbuf_advance(struct sbuf* buf, int len) { + buf->bufCur += len; +} + +/** + * @retval, the amount of memory needed for everything from the start (with the offset) + * to the current position of the buffer + */ +static __inline int sbuf_needed(struct sbuf* buf) { + return buf->bufCur - buf->bufStart; +} +/** + * @retval, the space left in the buffer. A negative value indicates overflow. + * A positive value includes the offset. + */ +static __inline int sbuf_left(struct sbuf* buf) { + return buf->bufEnd - buf->bufCur; +} + +//! @retval the current head pointer +static __inline void* sbuf_head(struct sbuf* buf) { + return (void*)buf->bufCur; +} + +//! @retval true if the current pointer is valid +static __inline int sbuf_valid(struct sbuf* buf) { + return buf->bufCur >= buf->buf && buf->bufCur < buf->bufEnd; +} + +//! advance the head pointer so the "needed" is aligned to the align value +#define _SBUF_ALIGN(x, y) (((x) + ((y)-1)) & ~((y)-1)) +static __inline void sbuf_align(struct sbuf* buf, uint32_t align) { + sbuf_advance(buf, _SBUF_ALIGN(sbuf_needed(buf), align) - sbuf_needed(buf)); +} + +/** + * Write to the buffer. + * @param src, the memory to read from. Will write srcLen bytes to buf from src + * from the buf's current position. Only the valid portion of data will + * be written. + * @param srcLen, the length of src. The buffer will be advanced by srcLen. + */ +static __inline void sbuf_write(struct sbuf* buf, void *psrc, int srcLen) { + uintptr_t src = (uintptr_t)psrc; + if(buf->bufCur + srcLen > buf->buf) { + int writeLen; + if(buf->bufCur < buf->buf) { + int len = buf->buf - buf->bufCur; + srcLen -= len; + src += len; + sbuf_advance(buf, len); + } + writeLen = STD_MIN(srcLen, sbuf_left(buf)); + if(writeLen > 0) { + std_memsmove((void*)buf->bufCur, buf->bufEnd - buf->bufCur, (void*)src, writeLen); + } + } + sbuf_advance(buf, srcLen); +} + +/** + * Read from the buffer into dst. + * @param dst, the data to write to. Will write dstLen to dst from buf + * from the current position of buf. Only valid memory + * will be written to dst. Invalid overlapping memory will + * remain untouched. + * @param dstLen, the length of dst. buf will be advanced by dstLen + */ +static __inline void sbuf_read(struct sbuf* buf, void *pdst, int dstLen) { + uintptr_t dst = (uintptr_t)pdst; + if(buf->bufCur + dstLen > buf->buf) { + int readLen; + if(buf->bufCur < buf->buf) { + int len = buf->buf - buf->bufCur; + dstLen -= len; + dst += len; + sbuf_advance(buf, len); + } + readLen = STD_MIN(dstLen, sbuf_left(buf)); + if(readLen > 0) { + std_memsmove((void*)dst, dstLen, (void*)buf->bufCur, readLen); + } + } + sbuf_advance(buf, dstLen); +} + +#endif |