#ifndef BYTEORDER_H
#define BYTEORDER_H

#define swapb16(a, b) {\
        uint8_t t = ((uint8_t *)b)[0]; \
        ((uint8_t *)a)[0] = ((uint8_t *)b)[1]; \
        ((uint8_t *)a)[1] = t; \
    }

#define swapb32(a, b) {\
        uint8_t t = ((uint8_t *)b)[0]; \
        ((uint8_t *)a)[0] = ((uint8_t *)b)[3]; \
        ((uint8_t *)a)[3] = t; \
        t = ((uint8_t *)b)[2]; \
        ((uint8_t *)a)[2] = ((uint8_t *)b)[1]; \
        ((uint8_t *)a)[1] = t; \
    }

#define swapb64(a, b) { \
        uint8_t t = ((uint8_t *)b)[0]; \
        ((uint8_t *)a)[0] = ((uint8_t *)b)[7]; \
        ((uint8_t *)a)[7] = t; \
        t = ((uint8_t *)b)[6]; \
        ((uint8_t *)a)[6] = ((uint8_t *)b)[1]; \
        ((uint8_t *)a)[1] = t; \
        t = ((uint8_t *)b)[5]; \
        ((uint8_t *)a)[5] = ((uint8_t *)b)[2]; \
        ((uint8_t *)a)[2] = t; \
        t = ((uint8_t *)b)[4]; \
        ((uint8_t *)a)[4] = ((uint8_t *)b)[3]; \
        ((uint8_t *)a)[3] = t; \
    }

/* LE - 16 */

static __inline
void le_host_16_reorder(void * dest, const void * src)
{
#if defined (WORDS_BIGENDIAN)
    swapb16(dest, src);
#elif defined STRICT_ALILGNMENT
    memmove(dest, src, sizeof(uint16_t));
#else
    *((uint16_t*)dest) = *((uint16_t*)src);
#endif
}

static __inline ATTR_USERES
uint16_t get_unaligned_le16(const void * ptr)
{
    uint16_t tmp;
    le_host_16_reorder(&tmp, ptr);
    return tmp;
}

static __inline
void put_unaligned_le16(void * dest, uint16_t src)
{
    le_host_16_reorder(dest, (void*)&src);
}

/* LE - 32 */

static __inline
void le_host_32_reorder(void * dest, const void * src)
{
#if defined (WORDS_BIGENDIAN)
    swapb32(dest, src);
#elif defined STRICT_ALILGNMENT
    memmove(dest, src, sizeof(uint32_t));
#else
    *((uint32_t*)dest) = *((uint32_t*)src);
#endif
}

static __inline ATTR_USERES
uint32_t get_unaligned_le32(const void * ptr)
{
    uint32_t tmp;
    le_host_32_reorder(&tmp, ptr);
    return tmp;
}

static __inline
void put_unaligned_le32(void * dest, uint32_t src)
{
    le_host_32_reorder(dest, (void*)&src);
}


/* LE - 64 */

static __inline
void le_host_64_reorder(void * dest, const void * src)
{
#if defined (WORDS_BIGENDIAN)
    swapb64(dest, src);
#elif defined STRICT_ALILGNMENT
    memmove(dest, src, sizeof(uint64_t));
#else
    *((uint64_t*)dest) = *((uint64_t*)src);
#endif
}

static __inline ATTR_USERES
uint64_t get_unaligned_le64(const void * ptr)
{
    uint64_t tmp;
    le_host_64_reorder(&tmp, ptr);
    return tmp;
}

static __inline
void put_unaligned_le64(void * dest, uint64_t src)
{
    le_host_64_reorder(dest, (void*)&src);
}


/* BE - 16 */

static __inline
void be_host_16_reorder(void * dest, const void * src)
{
#if !defined (WORDS_BIGENDIAN)
    swapb16(dest, src);
#elif defined STRICT_ALILGNMENT
    memmove(dest, src, sizeof(uint16_t));
#else
    *((uint16_t*)dest) = *((uint16_t*)src);
#endif
}

static __inline ATTR_USERES
uint16_t get_unaligned_be16(const void * ptr)
{
    uint16_t tmp;
    be_host_16_reorder(&tmp, ptr);
    return tmp;
}

static __inline
void put_unaligned_be16(void * dest, uint16_t src)
{
    be_host_16_reorder(dest, (void*)&src);
}

/* BE - 32 */

static __inline
void be_host_32_reorder(void * dest, const void * src)
{
#if !defined (WORDS_BIGENDIAN)
    swapb32(dest, src);
#elif defined STRICT_ALILGNMENT
    memmove(dest, src, sizeof(uint32_t));
#else
    *((uint32_t*)dest) = *((uint32_t*)src);
#endif
}

static __inline ATTR_USERES
uint32_t get_unaligned_be32(const void * ptr)
{
    uint32_t tmp;
    be_host_32_reorder(&tmp, ptr);
    return tmp;
}

static __inline
void put_unaligned_be32(void * dest, uint32_t src)
{
    be_host_32_reorder(dest, (void*)&src);
}


/* BE - 64 */

static __inline
void be_host_64_reorder(void * dest, const void * src)
{
#if !defined (WORDS_BIGENDIAN)
    swapb64(dest, src);
#elif defined STRICT_ALILGNMENT
    memmove(dest, src, sizeof(uint64_t));
#else
    *((uint64_t*)dest) = *((uint64_t*)src);
#endif
}

static __inline ATTR_USERES
uint64_t get_unaligned_be64(const void * ptr)
{
    uint64_t tmp;
    be_host_64_reorder(&tmp, ptr);
    return tmp;
}

static __inline
void put_unaligned_be64(void * dest, uint64_t src)
{
    be_host_64_reorder(dest, (void*)&src);
}

#endif // BYTEORDER_H
