/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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 H5encode_H
#define H5encode_H

#include "H5MMprivate.h" 

#define INT16ENCODE(p, i)                                                                                    \
    do {                                                                                                     \
        *(p) = (uint8_t)((unsigned)(i) & 0xff);                                                              \
        (p)++;                                                                                               \
        *(p) = (uint8_t)(((unsigned)(i) >> 8) & 0xff);                                                       \
        (p)++;                                                                                               \
    } while (0)

#define UINT16ENCODE(p, i)                                                                                   \
    do {                                                                                                     \
        *(p) = (uint8_t)((unsigned)(i) & 0xff);                                                              \
        (p)++;                                                                                               \
        *(p) = (uint8_t)(((unsigned)(i) >> 8) & 0xff);                                                       \
        (p)++;                                                                                               \
    } while (0)

#define INT32ENCODE(p, i)                                                                                    \
    do {                                                                                                     \
        *(p) = (uint8_t)((uint32_t)(i) & 0xff);                                                              \
        (p)++;                                                                                               \
        *(p) = (uint8_t)(((uint32_t)(i) >> 8) & 0xff);                                                       \
        (p)++;                                                                                               \
        *(p) = (uint8_t)(((uint32_t)(i) >> 16) & 0xff);                                                      \
        (p)++;                                                                                               \
        *(p) = (uint8_t)(((uint32_t)(i) >> 24) & 0xff);                                                      \
        (p)++;                                                                                               \
    } while (0)

#define UINT32ENCODE(p, i)                                                                                   \
    do {                                                                                                     \
        *(p) = (uint8_t)((i) & 0xff);                                                                        \
        (p)++;                                                                                               \
        *(p) = (uint8_t)(((i) >> 8) & 0xff);                                                                 \
        (p)++;                                                                                               \
        *(p) = (uint8_t)(((i) >> 16) & 0xff);                                                                \
        (p)++;                                                                                               \
        *(p) = (uint8_t)(((i) >> 24) & 0xff);                                                                \
        (p)++;                                                                                               \
    } while (0)

#define ENCODE_VAR(p, typ, n, l)                                                                             \
    do {                                                                                                     \
        typ      _n = (n);                                                                                   \
        size_t   _i;                                                                                         \
        uint8_t *_p = (uint8_t *)(p);                                                                        \
                                                                                                             \
        for (_i = 0; _i < l; _i++, _n >>= 8)                                                                 \
            *_p++ = (uint8_t)(_n & 0xff);                                                                    \
        (p) = (uint8_t *)(p) + l;                                                                            \
    } while (0)

#define UINT32ENCODE_VAR(p, n, l) ENCODE_VAR(p, uint32_t, n, l)

#define INT64ENCODE(p, n)                                                                                    \
    do {                                                                                                     \
        int64_t  _n = (n);                                                                                   \
        size_t   _i;                                                                                         \
        uint8_t *_p = (uint8_t *)(p);                                                                        \
                                                                                                             \
        for (_i = 0; _i < sizeof(int64_t); _i++, _n >>= 8)                                                   \
            *_p++ = (uint8_t)(_n & 0xff);                                                                    \
        for (; _i < 8; _i++)                                                                         \
            *_p++ = (uint8_t)((n) < 0 ? 0xff : 0);                                                           \
        (p) = (uint8_t *)(p) + 8;                                                                            \
    } while (0)

#define UINT64ENCODE(p, n)                                                                                   \
    do {                                                                                                     \
        uint64_t _n = (n);                                                                                   \
        size_t   _i;                                                                                         \
        uint8_t *_p = (uint8_t *)(p);                                                                        \
                                                                                                             \
        for (_i = 0; _i < sizeof(uint64_t); _i++, _n >>= 8)                                                  \
            *_p++ = (uint8_t)(_n & 0xff);                                                                    \
        for (; _i < 8; _i++)                                                                         \
            *_p++ = 0;                                                                                       \
        (p) = (uint8_t *)(p) + 8;                                                                            \
    } while (0)

#define UINT64ENCODE_VAR(p, n, l) ENCODE_VAR(p, uint64_t, n, l)

#define H5_ENCODE_UNSIGNED(p, n)                                                                             \
    do {                                                                                                     \
        HDcompile_assert(sizeof(unsigned) == sizeof(uint32_t));                                              \
        UINT32ENCODE(p, n);                                                                                  \
    } while (0)

#define H5_ENCODE_DOUBLE(p, n)                                                                               \
    do {                                                                                                     \
        uint64_t _n;                                                                                         \
        size_t   _u;                                                                                         \
        uint8_t *_p = (uint8_t *)(p);                                                                        \
                                                                                                             \
        HDcompile_assert(sizeof(double) == 8);                                                               \
        HDcompile_assert(sizeof(double) == sizeof(uint64_t));                                                \
        H5MM_memcpy(&_n, &n, sizeof(double));                                                                \
        for (_u = 0; _u < sizeof(uint64_t); _u++, _n >>= 8)                                                  \
            *_p++ = (uint8_t)(_n & 0xff);                                                                    \
        (p) = (uint8_t *)(p) + 8;                                                                            \
    } while (0)

#define INT16DECODE(p, i)                                                                                    \
    do {                                                                                                     \
        (i) = (int16_t)((*(p) & 0xff));                                                                      \
        (p)++;                                                                                               \
        (i) |= (int16_t)(((*(p) & 0xff) << 8) | ((*(p) & 0x80) ? ~0xffff : 0x0));                            \
        (p)++;                                                                                               \
    } while (0)

