0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00

SERVER-14852 AAE safe read/write primitives

Alignment, aliasing and endian safe read write primitives in the form
of DataView and DataCursor primitives.  These primitives provide safe
reads and writes with explicit endian variants that funnel through
std::memcpy to provide defined behavior.

Support for a safe packed struct idiom is also provided in the
encoded_value_storage class.
This commit is contained in:
Jason Carey 2014-08-11 10:03:42 -04:00
parent e2a58d5fd4
commit 8d0bf7dfbf
11 changed files with 1718 additions and 0 deletions

View File

@ -205,6 +205,9 @@ add_option( "dynamic-windows", "dynamically link on Windows", 0, True)
add_option( "64" , "whether to force 64 bit" , 0 , True , "force64" )
add_option( "32" , "whether to force 32 bit" , 0 , True , "force32" )
add_option( "endian" , "endianness of target platform" , 1 , False , "endian",
type="choice", choices=["big", "little", "auto"], default="auto" )
add_option( "cxx", "compiler to use" , 1 , True )
add_option( "cc", "compiler to use for c" , 1 , True )
add_option( "cc-use-shell-environment", "use $CC from shell for C compiler" , 0 , False )
@ -552,6 +555,16 @@ if has_option('mute'):
env.Append( SHLINKCOMSTR = env["LINKCOMSTR"] )
env.Append( ARCOMSTR = "Generating library $TARGET" )
endian = get_option( "endian" )
if endian == "auto":
endian = sys.byteorder
if endian == "little":
env.Append( CPPDEFINES=[("MONGO_BYTE_ORDER", "1234")] )
elif endian == "big":
env.Append( CPPDEFINES=[("MONGO_BYTE_ORDER", "4321")] )
env['_LIBDEPS'] = '$_LIBDEPS_OBJS'
if env['_LIBDEPS'] == '$_LIBDEPS_OBJS':

View File

@ -46,6 +46,15 @@ env.CppUnitTest('status_test',
'status_test.cpp',
LIBDEPS=['base'])
env.CppUnitTest('encoded_value_storage_test',
'encoded_value_storage_test.cpp')
env.CppUnitTest('data_view_test',
'data_view_test.cpp')
env.CppUnitTest('data_cursor_test',
'data_cursor_test.cpp')
env.CppUnitTest('counter_test',
'counter_test.cpp',
LIBDEPS=['base'])

View File

