Commit 2c06a905 authored by Mark Olesen's avatar Mark Olesen
Browse files

Cleanup endian support (closes #271)

- Place common code under OSspecific.

By including "endian.H", either one of WM_BIG_ENDIAN or WM_LITTLE_ENDIAN
will be defined.

Provides inline 32-bit and 64-bit byte swap routines that can be
used/re-used elsewhere.

The inplace memory swaps currently used by the VTK output are left for
the moment pending further cleanup of that code.
parent ec5eec3a
......@@ -42,28 +42,28 @@ int main(int argc, char * argv[])
SHA1 sha;
SHA1Digest shaDig;
std::string str("The quick brown fox jumps over the lazy dog");
Info<< shaDig << nl;
Info<< SHA1("The quick brown fox jumps over the lazy dog") << nl;
const std::string str("The quick brown fox jumps over the lazy dog");
Info<< shaDig << " : empty" << nl;
Info<< SHA1(str) << " : " << str << nl;
sha.append("The quick brown fox jumps over the lazy dog");
Info<< sha << nl;
sha.append(str);
Info<< sha << " : appended to empty" << nl;
sha.clear();
sha.append("The quick brown fox jumps over the lazy dog");
sha.append(str);
shaDig = sha;
sha.append("\n");
Info<< sha << nl;
Info<< sha << " : with trailing newline" << nl;
Info<< shaDig << nl;
if (sha == shaDig)
{
Info<<"SHA1 digests are identical\n";
Info<<"SHA1 digests are identical (unexpected)\n";
}
else
{
Info<<"SHA1 digests are different\n";
Info<<"SHA1 digests are different (expected)\n";
}
Info<<"lhs:" << sha << " rhs:" << shaDig << endl;
......@@ -99,7 +99,6 @@ int main(int argc, char * argv[])
os.rewind();
os << "The quick brown fox jumps over the lazy dog";
Info<< os.digest() << endl;
}
{
......
......@@ -27,8 +27,9 @@ Description
\*---------------------------------------------------------------------------*/
#include "ProfilingSysInfo.H"
#include "profilingSysInfo.H"
#include "IOstreams.H"
#include "endian.H"
using namespace Foam;
......@@ -37,7 +38,22 @@ using namespace Foam;
int main(int argc, char *argv[])
{
Profiling::sysInfo().write(Info);
profiling::sysInfo().write(Info);
#ifdef WM_BIG_ENDIAN
Info
<< "WM_BIG_ENDIAN is defined"
<< nl;
#endif
#ifdef WM_LITTLE_ENDIAN
Info
<< "WM_LITTLE_ENDIAN is defined"
<< nl;
#endif
Info<< "Runtime endian check: big=" << endian::isBig()
<< " little=" << endian::isLittle()
<< nl;
return 0;
}
......
......@@ -24,22 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "writeFuns.H"
#if defined(__mips)
#include <standards.h>
#include <sys/endian.h>
#endif
#if defined(LITTLE_ENDIAN) \
|| defined(_LITTLE_ENDIAN) \
|| defined(__LITTLE_ENDIAN)
#define LITTLEENDIAN 1
#elif defined(BIG_ENDIAN) || defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN)
#undef LITTLEENDIAN
#else
#error "Cannot find LITTLE_ENDIAN or BIG_ENDIAN symbol defined."
#error "Please add to compilation options"
#endif
#include "endian.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -75,7 +60,7 @@ void Foam::writeFuns::write
{
if (binary)
{
#ifdef LITTLEENDIAN
#ifdef WM_LITTLE_ENDIAN
swapWords(fField.size(), reinterpret_cast<int32_t*>(fField.begin()));
#endif
......@@ -124,7 +109,7 @@ void Foam::writeFuns::write
{
if (binary)
{
#ifdef LITTLEENDIAN
#ifdef WM_LITTLE_ENDIAN
swapWords
(
(sizeof(label)/4)*elems.size(),
......
......@@ -25,31 +25,7 @@ License
#include "writeFuns.H"
#include "vtkTopo.H"
#if defined(__mips)
#include <standards.h>
#include <sys/endian.h>
#endif
// MacOSX
#ifdef __DARWIN_BYTE_ORDER
#if __DARWIN_BYTE_ORDER==__DARWIN_BIG_ENDIAN
#undef LITTLE_ENDIAN
#else
#undef BIG_ENDIAN
#endif
#endif
#if defined(LITTLE_ENDIAN) \
|| defined(_LITTLE_ENDIAN) \
|| defined(__LITTLE_ENDIAN)
#define LITTLEENDIAN 1
#elif defined(BIG_ENDIAN) || defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN)
#undef LITTLEENDIAN
#else
#error "Cannot find LITTLE_ENDIAN or BIG_ENDIAN symbol defined."
#error "Please add to compilation options"
#endif
#include "endian.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -85,7 +61,7 @@ void Foam::writeFuns::write
{
if (binary)
{
#ifdef LITTLEENDIAN
#ifdef WM_LITTLE_ENDIAN
swapWords(fField.size(), reinterpret_cast<label*>(fField.begin()));
#endif
os.write
......@@ -138,7 +114,7 @@ void Foam::writeFuns::write
{
if (binary)
{
#ifdef LITTLEENDIAN
#ifdef WM_LITTLE_ENDIAN
swapWords(elems.size(), reinterpret_cast<label*>(elems.begin()));
#endif
os.write
......
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Help with architecture-specific aspects.
Defines WM_BIG_ENDIAN or WM_LITTLE_ENDIAN as well as providing a
few runtime methods. Primarily used as a namespace, but provided
as a class for possible future expansion.
SourceFiles
endianI.H
\*---------------------------------------------------------------------------*/
#ifndef foamEndian_H // prefixed with 'foam' to avoid potential collisions
#define foamEndian_H
#include <cstdint>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef __GNUC__
#include <endian.h>
#elif defined __mips
#include <standards.h>
#include <sys/endian.h>
#endif
#ifdef __BYTE_ORDER
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define WM_LITTLE_ENDIAN
#elif (__BYTE_ORDER == __BIG_ENDIAN)
#define WM_BIG_ENDIAN
#else
#error "__BYTE_ORDER defined, but not __LITTLE_ENDIAN or __BIG_ENDIAN."
#endif
#elif defined(__LITTLE_ENDIAN) \
|| defined(_LITTLE_ENDIAN) \
|| defined(LITTLE_ENDIAN)
#define WM_LITTLE_ENDIAN
#elif defined(__BIG_ENDIAN) \
|| defined(_BIG_ENDIAN) \
|| defined(BIG_ENDIAN)
#define WM_BIG_ENDIAN
#endif
// Special handling for OS-X
#ifdef __DARWIN_BYTE_ORDER
#if (__DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN)
#define WM_BIG_ENDIAN
#undef WM_LITTLE_ENDIAN
#elif (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN)
#define WM_LITTLE_ENDIAN
#undef WM_BIG_ENDIAN
#endif
#endif
// Could also downgrade to a warning, but then user always needs runtime check.
#if !defined(WM_BIG_ENDIAN) && !defined(WM_LITTLE_ENDIAN)
#error "Cannot determine BIG or LITTLE endian."
#error "Please add to compilation options"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class endian Declaration
\*---------------------------------------------------------------------------*/
class endian
{
// Private Member Functions
//- Disallow default bitwise copy construct
endian(const endian&) = delete;
//- Disallow default bitwise assignment
void operator=(const endian&) = delete;
public:
// Public data
//- Runtime check for big endian.
inline static bool isBig();
//- Runtime check for little endian.
inline static bool isLittle();
//- Byte endian swapping for 32-bits
inline static uint32_t swap32(uint32_t);
//- Byte endian swapping for 64-bits
inline static uint64_t swap64(uint64_t);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "endianI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "endian.H"
#ifdef __GNUC__
#define USE_BUILTIN_BYTESWAP
#else
#undef USE_BUILTIN_BYTESWAP
#endif
// for Debugging:
// #undef USE_BUILTIN_BYTESWAP
// Some ideas about a templated approach for swapping bytes:
// http://www.cplusplus.com/forum/general/27544/
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
inline bool Foam::endian::isBig()
{
const short testBig = 0x0100;
// Yields 0x01 for big endian
return *(reinterpret_cast<const char*>(&testBig));
}
inline bool Foam::endian::isLittle()
{
const short testLittle = 0x0001;
// Yields 0x01 for little endian
return *(reinterpret_cast<const char*>(&testLittle));
}
inline uint32_t Foam::endian::swap32(uint32_t u)
{
#ifdef USE_BUILTIN_BYTESWAP
return __builtin_bswap32(u);
#else
return
(
(((u) & 0xff000000) >> 24) // 3 -> 0
| (((u) & 0x00ff0000) >> 8) // 2 -> 1
| (((u) & 0x0000ff00) << 8) // 2 <- 1
| (((u) & 0x000000ff) << 24) // 3 <- 0
);
// alternative formulation
//
// u = ((u<<8) & 0xFF00FF00) | ((u>>8) & 0x00FF00FF);
// u = (u>>16) | (u<<16);
// return u;
#endif
}
inline uint64_t Foam::endian::swap64(uint64_t u)
{
#ifdef USE_BUILTIN_BYTESWAP
return __builtin_bswap64(u);
#else
return
(
(((u) & 0xff00000000000000ull) >> 56) // 7 -> 0
| (((u) & 0x00ff000000000000ull) >> 40) // 6 -> 1
| (((u) & 0x0000ff0000000000ull) >> 24) // 5 -> 2
| (((u) & 0x000000ff00000000ull) >> 8) // 4 -> 3
| (((u) & 0x00000000ff000000ull) << 8) // 4 <- 3
| (((u) & 0x0000000000ff0000ull) << 24) // 5 <- 2
| (((u) & 0x000000000000ff00ull) << 40) // 6 <- 1
| (((u) & 0x00000000000000ffull) << 56) // 7 <- 0
);
// alternative formulation
//
// u = ((u<< 8) & 0xFF00FF00FF00FF00ull) | ((u>> 8) & 0x00FF00FF00FF00FFull);
// u = ((u<<16) & 0xFFFF0000FFFF0000ull) | ((u>>16) & 0x0000FFFF0000FFFFull);
// return (u >> 32) | (u << 32);
#endif
}
// ************************************************************************* //
......@@ -27,10 +27,7 @@ Description
#include "Hasher.H"
#include "HasherInt.H"
#if defined (__GLIBC__)
#include <endian.h>
#endif
#include "endian.H"
// Left-rotate a 32-bit value and carry by nBits
#define bitRotateLeft(x, nBits) (((x) << (nBits)) | ((x) >> (32 - (nBits))))
......@@ -188,7 +185,7 @@ Description
// ----------------------------------------------------------------------------
// Specialized little-endian code
#if !defined (__BYTE_ORDER) || (__BYTE_ORDER == __LITTLE_ENDIAN)
#ifdef WM_LITTLE_ENDIAN
static unsigned jenkins_hashlittle
(
const void *key,
......@@ -357,8 +354,6 @@ static unsigned jenkins_hashlittle
#endif
// ----------------------------------------------------------------------------
// hashbig():
// This is the same as hashword() on big-endian machines. It is different
......@@ -366,7 +361,7 @@ static unsigned jenkins_hashlittle
// big-endian byte ordering.
// ----------------------------------------------------------------------------
// specialized big-endian code
#if !defined (__BYTE_ORDER) || (__BYTE_ORDER == __BIG_ENDIAN)
#ifdef WM_BIG_ENDIAN
static unsigned jenkins_hashbig
(
const void *key,
......@@ -479,25 +474,12 @@ unsigned Foam::Hasher
unsigned initval
)
{
#ifdef __BYTE_ORDER
#if (__BYTE_ORDER == __BIG_ENDIAN)
return jenkins_hashbig(key, length, initval);
#else
return jenkins_hashlittle(key, length, initval);
#endif
#if defined (WM_BIG_ENDIAN)
return jenkins_hashbig(key, length, initval);
#elif defined (WM_LITTLE_ENDIAN)
return jenkins_hashlittle(key, length, initval);
#else
// endian-ness not known at compile-time: runtime endian test
const short endianTest = 0x0100;
// yields 0x01 for big endian
if (*(reinterpret_cast<const char*>(&endianTest)))
{
return jenkins_hashbig(key, length, initval);
}
else
{
return jenkins_hashlittle(key, length, initval);
}
#error "Cannot determine WM_BIG_ENDIAN or WM_LITTLE_ENDIAN."
#endif
}
......
......@@ -35,14 +35,10 @@ Description
#include "SHA1.H"
#include "IOstreams.H"
#include "endian.H"
#include <cstring>
#if defined (__GLIBC__)
#include <endian.h>
#endif
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
//! \cond fileScope
......@@ -54,46 +50,25 @@ static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
// * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * //
inline uint32_t Foam::SHA1::swapBytes(uint32_t n)
//! \cond fileScope
//- Swap bytes from internal to network (big-endian) order
static inline uint32_t swapBytes(uint32_t n)
{
#ifdef __BYTE_ORDER
#if (__BYTE_ORDER == __BIG_ENDIAN)
return n;
#else
return
(
((n) << 24)
| (((n) & 0xff00) << 8)
| (((n) >> 8) & 0xff00)
| ((n) >> 24)
);
#endif
#else
const short x = 0x0100;
// yields 0x01 for big endian
if (*(reinterpret_cast<const char*>(&x)))
{
return n;
}
else
{
return
(
((n) << 24)
| (((n) & 0xff00) << 8)
| (((n) >> 8) & 0xff00)
| ((n) >> 24)
);
}
#endif
#ifdef WM_LITTLE_ENDIAN
return Foam::endian::swap32(n);
#else
return n;
#endif
}
inline void Foam::SHA1::set_uint32(unsigned char *cp, uint32_t v)
//- Copy the 4-byte value into the memory location pointed to by *dst.
// If the architecture allows unaligned access this is equivalent to
// *(uint32_t *) cp = val
static inline void set_uint32(unsigned char *dst, uint32_t v)
{
memcpy(cp, &v, sizeof(uint32_t));
memcpy(dst, &v, sizeof(uint32_t));
}
//! \endcond
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
......@@ -150,7 +125,7 @@ void Foam::SHA1::processBytes(const void *data, size_t len)
unsigned char* bufp = reinterpret_cast<unsigned char*>(buffer_);
size_t remaining = bufLen_;
memcpy (&bufp[remaining], data, len);
memcpy(&bufp[remaining], data, len);
remaining += len;
if (remaining >= 64)
{
......
......@@ -91,14 +91,6 @@ class SHA1
// Private Member Functions
//- Swap bytes from internal to network (big-endian) order
static inline uint32_t swapBytes(uint32_t);
//- Copy the 4-byte value into the memory location pointed to by *dst.
// If the architecture allows unaligned access this is equivalent to
// *(uint32_t *) cp = val
static inline void set_uint32(unsigned char *cp, uint32_t);
//- Process data block-wise, LEN must be a multiple of 64!
void processBlock(const void *data, size_t len);
......
......@@ -24,31 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "vtkTools.H"
#if defined(__mips)
#include <standards.h>
#include <sys/endian.h>
#endif
// MacOSX
#ifdef __DARWIN_BYTE_ORDER
#if __DARWIN_BYTE_ORDER==__DARWIN_BIG_ENDIAN
#undef LITTLE_ENDIAN
#else
#undef BIG_ENDIAN
#endif
#endif
#if defined(LITTLE_ENDIAN) \
|| defined(_LITTLE_ENDIAN) \
|| defined(__LITTLE_ENDIAN)
# define LITTLEENDIAN 1
#elif defined(BIG_ENDIAN) || defined(_BIG_ENDIAN) || defined(__BIG_ENDIAN)
# undef LITTLEENDIAN
#else
# error "Cannot find LITTLE_ENDIAN or BIG_ENDIAN symbol defined."
# error "Please add to compilation options"
#endif
#include "endian.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -84,9 +60,9 @@ void Foam::vtkTools::write
{
if (binary)
{
# ifdef LITTLEENDIAN
#ifdef WM_LITTLE_ENDIAN