blob: b2c91e795981e0b5a10f58fa811196e6d76c4351 [file] [log] [blame]
/* 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);
}