@ -0,0 +1,137 @@
/* Copyright 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#pragma once
#include <cstddef>
#include <cstring>
#include "mongo/base/data_view.h"
#include "mongo/platform/endian.h"
namespace mongo {
template <class T>
struct CursorMethods : public T {
CursorMethods(typename T::bytes_type bytes) : T(bytes) {}
T operator+(std::size_t s) const {
return this->T::view() + s;
}
T& operator+=(std::size_t s) {
*this = this->T::view() + s;
return *this;
}
T operator-(std::size_t s) const {
return this->T::view() - s;
}
T& operator-=(std::size_t s) {
*this = this->T::view() - s;
return *this;
}
T& operator++() {
return this->operator+=(1);
}
T operator++(int) {
T tmp = *this;
operator++();
return tmp;
}
T& operator--() {
return this->operator-=(1);
}
T operator--(int) {
T tmp = *this;
operator--();
return tmp;
}
template <typename U>
void skip() {
*this = this->T::view() + sizeof(U);
}
template <typename U>
U readNativeAndAdvance() {
U out = this->T::template readNative<U>();
this->skip<U>();
return out;
}
template <typename U>
U readLEAndAdvance() {
return littleToNative(readNativeAndAdvance<U>());
}
template <typename U>
U readBEAndAdvance() {
return bigToNative(readNativeAndAdvance<U>());
}
};
class ConstDataCursor : public CursorMethods<ConstDataView> {
public:
ConstDataCursor(ConstDataView::bytes_type bytes) : CursorMethods<ConstDataView>(bytes) {}
};
class DataCursor : public CursorMethods<DataView> {
public:
DataCursor(DataView::bytes_type bytes) : CursorMethods<DataView>(bytes) {}
template <typename T>
void writeNativeAndAdvance(const T& value) {
this->writeNative(value);
this->skip<T>();
}
template <typename T>
void writeLEAndAdvance(const T& value) {
return writeNativeAndAdvance(nativeToLittle(value));
}
template <typename T>
void writeBEAndAdvance(const T& value) {
return writeNativeAndAdvance(nativeToBig(value));
}
operator ConstDataCursor() const {
return view();
}
};
} // namespace mongo

View File

@ -0,0 +1,107 @@
/**
* Copyright (C) 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include "mongo/base/data_cursor.h"
#include "mongo/platform/endian.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
TEST(DataCursor, ConstDataCursor) {
char buf[100];
DataView(buf).writeNative<uint16_t>(1);
DataView(buf).writeLE<uint32_t>(2, sizeof(uint16_t));
DataView(buf).writeBE<uint64_t>(3, sizeof(uint16_t) + sizeof(uint32_t));
ConstDataCursor cdc(buf);
ASSERT_EQUALS(static_cast<uint16_t>(1), cdc.readNativeAndAdvance<uint16_t>());
ASSERT_EQUALS(static_cast<uint32_t>(2), cdc.readLEAndAdvance<uint32_t>());
ASSERT_EQUALS(static_cast<uint64_t>(3), cdc.readBEAndAdvance<uint64_t>());
// test skip()
cdc = buf;
cdc.skip<uint32_t>();
ASSERT_EQUALS(buf + sizeof(uint32_t), cdc.view());
// test x +
cdc = buf;
ASSERT_EQUALS(buf + sizeof(uint32_t), (cdc + sizeof(uint32_t)).view());
// test x -
cdc = buf + sizeof(uint32_t);
ASSERT_EQUALS(buf, (cdc - sizeof(uint32_t)).view());
// test x += and x -=
cdc = buf;
cdc += sizeof(uint32_t);
ASSERT_EQUALS(buf + sizeof(uint32_t), cdc.view());
cdc -= sizeof(uint16_t);
ASSERT_EQUALS(buf + sizeof(uint16_t), cdc.view());
// test ++x
cdc = buf;
ASSERT_EQUALS(buf + sizeof(uint8_t), (++cdc).view());
ASSERT_EQUALS(buf + sizeof(uint8_t), cdc.view());
// test x++
cdc = buf;
ASSERT_EQUALS(buf, (cdc++).view());
ASSERT_EQUALS(buf + sizeof(uint8_t), cdc.view());
// test --x
cdc = buf + sizeof(uint8_t);
ASSERT_EQUALS(buf, (--cdc).view());
ASSERT_EQUALS(buf, cdc.view());
// test x--
cdc = buf + sizeof(uint8_t);
ASSERT_EQUALS(buf + sizeof(uint8_t), (cdc--).view());
ASSERT_EQUALS(buf, cdc.view());
}
TEST(DataCursor, DataCursor) {
char buf[100];
DataCursor dc(buf);
dc.writeNativeAndAdvance<uint16_t>(1);
dc.writeLEAndAdvance<uint32_t>(2);
dc.writeBEAndAdvance<uint64_t>(3);
ConstDataCursor cdc(buf);
ASSERT_EQUALS(static_cast<uint16_t>(1), cdc.readNativeAndAdvance<uint16_t>());
ASSERT_EQUALS(static_cast<uint32_t>(2), cdc.readLEAndAdvance<uint32_t>());
ASSERT_EQUALS(static_cast<uint64_t>(3), cdc.readBEAndAdvance<uint64_t>());
}
} // namespace mongo

101
src/mongo/base/data_view.h Normal file
View File

@ -0,0 +1,101 @@
/* Copyright 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#pragma once
#include <cstring>
#include "mongo/platform/endian.h"
namespace mongo {
class ConstDataView {
public:
typedef const char* bytes_type;
ConstDataView(bytes_type bytes)
: _bytes(bytes) {
}
bytes_type view(std::size_t offset = 0) const {
return _bytes + offset;
}
template<typename T>
T readNative(std::size_t offset = 0) const {
T t;
std::memcpy(&t, view(offset), sizeof(t));
return t;
}
template<typename T>
T readLE(std::size_t offset = 0) const {
return littleToNative(readNative<T>(offset));
}
template<typename T>
T readBE(std::size_t offset = 0) const {
return bigToNative(readNative<T>(offset));
}
private:
bytes_type _bytes;
};
class DataView : public ConstDataView {
public:
typedef char* bytes_type;
DataView(bytes_type bytes)
: ConstDataView(bytes) {
}
bytes_type view(std::size_t offset = 0) const {
// It is safe to cast away const here since the pointer stored in our base class was
// originally non-const by way of our constructor.
return const_cast<bytes_type>(ConstDataView::view(offset));
}
template<typename T>
void writeNative(const T& value, std::size_t offset = 0) {
std::memcpy(view(offset), &value, sizeof(value));
}
template<typename T>
void writeLE(const T& value, std::size_t offset = 0) {
return writeNative(nativeToLittle(value), offset);
}
template<typename T>
void writeBE(const T& value, std::size_t offset = 0) {
return writeNative(nativeToBig(value), offset);
}
};
} // namespace mongo

View File

@ -0,0 +1,76 @@
/**
* Copyright (C) 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include "mongo/base/data_view.h"
#include <cstring>
#include "mongo/platform/endian.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
TEST(DataView, ConstDataView) {
char buf[sizeof(uint32_t) * 3];
uint32_t native = 1234;
uint32_t le = nativeToLittle(native);
uint32_t be = nativeToBig(native);
std::memcpy(buf, &native, sizeof(uint32_t));
std::memcpy(buf + sizeof(uint32_t), &le, sizeof(uint32_t));
std::memcpy(buf + sizeof(uint32_t) * 2, &be, sizeof(uint32_t));
ConstDataView cdv(buf);
ASSERT_EQUALS(buf, cdv.view());
ASSERT_EQUALS(buf + 5, cdv.view(5));
ASSERT_EQUALS(native, cdv.readNative<uint32_t>());
ASSERT_EQUALS(native, cdv.readLE<uint32_t>(sizeof(uint32_t)));
ASSERT_EQUALS(native, cdv.readBE<uint32_t>(sizeof(uint32_t) * 2));
}
TEST(DataView, DataView) {
char buf[sizeof(uint32_t) * 3];
uint32_t native = 1234;
DataView dv(buf);
dv.writeNative(native);
dv.writeLE(native, sizeof(uint32_t));
dv.writeBE(native, sizeof(uint32_t) * 2);
ASSERT_EQUALS(buf, dv.view());
ASSERT_EQUALS(buf + 5, dv.view(5));
ASSERT_EQUALS(native, dv.readNative<uint32_t>());
ASSERT_EQUALS(native, dv.readLE<uint32_t>(sizeof(uint32_t)));
ASSERT_EQUALS(native, dv.readBE<uint32_t>(sizeof(uint32_t) * 2));
}
} // namespace mongo

View File

@ -0,0 +1,86 @@
/* Copyright 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#pragma once
#include <cstring>
#include "mongo/base/data_view.h"
namespace mongo {
struct ZeroInitTag_t {
ZeroInitTag_t() {
};
};
const ZeroInitTag_t kZeroInitTag;
template<typename Layout, typename ConstView, typename View>
class EncodedValueStorage {
protected:
EncodedValueStorage() {
}
// This explicit constructor is provided to allow for easy zeroing
// during creation of a value. You might prefer this over an
// uninitialised value if the zeroed version provides a useful base
// state. Such cases might include a set of counters that begin at
// zero, flags that start off false or a larger structure where some
// significant portion of storage falls into those kind of use cases.
// Use this where you might have used calloc(1, sizeof(type)) in C.
//
// The added value of providing it as a constructor lies in the ability
// of subclasses to easily inherit a zeroed base state during
// initialization.
explicit EncodedValueStorage(ZeroInitTag_t) {
std::memset(_data, 0, sizeof(_data));
}
public:
View view() {
return _data;
}
ConstView constView() const {
return _data;
}
operator View() {
return view();
}
operator ConstView() const {
return constView();
}
private:
char _data[sizeof(Layout)];
};
} // namespace mongo

View File

@ -0,0 +1,145 @@
/**
* Copyright (C) 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include "mongo/base/encoded_value_storage.h"
#include <cstring>
#include "mongo/platform/endian.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
// Simplistic encoded value view and value classes to test EncodedValueStorage
namespace EncodedValueStorageTest {
#pragma pack(1)
struct Layout {
uint32_t native;
uint32_t le;
uint32_t be;
};
#pragma pack()
class ConstView {
public:
typedef ConstDataView view_type;
ConstView(const char* data) : _data(data) { }
const char* view2ptr() const {
return data().view();
}
uint32_t getNative() {
return data().readNative<uint32_t>(offsetof(Layout, native));
}
uint32_t getLE() {
return data().readLE<uint32_t>(offsetof(Layout, le));
}
uint32_t getBE() {
return data().readBE<uint32_t>(offsetof(Layout, be));
}
protected:
const view_type& data() const {
return _data;
}
private:
view_type _data;
};
class View : public ConstView {
public:
typedef DataView view_type;
View(char* data) : ConstView(data) {}
using ConstView::view2ptr;
char* view2ptr() {
return data().view();
}
void setNative(uint32_t value) {
data().writeNative(value, offsetof(Layout, native));
}
void setLE(uint32_t value) {
data().writeLE(value, offsetof(Layout, le));
}
void setBE(uint32_t value) {
data().writeBE(value, offsetof(Layout, be));
}
private:
view_type data() const {
return const_cast<char *>(ConstView::view2ptr());
}
};
class Value : public EncodedValueStorage<Layout, ConstView, View> {
public:
Value() {
BOOST_STATIC_ASSERT(sizeof(Value) == sizeof(Layout));
}
Value(ZeroInitTag_t zit) : EncodedValueStorage<Layout, ConstView, View>(zit) {}
};
}
TEST(EncodedValueStorage, EncodedValueStorage) {
EncodedValueStorageTest::Value raw;
EncodedValueStorageTest::Value zerod(kZeroInitTag);
char buf[sizeof(EncodedValueStorageTest::Layout)] = { 0 };
ASSERT_EQUALS(raw.view().view2ptr(), raw.constView().view2ptr());
// ensure zeroing with the init tag works
ASSERT_EQUALS(std::memcmp(zerod.view().view2ptr(), buf, sizeof(buf)), 0);
// see if value assignment and view() works
zerod.view().setNative(1234);
EncodedValueStorageTest::View(buf).setNative(1234);
raw = zerod;
ASSERT_EQUALS(std::memcmp(raw.view().view2ptr(), buf, sizeof(buf)), 0);
// see if view() and constView() work appropriately
raw.view().setNative(1);
raw.view().setLE(2);
raw.view().setBE(3);
ASSERT_EQUALS(static_cast<uint32_t>(1), raw.constView().getNative());
ASSERT_EQUALS(static_cast<uint32_t>(2), raw.constView().getLE());
ASSERT_EQUALS(static_cast<uint32_t>(3), raw.constView().getBE());
}
} // namespace mongo

View File

@ -12,5 +12,6 @@ env.Library('platform', [
env.CppUnitTest('atomic_word_test', 'atomic_word_test.cpp')
env.CppUnitTest('bits_test', 'bits_test.cpp')
env.CppUnitTest('endian_test', 'endian_test.cpp')
env.CppUnitTest('process_id_test', 'process_id_test.cpp', LIBDEPS=['platform'])
env.CppUnitTest('random_test', 'random_test.cpp', LIBDEPS=['platform'])

491
src/mongo/platform/endian.h Normal file
View File

@ -0,0 +1,491 @@
/* Copyright 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#pragma once
#include <cstring>
#include <boost/static_assert.hpp>
#include "mongo/platform/cstdint.h"
#pragma push_macro("MONGO_UINT16_SWAB")
#pragma push_macro("MONGO_UINT32_SWAB")
#pragma push_macro("MONGO_UINT64_SWAB")
#pragma push_macro("MONGO_LITTLE_ENDIAN")
#pragma push_macro("MONGO_BIG_ENDIAN")
#pragma push_macro("htobe16")
#pragma push_macro("htobe32")
#pragma push_macro("htobe64")
#pragma push_macro("htole16")
#pragma push_macro("htole32")
#pragma push_macro("htole64")
#pragma push_macro("be16toh")
#pragma push_macro("be32toh")
#pragma push_macro("be64toh")
#pragma push_macro("le16toh")
#pragma push_macro("le32toh")
#pragma push_macro("le64toh")
#undef MONGO_UINT16_SWAB
#undef MONGO_UINT32_SWAB
#undef MONGO_UINT64_SWAB
#undef MONGO_LITTLE_ENDIAN
#undef MONGO_BIG_ENDIAN
#undef htobe16
#undef htobe32
#undef htobe64
#undef htole16
#undef htole32
#undef htole64
#undef be16toh
#undef be32toh
#undef be64toh
#undef le16toh
#undef le32toh
#undef le64toh
#define MONGO_LITTLE_ENDIAN 1234
#define MONGO_BIG_ENDIAN 4321
#if defined(_MSC_VER) && (_MSC_VER >= 1300)
# include <cstdlib>
# define MONGO_UINT16_SWAB(v) _byteswap_ushort(v)
# define MONGO_UINT32_SWAB(v) _byteswap_ulong(v)
# define MONGO_UINT64_SWAB(v) _byteswap_uint64(v)
#elif defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && \
(__clang_major__ >= 3) && (__clang_minor__ >= 1)
# if __has_builtin(__builtin_bswap16)
# define MONGO_UINT16_SWAB(v) __builtin_bswap16(v)
# endif
# if __has_builtin(__builtin_bswap32)
# define MONGO_UINT32_SWAB(v) __builtin_bswap32(v)
# endif
# if __has_builtin(__builtin_bswap64)
# define MONGO_UINT64_SWAB(v) __builtin_bswap64(v)
# endif
#elif defined(__GNUC__) && (__GNUC__ >= 4)
# if __GNUC__ >= 4 && defined (__GNUC_MINOR__) && __GNUC_MINOR__ >= 3
# define MONGO_UINT32_SWAB(v) __builtin_bswap32(v)
# define MONGO_UINT64_SWAB(v) __builtin_bswap64(v)
# endif
# if __GNUC__ >= 4 && defined (__GNUC_MINOR__) && __GNUC_MINOR__ >= 8
# define MONGO_UINT16_SWAB(v) __builtin_bswap16(v)
# endif
#elif defined(__sun)
# include <sys/byteorder.h>
# define MONGO_UINT16_SWAB(v) BSWAP_16(v)
# define MONGO_UINT32_SWAB(v) BSWAP_32(v)
# define MONGO_UINT64_SWAB(v) BSWAP_64(v)
#endif
#ifndef MONGO_UINT16_SWAB
# define MONGO_UINT16_SWAB(v) endian::bswap_slow16(v)
#endif
#ifndef MONGO_UINT32_SWAB
# define MONGO_UINT32_SWAB(v) endian::bswap_slow32(v)
#endif
#ifndef MONGO_UINT64_SWAB
# define MONGO_UINT64_SWAB(v) endian::bswap_slow64(v)
#endif
#if MONGO_BYTE_ORDER == MONGO_LITTLE_ENDIAN
# define htobe16(v) MONGO_UINT16_SWAB(v)
# define htobe32(v) MONGO_UINT32_SWAB(v)
# define htobe64(v) MONGO_UINT64_SWAB(v)
# define htole16(v) (v)
# define htole32(v) (v)
# define htole64(v) (v)
# define be16toh(v) MONGO_UINT16_SWAB(v)
# define be32toh(v) MONGO_UINT32_SWAB(v)
# define be64toh(v) MONGO_UINT64_SWAB(v)
# define le16toh(v) (v)
# define le32toh(v) (v)
# define le64toh(v) (v)
#elif MONGO_BYTE_ORDER == MONGO_BIG_ENDIAN
# define htobe16(v) (v)
# define htobe32(v) (v)
# define htobe64(v) (v)
# define htole16(v) MONGO_UINT16_SWAB(v)
# define htole32(v) MONGO_UINT32_SWAB(v)
# define htole64(v) MONGO_UINT64_SWAB(v)
# define be16toh(v) (v)
# define be32toh(v) (v)
# define be64toh(v) (v)
# define le16toh(v) MONGO_UINT16_SWAB(v)
# define le32toh(v) MONGO_UINT32_SWAB(v)
# define le64toh(v) MONGO_UINT64_SWAB(v)
#else
# error "The endianness of target architecture is unknown. " \
"Please define MONGO_BYTE_ORDER"
#endif
namespace mongo {
namespace endian {
static inline uint16_t bswap_slow16(uint16_t v) {
return ((v & 0x00FF) << 8) |
((v & 0xFF00) >> 8);
}
static inline uint32_t bswap_slow32(uint32_t v) {
return ((v & 0x000000FFUL) << 24) |
((v & 0x0000FF00UL) << 8) |
((v & 0x00FF0000UL) >> 8) |
((v & 0xFF000000UL) >> 24);
}
static inline uint64_t bswap_slow64(uint64_t v) {
return ((v & 0x00000000000000FFULL) << 56) |
((v & 0x000000000000FF00ULL) << 40) |
((v & 0x0000000000FF0000ULL) << 24) |
((v & 0x00000000FF000000ULL) << 8) |
((v & 0x000000FF00000000ULL) >> 8) |
((v & 0x0000FF0000000000ULL) >> 24) |
((v & 0x00FF000000000000ULL) >> 40) |
((v & 0xFF00000000000000ULL) >> 56);
}
} // namespace endian
template<typename T>
struct ByteOrderConverter;
template<>
struct ByteOrderConverter<uint8_t> {
typedef uint8_t T;
inline static T nativeToBig(T t) {
return t;
}
inline static T bigToNative(T t) {
return t;
}
inline static T nativeToLittle(T t) {
return t;
}
inline static T littleToNative(T t) {
return t;
}
};
template<>
struct ByteOrderConverter<uint16_t> {
typedef uint16_t T;
inline static T nativeToBig(T t) {
return htobe16(t);
}
inline static T bigToNative(T t) {
return be16toh(t);
}
inline static T nativeToLittle(T t) {
return htole16(t);
}
inline static T littleToNative(T t) {
return le16toh(t);
}
};
template<>
struct ByteOrderConverter<uint32_t> {
typedef uint32_t T;
inline static T nativeToBig(T t) {
return htobe32(t);
}
inline static T bigToNative(T t) {
return be32toh(t);
}
inline static T nativeToLittle(T t) {
return htole32(t);
}
inline static T littleToNative(T t) {
return le32toh(t);
}
};
template<>
struct ByteOrderConverter<uint64_t> {
typedef uint64_t T;
inline static T nativeToBig(T t) {
return htobe64(t);
}
inline static T bigToNative(T t) {
return be64toh(t);
}
inline static T nativeToLittle(T t) {
return htole64(t);
}
inline static T littleToNative(T t) {
return le64toh(t);
}
};
template<>
struct ByteOrderConverter<int8_t> {
typedef int8_t T;
inline static T nativeToBig(T t) {
return t;
}
inline static T bigToNative(T t) {
return t;
}
inline static T nativeToLittle(T t) {
return t;
}
inline static T littleToNative(T t) {
return t;
}
};
template<>
struct ByteOrderConverter<int16_t> {
typedef int16_t T;
inline static T nativeToBig(T t) {
return htobe16(static_cast<uint16_t>(t));
}
inline static T bigToNative(T t) {
return be16toh(static_cast<uint16_t>(t));
}
inline static T nativeToLittle(T t) {
return htole16(static_cast<uint16_t>(t));
}
inline static T littleToNative(T t) {
return le16toh(static_cast<uint16_t>(t));
}
};
template<>
struct ByteOrderConverter<int32_t> {
typedef int32_t T;
inline static T nativeToBig(T t) {
return htobe32(static_cast<uint32_t>(t));
}
inline static T bigToNative(T t) {
return be32toh(static_cast<uint32_t>(t));
}
inline static T nativeToLittle(T t) {
return htole32(static_cast<uint32_t>(t));
}
inline static T littleToNative(T t) {
return le32toh(static_cast<uint32_t>(t));
}
};
template<>
struct ByteOrderConverter<int64_t> {
typedef int64_t T;
inline static T nativeToBig(T t) {
return htobe64(static_cast<uint64_t>(t));
}
inline static T bigToNative(T t) {
return be64toh(static_cast<uint64_t>(t));
}
inline static T nativeToLittle(T t) {
return htole64(static_cast<uint64_t>(t));
}
inline static T littleToNative(T t) {
return le64toh(static_cast<uint64_t>(t));
}
};
template<>
struct ByteOrderConverter<float> {
typedef float T;
inline static T nativeToBig(T t) {
BOOST_STATIC_ASSERT(sizeof(T) == sizeof(uint32_t));
uint32_t temp;
std::memcpy(&temp, &t, sizeof(t));
temp = htobe32(temp);
std::memcpy(&t, &temp, sizeof(t));
return t;
}
inline static T bigToNative(T t) {
uint32_t temp;
std::memcpy(&temp, &t, sizeof(t));
temp = be32toh(temp);
std::memcpy(&t, &temp, sizeof(t));
return t;
}
inline static T nativeToLittle(T t) {
uint32_t temp;
std::memcpy(&temp, &t, sizeof(t));
temp = htole32(temp);
std::memcpy(&t, &temp, sizeof(t));
return t;
}
inline static T littleToNative(T t) {
uint32_t temp;
std::memcpy(&temp, &t, sizeof(t));
temp = le32toh(temp);
std::memcpy(&t, &temp, sizeof(t));
return t;
}
};
template<>
struct ByteOrderConverter<double> {
typedef double T;
inline static T nativeToBig(T t) {
BOOST_STATIC_ASSERT(sizeof(T) == sizeof(uint64_t));
uint64_t temp;
std::memcpy(&temp, &t, sizeof(t));
temp = htobe64(temp);
std::memcpy(&t, &temp, sizeof(t));
return t;
}
inline static T bigToNative(T t) {
uint64_t temp;
std::memcpy(&temp, &t, sizeof(t));
temp = be64toh(temp);
std::memcpy(&t, &temp, sizeof(t));
return t;
}
inline static T nativeToLittle(T t) {
uint64_t temp;
std::memcpy(&temp, &t, sizeof(t));
temp = htole64(temp);
std::memcpy(&t, &temp, sizeof(t));
return t;
}
inline static T littleToNative(T t) {
uint64_t temp;
std::memcpy(&temp, &t, sizeof(t));
temp = le64toh(temp);
std::memcpy(&t, &temp, sizeof(t));
return t;
}
};
template<typename T>
inline T nativeToBig(T t) {
return ByteOrderConverter<T>::nativeToBig(t);
}
template<typename T>
inline T bigToNative(T t) {
return ByteOrderConverter<T>::bigToNative(t);
}
template<typename T>
inline T nativeToLittle(T t) {
return ByteOrderConverter<T>::nativeToLittle(t);
}
template<typename T>
inline T littleToNative(T t) {
return ByteOrderConverter<T>::littleToNative(t);
}
} // namespace mongo
#undef MONGO_UINT16_SWAB
#undef MONGO_UINT32_SWAB
#undef MONGO_UINT64_SWAB
#undef MONGO_LITTLE_ENDIAN
#undef MONGO_BIG_ENDIAN
#undef htobe16
#undef htobe32
#undef htobe64
#undef htole16
#undef htole32
#undef htole64
#undef be16toh
#undef be32toh
#undef be64toh
#undef le16toh
#undef le32toh
#undef le64toh
#pragma pop_macro("MONGO_UINT16_SWAB")
#pragma pop_macro("MONGO_UINT32_SWAB")
#pragma pop_macro("MONGO_UINT64_SWAB")
#pragma pop_macro("MONGO_LITTLE_ENDIAN")
#pragma pop_macro("MONGO_BIG_ENDIAN")
#pragma pop_macro("htobe16")
#pragma pop_macro("htobe32")
#pragma pop_macro("htobe64")
#pragma pop_macro("htole16")
#pragma pop_macro("htole32")
#pragma pop_macro("htole64")
#pragma pop_macro("be16toh")
#pragma pop_macro("be32toh")
#pragma pop_macro("be64toh")
#pragma pop_macro("le16toh")
#pragma pop_macro("le32toh")
#pragma pop_macro("le64toh")

View File

@ -0,0 +1,552 @@
/* Copyright 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include "mongo/platform/endian.h"
#include <cstring>
#include "mongo/unittest/unittest.h"
namespace mongo {
TEST( EndianTest, TestSlow16 ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
uint16_t le;
uint16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
ASSERT_EQUALS(be, endian::bswap_slow16(le));
ASSERT_EQUALS(le, endian::bswap_slow16(be));
}
TEST( EndianTest, TestSlow32 ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
uint32_t le;
uint32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
ASSERT_EQUALS(be, endian::bswap_slow32(le));
ASSERT_EQUALS(le, endian::bswap_slow32(be));
}
TEST( EndianTest, TestSlow64 ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
uint64_t le;
uint64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
ASSERT_EQUALS(be, endian::bswap_slow64(le));
ASSERT_EQUALS(le, endian::bswap_slow64(be));
}
TEST( EndianTest, NativeToBig_uint16_t ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
uint16_t le;
uint16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(be, nativeToBig(le));
#else
ASSERT_EQUALS(be, nativeToBig(be));
#endif
}
TEST( EndianTest, NativeToBig_uint32_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
uint32_t le;
uint32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(be, nativeToBig(le));
#else
ASSERT_EQUALS(be, nativeToBig(be));
#endif
}
TEST( EndianTest, NativeToBig_uint64_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
uint64_t le;
uint64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(be, nativeToBig(le));
#else
ASSERT_EQUALS(be, nativeToBig(be));
#endif
}
TEST( EndianTest, NativeToBig_int16_t ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
int16_t le;
int16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(be, nativeToBig(le));
#else
ASSERT_EQUALS(be, nativeToBig(be));
#endif
}
TEST( EndianTest, NativeToBig_int32_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
int32_t le;
int32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(be, nativeToBig(le));
#else
ASSERT_EQUALS(be, nativeToBig(be));
#endif
}
TEST( EndianTest, NativeToBig_int64_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
int64_t le;
int64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(be, nativeToBig(le));
#else
ASSERT_EQUALS(be, nativeToBig(be));
#endif
}
TEST( EndianTest, NativeToBig_float ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
float le;
float be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(be, nativeToBig(le));
#else
ASSERT_EQUALS(be, nativeToBig(be));
#endif
}
TEST( EndianTest, NativeToBig_double ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
double le;
double be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(be, nativeToBig(le));
#else
ASSERT_EQUALS(be, nativeToBig(be));
#endif
}
TEST( EndianTest, NativeToLittle_uint16_t ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
uint16_t le;
uint16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, nativeToLittle(le));
#else
ASSERT_EQUALS(le, nativeToLittle(be));
#endif
}
TEST( EndianTest, NativeToLittle_uint32_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
uint32_t le;
uint32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, nativeToLittle(le));
#else
ASSERT_EQUALS(le, nativeToLittle(be));
#endif
}
TEST( EndianTest, NativeToLittle_uint64_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
uint64_t le;
uint64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, nativeToLittle(le));
#else
ASSERT_EQUALS(le, nativeToLittle(be));
#endif
}
TEST( EndianTest, NativeToLittle_int16_t ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
int16_t le;
int16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, nativeToLittle(le));
#else
ASSERT_EQUALS(le, nativeToLittle(be));
#endif
}
TEST( EndianTest, NativeToLittle_int32_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
int32_t le;
int32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, nativeToLittle(le));
#else
ASSERT_EQUALS(le, nativeToLittle(be));
#endif
}
TEST( EndianTest, NativeToLittle_int64_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
int64_t le;
int64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, nativeToLittle(le));
#else
ASSERT_EQUALS(le, nativeToLittle(be));
#endif
}
TEST( EndianTest, NativeToLittle_float ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
float le;
float be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, nativeToLittle(le));
#else
ASSERT_EQUALS(le, nativeToLittle(be));
#endif
}
TEST( EndianTest, NativeToLittle_double ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
double le;
double be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, nativeToLittle(le));
#else
ASSERT_EQUALS(le, nativeToLittle(be));
#endif
}
TEST( EndianTest, LittleToNative_uint16_t ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
uint16_t le;
uint16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, littleToNative(le));
#else
ASSERT_EQUALS(be, littleToNative(le));
#endif
}
TEST( EndianTest, LittleToNative_uint32_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
uint32_t le;
uint32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, littleToNative(le));
#else
ASSERT_EQUALS(be, littleToNative(le));
#endif
}
TEST( EndianTest, LittleToNative_uint64_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
uint64_t le;
uint64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, littleToNative(le));
#else
ASSERT_EQUALS(be, littleToNative(le));
#endif
}
TEST( EndianTest, LittleToNative_int16_t ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
int16_t le;
int16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, littleToNative(le));
#else
ASSERT_EQUALS(be, littleToNative(le));
#endif
}
TEST( EndianTest, LittleToNative_int32_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
int32_t le;
int32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, littleToNative(le));
#else
ASSERT_EQUALS(be, littleToNative(le));
#endif
}
TEST( EndianTest, LittleToNative_int64_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
int64_t le;
int64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, littleToNative(le));
#else
ASSERT_EQUALS(be, littleToNative(le));
#endif
}
TEST( EndianTest, LittleToNative_float ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
float le;
float be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, littleToNative(le));
#else
ASSERT_EQUALS(be, littleToNative(le));
#endif
}
TEST( EndianTest, LittleToNative_double ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
double le;
double be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, littleToNative(le));
#else
ASSERT_EQUALS(be, littleToNative(le));
#endif
}
TEST( EndianTest, BigToNative_uint16_t ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
uint16_t le;
uint16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, bigToNative(be));
#else
ASSERT_EQUALS(be, bigToNative(be));
#endif
}
TEST( EndianTest, BigToNative_uint32_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
uint32_t le;
uint32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, bigToNative(be));
#else
ASSERT_EQUALS(be, bigToNative(be));
#endif
}
TEST( EndianTest, BigToNative_uint64_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
uint64_t le;
uint64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, bigToNative(be));
#else
ASSERT_EQUALS(be, bigToNative(be));
#endif
}
TEST( EndianTest, BigToNative_int16_t ) {
uint8_t le_buf[] = { 0x01, 0x02 };
uint8_t be_buf[] = { 0x02, 0x01 };
int16_t le;
int16_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, bigToNative(be));
#else
ASSERT_EQUALS(be, bigToNative(be));
#endif
}
TEST( EndianTest, BigToNative_int32_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
int32_t le;
int32_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, bigToNative(be));
#else
ASSERT_EQUALS(be, bigToNative(be));
#endif
}
TEST( EndianTest, BigToNative_int64_t ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
int64_t le;
int64_t be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, bigToNative(be));
#else
ASSERT_EQUALS(be, bigToNative(be));
#endif
}
TEST( EndianTest, BigToNative_float ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t be_buf[] = { 0x04, 0x03, 0x02, 0x01 };
float le;
float be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, bigToNative(be));
#else
ASSERT_EQUALS(be, bigToNative(be));
#endif
}
TEST( EndianTest, BigToNative_double ) {
uint8_t le_buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint8_t be_buf[] = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
double le;
double be;
std::memcpy(&le, le_buf, sizeof(le));
std::memcpy(&be, be_buf, sizeof(be));
#if MONGO_BYTE_ORDER == 1234
ASSERT_EQUALS(le, bigToNative(be));
#else
ASSERT_EQUALS(be, bigToNative(be));
#endif
}
} // namespace mongo