Commit c75d4bda authored by Kenton Varda's avatar Kenton Varda

Properly detect and support non-little-endian architectures.

parent aa8c3de4
......@@ -41,14 +41,14 @@ maintainer-clean-local:
-rm -rf build-aux
capnpc_inputs = \
src/capnproto/c++.capnp \
src/capnproto/schema.capnp
src/capnp/c++.capnp \
src/capnp/schema.capnp
capnpc_outputs = \
src/capnproto/c++.capnp.c++ \
src/capnproto/c++.capnp.h \
src/capnproto/schema.capnp.c++ \
src/capnproto/schema.capnp.h
src/capnp/c++.capnp.c++ \
src/capnp/c++.capnp.h \
src/capnp/schema.capnp.c++ \
src/capnp/schema.capnp.h
# This should depend on $(capnpc_inputs), but then make mysteriously complains
# about a cyclic dependency. I don't know where it is coming from. I rummaged
......@@ -74,19 +74,20 @@ includekj_HEADERS = \
src/kj/io.h
includecapnp_HEADERS = \
src/capnproto/common.h \
src/capnproto/blob.h \
src/capnproto/layout.h \
src/capnproto/list.h \
src/capnproto/message.h \
src/capnproto/schema.h \
src/capnproto/schema-loader.h \
src/capnproto/dynamic.h \
src/capnproto/serialize.h \
src/capnproto/serialize-packed.h \
src/capnproto/generated-header-support.h
src/capnp/common.h \
src/capnp/blob.h \
src/capnp/endian.h \
src/capnp/layout.h \
src/capnp/list.h \
src/capnp/message.h \
src/capnp/schema.h \
src/capnp/schema-loader.h \
src/capnp/dynamic.h \
src/capnp/serialize.h \
src/capnp/serialize-packed.h \
src/capnp/generated-header-support.h
nodist_includecapnp_HEADERS = \
src/capnproto/schema.capnp.h
src/capnp/schema.capnp.h
# No dynamic library for now since C++ binary compatibility is hard.
# It may make more sense to have every module statically link Cap'n Proto
......@@ -102,37 +103,37 @@ libcapnproto_a_SOURCES= \
src/kj/exception.c++ \
src/kj/debug.c++ \
src/kj/io.c++ \
src/capnproto/blob.c++ \
src/capnproto/arena.h \
src/capnproto/arena.c++ \
src/capnproto/layout.c++ \
src/capnproto/list.c++ \
src/capnproto/message.c++ \
src/capnproto/schema.c++ \
src/capnproto/schema-loader.c++ \
src/capnproto/dynamic.c++ \
src/capnproto/stringify.c++ \
src/capnproto/serialize.c++ \
src/capnproto/serialize-packed.c++
src/capnp/blob.c++ \
src/capnp/arena.h \
src/capnp/arena.c++ \
src/capnp/layout.c++ \
src/capnp/list.c++ \
src/capnp/message.c++ \
src/capnp/schema.c++ \
src/capnp/schema-loader.c++ \
src/capnp/dynamic.c++ \
src/capnp/stringify.c++ \
src/capnp/serialize.c++ \
src/capnp/serialize-packed.c++
nodist_libcapnproto_a_SOURCES = \
src/capnproto/schema.capnp.c++
src/capnp/schema.capnp.c++
# Source files intentionally not included in the dist at this time:
# src/capnproto/serialize-snappy*
# src/capnproto/benchmark/...
# src/capnproto/compiler/...
# src/capnp/serialize-snappy*
# src/capnp/benchmark/...
# src/capnp/compiler/...
# Tests ==============================================================
test_capnpc_inputs = \
src/capnproto/test.capnp \
src/capnproto/test-import.capnp
src/capnp/test.capnp \
src/capnp/test-import.capnp
test_capnpc_outputs = \
src/capnproto/test.capnp.c++ \
src/capnproto/test.capnp.h \
src/capnproto/test-import.capnp.c++ \
src/capnproto/test-import.capnp.h
src/capnp/test.capnp.c++ \
src/capnp/test.capnp.h \
src/capnp/test-import.capnp.c++ \
src/capnp/test-import.capnp.h
# This should depend on $(test_capnpc_inputs), but then make mysteriously complains
# about a cyclic dependency. I don't know where it is coming from. I rummaged
......@@ -155,18 +156,21 @@ capnproto_test_SOURCES = \
src/kj/string-test.c++ \
src/kj/debug-test.c++ \
src/kj/units-test.c++ \
src/capnproto/blob-test.c++ \
src/capnproto/layout-test.c++ \
src/capnproto/message-test.c++ \
src/capnproto/schema-test.c++ \
src/capnproto/schema-loader-test.c++ \
src/capnproto/dynamic-test.c++ \
src/capnproto/stringify-test.c++ \
src/capnproto/encoding-test.c++ \
src/capnproto/serialize-test.c++ \
src/capnproto/serialize-packed-test.c++ \
src/capnproto/test-util.c++ \
src/capnproto/test-util.h
src/capnp/blob-test.c++ \
src/capnp/endian-test.c++ \
src/capnp/endian-fallback-test.c++ \
src/capnp/endian-reverse-test.c++ \
src/capnp/layout-test.c++ \
src/capnp/message-test.c++ \
src/capnp/schema-test.c++ \
src/capnp/schema-loader-test.c++ \
src/capnp/dynamic-test.c++ \
src/capnp/stringify-test.c++ \
src/capnp/encoding-test.c++ \
src/capnp/serialize-test.c++ \
src/capnp/serialize-packed-test.c++ \
src/capnp/test-util.c++ \
src/capnp/test-util.h
nodist_capnproto_test_SOURCES = $(test_capnpc_outputs)
TESTS = capnproto-test
......@@ -3,7 +3,7 @@
# autoconf can't handle apostrophes in names...
AC_INIT([Capn Proto],[0.1.0],[capnproto@googlegroups.com],[capnproto])
AC_CONFIG_SRCDIR([src/capnproto/layout.c++])
AC_CONFIG_SRCDIR([src/capnp/layout.c++])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
......
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test that the shift-based implementation of WireValue works.
#define CAPNP_DISABLE_ENDIAN_DETECTION 1
#include "endian-test.c++"
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test that the code for the opposite endianness of our CPU works. E.g. on x86 this will test
// the bswap-based code.
#define CAPNP_REVERSE_ENDIAN 1
#include "endian.h"
#include <gtest/gtest.h>
namespace capnp {
namespace _ { // private
namespace {
TEST(EndianReverse, Byte) {
byte bytes[] = {123, 45, 67, 89};
WireValue<uint8_t>* vals = reinterpret_cast<WireValue<uint8_t>*>(bytes);
EXPECT_EQ(123, vals[0].get());
EXPECT_EQ(45, vals[1].get());
EXPECT_EQ(67, vals[2].get());
EXPECT_EQ(89, vals[3].get());
vals[0].set(21);
vals[1].set(43);
vals[2].set(65);
vals[3].set(87);
EXPECT_EQ(21, bytes[0]);
EXPECT_EQ(43, bytes[1]);
EXPECT_EQ(65, bytes[2]);
EXPECT_EQ(87, bytes[3]);
}
TEST(EndianReverse, TwoBytes) {
byte bytes[] = {0x12, 0x34, 0x56, 0x78};
WireValue<uint16_t>* vals = reinterpret_cast<WireValue<uint16_t>*>(bytes);
EXPECT_EQ(0x1234, vals[0].get());
EXPECT_EQ(0x5678, vals[1].get());
vals[0].set(0x2345);
vals[1].set(0x6789);
EXPECT_EQ(0x23, bytes[0]);
EXPECT_EQ(0x45, bytes[1]);
EXPECT_EQ(0x67, bytes[2]);
EXPECT_EQ(0x89, bytes[3]);
}
TEST(EndianReverse, FourBytes) {
byte bytes[] = {0x12, 0x34, 0x56, 0x78};
WireValue<uint32_t>* vals = reinterpret_cast<WireValue<uint32_t>*>(bytes);
EXPECT_EQ(0x12345678, vals[0].get());
vals[0].set(0x23456789);
EXPECT_EQ(0x23, bytes[0]);
EXPECT_EQ(0x45, bytes[1]);
EXPECT_EQ(0x67, bytes[2]);
EXPECT_EQ(0x89, bytes[3]);
}
TEST(EndianReverse, EightBytes) {
byte bytes[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
WireValue<uint64_t>* vals = reinterpret_cast<WireValue<uint64_t>*>(bytes);
EXPECT_EQ(0x123456789abcdef0, vals[0].get());
vals[0].set(0x23456789abcdef01);
EXPECT_EQ(0x23, bytes[0]);
EXPECT_EQ(0x45, bytes[1]);
EXPECT_EQ(0x67, bytes[2]);
EXPECT_EQ(0x89, bytes[3]);
EXPECT_EQ(0xab, bytes[4]);
EXPECT_EQ(0xcd, bytes[5]);
EXPECT_EQ(0xef, bytes[6]);
EXPECT_EQ(0x01, bytes[7]);
}
} // namespace
} // namespace _ (private)
} // namespace capnp
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "endian.h"
#include <gtest/gtest.h>
namespace capnp {
namespace _ { // private
namespace {
#if CAPNP_DISABLE_ENDIAN_DETECTION
#define Endian EndianUnoptimized
#endif
TEST(Endian, Byte) {
byte bytes[] = {123, 45, 67, 89};
WireValue<uint8_t>* vals = reinterpret_cast<WireValue<uint8_t>*>(bytes);
EXPECT_EQ(123, vals[0].get());
EXPECT_EQ(45, vals[1].get());
EXPECT_EQ(67, vals[2].get());
EXPECT_EQ(89, vals[3].get());
vals[0].set(21);
vals[1].set(43);
vals[2].set(65);
vals[3].set(87);
EXPECT_EQ(21, bytes[0]);
EXPECT_EQ(43, bytes[1]);
EXPECT_EQ(65, bytes[2]);
EXPECT_EQ(87, bytes[3]);
}
TEST(Endian, TwoBytes) {
byte bytes[] = {0x12, 0x34, 0x56, 0x78};
WireValue<uint16_t>* vals = reinterpret_cast<WireValue<uint16_t>*>(bytes);
EXPECT_EQ(0x3412, vals[0].get());
EXPECT_EQ(0x7856, vals[1].get());
vals[0].set(0x2345);
vals[1].set(0x6789);
EXPECT_EQ(0x45, bytes[0]);
EXPECT_EQ(0x23, bytes[1]);
EXPECT_EQ(0x89, bytes[2]);
EXPECT_EQ(0x67, bytes[3]);
}
TEST(Endian, FourBytes) {
byte bytes[] = {0x12, 0x34, 0x56, 0x78};
WireValue<uint32_t>* vals = reinterpret_cast<WireValue<uint32_t>*>(bytes);
EXPECT_EQ(0x78563412, vals[0].get());
vals[0].set(0x23456789);
EXPECT_EQ(0x89, bytes[0]);
EXPECT_EQ(0x67, bytes[1]);
EXPECT_EQ(0x45, bytes[2]);
EXPECT_EQ(0x23, bytes[3]);
}
TEST(Endian, EightBytes) {
byte bytes[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
WireValue<uint64_t>* vals = reinterpret_cast<WireValue<uint64_t>*>(bytes);
EXPECT_EQ(0xf0debc9a78563412, vals[0].get());
vals[0].set(0x23456789abcdef01);
EXPECT_EQ(0x01, bytes[0]);
EXPECT_EQ(0xef, bytes[1]);
EXPECT_EQ(0xcd, bytes[2]);
EXPECT_EQ(0xab, bytes[3]);
EXPECT_EQ(0x89, bytes[4]);
EXPECT_EQ(0x67, bytes[5]);
EXPECT_EQ(0x45, bytes[6]);
EXPECT_EQ(0x23, bytes[7]);
}
} // namespace
} // namespace _ (private)
} // namespace capnp
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CAPNP_ENDIAN_H_
#define CAPNP_ENDIAN_H_
#include "common.h"
#include <inttypes.h>
#include <string.h> // memcpy
namespace capnp {
namespace _ { // private
// WireValue
//
// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the
// wire, because little-endian is the most common endianness in modern CPUs.
//
// Note: In general, code that depends cares about byte ordering is bad. See:
// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over
// allocation and layout of memory, in order to squeeze out every last drop of performance.
#if CAPNP_REVERSE_ENDIAN
#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
#else
#define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
#endif
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER) && !CAPNP_DISABLE_ENDIAN_DETECTION
// CPU is little-endian. We can just read/write the memory directly.
template <typename T>
class WireValue {
public:
KJ_ALWAYS_INLINE(T get() const) { return value; }
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
private:
T value;
};
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION
// Big-endian, but GCC's __builtin_bswap() is available.
// TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have
// them.
// TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the
// compiler optimizes away the memcpy()s and keeps everything in registers.
template <typename T, size_t size = sizeof(T)>
class WireValue;
template <typename T>
class WireValue<T, 1> {
public:
KJ_ALWAYS_INLINE(T get() const) { return value; }
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
private:
T value;
};
template <typename T>
class WireValue<T, 2> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint16_t swapped = __builtin_bswap16(value);
T result;
memcpy(&result, &swapped, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint16_t raw;
memcpy(&raw, &newValue, sizeof(T));
value = __builtin_bswap16(raw);
}
private:
uint16_t value;
};
template <typename T>
class WireValue<T, 4> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint32_t swapped = __builtin_bswap32(value);
T result;
memcpy(&result, &swapped, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint32_t raw;
memcpy(&raw, &newValue, sizeof(T));
value = __builtin_bswap32(raw);
}
private:
uint32_t value;
};
template <typename T>
class WireValue<T, 8> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint64_t swapped = __builtin_bswap64(value);
T result;
memcpy(&result, &swapped, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint64_t raw;
memcpy(&raw, &newValue, sizeof(T));
value = __builtin_bswap64(raw);
}
private:
uint64_t value;
};
#else
// Unknown endianness. Fall back to bit shifts.
template <typename T, size_t size = sizeof(T)>
class WireValue;
template <typename T>
class WireValue<T, 1> {
public:
KJ_ALWAYS_INLINE(T get() const) { return value; }
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
private:
T value;
};
template <typename T>
class WireValue<T, 2> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint16_t raw = (static_cast<uint16_t>(bytes[0]) ) |
(static_cast<uint16_t>(bytes[1]) << 8);
T result;
memcpy(&result, &raw, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint16_t raw;
memcpy(&raw, &newValue, sizeof(T));
bytes[0] = raw;
bytes[1] = raw >> 8;
}
private:
union {
byte bytes[2];
uint16_t align;
};
};
template <typename T>
class WireValue<T, 4> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint32_t raw = (static_cast<uint32_t>(bytes[0]) ) |
(static_cast<uint32_t>(bytes[1]) << 8) |
(static_cast<uint32_t>(bytes[2]) << 16) |
(static_cast<uint32_t>(bytes[3]) << 24);
T result;
memcpy(&result, &raw, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint32_t raw;
memcpy(&raw, &newValue, sizeof(T));
bytes[0] = raw;
bytes[1] = raw >> 8;
bytes[2] = raw >> 16;
bytes[3] = raw >> 24;
}
private:
union {
byte bytes[4];
uint32_t align;
};
};
template <typename T>
class WireValue<T, 8> {
public:
KJ_ALWAYS_INLINE(T get() const) {
uint64_t raw = (static_cast<uint64_t>(bytes[0]) ) |
(static_cast<uint64_t>(bytes[1]) << 8) |
(static_cast<uint64_t>(bytes[2]) << 16) |
(static_cast<uint64_t>(bytes[3]) << 24) |
(static_cast<uint64_t>(bytes[4]) << 32) |
(static_cast<uint64_t>(bytes[5]) << 40) |
(static_cast<uint64_t>(bytes[6]) << 48) |
(static_cast<uint64_t>(bytes[7]) << 56);
T result;
memcpy(&result, &raw, sizeof(T));
return result;
}
KJ_ALWAYS_INLINE(void set(T newValue)) {
uint64_t raw;
memcpy(&raw, &newValue, sizeof(T));
bytes[0] = raw;
bytes[1] = raw >> 8;
bytes[2] = raw >> 16;
bytes[3] = raw >> 24;
bytes[4] = raw >> 32;
bytes[5] = raw >> 40;
bytes[6] = raw >> 48;
bytes[7] = raw >> 56;
}
private:
union {
byte bytes[8];
uint64_t align;
};
};
#endif
} // namespace _ (private)
} // namespace capnp
#endif // CAPNP_ENDIAN_H_
......@@ -34,6 +34,7 @@
#include <kj/common.h>
#include "common.h"
#include "blob.h"
#include "endian.h"
namespace capnp {
namespace _ { // private
......@@ -265,30 +266,7 @@ inline double unmask<double>(uint64_t value, uint64_t mask) {
// -------------------------------------------------------------------
template <typename T>
class WireValue {
// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the
// wire, because little-endian is the most common endianness in modern CPUs.
//
// TODO(soon): On big-endian systems, inject byte-swapping here. Most big-endian CPUs implement
// dedicated instructions for this, so use those rather than writing a bunch of shifts and
// masks. Note that GCC has e.g. __builtin__bswap32() for this.
//
// Note: In general, code that depends cares about byte ordering is bad. See:
// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over
// allocation and layout of memory, in order to squeeze out every last drop of performance.
public:
WireValue() = default;
KJ_ALWAYS_INLINE(WireValue(T value)): value(value) {}
KJ_ALWAYS_INLINE(T get() const) { return value; }
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
private:
T value;
};
// -------------------------------------------------------------------
class StructBuilder: public kj::DisallowConstCopy {
public:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment