#ifndef GENERIC_UNALIGNED_H
#define GENERIC_UNALIGNED_H

#define STRICT_ALIGNMENT 1

#if defined (PROCESSOR_TYPE) && \
        ((PROCESSOR_TYPE == PROC_TYPE_I386 || PROCESSOR_TYPE == PROC_TYPE_X64) || \
        (PROCESSOR_TYPE == PROC_TYPE_PPC64) || (PROCESSOR_TYPE == PROC_TYPE_PPC32))
        #undef STRICT_ALIGNMENT
#endif

#include "byteorder.h"

static __inline uint32_t
__bad_unaligned_access_size(void)
{
    return 0;
}

#define get_unaligned_le(ptr) (                                                 \
    ((sizeof(*(ptr)) == 1) ? (*(ptr)) :                                         \
    ((sizeof(*(ptr)) == 2) ? (get_unaligned_le16((void*)ptr)) :                 \
    ((sizeof(*(ptr)) == 4) ? (get_unaligned_le32((void*)ptr)) :                 \
    ((sizeof(*(ptr)) == 8) ? (get_unaligned_le64((void*)ptr)) :                 \
    __bad_unaligned_access_size())))));

#define get_unaligned_be(ptr) (                                         \
    ((sizeof(*(ptr)) == 1) ? (*(ptr)) :                                 \
    ((sizeof(*(ptr)) == 2) ? (get_unaligned_be16((void*)ptr)) :         \
    ((sizeof(*(ptr)) == 4) ? (get_unaligned_be32((void*)ptr)) :         \
    ((sizeof(*(ptr)) == 8) ? (get_unaligned_be64((void*)ptr)) :         \
    __bad_unaligned_access_size())))));

#define put_unaligned_le(ptr, val) {                                \
        switch (sizeof(*(ptr))) {                                   \
        case 1:                                                     \
            *(uint8_t*)(ptr) = (uint8_t)(val);                      \
            break;                                                  \
        case 2:                                                     \
            put_unaligned_le16((void*)(ptr), (uint16_t)(val));      \
            break;                                                  \
        case 4:                                                     \
            put_unaligned_le32((void*)(ptr), (uint32_t)(val));      \
            break;                                                  \
        case 8:                                                     \
            put_unaligned_le64((void*)(ptr), (uint64_t)(val));      \
            break;                                                  \
        default:                                                    \
            __bad_unaligned_access_size();                          \
            break;                                                  \
        }                                                           \
    }

#define put_unaligned_be(ptr, val) {                                \
        switch (sizeof(*(ptr))) {                                   \
        case 1:                                                     \
            *(uint8_t*)(ptr) = (uint8_t)(val);                      \
            break;                                                  \
        case 2:                                                     \
            put_unaligned_be16((void*)(ptr), (uint16_t)(val));      \
            break;                                                  \
        case 4:                                                     \
            put_unaligned_be32((void*)(ptr), (uint32_t)(val));      \
            break;                                                  \
        case 8:                                                     \
            put_unaligned_be64((void*)(ptr), (uint64_t)(val));      \
            break;                                                  \
        default:                                                    \
            __bad_unaligned_access_size();                          \
            break;                                                  \
        }                                                           \
    }

#if defined WORDS_BIGENDIAN
    #define put_unaligned put_unaligned_be
    #define get_unaligned get_unaligned_be
#else
    #define put_unaligned put_unaligned_le
    #define get_unaligned get_unaligned_le
#endif

#endif /* GENERIC_UNALIGNED_H */

