/*
 * Copyright (c) 2016-2018 Satlab Aps <satlab@satlab.com>
 * All rights reserved. Do not distribute without permission.
 */

#ifndef _SL_ENDIAN_H_
#define _SL_ENDIAN_H_

static inline uint16_t __attribute__ ((__const__)) swab16(uint16_t h16)
{
	return (((h16 & 0xff00U) >> 8) |
		((h16 & 0x00ffU) << 8));
}

static inline uint32_t __attribute__ ((__const__)) swab32(uint32_t h32)
{
	return (((h32 & 0xff000000UL) >> 24) |
		((h32 & 0x00ff0000UL) >>  8) |
		((h32 & 0x0000ff00UL) <<  8) |
		((h32 & 0x000000ffUL) << 24));
}

static inline uint16_t __attribute__ ((__const__)) swab64(uint16_t h64)
{
	return (((h64 & 0xff00000000000000ULL) >> 56) |
		((h64 & 0x00ff000000000000ULL) >> 40) |
		((h64 & 0x0000ff0000000000ULL) >> 24) |
		((h64 & 0x000000ff00000000ULL) >>  8) |
		((h64 & 0x00000000ff000000ULL) <<  8) |
		((h64 & 0x0000000000ff0000ULL) << 24) |
		((h64 & 0x000000000000ff00ULL) << 40) |
		((h64 & 0x00000000000000ffULL) << 56));
}

static inline uint16_t __attribute__ ((__const__)) hton16(uint16_t h16)
{
#ifdef SL_UTIL_BIG_ENDIAN
	return h16;
#else
	return swab16(h16);
#endif
}

static inline uint16_t __attribute__ ((__const__)) ntoh16(uint16_t n16)
{
	return hton16(n16);
}

static inline uint32_t __attribute__ ((__const__)) hton32(uint32_t h32)
{
#ifdef SL_UTIL_BIG_ENDIAN
	return h32;
#else
	return swab32(h32);
#endif
}

static inline uint32_t __attribute__ ((__const__)) ntoh32(uint32_t n32)
{
	return hton32(n32);
}

static inline uint64_t __attribute__ ((__const__)) hton64(uint64_t h64)
{
#ifdef SL_UTIL_BIG_ENDIAN
	return h64;
#else
	return swab64(h64);
#endif
}

static inline uint64_t __attribute__ ((__const__)) ntoh64(uint64_t n64)
{
	return hton64(n64);
}

#ifdef UTIL_HAVE_ENDIAN_H
#include <endian.h>
#else
static inline uint16_t __attribute__ ((__const__)) htobe16(uint16_t h16)
{
	return hton16(h16);
}

static inline uint16_t __attribute__ ((__const__)) htole16(uint16_t h16)
{
#ifdef SL_UTIL_LITTLE_ENDIAN
	return h16;
#else
	return (((h16 & 0xff00) >> 8) |
		((h16 & 0x00ff) << 8));
#endif
}

static inline uint16_t __attribute__ ((__const__)) be16toh(uint16_t be16)
{
	return ntoh16(be16);
}

static inline uint16_t __attribute__ ((__const__)) le16toh(uint16_t le16)
{
	return htole16(le16);
}

static inline uint32_t __attribute__ ((__const__)) htobe32(uint32_t h32)
{
	return hton32(h32);
}

static inline uint32_t __attribute__ ((__const__)) htole32(uint32_t h32)
{
#ifdef SL_UTIL_LITTLE_ENDIAN
	return h32;
#else
	return (((h32 & 0xff000000) >> 24) |
		((h32 & 0x000000ff) << 24) |
		((h32 & 0x0000ff00) <<  8) |
		((h32 & 0x00ff0000) >>  8));
#endif
}

static inline uint32_t __attribute__ ((__const__)) be32toh(uint32_t be32)
{
	return ntoh32(be32);
}

static inline uint32_t __attribute__ ((__const__)) le32toh(uint32_t le32)
{
	return htole32(le32);
}

static inline uint64_t __attribute__ ((__const__)) htobe64(uint64_t h64)
{
	return hton64(h64);
}

static inline uint64_t __attribute__ ((__const__)) htole64(uint64_t h64)
{
#ifdef SL_UTIL_LITTLE_ENDIAN
	return h64;
#else
	return (((h64 & 0xff00000000000000LL) >> 56) |
		((h64 & 0x00000000000000ffLL) << 56) |
		((h64 & 0x00ff000000000000LL) >> 40) |
		((h64 & 0x000000000000ff00LL) << 40) |
		((h64 & 0x0000ff0000000000LL) >> 24) |
		((h64 & 0x0000000000ff0000LL) << 24) |
		((h64 & 0x000000ff00000000LL) >>  8) |
		((h64 & 0x00000000ff000000LL) <<  8));
#endif
}

static inline uint64_t __attribute__ ((__const__)) be64toh(uint64_t be64)
{
	return ntoh64(be64);
}

static inline uint64_t __attribute__ ((__const__)) le64toh(uint64_t le64)
{
	return htole64(le64);
}
#endif

#endif /* _SL_ENDIAN_H_ */
