/**
* Copyright (C) Mellanox Technologies Ltd. 2001-2015. ALL RIGHTS RESERVED.
*
* See file LICENSE for terms.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "dt_iov.h"
#include <ucs/debug/assert.h>
#include <ucs/sys/math.h>
#include <string.h>
#include <unistd.h>
void ucp_dt_iov_gather(void *dest, const ucp_dt_iov_t *iov, size_t length,
size_t *iov_offset, size_t *iovcnt_offset)
{
size_t item_len, item_reminder, item_len_to_copy;
size_t length_it = 0;
ucs_assert(length > 0);
while (length_it < length) {
item_len = iov[*iovcnt_offset].length;
item_reminder = item_len - *iov_offset;
item_len_to_copy = item_reminder -
ucs_max((ssize_t)((length_it + item_reminder) - length), 0);
memcpy(UCS_PTR_BYTE_OFFSET(dest, length_it),
UCS_PTR_BYTE_OFFSET(iov[*iovcnt_offset].buffer, *iov_offset),
item_len_to_copy);
length_it += item_len_to_copy;
ucs_assert(length_it <= length);
if (length_it < length) {
*iov_offset = 0;
++(*iovcnt_offset);
} else {
*iov_offset += item_len_to_copy;
}
}
}
size_t ucp_dt_iov_scatter(ucp_dt_iov_t *iov, size_t iovcnt, const void *src,
size_t length, size_t *iov_offset, size_t *iovcnt_offset)
{
size_t item_len, item_len_to_copy;
size_t length_it = 0;
while ((length_it < length) && (*iovcnt_offset < iovcnt)) {
item_len = iov[*iovcnt_offset].length;
item_len_to_copy = ucs_min(ucs_max((ssize_t)(item_len - *iov_offset), 0),
length - length_it);
ucs_assert(*iov_offset <= item_len);
memcpy(UCS_PTR_BYTE_OFFSET(iov[*iovcnt_offset].buffer, *iov_offset),
UCS_PTR_BYTE_OFFSET(src, length_it),
item_len_to_copy);
length_it += item_len_to_copy;
ucs_assert(length_it <= length);
if (length_it < length) {
*iov_offset = 0;
++(*iovcnt_offset);
} else {
*iov_offset += item_len_to_copy;
}
}
return length_it;
}
void ucp_dt_iov_seek(ucp_dt_iov_t *iov, size_t iovcnt, ptrdiff_t distance,
size_t *iov_offset, size_t *iovcnt_offset)
{
ssize_t new_iov_offset; /* signed, since it can be negative */
size_t length_it;
new_iov_offset = ((ssize_t)*iov_offset) + distance;
if (new_iov_offset < 0) {
/* seek backwards */
do {
ucs_assert(*iovcnt_offset > 0);
--(*iovcnt_offset);
new_iov_offset += iov[*iovcnt_offset].length;
} while (new_iov_offset < 0);
} else {
/* seek forward */
while (new_iov_offset >= (length_it = iov[*iovcnt_offset].length)) {
new_iov_offset -= length_it;
++(*iovcnt_offset);
ucs_assert(*iovcnt_offset < iovcnt);
}
}
*iov_offset = new_iov_offset;
}
size_t ucp_dt_iov_count_nonempty(const ucp_dt_iov_t *iov, size_t iovcnt)
{
size_t iov_it, count;
count = 0;
for (iov_it = 0; iov_it < iovcnt; ++iov_it) {
count += iov[iov_it].length != 0;
}
return count;
}