Commit 36a60467 authored by Kenton Varda's avatar Kenton Varda

Moar type-safety, rewriting WireFormat to avoid descriptors (incomplete),…

Moar type-safety, rewriting WireFormat to avoid descriptors (incomplete), decided struct pointers should point at the beginning of the struct after all.
parent dd46a758
......@@ -31,8 +31,8 @@ namespace {
const int READONLY_SEGMENT_START = 123;
const FieldDescriptor TEST_FIELDS[2] = {
{ WordCount8(1 * WORDS), 0, 0, FieldSize::FOUR_BYTES, 1, 0, 0, 0 },
{ WordCount8(1 * WORDS), 1, 0, FieldSize::REFERENCE, 1, 0, 0, 0 }
{ 1 * WORDS, 0, 0, FieldSize::FOUR_BYTES, 1, 0, 0, 0 },
{ 1 * WORDS, 1, 0, FieldSize::REFERENCE, 1, 0, 0, 0 }
};
extern const StructDescriptor TEST_STRUCT;
......
This diff is collapsed.
......@@ -25,175 +25,17 @@
#define CAPNPROTO_MACROS_H_
#include <inttypes.h>
#include "unit.h"
namespace capnproto {
// TODO: Rename file "common.h" since it's no longer just macros.
#define CAPNPROTO_DISALLOW_COPY(classname) \
classname(const classname&) = delete; \
classname& operator=(const classname&) = delete
typedef unsigned int uint;
class byte { uint8_t content; CAPNPROTO_DISALLOW_COPY(byte); };
class word { uint64_t content; CAPNPROTO_DISALLOW_COPY(word); };
// byte and word are opaque types with sizes of 8 and 64 bits, respectively. These types are useful
// only to make pointer arithmetic clearer. Since the contents are private, the only way to access
// them is to first reinterpret_cast to some other pointer type.
//
// Coping is disallowed because you should always use memcpy(). Otherwise, you may run afoul of
// aliasing rules (particularly when copying words).
//
// A pointer of type word* should always be word-aligned even if won't actually be dereferenced as
// that type.
static_assert(sizeof(byte) == 1, "uint8_t is not one byte?");
static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?");
namespace internal { class bit; }
#ifdef __CDT_PARSER__
// Eclipse gets confused by decltypes, so we'll feed it these simplified-yet-compatible definitions.
//
// We could also consider using these definitions in opt builds. Trouble is, the mangled symbol
// names of any functions that take these types as inputs would be affected, so it would be
// important to compile the Cap'n Proto library and the client app with the same flags.
typedef uint BitCount;
typedef uint8_t BitCount8;
typedef uint16_t BitCount16;
typedef uint32_t BitCount32;
typedef uint64_t BitCount64;
typedef uint ByteCount;
typedef uint8_t ByteCount8;
typedef uint16_t ByteCount16;
typedef uint32_t ByteCount32;
typedef uint64_t ByteCount64;
typedef uint WordCount;
typedef uint8_t WordCount8;
typedef uint16_t WordCount16;
typedef uint32_t WordCount32;
typedef uint64_t WordCount64;
constexpr BitCount BITS = 1;
constexpr ByteCount BYTES = 1;
constexpr WordCount WORDS = 1;
constexpr uint BITS_PER_BYTE = 8;
constexpr uint BITS_PER_WORD = 64;
constexpr uint BYTES_PER_WORD = 8;
#else
typedef UnitMeasure<uint, internal::bit> BitCount;
typedef UnitMeasure<uint8_t, internal::bit> BitCount8;
typedef UnitMeasure<uint16_t, internal::bit> BitCount16;
typedef UnitMeasure<uint32_t, internal::bit> BitCount32;
typedef UnitMeasure<uint64_t, internal::bit> BitCount64;
typedef UnitMeasure<uint, byte> ByteCount;
typedef UnitMeasure<uint8_t, byte> ByteCount8;
typedef UnitMeasure<uint16_t, byte> ByteCount16;
typedef UnitMeasure<uint32_t, byte> ByteCount32;
typedef UnitMeasure<uint64_t, byte> ByteCount64;
typedef UnitMeasure<uint, word> WordCount;
typedef UnitMeasure<uint8_t, word> WordCount8;
typedef UnitMeasure<uint16_t, word> WordCount16;
typedef UnitMeasure<uint32_t, word> WordCount32;
typedef UnitMeasure<uint64_t, word> WordCount64;
constexpr BitCount BITS = BitCount::ONE;
constexpr ByteCount BYTES = ByteCount::ONE;
constexpr WordCount WORDS = WordCount::ONE;
constexpr UnitRatio<uint, internal::bit, byte> BITS_PER_BYTE(8);
constexpr UnitRatio<uint, internal::bit, word> BITS_PER_WORD(64);
constexpr UnitRatio<uint, byte, word> BYTES_PER_WORD(8);
template <typename T>
inline constexpr byte* operator+(byte* ptr, UnitMeasure<T, byte> offset) {
return ptr + offset / BYTES;
}
template <typename T>
inline constexpr const byte* operator+(const byte* ptr, UnitMeasure<T, byte> offset) {
return ptr + offset / BYTES;
}
template <typename T>
inline constexpr byte* operator+=(byte*& ptr, UnitMeasure<T, byte> offset) {
return ptr = ptr + offset / BYTES;
}
template <typename T>
inline constexpr const byte* operator+=(const byte* ptr, UnitMeasure<T, byte> offset) {
return ptr = ptr + offset / BYTES;
}
template <typename T>
inline constexpr word* operator+(word* ptr, UnitMeasure<T, word> offset) {
return ptr + offset / WORDS;
}
template <typename T>
inline constexpr const word* operator+(const word* ptr, UnitMeasure<T, word> offset) {
return ptr + offset / WORDS;
}
template <typename T>
inline constexpr word* operator+=(word*& ptr, UnitMeasure<T, word> offset) {
return ptr = ptr + offset / WORDS;
}
template <typename T>
inline constexpr const word* operator+=(const word*& ptr, UnitMeasure<T, word> offset) {
return ptr = ptr + offset / WORDS;
}
template <typename T>
inline constexpr byte* operator-(byte* ptr, UnitMeasure<T, byte> offset) {
return ptr - offset / BYTES;
}
template <typename T>
inline constexpr const byte* operator-(const byte* ptr, UnitMeasure<T, byte> offset) {
return ptr - offset / BYTES;
}
template <typename T>
inline constexpr byte* operator-=(byte*& ptr, UnitMeasure<T, byte> offset) {
return ptr = ptr - offset / BYTES;
}
template <typename T>
inline constexpr const byte* operator-=(const byte* ptr, UnitMeasure<T, byte> offset) {
return ptr = ptr - offset / BYTES;
}
template <typename T>
inline constexpr word* operator-(word* ptr, UnitMeasure<T, word> offset) {
return ptr - offset / WORDS;
}
template <typename T>
inline constexpr const word* operator-(const word* ptr, UnitMeasure<T, word> offset) {
return ptr - offset / WORDS;
}
template <typename T>
inline constexpr word* operator-=(word*& ptr, UnitMeasure<T, word> offset) {
return ptr = ptr - offset / WORDS;
}
template <typename T>
inline constexpr const word* operator-=(const word*& ptr, UnitMeasure<T, word> offset) {
return ptr = ptr - offset / WORDS;
}
#endif
inline constexpr ByteCount intervalLength(const byte* a, const byte* b) {
return uint(b - a) * BYTES;
}
inline constexpr WordCount intervalLength(const word* a, const word* b) {
return uint(b - a) * WORDS;
}
namespace internal {
#define CAPNPROTO_OFFSETOF(type, member) __builtin_offsetof(type, member)
#define CAPNPROTO_EXPECT_TRUE(condition) __builtin_expect(condition, true)
#define CAPNPROTO_EXPECT_FALSE(condition) __builtin_expect(condition, false)
// Branch prediction macros. Evaluates to the condition given, but also tells the compiler that we
......@@ -206,19 +48,18 @@ namespace internal {
void assertionFailure(const char* file, int line, const char* expectation, const char* message)
__attribute__((noreturn));
#define CAPNPROTO_ASSERT(condition, message) \
if (CAPNPROTO_EXPECT_TRUE(condition)); else ::capnproto::internal::assertionFailure(\
__FILE__, __LINE__, #condition, message)
// CAPNPROTO_ASSERT is just like assert() except it avoids polluting the global namespace with an
// unqualified macro name and it throws an exception (derived from std::exception).
#ifdef NDEBUG
#define CAPNPROTO_DEBUG_ASSERT(condition, message)
#else
#define CAPNPROTO_DEBUG_ASSERT(condition, message) \
if (CAPNPROTO_EXPECT_TRUE(condition)); else ::capnproto::internal::assertionFailure(\
__FILE__, __LINE__, #condition, message)
#define CAPNPROTO_DEBUG_ASSERT(condition, message) CAPNPROTO_ASSERT(condition, message)
#endif
#define CAPNPROTO_ASSERT(condition, message) \
::capnproto::internal::assertionFailure(__FILE__, __LINE__, #condition, message)
} // namespace internal
template <typename T, typename U>
......
......@@ -23,6 +23,7 @@
#include <cstddef>
#include "macros.h"
#include "type-safety.h"
#ifndef CAPNPROTO_MESSAGE_H_
#define CAPNPROTO_MESSAGE_H_
......@@ -35,21 +36,7 @@ class MessageReader;
class MessageBuilder;
class ReadLimiter;
struct SegmentId {
// TODO: Generalize this. class Id<Base, Type>.
uint32_t number;
inline constexpr SegmentId(): number(0) {}
inline constexpr explicit SegmentId(int number): number(number) {}
inline constexpr bool operator==(const SegmentId& other) { return number == other.number; }
inline constexpr bool operator!=(const SegmentId& other) { return number != other.number; }
inline constexpr bool operator<=(const SegmentId& other) { return number <= other.number; }
inline constexpr bool operator>=(const SegmentId& other) { return number >= other.number; }
inline constexpr bool operator< (const SegmentId& other) { return number < other.number; }
inline constexpr bool operator> (const SegmentId& other) { return number > other.number; }
};
typedef Id<uint32_t, SegmentReader> SegmentId;
class MessageReader {
// Abstract interface encapsulating a readable message. By implementing this interface, you can
......@@ -82,6 +69,10 @@ public:
//
// As with reportInvalidData(), this may throw an exception, and if it doesn't, default values
// will be used in place of the actual message data.
//
// If this method returns rather that throwing, many other errors are likely to be reported as
// a side-effect of reading being blocked. The MessageReader should ignore all further errors
// after this call.
// TODO: Methods to deal with bundled capabilities.
};
......@@ -122,10 +113,12 @@ public:
inline explicit ReadLimiter(); // No limit.
inline explicit ReadLimiter(WordCount64 limit); // Limit to the given number of words.
inline bool canRead(WordCount amount);
CAPNPROTO_ALWAYS_INLINE(bool canRead(WordCount amount, MessageReader* message));
private:
WordCount64 limit;
CAPNPROTO_DISALLOW_COPY(ReadLimiter);
};
class SegmentReader {
......@@ -133,8 +126,7 @@ public:
inline SegmentReader(MessageReader* message, SegmentId id, const word ptr[], WordCount size,
ReadLimiter* readLimiter);
CAPNPROTO_ALWAYS_INLINE(const word* getPtrChecked(
WordCount offset, WordCount before, WordCount after));
CAPNPROTO_ALWAYS_INLINE(bool containsInterval(const word* from, const word* to));
inline MessageReader* getMessage();
inline SegmentId getSegmentId();
......@@ -150,8 +142,7 @@ private:
const word* start;
ReadLimiter* readLimiter;
SegmentReader(const SegmentReader& other) = delete;
SegmentReader& operator=(const SegmentReader& other) = delete;
CAPNPROTO_DISALLOW_COPY(SegmentReader);
friend class SegmentBuilder;
};
......@@ -170,8 +161,7 @@ private:
word* end;
ReadLimiter dummyLimiter;
SegmentBuilder(const SegmentBuilder& other) = delete;
SegmentBuilder& operator=(const SegmentBuilder& other) = delete;
CAPNPROTO_DISALLOW_COPY(SegmentBuilder);
// TODO: Do we need mutex locking?
};
......@@ -184,8 +174,9 @@ inline ReadLimiter::ReadLimiter()
inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(limit) {}
inline bool ReadLimiter::canRead(WordCount amount) {
if (amount > limit) {
inline bool ReadLimiter::canRead(WordCount amount, MessageReader* message) {
if (CAPNPROTO_EXPECT_FALSE(amount > limit)) {
message->reportReadLimitReached();
return false;
} else {
limit -= amount;
......@@ -199,22 +190,9 @@ inline SegmentReader::SegmentReader(MessageReader* message, SegmentId id, const
WordCount size, ReadLimiter* readLimiter)
: message(message), id(id), size(size), start(ptr), readLimiter(readLimiter) {}
inline const word* SegmentReader::getPtrChecked(
WordCount offset, WordCount before, WordCount after) {
// Check bounds. Watch out for overflow and underflow here.
if (offset > size ||
before > offset ||
after > size - offset) {
return nullptr;
} else {
// Enforce the read limit. Synchronization is not necessary because readLimit is just a rough
// counter to prevent infinite loops leading to DoS attacks.
if (CAPNPROTO_EXPECT_FALSE(!readLimiter->canRead(before + after))) {
message->reportReadLimitReached();
}
return start + offset;
}
inline bool SegmentReader::containsInterval(const word* from, const word* to) {
return from >= this->start && to <= this->start + size &&
readLimiter->canRead(intervalLength(from, to), message);
}
inline MessageReader* SegmentReader::getMessage() { return message; }
......
......@@ -21,7 +21,7 @@
// (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 "unit.h"
#include "type-safety.h"
#include <gtest/gtest.h>
#include <iostream>
......@@ -32,21 +32,21 @@ class Bytes;
class KiB;
class MiB;
typedef UnitMeasure<int, Bytes> ByteCount;
typedef UnitMeasure<int, KiB> KiBCount;
typedef UnitMeasure<int, MiB> MiBCount;
typedef Quantity<int, Bytes> ByteCount;
typedef Quantity<int, KiB> KiBCount;
typedef Quantity<int, MiB> MiBCount;
constexpr ByteCount BYTE = ByteCount::ONE;
constexpr KiBCount KIB = KiBCount::ONE;
constexpr MiBCount MIB = MiBCount::ONE;
constexpr ByteCount BYTE = unit<ByteCount>();
constexpr KiBCount KIB = unit<KiBCount>();
constexpr MiBCount MIB = unit<MiBCount>();
constexpr UnitRatio<int, Bytes, KiB> BYTES_PER_KIB(1024);
constexpr UnitRatio<int, Bytes, MiB> BYTES_PER_MIB(1024*1024);
constexpr UnitRatio<int, KiB, MiB> KIB_PER_MIB(1024);
constexpr UnitRatio<int, Bytes, KiB> BYTES_PER_KIB = 1024 * BYTE / KIB;
constexpr UnitRatio<int, Bytes, MiB> BYTES_PER_MIB = 1024 * 1024 * BYTE / MIB;
constexpr auto KIB_PER_MIB = 1024 * KIB / MIB;
template <typename T, typename U>
std::ostream& operator<<(std::ostream& os, UnitMeasure<T, U> value) {
return os << (value / UnitMeasure<T, U>::ONE);
std::ostream& operator<<(std::ostream& os, Quantity<T, U> value) {
return os << (value / unit<Quantity<T, U>>());
}
TEST(UnitMeasure, Basics) {
......
......@@ -21,7 +21,7 @@
// (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 "unit.h"
#include "type-safety.h"
namespace capnproto {
......
This diff is collapsed.
// 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 CAPNPROTO_UNIT_H_
#define CAPNPROTO_UNIT_H_
namespace capnproto {
template <typename Number, typename Unit1, typename Unit2>
class UnitRatio {
public:
constexpr UnitRatio(Number unit1PerUnit2): unit1PerUnit2(unit1PerUnit2) {}
Number unit1PerUnit2;
};
template <typename T>
T any();
template <typename Number, typename Unit>
class UnitMeasure {
public:
inline constexpr UnitMeasure() {}
template <typename OtherNumber>
inline constexpr UnitMeasure(const UnitMeasure<OtherNumber, Unit>& other)
: value(other.value) {}
static constexpr UnitMeasure ONE = UnitMeasure(1);
template <typename OtherNumber>
inline constexpr auto operator+(const UnitMeasure<OtherNumber, Unit>& other) const
-> UnitMeasure<decltype(any<Number>() + any<OtherNumber>()), Unit> {
return UnitMeasure<decltype(any<Number>() + any<OtherNumber>()), Unit>(value + other.value);
}
template <typename OtherNumber>
inline constexpr auto operator-(const UnitMeasure<OtherNumber, Unit>& other) const
-> UnitMeasure<decltype(any<Number>() - any<OtherNumber>()), Unit> {
return UnitMeasure<decltype(any<Number>() - any<OtherNumber>()), Unit>(value - other.value);
}
template <typename OtherNumber>
inline constexpr auto operator*(OtherNumber other) const
-> UnitMeasure<decltype(any<Number>() * other), Unit> {
return UnitMeasure<decltype(any<Number>() * other), Unit>(value * other);
}
template <typename OtherNumber>
inline constexpr auto operator/(OtherNumber other) const
-> UnitMeasure<decltype(any<Number>() / other), Unit> {
return UnitMeasure<decltype(any<Number>() / other), Unit>(value / other);
}
template <typename OtherNumber>
inline constexpr auto operator/(const UnitMeasure<OtherNumber, Unit>& other) const
-> decltype(any<Number>() / any<OtherNumber>()) {
return value / other.value;
}
template <typename OtherNumber>
inline constexpr auto operator%(const UnitMeasure<OtherNumber, Unit>& other) const
-> decltype(any<Number>() % any<OtherNumber>()) {
return value % other.value;
}
template <typename OtherNumber, typename OtherUnit>
inline constexpr auto operator*(const UnitRatio<OtherNumber, OtherUnit, Unit>& ratio) const
-> UnitMeasure<decltype(any<Number>() * any<OtherNumber>()), OtherUnit> {
return UnitMeasure<decltype(any<Number>() * any<OtherNumber>()), OtherUnit>(
value * ratio.unit1PerUnit2);
}
template <typename OtherNumber, typename OtherUnit>
inline constexpr auto operator/(const UnitRatio<OtherNumber, Unit, OtherUnit>& ratio) const
-> UnitMeasure<decltype(any<Number>() / any<OtherNumber>()), OtherUnit> {
return UnitMeasure<decltype(any<Number>() / any<OtherNumber>()), OtherUnit>(
value / ratio.unit1PerUnit2);
}
template <typename OtherNumber, typename OtherUnit>
inline constexpr auto operator%(const UnitRatio<OtherNumber, Unit, OtherUnit>& ratio) const
-> UnitMeasure<decltype(any<Number>() % any<OtherNumber>()), Unit> {
return UnitMeasure<decltype(any<Number>() % any<OtherNumber>()), Unit>(
value % ratio.unit1PerUnit2);
}
template <typename OtherNumber>
inline constexpr bool operator==(const UnitMeasure<OtherNumber, Unit>& other) const {
return value == other.value;
}
template <typename OtherNumber>
inline constexpr bool operator!=(const UnitMeasure<OtherNumber, Unit>& other) const {
return value != other.value;
}
template <typename OtherNumber>
inline constexpr bool operator<=(const UnitMeasure<OtherNumber, Unit>& other) const {
return value <= other.value;
}
template <typename OtherNumber>
inline constexpr bool operator>=(const UnitMeasure<OtherNumber, Unit>& other) const {
return value >= other.value;
}
template <typename OtherNumber>
inline constexpr bool operator<(const UnitMeasure<OtherNumber, Unit>& other) const {
return value < other.value;
}
template <typename OtherNumber>
inline constexpr bool operator>(const UnitMeasure<OtherNumber, Unit>& other) const {
return value > other.value;
}
template <typename OtherNumber>
inline UnitMeasure& operator+=(const UnitMeasure<OtherNumber, Unit>& other) {
value += other.value;
return *this;
}
template <typename OtherNumber>
inline UnitMeasure& operator-=(const UnitMeasure<OtherNumber, Unit>& other) {
value -= other.value;
return *this;
}
template <typename OtherNumber>
inline UnitMeasure& operator*=(OtherNumber other) {
value *= other;
return *this;
}
template <typename OtherNumber>
inline UnitMeasure& operator/=(OtherNumber other) {
value /= other.value;
return *this;
}
private:
inline explicit constexpr UnitMeasure(Number value): value(value) {}
Number value;
template <typename OtherNumber, typename OtherUnit>
friend class UnitMeasure;
template <typename Number1, typename Number2, typename Unit2>
friend inline constexpr auto operator*(Number1 a, UnitMeasure<Number2, Unit2> b)
-> UnitMeasure<decltype(any<Number1>() * any<Number2>()), Unit2>;
};
template <typename Number, typename Unit>
constexpr UnitMeasure<Number, Unit> UnitMeasure<Number, Unit>::ONE;
template <typename Number1, typename Number2, typename Unit>
inline constexpr auto operator*(Number1 a, UnitMeasure<Number2, Unit> b)
-> UnitMeasure<decltype(any<Number1>() * any<Number2>()), Unit> {
return UnitMeasure<decltype(any<Number1>() * any<Number2>()), Unit>(a * b.value);
}
template <typename Number1, typename Number2, typename Unit, typename Unit2>
inline constexpr auto operator*(UnitRatio<Number1, Unit2, Unit> ratio,
UnitMeasure<Number2, Unit> measure)
-> decltype(measure * ratio) {
return measure * ratio;
}
} // namespace capnproto
#endif // CAPNPROTO_UNIT_H_
This diff is collapsed.
This diff is collapsed.
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