Commit d43aec91 authored by Kenton Varda's avatar Kenton Varda

When getting a list from a builder, if the list elements are too small, upgrade it.

parent 917f459e
......@@ -665,11 +665,20 @@ DynamicValue::Builder DynamicStruct::Builder::getImpl(
typedDval.data(), typedDval.size() * BYTES));
}
case schema::Type::Body::LIST_TYPE:
return DynamicValue::Builder(DynamicList::Builder(
ListSchema::of(type.getListType(), member.getContainingStruct()),
builder.getListField(field.getOffset() * POINTERS,
dval.getListValue<internal::TrustedMessage>())));
case schema::Type::Body::LIST_TYPE: {
ListSchema listType = ListSchema::of(type.getListType(), member.getContainingStruct());
if (listType.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
return DynamicValue::Builder(DynamicList::Builder(listType,
builder.getStructListField(field.getOffset() * POINTERS,
structSizeFromSchema(listType.getStructElementType()),
dval.getListValue<internal::TrustedMessage>())));
} else {
return DynamicValue::Builder(DynamicList::Builder(listType,
builder.getListField(field.getOffset() * POINTERS,
elementSizeFor(listType.whichElementType()),
dval.getListValue<internal::TrustedMessage>())));
}
}
case schema::Type::Body::STRUCT_TYPE: {
auto structSchema =
......@@ -711,10 +720,19 @@ DynamicStruct::Builder DynamicStruct::Builder::getObjectImpl(
}
DynamicList::Builder DynamicStruct::Builder::getObjectImpl(
internal::StructBuilder builder, StructSchema::Member field, ListSchema type) {
return DynamicList::Builder(type,
builder.getListField(
field.getProto().getBody().getFieldMember().getOffset() * POINTERS,
nullptr));
if (type.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
return DynamicList::Builder(type,
builder.getStructListField(
field.getProto().getBody().getFieldMember().getOffset() * POINTERS,
structSizeFromSchema(type.getStructElementType()),
nullptr));
} else {
return DynamicList::Builder(type,
builder.getListField(
field.getProto().getBody().getFieldMember().getOffset() * POINTERS,
elementSizeFor(type.whichElementType()),
nullptr));
}
}
Text::Builder DynamicStruct::Builder::getObjectAsTextImpl(
internal::StructBuilder builder, StructSchema::Member field) {
......@@ -1007,9 +1025,20 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) const {
case schema::Type::Body::DATA_TYPE:
return DynamicValue::Builder(builder.getBlobElement<Data>(index * ELEMENTS));
case schema::Type::Body::LIST_TYPE:
return DynamicValue::Builder(DynamicList::Builder(
schema.getListElementType(), builder.getListElement(index * ELEMENTS)));
case schema::Type::Body::LIST_TYPE: {
ListSchema elementType = schema.getListElementType();
if (elementType.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
return DynamicValue::Builder(DynamicList::Builder(elementType,
builder.getStructListElement(
index * ELEMENTS,
structSizeFromSchema(elementType.getStructElementType()))));
} else {
return DynamicValue::Builder(DynamicList::Builder(elementType,
builder.getListElement(
index * ELEMENTS,
elementSizeFor(elementType.whichElementType()))));
}
}
case schema::Type::Body::STRUCT_TYPE:
return DynamicValue::Builder(DynamicStruct::Builder(
......@@ -1388,7 +1417,15 @@ DynamicList::Reader PointerHelpers<DynamicList, Kind::UNKNOWN>::getDynamic(
}
DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::getDynamic(
StructBuilder builder, WirePointerCount index, ListSchema schema) {
return DynamicList::Builder(schema, builder.getListField(index, nullptr));
if (schema.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
return DynamicList::Builder(schema,
builder.getStructListField(index,
structSizeFromSchema(schema.getStructElementType()),
nullptr));
} else {
return DynamicList::Builder(schema,
builder.getListField(index, elementSizeFor(schema.whichElementType()), nullptr));
}
}
void PointerHelpers<DynamicList, Kind::UNKNOWN>::set(
StructBuilder builder, WirePointerCount index, DynamicList::Reader value) {
......
This diff is collapsed.
......@@ -182,7 +182,7 @@ static void checkStruct(StructBuilder builder) {
}
{
ListBuilder list = builder.getListField(1 * POINTERS, nullptr);
ListBuilder list = builder.getListField(1 * POINTERS, FieldSize::FOUR_BYTES, nullptr);
ASSERT_EQ(3 * ELEMENTS, list.size());
EXPECT_EQ(200, list.getDataElement<int32_t>(0 * ELEMENTS));
EXPECT_EQ(201, list.getDataElement<int32_t>(1 * ELEMENTS));
......@@ -190,7 +190,7 @@ static void checkStruct(StructBuilder builder) {
}
{
ListBuilder list = builder.getListField(2 * POINTERS, nullptr);
ListBuilder list = builder.getStructListField(2 * POINTERS, STRUCTLIST_ELEMENT_SIZE, nullptr);
ASSERT_EQ(4 * ELEMENTS, list.size());
for (int i = 0; i < 4; i++) {
StructBuilder element = list.getStructElement(i * ELEMENTS);
......@@ -204,10 +204,10 @@ static void checkStruct(StructBuilder builder) {
}
{
ListBuilder list = builder.getListField(3 * POINTERS, nullptr);
ListBuilder list = builder.getListField(3 * POINTERS, FieldSize::POINTER, nullptr);
ASSERT_EQ(5 * ELEMENTS, list.size());
for (uint i = 0; i < 5; i++) {
ListBuilder element = list.getListElement(i * ELEMENTS);
ListBuilder element = list.getListElement(i * ELEMENTS, FieldSize::TWO_BYTES);
ASSERT_EQ((i + 1) * ELEMENTS, element.size());
for (uint j = 0; j <= i; j++) {
EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS));
......
This diff is collapsed.
......@@ -54,6 +54,11 @@ class SegmentBuilder;
enum class FieldSize: uint8_t {
// TODO: Rename to FieldLayout or maybe ValueLayout.
// Notice that each member of this enum, when representing a list element size, represents a
// size that is greater than or equal to the previous members, since INLINE_COMPOSITE is used
// only for multi-word structs. This is important because it allows us to compare FieldSize
// values for the purpose of deciding when we need to upgrade a list.
VOID = 0,
BIT = 1,
BYTE = 2,
......@@ -340,8 +345,17 @@ public:
// Allocates a new list of the given size for the field at the given index in the pointer
// segment, and return a pointer to it. Each element is initialized to its empty state.
ListBuilder getListField(WirePointerCount ptrIndex, const word* defaultValue) const;
// Gets the already-allocated list field for the given pointer index. If the list is not
ListBuilder getListField(WirePointerCount ptrIndex, FieldSize elementSize,
const word* defaultValue) const;
// Gets the already-allocated list field for the given pointer index, ensuring that the list is
// suitable for storing non-struct elements of the given size. If the list is not already
// allocated, it is allocated as a deep copy of the given default value (a trusted message). If
// the default value is null, an empty list is used.
ListBuilder getStructListField(WirePointerCount ptrIndex, StructSize elementSize,
const word* defaultValue) const;
// Gets the already-allocated list field for the given pointer index, ensuring that the list
// is suitable for storing struct elements of the given size. If the list is not
// already allocated, it is allocated as a deep copy of the given default value (a trusted
// message). If the default value is null, an empty list is used.
......@@ -515,9 +529,15 @@ public:
// Allocates a new list of the given size for the field at the given index in the pointer
// segment, and return a pointer to it. Each element is initialized to its empty state.
ListBuilder getListElement(ElementCount index) const;
// Get the existing list element at the given index. Returns an empty list if the element is
// not initialized.
ListBuilder getListElement(ElementCount index, FieldSize elementSize) const;
// Get the existing list element at the given index, making sure it is suitable for storing
// non-struct elements of the given size. Returns an empty list if the element is not
// initialized.
ListBuilder getStructListElement(ElementCount index, StructSize elementSize) const;
// Get the existing list element at the given index, making sure it is suitable for storing
// struct elements of the given size. Returns an empty list if the element is not
// initialized.
template <typename T>
typename T::Builder initBlobElement(ElementCount index, ByteCount size) const;
......
......@@ -257,7 +257,7 @@ private:
}
inline static internal::ListBuilder getAsElementOf(
const internal::ListBuilder& builder, uint index) {
return builder.getListElement(index * ELEMENTS);
return builder.getListElement(index * ELEMENTS, internal::FieldSizeForType<T>::value);
}
inline static internal::ListReader getAsElementOf(
const internal::ListReader& reader, uint index) {
......@@ -270,7 +270,7 @@ private:
}
inline static internal::ListBuilder getAsFieldOf(
internal::StructBuilder& builder, WirePointerCount index, const word* defaultValue) {
return builder.getListField(index, defaultValue);
return builder.getListField(index, internal::FieldSizeForType<T>::value, defaultValue);
}
inline static internal::ListReader getAsFieldOf(
internal::StructReader& reader, WirePointerCount index, const word* defaultValue) {
......@@ -343,7 +343,7 @@ private:
}
inline static internal::ListBuilder getAsElementOf(
const internal::ListBuilder& builder, uint index) {
return builder.getListElement(index * ELEMENTS);
return builder.getStructListElement(index * ELEMENTS, internal::structSize<T>());
}
inline static internal::ListReader getAsElementOf(
const internal::ListReader& reader, uint index) {
......@@ -356,7 +356,7 @@ private:
}
inline static internal::ListBuilder getAsFieldOf(
internal::StructBuilder& builder, WirePointerCount index, const word* defaultValue) {
return builder.getListField(index, defaultValue);
return builder.getStructListField(index, internal::structSize<T>(), defaultValue);
}
inline static internal::ListReader getAsFieldOf(
internal::StructReader& reader, WirePointerCount index, const word* defaultValue) {
......@@ -429,7 +429,7 @@ private:
}
inline static internal::ListBuilder getAsElementOf(
const internal::ListBuilder& builder, uint index) {
return builder.getListElement(index * ELEMENTS);
return builder.getListElement(index * ELEMENTS, internal::FieldSize::POINTER);
}
inline static internal::ListReader getAsElementOf(
const internal::ListReader& reader, uint index) {
......@@ -442,7 +442,7 @@ private:
}
inline static internal::ListBuilder getAsFieldOf(
internal::StructBuilder& builder, WirePointerCount index, const word* defaultValue) {
return builder.getListField(index, defaultValue);
return builder.getListField(index, internal::FieldSize::POINTER, defaultValue);
}
inline static internal::ListReader getAsFieldOf(
internal::StructReader& reader, WirePointerCount index, const word* defaultValue) {
......@@ -530,7 +530,7 @@ private:
}
inline static internal::ListBuilder getAsElementOf(
const internal::ListBuilder& builder, uint index) {
return builder.getListElement(index * ELEMENTS);
return builder.getListElement(index * ELEMENTS, internal::FieldSize::POINTER);
}
inline static internal::ListReader getAsElementOf(
const internal::ListReader& reader, uint index) {
......@@ -543,7 +543,7 @@ private:
}
inline static internal::ListBuilder getAsFieldOf(
internal::StructBuilder& builder, WirePointerCount index, const word* defaultValue) {
return builder.getListField(index, defaultValue);
return builder.getListField(index, internal::FieldSize::POINTER, defaultValue);
}
inline static internal::ListReader getAsFieldOf(
internal::StructReader& reader, WirePointerCount index, const word* defaultValue) {
......
......@@ -357,14 +357,14 @@ struct TestLateUnion {
struct TestOldVersion {
# A subset of TestNewVersion.
old1 @0 :Int32;
old1 @0 :Int64;
old2 @1 :Text;
old3 @2 :TestOldVersion;
}
struct TestNewVersion {
# A superset of TestOldVersion.
old1 @0 :Int32;
old1 @0 :Int64;
old2 @1 :Text;
old3 @2 :TestNewVersion;
new1 @3 :Int64 = 987;
......
......@@ -519,6 +519,19 @@ public:
inline constexpr UnitRatio(const UnitRatio<OtherNumber, Unit1, Unit2>& other)
: unit1PerUnit2(other.unit1PerUnit2) {}
template <typename OtherNumber>
inline constexpr UnitRatio<decltype(Number(1)+OtherNumber(1)), Unit1, Unit2>
operator+(UnitRatio<OtherNumber, Unit1, Unit2> other) {
return UnitRatio<decltype(Number(1)+OtherNumber(1)), Unit1, Unit2>(
unit1PerUnit2 + other.unit1PerUnit2);
}
template <typename OtherNumber>
inline constexpr UnitRatio<decltype(Number(1)-OtherNumber(1)), Unit1, Unit2>
operator-(UnitRatio<OtherNumber, Unit1, Unit2> other) {
return UnitRatio<decltype(Number(1)-OtherNumber(1)), Unit1, Unit2>(
unit1PerUnit2 - other.unit1PerUnit2);
}
template <typename OtherNumber, typename Unit3>
inline constexpr UnitRatio<decltype(Number(1)*OtherNumber(1)), Unit3, Unit2>
operator*(UnitRatio<OtherNumber, Unit3, Unit1> other) {
......
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