Commit 7b187dbd authored by Kenton Varda's avatar Kenton Varda

More benchmark updates, delete unused descriptor code.

parent 4dd3161d
...@@ -93,6 +93,8 @@ void randomCar(Car::Builder car) { ...@@ -93,6 +93,8 @@ void randomCar(Car::Builder car) {
engine.setHorsepower(100 * fastRand(400)); engine.setHorsepower(100 * fastRand(400));
engine.setCylinders(4 + 2 * fastRand(3)); engine.setCylinders(4 + 2 * fastRand(3));
engine.setCc(800 + fastRand(10000)); engine.setCc(800 + fastRand(10000));
engine.setUsesGas(true);
engine.setUsesElectric(fastRand(2));
car.setFuelCapacity(10.0 + fastRandDouble(30.0)); car.setFuelCapacity(10.0 + fastRandDouble(30.0));
car.setFuelLevel(fastRandDouble(car.getFuelCapacity())); car.setFuelLevel(fastRandDouble(car.getFuelCapacity()));
......
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
#include "common.h" #include "common.h"
#include <capnproto/serialize.h> #include <capnproto/serialize.h>
#include <capnproto/serialize-packed.h> #include <capnproto/serialize-packed.h>
#if HAVE_SNAPPY
#include <capnproto/serialize-snappy.h> #include <capnproto/serialize-snappy.h>
#endif // HAVE_SNAPPY
#include <thread> #include <thread>
namespace capnproto { namespace capnproto {
...@@ -96,6 +98,7 @@ struct Packed { ...@@ -96,6 +98,7 @@ struct Packed {
} }
}; };
#if HAVE_SNAPPY
static byte snappyReadBuffer[SNAPPY_BUFFER_SIZE]; static byte snappyReadBuffer[SNAPPY_BUFFER_SIZE];
static byte snappyWriteBuffer[SNAPPY_BUFFER_SIZE]; static byte snappyWriteBuffer[SNAPPY_BUFFER_SIZE];
static byte snappyCompressedBuffer[SNAPPY_COMPRESSED_BUFFER_SIZE]; static byte snappyCompressedBuffer[SNAPPY_COMPRESSED_BUFFER_SIZE];
...@@ -120,6 +123,7 @@ struct SnappyCompressed { ...@@ -120,6 +123,7 @@ struct SnappyCompressed {
arrayPtr(snappyCompressedBuffer, SNAPPY_COMPRESSED_BUFFER_SIZE)); arrayPtr(snappyCompressedBuffer, SNAPPY_COMPRESSED_BUFFER_SIZE));
} }
}; };
#endif // HAVE_SNAPPY
// ======================================================================================= // =======================================================================================
...@@ -395,7 +399,9 @@ struct BenchmarkMethods { ...@@ -395,7 +399,9 @@ struct BenchmarkMethods {
struct BenchmarkTypes { struct BenchmarkTypes {
typedef capnp::Uncompressed Uncompressed; typedef capnp::Uncompressed Uncompressed;
typedef capnp::Packed Packed; typedef capnp::Packed Packed;
#if HAVE_SNAPPY
typedef capnp::SnappyCompressed SnappyCompressed; typedef capnp::SnappyCompressed SnappyCompressed;
#endif // HAVE_SNAPPY
typedef capnp::UseScratch ReusableResources; typedef capnp::UseScratch ReusableResources;
typedef capnp::NoScratch SingleUseResources; typedef capnp::NoScratch SingleUseResources;
......
...@@ -254,9 +254,11 @@ uint64_t doBenchmark3(const std::string& mode, const std::string& reuse, ...@@ -254,9 +254,11 @@ uint64_t doBenchmark3(const std::string& mode, const std::string& reuse,
} else if (compression == "packed") { } else if (compression == "packed") {
return doBenchmark2<BenchmarkTypes, TestCase, typename BenchmarkTypes::Packed>( return doBenchmark2<BenchmarkTypes, TestCase, typename BenchmarkTypes::Packed>(
mode, reuse, iters); mode, reuse, iters);
#if HAVE_SNAPPY
} else if (compression == "snappy") { } else if (compression == "snappy") {
return doBenchmark2<BenchmarkTypes, TestCase, typename BenchmarkTypes::SnappyCompressed>( return doBenchmark2<BenchmarkTypes, TestCase, typename BenchmarkTypes::SnappyCompressed>(
mode, reuse, iters); mode, reuse, iters);
#endif // HAVE_SNAPPY
} else { } else {
fprintf(stderr, "Unknown compression mode: %s\n", compression.c_str()); fprintf(stderr, "Unknown compression mode: %s\n", compression.c_str());
exit(1); exit(1);
......
...@@ -27,7 +27,7 @@ namespace capnproto { ...@@ -27,7 +27,7 @@ namespace capnproto {
namespace benchmark { namespace benchmark {
namespace null { namespace null {
enum class Color { enum class Color: uint8_t {
BLACK, BLACK,
WHITE, WHITE,
RED, RED,
...@@ -41,38 +41,55 @@ enum class Color { ...@@ -41,38 +41,55 @@ enum class Color {
constexpr uint COLOR_RANGE = static_cast<uint>(Color::SILVER) + 1; constexpr uint COLOR_RANGE = static_cast<uint>(Color::SILVER) + 1;
struct Wheel { struct Wheel {
uint16_t diameter;
float airPressure; float airPressure;
uint16_t diameter;
bool snowTires; bool snowTires;
}; };
struct Engine { struct Engine {
uint32_t cc;
uint16_t horsepower; uint16_t horsepower;
uint8_t cylinders; uint8_t cylinders;
uint32_t cc; uint8_t bits;
bool usesGas; inline bool usesGas() const { return bits & 1; }
bool usesElectric; inline bool usesElectric() const { return bits & 2; }
inline void setBits(bool usesGas, bool usesElectric) {
bits = (uint8_t)usesGas | ((uint8_t)usesElectric << 1);
}
}; };
struct Car { struct Car {
// SORT FIELDS BY SIZE since we need "theoretical best" memory usage
Engine engine;
List<Wheel> wheels;
const char* make; const char* make;
const char* model; const char* model;
Color color; float fuelCapacity;
uint8_t seats; float fuelLevel;
uint8_t doors; uint32_t weight;
List<Wheel> wheels;
uint16_t length; uint16_t length;
uint16_t width; uint16_t width;
uint16_t height; uint16_t height;
uint32_t weight; Color color;
Engine engine; uint8_t seats;
float fuelCapacity; uint8_t doors;
float fuelLevel;
bool hasPowerWindows;
bool hasPowerSteering;
bool hasCruiseControl;
uint8_t cupHolders; uint8_t cupHolders;
bool hasNavSystem;
uint8_t bits;
inline bool hasPowerWindows() const { return bits & 1; }
inline bool hasPowerSteering() const { return bits & 2; }
inline bool hasCruiseControl() const { return bits & 4; }
inline bool hasNavSystem() const { return bits & 8; }
inline void setBits(bool hasPowerWindows, bool hasPowerSteering,
bool hasCruiseControl, bool hasNavSystem) {
bits = (uint8_t)hasPowerWindows
| ((uint8_t)hasPowerSteering << 1)
| ((uint8_t)hasCruiseControl << 2)
| ((uint8_t)hasNavSystem << 3);
}
}; };
...@@ -92,8 +109,8 @@ uint64_t carValue(const Car& car) { ...@@ -92,8 +109,8 @@ uint64_t carValue(const Car& car) {
auto engine = car.engine; auto engine = car.engine;
result += engine.horsepower * 40; result += engine.horsepower * 40;
if (engine.usesElectric) { if (engine.usesElectric()) {
if (engine.usesGas) { if (engine.usesGas()) {
// hybrid // hybrid
result += 5000; result += 5000;
} else { } else {
...@@ -101,10 +118,10 @@ uint64_t carValue(const Car& car) { ...@@ -101,10 +118,10 @@ uint64_t carValue(const Car& car) {
} }
} }
result += car.hasPowerWindows ? 100 : 0; result += car.hasPowerWindows() ? 100 : 0;
result += car.hasPowerSteering ? 200 : 0; result += car.hasPowerSteering() ? 200 : 0;
result += car.hasCruiseControl ? 400 : 0; result += car.hasCruiseControl() ? 400 : 0;
result += car.hasNavSystem ? 2000 : 0; result += car.hasNavSystem() ? 2000 : 0;
result += car.cupHolders * 25; result += car.cupHolders * 25;
...@@ -138,14 +155,16 @@ void randomCar(Car* car) { ...@@ -138,14 +155,16 @@ void randomCar(Car* car) {
car->engine.horsepower = 100 * fastRand(400); car->engine.horsepower = 100 * fastRand(400);
car->engine.cylinders = 4 + 2 * fastRand(3); car->engine.cylinders = 4 + 2 * fastRand(3);
car->engine.cc = 800 + fastRand(10000); car->engine.cc = 800 + fastRand(10000);
car->engine.setBits(true, fastRand(2));
car->fuelCapacity = 10.0 + fastRandDouble(30.0); car->fuelCapacity = 10.0 + fastRandDouble(30.0);
car->fuelLevel = fastRandDouble(car->fuelCapacity); car->fuelLevel = fastRandDouble(car->fuelCapacity);
car->hasPowerWindows = fastRand(2); bool hasPowerWindows = fastRand(2);
car->hasPowerSteering = fastRand(2); bool hasPowerSteering = fastRand(2);
car->hasCruiseControl = fastRand(2); bool hasCruiseControl = fastRand(2);
car->cupHolders = fastRand(12); car->cupHolders = fastRand(12);
car->hasNavSystem = fastRand(2); bool hasNavSystem = fastRand(2);
car->setBits(hasPowerWindows, hasPowerSteering, hasCruiseControl, hasNavSystem);
} }
class CarSalesTestCase { class CarSalesTestCase {
......
...@@ -65,24 +65,35 @@ struct List { ...@@ -65,24 +65,35 @@ struct List {
// ======================================================================================= // =======================================================================================
struct SingleUseObjects { struct SingleUseObjects {
template <typename ObjectType> class ObjectSizeCounter {
struct Object { public:
struct Reusable {}; ObjectSizeCounter(uint64_t iters): counter(0) {}
struct SingleUse {
ObjectType value; void add(uint64_t wordCount) {
inline SingleUse(Reusable&) {} counter += wordCount;
}; }
uint64_t get() { return counter; }
private:
uint64_t counter;
}; };
}; };
struct ReusableObjects { struct ReusableObjects {
template <typename ObjectType> class ObjectSizeCounter {
struct Object { public:
typedef ObjectType Reusable; ObjectSizeCounter(uint64_t iters): iters(iters), maxSize(0) {}
struct SingleUse {
ObjectType& value; void add(size_t wordCount) {
inline SingleUse(Reusable& reusable): value(reusable) {} maxSize = std::max(wordCount, maxSize);
}; }
uint64_t get() { return iters * maxSize; }
private:
uint64_t iters;
size_t maxSize;
}; };
}; };
...@@ -120,7 +131,7 @@ struct BenchmarkMethods { ...@@ -120,7 +131,7 @@ struct BenchmarkMethods {
} }
static uint64_t passByObject(uint64_t iters, bool countObjectSize) { static uint64_t passByObject(uint64_t iters, bool countObjectSize) {
uint64_t throughput = 0; typename ReuseStrategy::ObjectSizeCounter sizeCounter(iters);
for (; iters > 0; --iters) { for (; iters > 0; --iters) {
arenaPos = arena; arenaPos = arena;
...@@ -134,10 +145,10 @@ struct BenchmarkMethods { ...@@ -134,10 +145,10 @@ struct BenchmarkMethods {
throw std::logic_error("Incorrect response."); throw std::logic_error("Incorrect response.");
} }
throughput += (arenaPos - arena) * sizeof(arena[0]); sizeCounter.add((arenaPos - arena) * sizeof(arena[0]));
} }
return throughput; return sizeCounter.get();
} }
static uint64_t passByBytes(uint64_t iters) { static uint64_t passByBytes(uint64_t iters) {
...@@ -149,10 +160,12 @@ struct BenchmarkMethods { ...@@ -149,10 +160,12 @@ struct BenchmarkMethods {
struct BenchmarkTypes { struct BenchmarkTypes {
typedef void Uncompressed; typedef void Uncompressed;
typedef void Packed; typedef void Packed;
#if HAVE_SNAPPY
typedef void SnappyCompressed; typedef void SnappyCompressed;
#endif // HAVE_SNAPPY
typedef void ReusableResources; typedef ReusableObjects ReusableResources;
typedef void SingleUseResources; typedef SingleUseObjects SingleUseResources;
template <typename TestCase, typename ReuseStrategy, typename Compression> template <typename TestCase, typename ReuseStrategy, typename Compression>
struct BenchmarkMethods: public null::BenchmarkMethods<TestCase, ReuseStrategy, Compression> {}; struct BenchmarkMethods: public null::BenchmarkMethods<TestCase, ReuseStrategy, Compression> {};
......
...@@ -92,6 +92,8 @@ void randomCar(Car* car) { ...@@ -92,6 +92,8 @@ void randomCar(Car* car) {
engine->set_horsepower(100 * fastRand(400)); engine->set_horsepower(100 * fastRand(400));
engine->set_cylinders(4 + 2 * fastRand(3)); engine->set_cylinders(4 + 2 * fastRand(3));
engine->set_cc(800 + fastRand(10000)); engine->set_cc(800 + fastRand(10000));
engine->set_uses_gas(true);
engine->set_uses_electric(fastRand(2));
car->set_fuel_capacity(10.0 + fastRandDouble(30.0)); car->set_fuel_capacity(10.0 + fastRandDouble(30.0));
car->set_fuel_level(fastRandDouble(car->fuel_capacity())); car->set_fuel_level(fastRandDouble(car->fuel_capacity()));
......
...@@ -24,8 +24,10 @@ ...@@ -24,8 +24,10 @@
#include "common.h" #include "common.h"
#include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/io/zero_copy_stream_impl.h>
#include <thread> #include <thread>
#if HAVE_SNAPPY
#include <snappy/snappy.h> #include <snappy/snappy.h>
#include <snappy/snappy-sinksource.h> #include <snappy/snappy-sinksource.h>
#endif // HAVE_SNAPPY
namespace capnproto { namespace capnproto {
namespace benchmark { namespace benchmark {
...@@ -121,6 +123,8 @@ struct Uncompressed { ...@@ -121,6 +123,8 @@ struct Uncompressed {
// arrays in some static scratch space. This probably gives protobufs an edge that it doesn't // arrays in some static scratch space. This probably gives protobufs an edge that it doesn't
// deserve. // deserve.
#if HAVE_SNAPPY
static char scratch[1 << 20]; static char scratch[1 << 20];
static char scratch2[1 << 20]; static char scratch2[1 << 20];
...@@ -158,6 +162,8 @@ struct SnappyCompressed { ...@@ -158,6 +162,8 @@ struct SnappyCompressed {
static void flush(OutputStream*) {} static void flush(OutputStream*) {}
}; };
#endif // HAVE_SNAPPY
// ======================================================================================= // =======================================================================================
#define REUSABLE(type) \ #define REUSABLE(type) \
...@@ -337,7 +343,9 @@ struct BenchmarkMethods { ...@@ -337,7 +343,9 @@ struct BenchmarkMethods {
struct BenchmarkTypes { struct BenchmarkTypes {
typedef protobuf::Uncompressed Uncompressed; typedef protobuf::Uncompressed Uncompressed;
typedef protobuf::Uncompressed Packed; typedef protobuf::Uncompressed Packed;
#if HAVE_SNAPPY
typedef protobuf::SnappyCompressed SnappyCompressed; typedef protobuf::SnappyCompressed SnappyCompressed;
#endif // HAVE_SNAPPY
typedef protobuf::ReusableMessages ReusableResources; typedef protobuf::ReusableMessages ReusableResources;
typedef protobuf::SingleUseMessages SingleUseResources; typedef protobuf::SingleUseMessages SingleUseResources;
......
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.
#include "descriptor.h"
#include <gtest/gtest.h>
namespace capnproto {
namespace internal {
namespace {
const int READONLY_SEGMENT_START = 123;
const FieldDescriptor TEST_FIELDS[2] = {
{ 1*WORDS, 0*REFERENCES, FieldSize::FOUR_BYTES, 0*ELEMENTS, 0*BYTES, 1, 0, 0*BYTES, 0*BITS, nullptr, nullptr },
{ 1*WORDS, 1*REFERENCES, FieldSize::REFERENCE , 0*ELEMENTS, 0*BYTES, 1, 0, 0*BYTES, 0*BITS, nullptr, nullptr }
};
extern const StructDescriptor TEST_STRUCT;
const AlignedData<1> TEST_STRUCT_DEFAULT_VALUE = {
{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 }
};
const StructDescriptor TEST_STRUCT = {
{ Descriptor::Kind::STRUCT },
FieldNumber(2),
1 * WORDS,
1 * REFERENCES,
TEST_FIELDS,
TEST_STRUCT_DEFAULT_VALUE.words
};
const int READONLY_SEGMENT_END = 321;
TEST(Descriptors, InReadOnlySegment) {
// It's extremely important that statically-initialized descriptors end up in the read-only
// segment, proving that they will not require any dynamic initialization at startup. We hackily
// assume that variables will be placed in each segment in the order that they appear, therefore
// if our test declarations above do in fact land in the read-only segment, they should appear
// between READONLY_SEGMENT_START and READONLY_SEGMENT_END.
EXPECT_LE((const void*)&READONLY_SEGMENT_START, (const void*)&TEST_FIELDS);
EXPECT_GE((const void*)&READONLY_SEGMENT_END , (const void*)&TEST_FIELDS);
EXPECT_LE((const void*)&READONLY_SEGMENT_START, (const void*)&TEST_STRUCT_DEFAULT_VALUE);
EXPECT_GE((const void*)&READONLY_SEGMENT_END , (const void*)&TEST_STRUCT_DEFAULT_VALUE);
EXPECT_LE((const void*)&READONLY_SEGMENT_START, (const void*)&TEST_STRUCT);
EXPECT_GE((const void*)&READONLY_SEGMENT_END , (const void*)&TEST_STRUCT);
}
} // namespace
} // namespace internal
} // namespace capnproto
// 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 "descriptor.h"
namespace capnproto {
namespace internal {
} // namespace internal
} // namespace capnproto
This diff is collapsed.
...@@ -29,6 +29,4 @@ ...@@ -29,6 +29,4 @@
#include "wire-format.h" #include "wire-format.h"
#include "list.h" #include "list.h"
#include "descriptor.h" // TODO: Eliminate this.
#endif // CAPNPROTO_GENERATED_HEADER_SUPPORT_H_ #endif // CAPNPROTO_GENERATED_HEADER_SUPPORT_H_
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#define CAPNPROTO_LIST_H_ #define CAPNPROTO_LIST_H_
#include "wire-format.h" #include "wire-format.h"
#include "descriptor.h" // only for FieldSize; TODO: Eliminate this
#include <initializer_list> #include <initializer_list>
namespace capnproto { namespace capnproto {
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "wire-format.h" #include "wire-format.h"
#include "descriptor.h"
#include "message.h" #include "message.h"
#include "arena.h" #include "arena.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "wire-format.h" #include "wire-format.h"
#include "arena.h" #include "arena.h"
#include "descriptor.h"
#include <string.h> #include <string.h>
#include <limits> #include <limits>
......
...@@ -37,10 +37,6 @@ ...@@ -37,10 +37,6 @@
namespace capnproto { namespace capnproto {
namespace internal { namespace internal {
class FieldDescriptor;
typedef Id<uint8_t, FieldDescriptor> FieldNumber;
enum class FieldSize: uint8_t;
class StructBuilder; class StructBuilder;
class StructReader; class StructReader;
class ListBuilder; class ListBuilder;
...@@ -50,6 +46,82 @@ struct WireHelpers; ...@@ -50,6 +46,82 @@ struct WireHelpers;
class SegmentReader; class SegmentReader;
class SegmentBuilder; class SegmentBuilder;
class FieldDescriptor;
typedef Id<uint8_t, FieldDescriptor> FieldNumber;
enum class FieldSize: uint8_t;
enum class FieldSize: uint8_t {
// TODO: Rename to FieldLayout or maybe ValueLayout.
VOID = 0,
BIT = 1,
BYTE = 2,
TWO_BYTES = 3,
FOUR_BYTES = 4,
EIGHT_BYTES = 5,
REFERENCE = 6, // Indicates that the field lives in the reference segment, not the data segment.
INLINE_COMPOSITE = 7
// A composite type of fixed width. This serves two purposes:
// 1) For lists of composite types where all the elements would have the exact same width,
// allocating a list of references which in turn point at the elements would waste space. We
// can avoid a layer of indirection by placing all the elements in a flat sequence, and only
// indicating the element properties (e.g. field count for structs) once.
//
// Specifically, a list reference indicating INLINE_COMPOSITE element size actually points to
// a "tag" describing one element. This tag is formatted like a wire reference, but the
// "offset" instead stores the element count of the list. The flat list of elements appears
// immediately after the tag. In the list reference itself, the element count is replaced with
// a word count for the whole list (excluding tag). This allows the tag and elements to be
// precached in a single step rather than two sequential steps.
//
// It is NOT intended to be possible to substitute an INLINE_COMPOSITE list for a REFERENCE
// list or vice-versa without breaking recipients. Recipients expect one or the other
// depending on the message definition.
//
// However, it IS allowed to substitute an INLINE_COMPOSITE list -- specifically, of structs --
// when a list was expected, or vice versa, with the assumption that the first field of the
// struct (field number zero) correspond to the element type. This allows a list of
// primitives to be upgraded to a list of structs, avoiding the need to use parallel arrays
// when you realize that you need to attach some extra information to each element of some
// primitive list.
//
// 2) For struct fields of composite types where the field's total size is known at compile time,
// we can embed the field directly into the parent struct to avoid indirection through a
// reference. However, this means that the field size can never change -- e.g. if it is a
// struct, new fields cannot be added to it. It's unclear if this is really useful so at this
// time it is not supported.
};
typedef decltype(BITS / ELEMENTS) BitsPerElement;
namespace internal {
static constexpr BitsPerElement BITS_PER_ELEMENT_TABLE[8] = {
0 * BITS / ELEMENTS,
1 * BITS / ELEMENTS,
8 * BITS / ELEMENTS,
16 * BITS / ELEMENTS,
32 * BITS / ELEMENTS,
64 * BITS / ELEMENTS,
64 * BITS / ELEMENTS,
0 * BITS / ELEMENTS
};
}
inline constexpr BitsPerElement bitsPerElement(FieldSize size) {
return internal::BITS_PER_ELEMENT_TABLE[static_cast<int>(size)];
}
template <int wordCount>
union AlignedData {
// Useful for declaring static constant data blobs as an array of bytes, but forcing those
// bytes to be word-aligned.
uint8_t bytes[wordCount * sizeof(word)];
word words[wordCount];
};
// ------------------------------------------------------------------- // -------------------------------------------------------------------
template <typename T> template <typename T>
......
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