#include "src/include/pmix_config.h"
#include "pmix_common.h"
#include "src/include/pmix_globals.h"
#include "src/include/pmix_socket_errno.h"
#include "src/util/pmix_argv.h"
#include "src/util/pmix_error.h"
#include "src/util/pmix_output.h"
#include <unistd.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include "psquash_flex128.h"
#include "src/mca/psquash/base/base.h"
#define FLEX_BASE7_MAX_BUF_SIZE (SIZEOF_SIZE_T + 1)
#define FLEX_BASE7_MASK ((1 << 7) - 1)
#define FLEX_BASE7_SHIFT 7
#define FLEX_BASE7_CONT_FLAG (1 << 7)
#define FLEX128_PACK_CONVERT_SIGNED(type, ptr, out) \
do { \
type __tbuf = 0; \
size_t __tmp; \
int __sign = 0; \
memcpy(&__tbuf, (ptr), sizeof(type)); \
__tmp = __tbuf; \
(out) = (size_t) __tmp; \
if (__tmp & (1UL << (sizeof(__tmp) * CHAR_BIT - 1))) { \
__sign = 1; \
out = ~(out); \
} \
(out) = ((out) << 1) + __sign; \
} while (0)
#define FLEX128_PACK_CONVERT_UNSIGNED(type, ptr, out) \
do { \
type __tbuf = 0; \
memcpy(&__tbuf, (ptr), sizeof(type)); \
out = __tbuf; \
} while (0)
#define FLEX128_PACK_CONVERT(r, t, s, d) \
do { \
(r) = PMIX_SUCCESS; \
switch (t) { \
case PMIX_INT16: \
FLEX128_PACK_CONVERT_SIGNED(int16_t, s, d); \
break; \
case PMIX_UINT16: \
FLEX128_PACK_CONVERT_UNSIGNED(uint16_t, s, d); \
break; \
case PMIX_INT: \
case PMIX_INT32: \
FLEX128_PACK_CONVERT_SIGNED(int32_t, s, d); \
break; \
case PMIX_UINT: \
case PMIX_UINT32: \
FLEX128_PACK_CONVERT_UNSIGNED(uint32_t, s, d); \
break; \
case PMIX_INT64: \
FLEX128_PACK_CONVERT_SIGNED(int64_t, s, d); \
break; \
case PMIX_SIZE: \
FLEX128_PACK_CONVERT_UNSIGNED(size_t, s, d); \
break; \
case PMIX_UINT64: \
FLEX128_PACK_CONVERT_UNSIGNED(uint64_t, s, d); \
break; \
default: \
(r) = PMIX_ERR_BAD_PARAM; \
} \
} while (0)
#define FLEX128_UNPACK_CONVERT_SIGNED(type, val, ptr) \
do { \
type __tbuf = 0; \
size_t __tmp = val; \
int sign = (__tmp) &1; \
__tmp >>= 1; \
if (sign) { \
__tmp = ~__tmp; \
} \
__tbuf = (type) __tmp; \
memcpy(ptr, &__tbuf, sizeof(type)); \
} while (0)
#define FLEX128_UNPACK_CONVERT_UNSIGNED(type, val, ptr) \
do { \
type __tbuf = 0; \
__tbuf = (type) val; \
memcpy(ptr, &__tbuf, sizeof(type)); \
} while (0)
#define FLEX128_UNPACK_CONVERT(r, t, s, d) \
do { \
(r) = PMIX_SUCCESS; \
switch (t) { \
case PMIX_INT16: \
FLEX128_UNPACK_CONVERT_SIGNED(int16_t, s, d); \
break; \
case PMIX_UINT16: \
FLEX128_UNPACK_CONVERT_UNSIGNED(uint16_t, s, d); \
break; \
case PMIX_INT: \
case PMIX_INT32: \
FLEX128_UNPACK_CONVERT_SIGNED(int32_t, s, d); \
break; \
case PMIX_UINT: \
case PMIX_UINT32: \
FLEX128_UNPACK_CONVERT_UNSIGNED(uint32_t, s, d); \
break; \
case PMIX_INT64: \
FLEX128_UNPACK_CONVERT_SIGNED(int64_t, s, d); \
break; \
case PMIX_SIZE: \
FLEX128_UNPACK_CONVERT_UNSIGNED(size_t, s, d); \
break; \
case PMIX_UINT64: \
FLEX128_UNPACK_CONVERT_UNSIGNED(uint64_t, s, d); \
break; \
default: \
(r) = PMIX_ERR_BAD_PARAM; \
} \
} while (0)
static pmix_status_t flex128_init(void);
static void flex128_finalize(void);
static pmix_status_t flex128_get_max_size(pmix_data_type_t type, size_t *size);
static pmix_status_t flex128_encode_int(pmix_data_type_t type, void *src, void *dst, size_t *size);
static pmix_status_t flex128_decode_int(pmix_data_type_t type, void *src, size_t src_len,
void *dest, size_t *dst_size);
static size_t flex_pack_integer(size_t val, uint8_t out_buf[FLEX_BASE7_MAX_BUF_SIZE]);
static size_t flex_unpack_integer(const uint8_t in_buf[], size_t buf_size, size_t *out_val,
size_t *out_val_size);
pmix_psquash_base_module_t pmix_flex128_module = {.name = "flex128",
.int_type_is_encoded = true,
.init = flex128_init,
.finalize = flex128_finalize,
.get_max_size = flex128_get_max_size,
.encode_int = flex128_encode_int,
.decode_int = flex128_decode_int};
static pmix_status_t flex128_init(void)
{
pmix_output_verbose(2, pmix_globals.debug_output, "psquash: flex128 init");
return PMIX_SUCCESS;
}
static void flex128_finalize(void)
{
pmix_output_verbose(2, pmix_globals.debug_output, "psquash: flex128 finalize");
}
static pmix_status_t flex128_get_max_size(pmix_data_type_t type, size_t *size)
{
pmix_status_t rc;
PMIX_SQUASH_TYPE_SIZEOF(rc, type, *size);
*size += 1;
return rc;
}
static pmix_status_t flex128_encode_int(pmix_data_type_t type, void *src, void *dst, size_t *size)
{
pmix_status_t rc = PMIX_SUCCESS;
uint8_t tmp_buf[FLEX_BASE7_MAX_BUF_SIZE];
uint64_t tmp;
FLEX128_PACK_CONVERT(rc, type, (uint8_t *) src, tmp);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
return rc;
}
*size = flex_pack_integer(tmp, tmp_buf);
memcpy(dst, tmp_buf, *size);
return rc;
}
static pmix_status_t flex128_decode_int(pmix_data_type_t type, void *src, size_t src_len,
void *dest, size_t *dst_size)
{
pmix_status_t rc = PMIX_SUCCESS;
size_t tmp;
size_t val_size, unpack_val_size;
PMIX_SQUASH_TYPE_SIZEOF(rc, type, val_size);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
return rc;
}
*dst_size = flex_unpack_integer(src, src_len, &tmp, &unpack_val_size);
if (val_size < unpack_val_size) { rc = PMIX_ERR_UNPACK_FAILURE;
PMIX_ERROR_LOG(rc);
return rc;
}
FLEX128_UNPACK_CONVERT(rc, type, tmp, (uint8_t *) dest);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
return rc;
}
return rc;
}
static size_t flex_pack_integer(size_t val, uint8_t out_buf[FLEX_BASE7_MAX_BUF_SIZE])
{
size_t tmp = val;
size_t idx = 0;
do {
uint8_t encoding = tmp & FLEX_BASE7_MASK;
tmp >>= FLEX_BASE7_SHIFT;
if (PMIX_UNLIKELY(tmp)) {
encoding |= FLEX_BASE7_CONT_FLAG;
}
out_buf[idx++] = encoding;
} while (tmp && idx < SIZEOF_SIZE_T);
if (PMIX_UNLIKELY(SIZEOF_SIZE_T == idx && tmp)) {
out_buf[idx++] = tmp;
}
return idx;
}
static size_t flex_unpack_integer(const uint8_t in_buf[], size_t buf_size, size_t *out_val,
size_t *out_val_size)
{
size_t value = 0, shift = 0, shift_last = 0;
size_t idx = 0;
uint8_t val = 0, val_last = 0;
uint8_t hi_bit = 0;
size_t flex_size = buf_size;
if (buf_size > FLEX_BASE7_MAX_BUF_SIZE) {
flex_size = FLEX_BASE7_MAX_BUF_SIZE;
}
do {
val = in_buf[idx++];
val_last = val;
shift_last = shift;
value = value + (((uint64_t) val & FLEX_BASE7_MASK) << shift);
shift += FLEX_BASE7_SHIFT;
} while (PMIX_UNLIKELY((val & FLEX_BASE7_CONT_FLAG) && (idx < (flex_size - 1))));
if (PMIX_UNLIKELY((flex_size - 1) == idx && (val & FLEX_BASE7_CONT_FLAG))) {
val = in_buf[idx++];
val_last = val;
value = value + ((uint64_t) val << shift);
shift_last = shift;
}
while (val_last != 0) {
val_last >>= 1;
hi_bit++;
}
*out_val_size = (hi_bit + shift_last) / CHAR_BIT + !!((hi_bit + shift_last) & (CHAR_BIT - 1));
*out_val = value;
return idx;
}