parlib: Add IOVEC helpers
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 9 Jan 2017 20:01:41 +0000 (15:01 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 10 Jan 2017 00:01:40 +0000 (19:01 -0500)
These operations allow accessing an iovec's contents without worrying about
boundaries between the vectors.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/parlib/include/parlib/iovec.h [new file with mode: 0644]
user/parlib/iovec.c [new file with mode: 0644]

diff --git a/user/parlib/include/parlib/iovec.h b/user/parlib/include/parlib/iovec.h
new file mode 100644 (file)
index 0000000..58badc7
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (c) 2016 Google Inc
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Various iovec utility functions. */
+
+#pragma once
+
+#include <sys/uio.h>
+#include <stdint.h>
+#include <ros/common.h>
+
+void iov_strip_bytes(struct iovec *iov, int iovcnt, size_t amt);
+void iov_drop_trailing_bytes(struct iovec *iov, int iovcnt, size_t amt);
+void iov_trim_len_to(struct iovec *iov, int iovcnt, size_t new_len);
+
+bool iov_has_bytes(struct iovec *iov, int iovcnt, size_t amt);
+size_t iov_get_len(struct iovec *iov, int iovcnt);
+void iov_linearize(struct iovec *iov, int iovcnt, uint8_t *buf, size_t len);
+
+void iov_set_byte(struct iovec *iov, int iovcnt, size_t idx, uint8_t val);
+uint8_t iov_get_byte(struct iovec *iov, int iovcnt, size_t idx);
+void iov_memcpy_from(struct iovec *iov, int iovcnt, size_t idx,
+                     void *to, size_t amt);
+void iov_memcpy_to(struct iovec *iov, int iovcnt, size_t to,
+                   void *from, size_t amt);
+
+uint16_t iov_get_be16(struct iovec *iov, int iovcnt, size_t idx);
+uint16_t iov_get_be32(struct iovec *iov, int iovcnt, size_t idx);
+void iov_put_be16(struct iovec *iov, int iovcnt, size_t idx, uint16_t val);
+void iov_put_be32(struct iovec *iov, int iovcnt, size_t idx, uint32_t val);
diff --git a/user/parlib/iovec.c b/user/parlib/iovec.c
new file mode 100644 (file)
index 0000000..b2c91e7
--- /dev/null
@@ -0,0 +1,202 @@
+/* Copyright (c) 2016 Google Inc
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Various utility functions. */
+
+#include <parlib/iovec.h>
+#include <assert.h>
+#include <sys/param.h>
+
+/* Strips bytes from the front of the iovec.  This modifies the base and
+ * length of the iovecs in the array. */
+void iov_strip_bytes(struct iovec *iov, int iovcnt, size_t amt)
+{
+       for (int i = 0; i < iovcnt; i++) {
+               if (iov[i].iov_len <= amt) {
+                       amt -= iov[i].iov_len;
+                       iov[i].iov_len = 0;
+                       continue;
+               }
+               iov[i].iov_len -= amt;
+               iov[i].iov_base += amt;
+               amt = 0;
+       }
+}
+
+/* Drops bytes from the end of the iovec.  This modified the length of the
+ * iovecs in the array. */
+void iov_drop_trailing_bytes(struct iovec *iov, int iovcnt, size_t amt)
+{
+       for (int i = iovcnt - 1; i >= 0; i--) {
+               if (iov[i].iov_len <= amt) {
+                       amt -= iov[i].iov_len;
+                       iov[i].iov_len = 0;
+                       continue;
+               }
+               iov[i].iov_len -= amt;
+               break;
+       }
+}
+
+/* Trims the iov's length to new_len, modifying the iov_lens.  If the iov is
+ * shorter than new_len, it will not grow. */
+void iov_trim_len_to(struct iovec *iov, int iovcnt, size_t new_len)
+{
+       for (int i = 0; i < iovcnt; i++) {
+               if (iov[i].iov_len <= new_len) {
+                       new_len -= iov[i].iov_len;
+                       continue;
+               }
+               iov[i].iov_len = new_len;
+               break;
+       }
+}
+
+/* Checks if iov has amt bytes in it. */
+bool iov_has_bytes(struct iovec *iov, int iovcnt, size_t amt)
+{
+       for (int i = 0; i < iovcnt; i++) {
+               if (iov[i].iov_len >= amt)
+                       return TRUE;
+               amt -= iov[i].iov_len;
+       }
+       return FALSE;
+}
+
+size_t iov_get_len(struct iovec *iov, int iovcnt)
+{
+       size_t ret = 0;
+
+       for (int i = 0; i < iovcnt; i++)
+               ret += iov[i].iov_len;
+       return ret;
+}
+
+/* Copies up to len bytes of the contents of IOV into buf. */
+void iov_linearize(struct iovec *iov, int iovcnt, uint8_t *buf, size_t len)
+{
+       size_t copy_amt;
+       size_t sofar = 0;
+
+       for (int i = 0; i < iovcnt; i++) {
+               if (!len)
+                       break;
+               copy_amt = MIN(iov[i].iov_len, len);
+               memcpy(buf + sofar, iov[i].iov_base, copy_amt);
+               sofar += copy_amt;
+               len -= copy_amt;
+       }
+}
+
+/* Sets a byte in an iov, essentially iov_mem[idx] = val. */
+void iov_set_byte(struct iovec *iov, int iovcnt, size_t idx, uint8_t val)
+{
+       uint8_t *p = NULL;
+
+       for (int i = 0; i < iovcnt; i++) {
+               if (iov[i].iov_len <= idx) {
+                       idx -= iov[i].iov_len;
+                       continue;
+               }
+               p = iov[i].iov_base + idx;
+               break;
+       }
+       assert(p);
+       *p = val;
+}
+
+/* Sets a byte in an iov, essentially *val = iov_mem[idx]. */
+uint8_t iov_get_byte(struct iovec *iov, int iovcnt, size_t idx)
+{
+       uint8_t *p = NULL;
+
+       for (int i = 0; i < iovcnt; i++) {
+               if (iov[i].iov_len <= idx) {
+                       idx -= iov[i].iov_len;
+                       continue;
+               }
+               p = iov[i].iov_base + idx;
+               break;
+       }
+       assert(p);
+       return *p;
+}
+
+void iov_memcpy_from(struct iovec *iov, int iovcnt, size_t from,
+                     void *to, size_t amt)
+{
+       size_t copy_amt;
+       void *copy_start;
+       size_t sofar = 0;
+
+       for (int i = 0; i < iovcnt; i++) {
+               if (!amt)
+                       break;
+               if (iov[i].iov_len <= from) {
+                       from -= iov[i].iov_len;
+                       continue;
+               }
+               copy_start = iov[i].iov_base + from;
+               copy_amt = iov[i].iov_len - from;
+               from = 0;
+               copy_amt = MIN(copy_amt, amt);
+               memcpy(to + sofar, copy_start, copy_amt);
+               sofar += copy_amt;
+               amt -= copy_amt;
+       }
+       assert(!amt);
+}
+
+void iov_memcpy_to(struct iovec *iov, int iovcnt, size_t to,
+                   void *from, size_t amt)
+{
+       size_t copy_amt;
+       void *copy_start;
+       size_t sofar = 0;
+
+       for (int i = 0; i < iovcnt; i++) {
+               if (!amt)
+                       break;
+               if (iov[i].iov_len <= to) {
+                       to -= iov[i].iov_len;
+                       continue;
+               }
+               copy_start = iov[i].iov_base + to;
+               copy_amt = iov[i].iov_len - to;
+               to = 0;
+               copy_amt = MIN(copy_amt, amt);
+               memcpy(copy_start, from + sofar, copy_amt);
+               sofar += copy_amt;
+               amt -= copy_amt;
+       }
+       assert(!amt);
+}
+
+uint16_t iov_get_be16(struct iovec *iov, int iovcnt, size_t idx)
+{
+       return ((uint16_t)iov_get_byte(iov, iovcnt, idx + 0) << 8)
+            | ((uint16_t)iov_get_byte(iov, iovcnt, idx + 1) << 0);
+}
+
+uint16_t iov_get_be32(struct iovec *iov, int iovcnt, size_t idx)
+{
+       return ((uint32_t)iov_get_byte(iov, iovcnt, idx + 0) << 24)
+            | ((uint32_t)iov_get_byte(iov, iovcnt, idx + 1) << 16)
+            | ((uint32_t)iov_get_byte(iov, iovcnt, idx + 2) << 8)
+            | ((uint32_t)iov_get_byte(iov, iovcnt, idx + 3) << 0);
+}
+
+void iov_put_be16(struct iovec *iov, int iovcnt, size_t idx, uint16_t val)
+{
+       iov_set_byte(iov, iovcnt, idx + 0, (val >> 8) & 0xff);
+       iov_set_byte(iov, iovcnt, idx + 1, (val >> 0) & 0xff);
+}
+
+void iov_put_be32(struct iovec *iov, int iovcnt, size_t idx, uint32_t val)
+{
+       iov_set_byte(iov, iovcnt, idx + 0, (val >> 24) & 0xff);
+       iov_set_byte(iov, iovcnt, idx + 1, (val >> 16) & 0xff);
+       iov_set_byte(iov, iovcnt, idx + 2, (val >>  8) & 0xff);
+       iov_set_byte(iov, iovcnt, idx + 3, (val >>  0) & 0xff);
+}