1
0
forked from 0ad/0ad
0ad/source/lib/byte_order.cpp
janwas c0ed950657 had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).

it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.

after several hours, the code now requires fewer casts and less
guesswork.

other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.

This was SVN commit r5942.
2008-05-11 18:48:32 +00:00

220 lines
3.3 KiB
C++

/**
* =========================================================================
* File : byte_order.cpp
* Project : 0 A.D.
* Description : byte order (endianness) support routines.
* =========================================================================
*/
// license: GPL; see lib/license.txt
#include "precompiled.h"
#include "byte_order.h"
#include "bits.h"
#ifndef swap16
u16 swap16(const u16 x)
{
return (u16)(((x & 0xff) << 8) | (x >> 8));
}
u32 swap32(const u32 x)
{
return (x << 24) |
(x >> 24) |
((x << 8) & 0x00ff0000) |
((x >> 8) & 0x0000ff00);
}
u64 swap64(const u64 x)
{
const u32 lo = (u32)(x & 0xFFFFFFFF);
const u32 hi = (u32)(x >> 32);
u64 ret = swap32(lo);
ret <<= 32;
// careful: must shift var of type u64, not u32
ret |= swap32(hi);
return ret;
}
#endif // #ifndef swap16
//-----------------------------------------------------------------------------
u16 to_le16(u16 x)
{
#if BYTE_ORDER == BIG_ENDIAN
return swap16(x);
#else
return x;
#endif
}
u32 to_le32(u32 x)
{
#if BYTE_ORDER == BIG_ENDIAN
return swap32(x);
#else
return x;
#endif
}
u64 to_le64(u64 x)
{
#if BYTE_ORDER == BIG_ENDIAN
return swap64(x);
#else
return x;
#endif
}
u16 to_be16(u16 x)
{
#if BYTE_ORDER == BIG_ENDIAN
return x;
#else
return swap16(x);
#endif
}
u32 to_be32(u32 x)
{
#if BYTE_ORDER == BIG_ENDIAN
return x;
#else
return swap32(x);
#endif
}
u64 to_be64(u64 x)
{
#if BYTE_ORDER == BIG_ENDIAN
return x;
#else
return swap64(x);
#endif
}
u16 read_le16(const void* p)
{
return to_le16(*(u16*)p);
}
u32 read_le32(const void* p)
{
return to_le32(*(u32*)p);
}
u64 read_le64(const void* p)
{
return to_le64(*(u64*)p);
}
u16 read_be16(const void* p)
{
return to_be16(*(u16*)p);
}
u32 read_be32(const void* p)
{
return to_be32(*(u32*)p);
}
u64 read_be64(const void* p)
{
return to_be64(*(u64*)p);
}
void write_le16(void* p, u16 x)
{
*(u16*)p = to_le16(x);
}
void write_le32(void* p, u32 x)
{
*(u32*)p = to_le32(x);
}
void write_le64(void* p, u64 x)
{
*(u64*)p = to_le64(x);
}
void write_be16(void* p, u16 x)
{
*(u16*)p = to_be16(x);
}
void write_be32(void* p, u32 x)
{
*(u32*)p = to_be32(x);
}
void write_be64(void* p, u64 x)
{
*(u64*)p = to_be64(x);
}
u64 movzx_le64(const u8* p, size_t size_bytes)
{
u64 number = 0;
for(size_t i = 0; i < std::min(size_bytes, (size_t)8u); i++)
number |= ((u64)p[i]) << (i*8);
return number;
}
u64 movzx_be64(const u8* p, size_t size_bytes)
{
u64 number = 0;
for(size_t i = 0; i < std::min(size_bytes, (size_t)8u); i++)
{
number <<= 8;
number |= p[i];
}
return number;
}
static inline i64 SignExtend(u64 bits, size_t size_bytes)
{
// no point in sign-extending if >= 8 bytes were requested
if(size_bytes < 8)
{
const u64 sign_bit = BIT64((size_bytes*8)-1);
// number would be negative in the smaller type,
// so sign-extend, i.e. set all more significant bits.
if(bits & sign_bit)
{
const u64 valid_bit_mask = (sign_bit+sign_bit)-1;
bits |= ~valid_bit_mask;
}
}
const i64 number = static_cast<i64>(bits);
return number;
}
i64 movsx_le64(const u8* p, size_t size_bytes)
{
const u64 number = movzx_le64(p, size_bytes);
return SignExtend(number, size_bytes);
}
i64 movsx_be64(const u8* p, size_t size_bytes)
{
const u64 number = movzx_be64(p, size_bytes);
return SignExtend(number, size_bytes);
}