#define UINT16DECODE(p, i)                                                                                   \
    do {                                                                                                     \
        (i) = (uint16_t)(*(p) & 0xff);                                                                       \
        (p)++;                                                                                               \
        (i) |= (uint16_t)((*(p) & 0xff) << 8);                                                               \
        (p)++;                                                                                               \
    } while (0)

#define INT32DECODE(p, i)                                                                                    \
    do {                                                                                                     \
        (i) = ((int32_t)(*(p) & 0xff));                                                                      \
        (p)++;                                                                                               \
        (i) |= ((int32_t)(*(p) & 0xff) << 8);                                                                \
        (p)++;                                                                                               \
        (i) |= ((int32_t)(*(p) & 0xff) << 16);                                                               \
        (p)++;                                                                                               \
        (i) |= ((int32_t)(((*(p) & (unsigned)0xff) << 24) | ((*(p) & 0x80) ? ~0xffffffffULL : 0x0ULL)));     \
        (p)++;                                                                                               \
    } while (0)

#define UINT32DECODE(p, i)                                                                                   \
    do {                                                                                                     \
        (i) = (uint32_t)(*(p) & 0xff);                                                                       \
        (p)++;                                                                                               \
        (i) |= ((uint32_t)(*(p) & 0xff) << 8);                                                               \
        (p)++;                                                                                               \
        (i) |= ((uint32_t)(*(p) & 0xff) << 16);                                                              \
        (p)++;                                                                                               \
        (i) |= ((uint32_t)(*(p) & 0xff) << 24);                                                              \
        (p)++;                                                                                               \
    } while (0)

#define DECODE_VAR(p, n, l)                                                                                  \
    do {                                                                                                     \
        size_t _i;                                                                                           \
                                                                                                             \
        n = 0;                                                                                               \
        (p) += l;                                                                                            \
        for (_i = 0; _i < l; _i++)                                                                           \
            n = (n << 8) | *(--p);                                                                           \
        (p) += l;                                                                                            \
    } while (0)

#define UINT32DECODE_VAR(p, n, l) DECODE_VAR(p, n, l)

#define INT64DECODE(p, n)                                                                                    \
    do {                                                                                                     \
                                                                           \
        size_t _i;                                                                                           \
                                                                                                             \
        n = 0;                                                                                               \
        (p) += 8;                                                                                            \
        for (_i = 0; _i < sizeof(int64_t); _i++)                                                             \
            n = (int64_t)(((uint64_t)n << 8) | *(--p));                                                      \
        (p) += 8;                                                                                            \
    } while (0)

#define UINT64DECODE(p, n)                                                                                   \
    do {                                                                                                     \
                                                                           \
        size_t _i;                                                                                           \
                                                                                                             \
        n = 0;                                                                                               \
        (p) += 8;                                                                                            \
        for (_i = 0; _i < sizeof(uint64_t); _i++)                                                            \
            n = (uint64_t)(((uint64_t)n << 8) | *(--p));                                                     \
        (p) += 8;                                                                                            \
    } while (0)

#define UINT64DECODE_VAR(p, n, l) DECODE_VAR(p, n, l)

#define H5_DECODE_UNSIGNED(p, n)                                                                             \
    do {                                                                                                     \
        HDcompile_assert(sizeof(unsigned) == sizeof(uint32_t));                                              \
        UINT32DECODE(p, n);                                                                                  \
    } while (0)

#define H5_DECODE_DOUBLE(p, n)                                                                               \
    do {                                                                                                     \
        uint64_t _n;                                                                                         \
        size_t   _u;                                                                                         \
                                                                                                             \
        HDcompile_assert(sizeof(double) == 8);                                                               \
        HDcompile_assert(sizeof(double) == sizeof(uint64_t));                                                \
        _n = 0;                                                                                              \
        (p) += 8;                                                                                            \
        for (_u = 0; _u < sizeof(uint64_t); _u++)                                                            \
            _n = (_n << 8) | *(--p);                                                                         \
        H5MM_memcpy(&(n), &_n, sizeof(double));                                                              \
        (p) += 8;                                                                                            \
    } while (0)

#define H5_ENCODE_LENGTH_LEN(p, l, s)                                                                        \
    do {                                                                                                     \
        switch (s) {                                                                                         \
            case 4:                                                                                          \
                UINT32ENCODE(p, l);                                                                          \
                break;                                                                                       \
            case 8:                                                                                          \
                UINT64ENCODE(p, l);                                                                          \
                break;                                                                                       \
            case 2:                                                                                          \
                UINT16ENCODE(p, l);                                                                          \
                break;                                                                                       \
            default:                                                                                         \
                assert("bad sizeof size" && 0);                                                              \
        }                                                                                                    \
    } while (0)

#define H5_DECODE_LENGTH_LEN(p, l, s)                                                                        \
    do {                                                                                                     \
        switch (s) {                                                                                         \
            case 4:                                                                                          \
                UINT32DECODE(p, l);                                                                          \
                break;                                                                                       \
            case 8:                                                                                          \
                UINT64DECODE(p, l);                                                                          \
                break;                                                                                       \
            case 2:                                                                                          \
                UINT16DECODE(p, l);                                                                          \
                break;                                                                                       \
            default:                                                                                         \
                assert("bad sizeof size" && 0);                                                              \
        }                                                                                                    \
    } while (0)

#endif 
