| /* 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); |
| } |