/*
 * This file is part of libdcadec.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef COMPILER_H
#define COMPILER_H

#ifdef __GNUC__

#define dca_bswap16(x)  __builtin_bswap16(x)
#define dca_bswap32(x)  __builtin_bswap32(x)
#define dca_bswap64(x)  __builtin_bswap64(x)
#define dca_clz32(x)    __builtin_clz(x)
#define dca_clz64(x)    __builtin_clzll(x)
#define dca_popcount(x) __builtin_popcount(x)

#elif (defined(_MSC_VER) && defined(WIN32))

#define __ORDER_LITTLE_ENDIAN__ 0x1234
#define __ORDER_BIG_ENDIAN__    0x4321
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__

#include <stdint.h>
#include <stdlib.h>
#pragma intrinsic(_byteswap_ulong, _byteswap_uint64, _byteswap_ushort)

extern "C" unsigned char _BitScanReverse (unsigned int *Index,unsigned int Mask);
extern "C" unsigned int __popcnt(unsigned int value);
#pragma intrinsic(_BitScanReverse,__popcnt)

#define dca_bswap16(x)  _byteswap_ushort((x))
#define dca_bswap32(x)  _byteswap_ulong((x))
#define dca_bswap64(x)  _byteswap_uint64((x))
#define dca_clz32(x)    (31-msvc_bsr32((x)))
#define dca_clz64(x)    (63-msvc_bsr64((x)))
#define dca_popcount(x) __popcnt((x))

static unsigned int inline __forceinline msvc_bsr32(uint32_t value)
{
    unsigned int r;
    _BitScanReverse(&r,value);
    return r;
}

#ifdef _WIN64
extern "C" unsigned char _BitScanReverse64 (unsigned int *Index,uint64_t Mask);
#pragma intrinsic(_BitScanReverse64)
static unsigned int inline __forceinline msvc_bsr64(uint64_t value)
{
    unsigned int r;
    _BitScanReverse64(&r,value);
    return r;
}
#else
static uint32_t inline __forceinline msvc_bsr64(uint64_t value)
{
    uint32_t top = (uint32_t)(value>>32);
    if (0==top)
    {
        return msvc_bsr32((uint32_t)value);
    } else {
        return 32+msvc_bsr32(top);
    }
}
#endif

#else
#error Unsupported compiler
#endif

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define DCA_16LE(x) ((uint16_t)(x))
#define DCA_32LE(x) ((uint32_t)(x))
#define DCA_64LE(x) ((uint64_t)(x))
#define DCA_16BE(x) dca_bswap16(x)
#define DCA_32BE(x) dca_bswap32(x)
#define DCA_64BE(x) dca_bswap64(x)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define DCA_16LE(x) dca_bswap16(x)
#define DCA_32LE(x) dca_bswap32(x)
#define DCA_64LE(x) dca_bswap64(x)
#define DCA_16BE(x) ((uint16_t)(x))
#define DCA_32BE(x) ((uint32_t)(x))
#define DCA_64BE(x) ((uint64_t)(x))
#else
#error Unsupported byte order
#endif


#endif
