/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the LICENSE file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef H5VMprivate_H
#define H5VMprivate_H

#include "H5private.h"   
#include "H5Eprivate.h"  
#include "H5MMprivate.h" 

typedef herr_t (*H5VM_opvv_func_t)(hsize_t dst_off, hsize_t src_off, size_t len, void *udata);

#define H5VM_vector_eq_s(N, V1, V2) (H5VM_vector_cmp_s(N, V1, V2) == 0)
#define H5VM_vector_lt_s(N, V1, V2) (H5VM_vector_cmp_s(N, V1, V2) < 0)
#define H5VM_vector_gt_s(N, V1, V2) (H5VM_vector_cmp_s(N, V1, V2) > 0)
#define H5VM_vector_le_s(N, V1, V2) (H5VM_vector_cmp_s(N, V1, V2) <= 0)
#define H5VM_vector_ge_s(N, V1, V2) (H5VM_vector_cmp_s(N, V1, V2) >= 0)
#define H5VM_vector_eq_u(N, V1, V2) (H5VM_vector_cmp_u(N, V1, V2) == 0)
#define H5VM_vector_lt_u(N, V1, V2) (H5VM_vector_cmp_u(N, V1, V2) < 0)
#define H5VM_vector_gt_u(N, V1, V2) (H5VM_vector_cmp_u(N, V1, V2) > 0)
#define H5VM_vector_le_u(N, V1, V2) (H5VM_vector_cmp_u(N, V1, V2) <= 0)
#define H5VM_vector_ge_u(N, V1, V2) (H5VM_vector_cmp_u(N, V1, V2) >= 0)

#define H5VM_vector_cpy(N, DST, SRC)                                                                         \
    do {                                                                                                     \
        assert(sizeof(*(DST)) == sizeof(*(SRC)));                                                            \
        if (SRC)                                                                                             \
            H5MM_memcpy(DST, SRC, (N) * sizeof(*(DST)));                                                     \
        else                                                                                                 \
            memset(DST, 0, (N) * sizeof(*(DST)));                                                            \
    } while (0)

#define H5VM_vector_zero(N, DST) memset(DST, 0, (N) * sizeof(*(DST)))

#define H5VM_swizzle_coords(TYPE, COORDS, UNLIM_DIM)                                                         \
    do {                                                                                                     \
                                                                   \
        assert(sizeof(COORDS[0]) == sizeof(TYPE));                                                           \
                                                                                                             \
                                                \
        if (0 != (UNLIM_DIM)) {                                                                              \
            TYPE _tmp = (COORDS)[UNLIM_DIM];                                                                 \
                                                                                                             \
            memmove(&(COORDS)[1], &(COORDS)[0], sizeof(TYPE) * (UNLIM_DIM));                                 \
            (COORDS)[0] = _tmp;                                                                              \
        }                                                                                        \
    } while (0)

#define H5VM_unswizzle_coords(TYPE, COORDS, UNLIM_DIM)                                                       \
    do {                                                                                                     \
                                                                   \
        assert(sizeof(COORDS[0]) == sizeof(TYPE));                                                           \
                                                                                                             \
                                                \
        if (0 != (UNLIM_DIM)) {                                                                              \
            TYPE _tmp = (COORDS)[0];                                                                         \
                                                                                                             \
            memmove(&(COORDS)[0], &(COORDS)[1], sizeof(TYPE) * (UNLIM_DIM));                                 \
            (COORDS)[UNLIM_DIM] = _tmp;                                                                      \
        }                                                                                        \
    } while (0)

#define H5VM_ZERO NULL

H5_DLL hsize_t H5VM_hyper_stride(unsigned n, const hsize_t *size, const hsize_t *total_size,
                                 const hsize_t *offset, hsize_t *stride);
H5_DLL htri_t  H5VM_hyper_eq(unsigned n, const hsize_t *offset1, const hsize_t *size1, const hsize_t *offset2,
                             const hsize_t *size2);
H5_DLL herr_t  H5VM_hyper_fill(unsigned n, const hsize_t *_size, const hsize_t *total_size,
                               const hsize_t *offset, void *_dst, unsigned fill_value);
H5_DLL herr_t  H5VM_hyper_copy(unsigned n, const hsize_t *size, const hsize_t *dst_total_size,
                               const hsize_t *dst_offset, void *_dst, const hsize_t *src_total_size,
                               const hsize_t *src_offset, const void *_src);
