summaryrefslogtreecommitdiff
path: root/inc/sbuf.h
diff options
context:
space:
mode:
Diffstat (limited to 'inc/sbuf.h')
-rw-r--r--inc/sbuf.h175
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