H5_DLL herr_t  H5VM_stride_fill(unsigned n, hsize_t elmt_size, const hsize_t *size, const hsize_t *stride,
                                void *_dst, unsigned fill_value);
H5_DLL herr_t H5VM_stride_copy(unsigned n, hsize_t elmt_size, const hsize_t *_size, const hsize_t *dst_stride,
                               void *_dst, const hsize_t *src_stride, const void *_src);
H5_DLL herr_t H5VM_stride_copy_s(unsigned n, hsize_t elmt_size, const hsize_t *_size,
                                 const hssize_t *dst_stride, void *_dst, const hssize_t *src_stride,
                                 const void *_src);
H5_DLL herr_t H5VM_array_fill(void *_dst, const void *src, size_t size, size_t count);
H5_DLL void   H5VM_array_down(unsigned n, const hsize_t *total_size, hsize_t *down);
H5_DLL hsize_t H5VM_array_offset_pre(unsigned n, const hsize_t *acc, const hsize_t *offset);
H5_DLL hsize_t H5VM_array_offset(unsigned n, const hsize_t *total_size, const hsize_t *offset);
H5_DLL herr_t  H5VM_array_calc_pre(hsize_t offset, unsigned n, const hsize_t *down, hsize_t *coords);
H5_DLL herr_t  H5VM_array_calc(hsize_t offset, unsigned n, const hsize_t *total_size, hsize_t *coords);
H5_DLL hsize_t H5VM_chunk_index(unsigned ndims, const hsize_t *coord, const hsize_t *chunk,
                                const hsize_t *down_nchunks);
H5_DLL void    H5VM_chunk_scaled(unsigned ndims, const hsize_t *coord, const hsize_t *chunk, hsize_t *scaled);
H5_DLL hsize_t H5VM_chunk_index_scaled(unsigned ndims, const hsize_t *coord, const hsize_t *chunk,
                                       const hsize_t *down_nchunks, hsize_t *scaled);
H5_DLL ssize_t H5VM_opvv(size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[],
                         hsize_t dst_off_arr[], size_t src_max_nseq, size_t *src_curr_seq,
                         size_t src_len_arr[], hsize_t src_off_arr[], H5VM_opvv_func_t op, void *op_data);
H5_DLL ssize_t H5VM_memcpyvv(void *_dst, size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[],
                             hsize_t dst_off_arr[], const void *_src, size_t src_max_nseq,
                             size_t *src_curr_seq, size_t src_len_arr[], hsize_t src_off_arr[]);

static inline hsize_t H5_ATTR_UNUSED
H5VM_vector_reduce_product(unsigned n, const hsize_t *v)
{
    hsize_t ret_value = 1;

    
    FUNC_ENTER_NOAPI_NOINIT_NOERR

    if (n && !v)
        HGOTO_DONE(0);
    while (n--)
        ret_value *= *v++;

done:
    FUNC_LEAVE_NOAPI(ret_value)
}

static inline htri_t H5_ATTR_UNUSED
H5VM_vector_zerop_u(int n, const hsize_t *v)
{
    htri_t ret_value = true; 

    
    FUNC_ENTER_NOAPI_NOINIT_NOERR

    if (!v)
        HGOTO_DONE(true);
    while (n--)
        if (*v++)
            HGOTO_DONE(false);

done:
    FUNC_LEAVE_NOAPI(ret_value)
}

static inline htri_t H5_ATTR_UNUSED
H5VM_vector_zerop_s(int n, const hssize_t *v)
{
    htri_t ret_value = true; 

    
    FUNC_ENTER_NOAPI_NOINIT_NOERR

    if (!v)
        HGOTO_DONE(true);
    while (n--)
        if (*v++)
            HGOTO_DONE(false);

done:
    FUNC_LEAVE_NOAPI(ret_value)
}

static inline int H5_ATTR_UNUSED
H5VM_vector_cmp_u(unsigned n, const hsize_t *v1, const hsize_t *v2)
{
    int ret_value = 0; 

    
    FUNC_ENTER_NOAPI_NOINIT_NOERR

    if (v1 == v2)
        HGOTO_DONE(0);
    if (v1 == NULL)
        HGOTO_DONE(-1);
    if (v2 == NULL)
        HGOTO_DONE(1);
    while (n--) {
        if (*v1 < *v2)
            HGOTO_DONE(-1);
        if (*v1 > *v2)
            HGOTO_DONE(1);
        v1++;
        v2++;
    }

done:
    FUNC_LEAVE_NOAPI(ret_value)
}

static inline int H5_ATTR_UNUSED
H5VM_vector_cmp_s(unsigned n, const hssize_t *v1, const hssize_t *v2)
{
    int ret_value = 0; 

    
    FUNC_ENTER_NOAPI_NOINIT_NOERR

    if (v1 == v2)
        HGOTO_DONE(0);
    if (v1 == NULL)
        HGOTO_DONE(-1);
    if (v2 == NULL)
        HGOTO_DONE(1);
    while (n--) {
        if (*v1 < *v2)
            HGOTO_DONE(-1);
        if (*v1 > *v2)
            HGOTO_DONE(1);
        v1++;
        v2++;
    }

done:
    FUNC_LEAVE_NOAPI(ret_value)
}

static inline void H5_ATTR_UNUSED
H5VM_vector_inc(int n, hsize_t *v1, const hsize_t *v2)
{
    while (n--)
        *v1++ += *v2++;
}

static const unsigned char LogTable256[] = {
    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};

static inline unsigned H5_ATTR_UNUSED
H5VM_log2_gen(uint64_t n)
{
    unsigned     r;          
    unsigned int t, tt, ttt; 

    if ((ttt = (unsigned)(n >> 32)))
        if ((tt = (unsigned)(n >> 48)))
            r = (t = (unsigned)(n >> 56)) ? 56 + (unsigned)LogTable256[t]
                                          : 48 + (unsigned)LogTable256[tt & 0xFF];
        else
            r = (t = (unsigned)(n >> 40)) ? 40 + (unsigned)LogTable256[t]
                                          : 32 + (unsigned)LogTable256[ttt & 0xFF];
    else if ((tt = (unsigned)(n >> 16)))
        r = (t = (unsigned)(n >> 24)) ? 24 + (unsigned)LogTable256[t] : 16 + (unsigned)LogTable256[tt & 0xFF];
    else
        
        r = (t = (unsigned)(n >> 8)) ? 8 + (unsigned)LogTable256[t] : (unsigned)LogTable256[(uint8_t)n];

    return (r);
} 

static const unsigned MultiplyDeBruijnBitPosition[32] = {0,  1,  28, 2,  29, 14, 24, 3,  30, 22, 20,
                                                         15, 25, 17, 4,  8,  31, 27, 13, 23, 21, 19,
                                                         16, 7,  26, 12, 18, 6,  11, 5,  10, 9};

static inline H5_ATTR_PURE unsigned
H5VM_log2_of2(uint32_t n)
{
#ifndef NDEBUG
    assert(POWER_OF_TWO(n));
#endif 
    return (MultiplyDeBruijnBitPosition[(n * (uint32_t)0x077CB531UL) >> 27]);
} 

static inline H5_ATTR_CONST hsize_t
H5VM_power2up(hsize_t n)
{
    hsize_t ret_value = 1; 

    
    if (n >= (hsize_t)1 << ((sizeof(hsize_t) * CHAR_BIT) - 1))
        ret_value = 0;

    while (ret_value && ret_value < n)
        ret_value <<= 1;

    return (ret_value);
} 

static inline unsigned H5_ATTR_UNUSED
H5VM_limit_enc_size(uint64_t limit)
{
    return (H5VM_log2_gen(limit) / 8) + 1;
} 

static const unsigned char H5VM_bit_set_g[8]   = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
static const unsigned char H5VM_bit_clear_g[8] = {0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE};

static inline bool H5_ATTR_UNUSED
H5VM_bit_get(const unsigned char *buf, size_t offset)
{
    
    return (bool)((buf[offset / 8] & (H5VM_bit_set_g[offset % 8])) ? true : false);
} 

static inline void H5_ATTR_UNUSED
H5VM_bit_set(unsigned char *buf, size_t offset, bool val)
{
    
    if (val)
        buf[offset / 8] |= H5VM_bit_set_g[offset % 8];
    else
        buf[offset / 8] &= H5VM_bit_clear_g[offset % 8];
} 

#endif 
