Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
d43aec91
Commit
d43aec91
authored
May 16, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
When getting a list from a builder, if the list elements are too small, upgrade it.
parent
917f459e
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
744 additions
and
51 deletions
+744
-51
dynamic.c++
c++/src/capnproto/dynamic.c++
+44
-7
encoding-test.c++
c++/src/capnproto/encoding-test.c++
+291
-5
layout-test.c++
c++/src/capnproto/layout-test.c++
+4
-4
layout.c++
c++/src/capnproto/layout.c++
+357
-20
layout.h
c++/src/capnproto/layout.h
+25
-5
list.h
c++/src/capnproto/list.h
+8
-8
test.capnp
c++/src/capnproto/test.capnp
+2
-2
type-safety.h
c++/src/capnproto/type-safety.h
+13
-0
No files found.
c++/src/capnproto/dynamic.c++
View file @
d43aec91
...
...
@@ -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
()),
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
)
{
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
)
{
...
...
c++/src/capnproto/encoding-test.c++
View file @
d43aec91
...
...
@@ -577,12 +577,12 @@ TEST(Encoding, BitListUpgrade) {
root
.
initObjectField
<
List
<
bool
>>
(
4
).
copyFrom
({
true
,
false
,
true
,
true
});
{
auto
l
=
root
.
getObjectField
<
List
<
test
::
Test
FieldZeroIsBit
>>
();
auto
l
=
root
.
getObjectField
<
List
<
test
::
Test
Lists
::
Struct1
>>
();
ASSERT_EQ
(
4u
,
l
.
size
());
EXPECT_TRUE
(
l
[
0
].
get
Bit
());
EXPECT_FALSE
(
l
[
1
].
get
Bit
());
EXPECT_TRUE
(
l
[
2
].
get
Bit
());
EXPECT_TRUE
(
l
[
3
].
get
Bit
());
EXPECT_TRUE
(
l
[
0
].
get
F
());
EXPECT_FALSE
(
l
[
1
].
get
F
());
EXPECT_TRUE
(
l
[
2
].
get
F
());
EXPECT_TRUE
(
l
[
3
].
get
F
());
}
auto
reader
=
root
.
asReader
();
...
...
@@ -865,6 +865,292 @@ TEST(Encoding, UpgradeStructInBuilderDoubleFarPointers) {
EXPECT_EQ
(
2u
,
builder
.
getSegmentsForOutput
()[
2
].
size
());
}
void
checkList
(
List
<
test
::
TestNewVersion
>::
Builder
builder
,
std
::
initializer_list
<
int64_t
>
expectedData
,
std
::
initializer_list
<
Text
::
Reader
>
expectedPointers
)
{
ASSERT_EQ
(
expectedData
.
size
(),
builder
.
size
());
for
(
uint
i
=
0
;
i
<
expectedData
.
size
();
i
++
)
{
EXPECT_EQ
(
expectedData
.
begin
()[
i
],
builder
[
i
].
getOld1
());
EXPECT_EQ
(
expectedPointers
.
begin
()[
i
],
builder
[
i
].
getOld2
());
// Other fields shouldn't be set.
EXPECT_EQ
(
0
,
builder
[
i
].
asReader
().
getOld3
().
getOld1
());
EXPECT_EQ
(
""
,
builder
[
i
].
asReader
().
getOld3
().
getOld2
());
EXPECT_EQ
(
987
,
builder
[
i
].
getNew1
());
EXPECT_EQ
(
"baz"
,
builder
[
i
].
getNew2
());
}
}
void
checkUpgradedList
(
test
::
TestObject
::
Builder
root
,
std
::
initializer_list
<
int64_t
>
expectedData
,
std
::
initializer_list
<
Text
::
Reader
>
expectedPointers
)
{
{
auto
builder
=
root
.
getObjectField
<
List
<
test
::
TestNewVersion
>>
();
ASSERT_EQ
(
expectedData
.
size
(),
builder
.
size
());
for
(
uint
i
=
0
;
i
<
expectedData
.
size
();
i
++
)
{
EXPECT_EQ
(
expectedData
.
begin
()[
i
],
builder
[
i
].
getOld1
());
EXPECT_EQ
(
expectedPointers
.
begin
()[
i
],
builder
[
i
].
getOld2
());
// Other fields shouldn't be set.
EXPECT_EQ
(
0
,
builder
[
i
].
asReader
().
getOld3
().
getOld1
());
EXPECT_EQ
(
""
,
builder
[
i
].
asReader
().
getOld3
().
getOld2
());
EXPECT_EQ
(
987
,
builder
[
i
].
getNew1
());
EXPECT_EQ
(
"baz"
,
builder
[
i
].
getNew2
());
// Write some new data.
builder
[
i
].
setOld1
(
i
*
123
);
builder
[
i
].
setOld2
(
str
(
"qux"
,
i
,
'\0'
).
begin
());
builder
[
i
].
setNew1
(
i
*
456
);
builder
[
i
].
setNew2
(
str
(
"corge"
,
i
,
'\0'
).
begin
());
}
}
// Read the newly-written data as TestOldVersion to ensure it was updated.
{
auto
builder
=
root
.
getObjectField
<
List
<
test
::
TestOldVersion
>>
();
ASSERT_EQ
(
expectedData
.
size
(),
builder
.
size
());
for
(
uint
i
=
0
;
i
<
expectedData
.
size
();
i
++
)
{
EXPECT_EQ
(
i
*
123
,
builder
[
i
].
getOld1
());
EXPECT_EQ
(
Text
::
Reader
(
str
(
"qux"
,
i
,
"
\0
"
).
begin
()),
builder
[
i
].
getOld2
());
}
}
// Also read back as TestNewVersion again.
{
auto
builder
=
root
.
getObjectField
<
List
<
test
::
TestNewVersion
>>
();
ASSERT_EQ
(
expectedData
.
size
(),
builder
.
size
());
for
(
uint
i
=
0
;
i
<
expectedData
.
size
();
i
++
)
{
EXPECT_EQ
(
i
*
123
,
builder
[
i
].
getOld1
());
EXPECT_EQ
(
Text
::
Reader
(
str
(
"qux"
,
i
,
'\0'
).
begin
()),
builder
[
i
].
getOld2
());
EXPECT_EQ
(
i
*
456
,
builder
[
i
].
getNew1
());
EXPECT_EQ
(
Text
::
Reader
(
str
(
"corge"
,
i
,
'\0'
).
begin
()),
builder
[
i
].
getNew2
());
}
}
}
TEST
(
Encoding
,
UpgradeListInBuilder
)
{
// Test every damned list upgrade.
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
// -----------------------------------------------------------------
root
.
initObjectField
<
List
<
Void
>>
(
4
);
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
bool
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint8_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint16_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
checkList
(
root
.
getObjectField
<
List
<
test
::
TestNewVersion
>>
(),
{
0
,
0
,
0
,
0
},
{
""
,
""
,
""
,
""
});
// -----------------------------------------------------------------
root
.
initObjectField
<
List
<
bool
>>
(
4
).
copyFrom
({
true
,
false
,
true
,
true
});
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
true
,
false
,
true
,
true
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint8_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint16_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
checkUpgradedList
(
root
,
{
1
,
0
,
1
,
1
},
{
""
,
""
,
""
,
""
});
// -----------------------------------------------------------------
root
.
initObjectField
<
List
<
uint8_t
>>
(
4
).
copyFrom
({
0x12
,
0x23
,
0x33
,
0x44
});
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
false
,
true
,
true
,
false
});
checkList
(
root
.
getObjectField
<
List
<
uint8_t
>>
(),
{
0x12
,
0x23
,
0x33
,
0x44
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint16_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
checkUpgradedList
(
root
,
{
0x12
,
0x23
,
0x33
,
0x44
},
{
""
,
""
,
""
,
""
});
// -----------------------------------------------------------------
root
.
initObjectField
<
List
<
uint16_t
>>
(
4
).
copyFrom
({
0x5612
,
0x7823
,
0xab33
,
0xcd44
});
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
false
,
true
,
true
,
false
});
checkList
(
root
.
getObjectField
<
List
<
uint8_t
>>
(),
{
0x12
,
0x23
,
0x33
,
0x44
});
checkList
(
root
.
getObjectField
<
List
<
uint16_t
>>
(),
{
0x5612
,
0x7823
,
0xab33
,
0xcd44
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
checkUpgradedList
(
root
,
{
0x5612
,
0x7823
,
0xab33
,
0xcd44
},
{
""
,
""
,
""
,
""
});
// -----------------------------------------------------------------
root
.
initObjectField
<
List
<
uint32_t
>>
(
4
).
copyFrom
({
0x17595612
,
0x29347823
,
0x5923ab32
,
0x1a39cd45
});
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
false
,
true
,
false
,
true
});
checkList
(
root
.
getObjectField
<
List
<
uint8_t
>>
(),
{
0x12
,
0x23
,
0x32
,
0x45
});
checkList
(
root
.
getObjectField
<
List
<
uint16_t
>>
(),
{
0x5612
,
0x7823
,
0xab32
,
0xcd45
});
checkList
(
root
.
getObjectField
<
List
<
uint32_t
>>
(),
{
0x17595612u
,
0x29347823u
,
0x5923ab32u
,
0x1a39cd45u
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
checkUpgradedList
(
root
,
{
0x17595612
,
0x29347823
,
0x5923ab32
,
0x1a39cd45
},
{
""
,
""
,
""
,
""
});
// -----------------------------------------------------------------
root
.
initObjectField
<
List
<
uint64_t
>>
(
2
).
copyFrom
({
0x1234abcd8735fe21
,
0x7173bc0e1923af36
});
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
});
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
true
,
false
});
checkList
(
root
.
getObjectField
<
List
<
uint8_t
>>
(),
{
0x21
,
0x36
});
checkList
(
root
.
getObjectField
<
List
<
uint16_t
>>
(),
{
0xfe21
,
0xaf36
});
checkList
(
root
.
getObjectField
<
List
<
uint32_t
>>
(),
{
0x8735fe21u
,
0x1923af36u
});
checkList
(
root
.
getObjectField
<
List
<
uint64_t
>>
(),
{
0x1234abcd8735fe21ull
,
0x7173bc0e1923af36ull
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
checkUpgradedList
(
root
,
{
0x1234abcd8735fe21ull
,
0x7173bc0e1923af36ull
},
{
""
,
""
});
// -----------------------------------------------------------------
root
.
initObjectField
<
List
<
Text
>>
(
3
).
copyFrom
({
"foo"
,
"bar"
,
"baz"
});
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
bool
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint8_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint16_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
checkList
(
root
.
getObjectField
<
List
<
Text
>>
(),
{
"foo"
,
"bar"
,
"baz"
});
checkUpgradedList
(
root
,
{
0
,
0
,
0
},
{
"foo"
,
"bar"
,
"baz"
});
// -----------------------------------------------------------------
root
.
initObjectField
<
List
<
Text
>>
(
3
).
copyFrom
({
"foo"
,
"bar"
,
"baz"
});
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
bool
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint8_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint16_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
checkList
(
root
.
getObjectField
<
List
<
Text
>>
(),
{
"foo"
,
"bar"
,
"baz"
});
checkUpgradedList
(
root
,
{
0
,
0
,
0
},
{
"foo"
,
"bar"
,
"baz"
});
// -----------------------------------------------------------------
{
auto
l
=
root
.
initObjectField
<
List
<
test
::
TestOldVersion
>>
(
3
);
l
[
0
].
setOld1
(
0x1234567890abcdef
);
l
[
1
].
setOld1
(
0x234567890abcdef1
);
l
[
2
].
setOld1
(
0x34567890abcdef12
);
l
[
0
].
setOld2
(
"foo"
);
l
[
1
].
setOld2
(
"bar"
);
l
[
2
].
setOld2
(
"baz"
);
}
checkList
(
root
.
getObjectField
<
List
<
Void
>>
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
true
,
true
,
false
});
checkList
(
root
.
getObjectField
<
List
<
uint8_t
>>
(),
{
0xefu
,
0xf1u
,
0x12u
});
checkList
(
root
.
getObjectField
<
List
<
uint16_t
>>
(),
{
0xcdefu
,
0xdef1u
,
0xef12u
});
checkList
(
root
.
getObjectField
<
List
<
uint32_t
>>
(),
{
0x90abcdefu
,
0x0abcdef1u
,
0xabcdef12u
});
checkList
(
root
.
getObjectField
<
List
<
uint64_t
>>
(),
{
0x1234567890abcdefull
,
0x234567890abcdef1ull
,
0x34567890abcdef12ull
});
checkList
(
root
.
getObjectField
<
List
<
Text
>>
(),
{
"foo"
,
"bar"
,
"baz"
});
checkUpgradedList
(
root
,
{
0x1234567890abcdefull
,
0x234567890abcdef1ull
,
0x34567890abcdef12ull
},
{
"foo"
,
"bar"
,
"baz"
});
// -----------------------------------------------------------------
// OK, now we've tested upgrading every primitive list to every primitive list, every primitive
// list to a multi-word struct, and a multi-word struct to every primitive list. But we haven't
// tried upgrading primitive lists to sub-word structs.
// Upgrade from bool.
root
.
initObjectField
<
List
<
bool
>>
(
4
).
copyFrom
({
true
,
false
,
true
,
true
});
{
auto
l
=
root
.
getObjectField
<
List
<
test
::
TestLists
::
Struct16
>>
();
ASSERT_EQ
(
4u
,
l
.
size
());
EXPECT_EQ
(
1u
,
l
[
0
].
getF
());
EXPECT_EQ
(
0u
,
l
[
1
].
getF
());
EXPECT_EQ
(
1u
,
l
[
2
].
getF
());
EXPECT_EQ
(
1u
,
l
[
3
].
getF
());
l
[
0
].
setF
(
12573
);
l
[
1
].
setF
(
3251
);
l
[
2
].
setF
(
9238
);
l
[
3
].
setF
(
5832
);
}
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
true
,
true
,
false
,
false
});
checkList
(
root
.
getObjectField
<
List
<
uint16_t
>>
(),
{
12573u
,
3251u
,
9238u
,
5832u
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
// Upgrade from multi-byte, sub-word data.
root
.
initObjectField
<
List
<
uint16_t
>>
(
4
).
copyFrom
({
12u
,
34u
,
56u
,
78u
});
{
auto
l
=
root
.
getObjectField
<
List
<
test
::
TestLists
::
Struct32
>>
();
ASSERT_EQ
(
4u
,
l
.
size
());
EXPECT_EQ
(
12u
,
l
[
0
].
getF
());
EXPECT_EQ
(
34u
,
l
[
1
].
getF
());
EXPECT_EQ
(
56u
,
l
[
2
].
getF
());
EXPECT_EQ
(
78u
,
l
[
3
].
getF
());
l
[
0
].
setF
(
0x65ac1235u
);
l
[
1
].
setF
(
0x13f12879u
);
l
[
2
].
setF
(
0x33423082u
);
l
[
3
].
setF
(
0x12988948u
);
}
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
true
,
true
,
false
,
false
});
checkList
(
root
.
getObjectField
<
List
<
uint8_t
>>
(),
{
0x35u
,
0x79u
,
0x82u
,
0x48u
});
checkList
(
root
.
getObjectField
<
List
<
uint16_t
>>
(),
{
0x1235u
,
0x2879u
,
0x3082u
,
0x8948u
});
checkList
(
root
.
getObjectField
<
List
<
uint32_t
>>
(),
{
0x65ac1235u
,
0x13f12879u
,
0x33423082u
,
0x12988948u
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
// Upgrade from void -> data struct
root
.
initObjectField
<
List
<
Void
>>
(
4
).
copyFrom
({
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
{
auto
l
=
root
.
getObjectField
<
List
<
test
::
TestLists
::
Struct16
>>
();
ASSERT_EQ
(
4u
,
l
.
size
());
EXPECT_EQ
(
0u
,
l
[
0
].
getF
());
EXPECT_EQ
(
0u
,
l
[
1
].
getF
());
EXPECT_EQ
(
0u
,
l
[
2
].
getF
());
EXPECT_EQ
(
0u
,
l
[
3
].
getF
());
l
[
0
].
setF
(
12573
);
l
[
1
].
setF
(
3251
);
l
[
2
].
setF
(
9238
);
l
[
3
].
setF
(
5832
);
}
checkList
(
root
.
getObjectField
<
List
<
bool
>>
(),
{
true
,
true
,
false
,
false
});
checkList
(
root
.
getObjectField
<
List
<
uint16_t
>>
(),
{
12573u
,
3251u
,
9238u
,
5832u
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
// Upgrade from void -> pointer struct
root
.
initObjectField
<
List
<
Void
>>
(
4
).
copyFrom
({
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
{
auto
l
=
root
.
getObjectField
<
List
<
test
::
TestLists
::
StructP
>>
();
ASSERT_EQ
(
4u
,
l
.
size
());
EXPECT_EQ
(
""
,
l
[
0
].
getF
());
EXPECT_EQ
(
""
,
l
[
1
].
getF
());
EXPECT_EQ
(
""
,
l
[
2
].
getF
());
EXPECT_EQ
(
""
,
l
[
3
].
getF
());
l
[
0
].
setF
(
"foo"
);
l
[
1
].
setF
(
"bar"
);
l
[
2
].
setF
(
"baz"
);
l
[
3
].
setF
(
"qux"
);
}
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
bool
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint16_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint32_t
>>
());
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
uint64_t
>>
());
checkList
(
root
.
getObjectField
<
List
<
Text
>>
(),
{
"foo"
,
"bar"
,
"baz"
,
"qux"
});
// Verify that we cannot "side-grade" a pointer list to a data struct list, or a data list to
// a pointer struct list.
root
.
initObjectField
<
List
<
Text
>>
(
4
).
copyFrom
({
"foo"
,
"bar"
,
"baz"
,
"qux"
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
test
::
TestLists
::
Struct32
>>
());
root
.
initObjectField
<
List
<
uint32_t
>>
(
4
).
copyFrom
({
12
,
34
,
56
,
78
});
EXPECT_ANY_THROW
(
root
.
getObjectField
<
List
<
Text
>>
());
}
// =======================================================================================
// Tests of generated code, not really of the encoding.
// TODO(cleanup): Move to a different test?
...
...
c++/src/capnproto/layout-test.c++
View file @
d43aec91
...
...
@@ -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
.
get
ListField
(
2
*
POINTERS
,
nullptr
);
ListBuilder
list
=
builder
.
get
StructListField
(
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
));
...
...
c++/src/capnproto/layout.c++
View file @
d43aec91
...
...
@@ -588,39 +588,363 @@ struct WireHelpers {
}
static
CAPNPROTO_ALWAYS_INLINE
(
ListBuilder
getWritableListPointer
(
WirePointer
*
ref
,
SegmentBuilder
*
segment
,
const
word
*
defaultValue
))
{
const
WirePointer
*
defaultRef
=
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
);
word
*
ptr
;
WirePointer
*
origRef
,
SegmentBuilder
*
origSegment
,
FieldSize
elementSize
,
const
word
*
defaultValue
))
{
DPRECOND
(
elementSize
!=
FieldSize
::
INLINE_COMPOSITE
,
"Use getStructList{Element,Field}() for structs."
);
if
(
ref
->
isNull
())
{
if
(
origRef
->
isNull
())
{
useDefault
:
if
(
defaultValue
==
nullptr
||
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
)
->
isNull
())
{
memset
(
origRef
,
0
,
sizeof
(
*
origRef
));
return
ListBuilder
();
}
ptr
=
copyMessage
(
segment
,
ref
,
defaultRef
);
word
*
ptr
=
copyMessage
(
origSegment
,
origRef
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
BitCount
dataSize
=
dataBitsPerElement
(
elementSize
)
*
ELEMENTS
;
WirePointerCount
pointerCount
=
pointersPerElement
(
elementSize
)
*
ELEMENTS
;
auto
step
=
(
dataSize
+
pointerCount
*
BITS_PER_POINTER
)
/
ELEMENTS
;
return
ListBuilder
(
origSegment
,
ptr
,
step
,
origRef
->
listRef
.
elementCount
(),
dataSize
,
pointerCount
);
}
else
{
ptr
=
followFars
(
ref
,
segment
);
// The pointer is already initialized. We must verify that it has the right size. Unlike
// in getWritableStructListReference(), we never need to "upgrade" the data, because this
// method is called only for non-struct lists, and there is no allowed upgrade path *to*
// a non-struct list, only *from* them.
PRECOND
(
ref
->
kind
()
==
WirePointer
::
LIST
,
"Called getList{Field,Element}() but existing pointer is not a list."
);
WirePointer
*
ref
=
origRef
;
SegmentBuilder
*
segment
=
origSegment
;
word
*
ptr
=
followFars
(
ref
,
segment
);
VALIDATE_INPUT
(
ref
->
kind
()
==
WirePointer
::
LIST
,
"Called getList{Field,Element}() but existing pointer is not a list."
)
{
goto
useDefault
;
}
if
(
ref
->
listRef
.
elementSize
()
==
FieldSize
::
INLINE_COMPOSITE
)
{
FieldSize
oldSize
=
ref
->
listRef
.
elementSize
();
if
(
oldSize
==
FieldSize
::
INLINE_COMPOSITE
)
{
// The existing element size is INLINE_COMPOSITE, which means that it is at least two
// words, which makes it bigger than the expected element size. Since fields can only
// grow when upgraded, the existing data must have been written with a newer version of
// the protocol. We therefore never need to upgrade the data in this case, but we do
// need to validate that it is a valid upgrade from what we expected.
// Read the tag to get the actual element count.
WirePointer
*
tag
=
reinterpret_cast
<
WirePointer
*>
(
ptr
);
PRECOND
(
tag
->
kind
()
==
WirePointer
::
STRUCT
,
"INLINE_COMPOSITE list with non-STRUCT elements not supported."
);
ptr
+=
POINTER_SIZE_IN_WORDS
;
// First list element is at tag + 1 pointer.
return
ListBuilder
(
segment
,
tag
+
1
,
tag
->
structRef
.
wordSize
()
*
BITS_PER_WORD
/
ELEMENTS
,
WordCount
dataSize
=
tag
->
structRef
.
dataSize
.
get
();
WirePointerCount
pointerCount
=
tag
->
structRef
.
ptrCount
.
get
();
switch
(
elementSize
)
{
case
FieldSize
:
:
VOID
:
// Anything is a valid upgrade from Void.
break
;
case
FieldSize
:
:
BIT
:
case
FieldSize
:
:
BYTE
:
case
FieldSize
:
:
TWO_BYTES
:
case
FieldSize
:
:
FOUR_BYTES
:
case
FieldSize
:
:
EIGHT_BYTES
:
VALIDATE_INPUT
(
dataSize
>=
1
*
WORDS
,
"Existing list value is incompatible with expected type."
);
break
;
case
FieldSize
:
:
POINTER
:
VALIDATE_INPUT
(
pointerCount
>=
1
*
POINTERS
,
"Existing list value is incompatible with expected type."
);
// Adjust the pointer to point at the reference segment.
ptr
+=
dataSize
;
break
;
case
FieldSize
:
:
INLINE_COMPOSITE
:
FAIL_CHECK
(
"Can't get here."
);
break
;
}
// OK, looks valid.
return
ListBuilder
(
segment
,
ptr
,
tag
->
structRef
.
wordSize
()
*
BITS_PER_WORD
/
ELEMENTS
,
tag
->
inlineCompositeListElementCount
(),
tag
->
structRef
.
dataSize
.
get
()
*
BITS_PER_WORD
,
tag
->
structRef
.
ptrCount
.
get
());
dataSize
*
BITS_PER_WORD
,
pointerCount
);
}
else
{
BitCount
dataSize
=
dataBitsPerElement
(
ref
->
listRef
.
elementSize
())
*
ELEMENTS
;
WirePointerCount
pointerCount
=
pointersPerElement
(
ref
->
listRef
.
elementSize
())
*
ELEMENTS
;
BitCount
dataSize
=
dataBitsPerElement
(
oldSize
)
*
ELEMENTS
;
WirePointerCount
pointerCount
=
pointersPerElement
(
oldSize
)
*
ELEMENTS
;
VALIDATE_INPUT
(
dataSize
>=
dataBitsPerElement
(
elementSize
)
*
ELEMENTS
,
"Existing list value is incompatible with expected type."
);
VALIDATE_INPUT
(
pointerCount
>=
pointersPerElement
(
elementSize
)
*
ELEMENTS
,
"Existing list value is incompatible with expected type."
);
auto
step
=
(
dataSize
+
pointerCount
*
BITS_PER_POINTER
)
/
ELEMENTS
;
return
ListBuilder
(
segment
,
ptr
,
step
,
ref
->
listRef
.
elementCount
(),
dataSize
,
pointerCount
);
return
ListBuilder
(
segment
,
ptr
,
step
,
ref
->
listRef
.
elementCount
(),
dataSize
,
pointerCount
);
}
}
}
static
CAPNPROTO_ALWAYS_INLINE
(
ListBuilder
getWritableStructListPointer
(
WirePointer
*
origRef
,
SegmentBuilder
*
origSegment
,
StructSize
elementSize
,
const
word
*
defaultValue
))
{
if
(
origRef
->
isNull
())
{
useDefault
:
if
(
defaultValue
==
nullptr
||
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
)
->
isNull
())
{
memset
(
origRef
,
0
,
sizeof
(
*
origRef
));
return
ListBuilder
();
}
word
*
ptr
=
copyMessage
(
origSegment
,
origRef
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
// Assume the default value is valid.
if
(
elementSize
.
preferredListEncoding
==
FieldSize
::
INLINE_COMPOSITE
)
{
WirePointer
*
tag
=
reinterpret_cast
<
WirePointer
*>
(
ptr
);
return
ListBuilder
(
origSegment
,
tag
+
1
,
elementSize
.
total
()
*
BITS_PER_WORD
/
ELEMENTS
,
tag
->
inlineCompositeListElementCount
(),
elementSize
.
data
*
BITS_PER_WORD
,
elementSize
.
pointers
);
}
else
{
BitCount
dataSize
=
dataBitsPerElement
(
elementSize
.
preferredListEncoding
)
*
ELEMENTS
;
WirePointerCount
pointerCount
=
pointersPerElement
(
elementSize
.
preferredListEncoding
)
*
ELEMENTS
;
auto
step
=
(
dataSize
+
pointerCount
*
BITS_PER_POINTER
)
/
ELEMENTS
;
return
ListBuilder
(
origSegment
,
ptr
,
step
,
origRef
->
listRef
.
elementCount
(),
dataSize
,
pointerCount
);
}
}
else
{
// The pointer is already initialized. We must verify that it has the right size and
// potentially upgrade it if not.
WirePointer
*
oldRef
=
origRef
;
SegmentBuilder
*
oldSegment
=
origSegment
;
word
*
oldPtr
=
followFars
(
oldRef
,
oldSegment
);
VALIDATE_INPUT
(
oldRef
->
kind
()
==
WirePointer
::
LIST
,
"Called getList{Field,Element}() but existing pointer is not a list."
)
{
goto
useDefault
;
}
FieldSize
oldSize
=
oldRef
->
listRef
.
elementSize
();
if
(
oldSize
==
FieldSize
::
INLINE_COMPOSITE
)
{
// Existing list is INLINE_COMPOSITE, but we need to verify that the sizes match.
WirePointer
*
oldTag
=
reinterpret_cast
<
WirePointer
*>
(
oldPtr
);
oldPtr
+=
POINTER_SIZE_IN_WORDS
;
VALIDATE_INPUT
(
oldTag
->
kind
()
==
WirePointer
::
STRUCT
,
"INLINE_COMPOSITE list with non-STRUCT elements not supported."
)
{
goto
useDefault
;
}
WordCount
oldDataSize
=
oldTag
->
structRef
.
dataSize
.
get
();
WirePointerCount
oldPointerCount
=
oldTag
->
structRef
.
ptrCount
.
get
();
auto
oldStep
=
(
oldDataSize
+
oldPointerCount
*
WORDS_PER_POINTER
)
/
ELEMENTS
;
ElementCount
elementCount
=
oldTag
->
inlineCompositeListElementCount
();
if
(
oldDataSize
>=
elementSize
.
data
&&
oldPointerCount
>=
elementSize
.
pointers
)
{
// Old size is at least as large as we need. Ship it.
return
ListBuilder
(
oldSegment
,
oldPtr
,
oldStep
*
BITS_PER_WORD
,
elementCount
,
oldDataSize
*
BITS_PER_WORD
,
oldPointerCount
);
}
// The structs in this list are smaller than expected, probably written using an older
// version of the protocol. We need to make a copy and expand them.
WordCount
newDataSize
=
std
::
max
<
WordCount
>
(
oldDataSize
,
elementSize
.
data
);
WirePointerCount
newPointerCount
=
std
::
max
<
WirePointerCount
>
(
oldPointerCount
,
elementSize
.
pointers
);
auto
newStep
=
(
newDataSize
+
newPointerCount
*
WORDS_PER_POINTER
)
/
ELEMENTS
;
WordCount
totalSize
=
newStep
*
elementCount
;
word
*
newPtr
=
allocate
(
origRef
,
origSegment
,
totalSize
+
POINTER_SIZE_IN_WORDS
,
WirePointer
::
LIST
);
origRef
->
listRef
.
setInlineComposite
(
totalSize
);
WirePointer
*
newTag
=
reinterpret_cast
<
WirePointer
*>
(
newPtr
);
newTag
->
setKindAndInlineCompositeListElementCount
(
WirePointer
::
STRUCT
,
elementCount
);
newTag
->
structRef
.
set
(
newDataSize
,
newPointerCount
);
newPtr
+=
POINTER_SIZE_IN_WORDS
;
word
*
src
=
oldPtr
;
word
*
dst
=
newPtr
;
for
(
uint
i
=
0
;
i
<
elementCount
/
ELEMENTS
;
i
++
)
{
// Copy data section.
memcpy
(
dst
,
src
,
oldDataSize
*
BYTES_PER_WORD
/
BYTES
);
// Copy pointer section.
WirePointer
*
newPointerSection
=
reinterpret_cast
<
WirePointer
*>
(
dst
+
newDataSize
);
WirePointer
*
oldPointerSection
=
reinterpret_cast
<
WirePointer
*>
(
src
+
oldDataSize
);
for
(
uint
i
=
0
;
i
<
oldPointerCount
/
POINTERS
;
i
++
)
{
transferPointer
(
origSegment
,
newPointerSection
+
i
,
oldSegment
,
oldPointerSection
+
i
);
}
dst
+=
newStep
*
(
1
*
ELEMENTS
);
src
+=
oldStep
*
(
1
*
ELEMENTS
);
}
return
ListBuilder
(
origSegment
,
newPtr
,
newStep
*
BITS_PER_WORD
,
elementCount
,
newDataSize
*
BITS_PER_WORD
,
newPointerCount
);
}
else
if
(
oldSize
==
elementSize
.
preferredListEncoding
)
{
// Old size matches exactly.
auto
dataSize
=
dataBitsPerElement
(
oldSize
);
auto
pointerCount
=
pointersPerElement
(
oldSize
);
auto
step
=
dataSize
+
pointerCount
*
BITS_PER_POINTER
;
return
ListBuilder
(
oldSegment
,
oldPtr
,
step
,
oldRef
->
listRef
.
elementCount
(),
dataSize
*
(
1
*
ELEMENTS
),
pointerCount
*
(
1
*
ELEMENTS
));
}
else
{
switch
(
elementSize
.
preferredListEncoding
)
{
case
FieldSize
:
:
VOID
:
// No expectations.
break
;
case
FieldSize
:
:
POINTER
:
VALIDATE_INPUT
(
oldSize
==
FieldSize
::
POINTER
||
oldSize
==
FieldSize
::
VOID
,
"Struct list has incompatible element size."
)
{
goto
useDefault
;
}
break
;
case
FieldSize
:
:
INLINE_COMPOSITE
:
// Old size can be anything.
break
;
case
FieldSize
:
:
BIT
:
case
FieldSize
:
:
BYTE
:
case
FieldSize
:
:
TWO_BYTES
:
case
FieldSize
:
:
FOUR_BYTES
:
case
FieldSize
:
:
EIGHT_BYTES
:
// Preferred size is data-only.
VALIDATE_INPUT
(
oldSize
!=
FieldSize
::
POINTER
,
"Struct list has incompatible element size."
)
{
goto
useDefault
;
}
break
;
}
// OK, the old size is compatible with the preferred, but is not exactly the same. We may
// need to upgrade it.
BitCount
oldDataSize
=
dataBitsPerElement
(
oldSize
)
*
ELEMENTS
;
WirePointerCount
oldPointerCount
=
pointersPerElement
(
oldSize
)
*
ELEMENTS
;
auto
oldStep
=
(
oldDataSize
+
oldPointerCount
*
BITS_PER_POINTER
)
/
ELEMENTS
;
ElementCount
elementCount
=
oldRef
->
listRef
.
elementCount
();
if
(
oldSize
>=
elementSize
.
preferredListEncoding
)
{
// The old size is at least as large as the preferred, so we don't need to upgrade.
return
ListBuilder
(
oldSegment
,
oldPtr
,
oldStep
,
elementCount
,
oldDataSize
,
oldPointerCount
);
}
// Upgrade is necessary.
if
(
oldSize
==
FieldSize
::
VOID
)
{
// Nothing to copy, just allocate a new list.
return
initStructListPointer
(
origRef
,
origSegment
,
elementCount
,
elementSize
);
}
else
if
(
elementSize
.
preferredListEncoding
==
FieldSize
::
INLINE_COMPOSITE
)
{
// Upgrading to an inline composite list.
WordCount
newDataSize
=
elementSize
.
data
;
WirePointerCount
newPointerCount
=
elementSize
.
pointers
;
if
(
oldSize
==
FieldSize
::
POINTER
)
{
newPointerCount
=
std
::
max
(
newPointerCount
,
1
*
POINTERS
);
}
else
{
// Old list contains data elements, so we need at least 1 word of data.
newDataSize
=
std
::
max
(
newDataSize
,
1
*
WORDS
);
}
auto
newStep
=
(
newDataSize
+
newPointerCount
*
WORDS_PER_POINTER
)
/
ELEMENTS
;
WordCount
totalWords
=
elementCount
*
newStep
;
word
*
newPtr
=
allocate
(
origRef
,
origSegment
,
totalWords
+
POINTER_SIZE_IN_WORDS
,
WirePointer
::
LIST
);
origRef
->
listRef
.
setInlineComposite
(
totalWords
);
WirePointer
*
tag
=
reinterpret_cast
<
WirePointer
*>
(
newPtr
);
tag
->
setKindAndInlineCompositeListElementCount
(
WirePointer
::
STRUCT
,
elementCount
);
tag
->
structRef
.
set
(
newDataSize
,
newPointerCount
);
newPtr
+=
POINTER_SIZE_IN_WORDS
;
if
(
oldSize
==
FieldSize
::
POINTER
)
{
WirePointer
*
dst
=
reinterpret_cast
<
WirePointer
*>
(
newPtr
+
newDataSize
);
WirePointer
*
src
=
reinterpret_cast
<
WirePointer
*>
(
oldPtr
);
for
(
uint
i
=
0
;
i
<
elementCount
/
ELEMENTS
;
i
++
)
{
transferPointer
(
origSegment
,
dst
,
oldSegment
,
src
);
dst
+=
newStep
/
WORDS_PER_POINTER
*
(
1
*
ELEMENTS
);
++
src
;
}
}
else
if
(
oldSize
==
FieldSize
::
BIT
)
{
word
*
dst
=
newPtr
;
char
*
src
=
reinterpret_cast
<
char
*>
(
oldPtr
);
for
(
uint
i
=
0
;
i
<
elementCount
/
ELEMENTS
;
i
++
)
{
*
reinterpret_cast
<
char
*>
(
dst
)
=
(
src
[
i
/
8
]
>>
(
i
%
8
))
&
1
;
dst
+=
newStep
*
(
1
*
ELEMENTS
);
}
}
else
{
word
*
dst
=
newPtr
;
char
*
src
=
reinterpret_cast
<
char
*>
(
oldPtr
);
ByteCount
oldByteStep
=
oldDataSize
/
BITS_PER_BYTE
;
for
(
uint
i
=
0
;
i
<
elementCount
/
ELEMENTS
;
i
++
)
{
memcpy
(
dst
,
src
,
oldByteStep
/
BYTES
);
src
+=
oldByteStep
/
BYTES
;
dst
+=
newStep
*
(
1
*
ELEMENTS
);
}
}
return
ListBuilder
(
origSegment
,
newPtr
,
newStep
*
BITS_PER_WORD
,
elementCount
,
newDataSize
*
BITS_PER_WORD
,
newPointerCount
);
}
else
{
// If oldSize were POINTER or EIGHT_BYTES then the preferred size must be
// INLINE_COMPOSITE because any other compatible size would not require an upgrade.
CHECK
(
oldSize
<
FieldSize
::
EIGHT_BYTES
);
// If the preferred size were BIT then oldSize must be VOID, but we handled that case
// above.
CHECK
(
elementSize
.
preferredListEncoding
>=
FieldSize
::
BIT
);
// OK, so the expected list elements are all data and between 1 byte and 1 word each,
// and the old element are data between 1 bit and 4 bytes. We're upgrading from one
// primitive data type to another, larger one.
BitCount
newDataSize
=
dataBitsPerElement
(
elementSize
.
preferredListEncoding
)
*
ELEMENTS
;
WordCount
totalWords
=
roundUpToWords
(
BitCount64
(
newDataSize
)
*
(
elementCount
/
ELEMENTS
));
word
*
newPtr
=
allocate
(
origRef
,
origSegment
,
totalWords
,
WirePointer
::
LIST
);
origRef
->
listRef
.
set
(
elementSize
.
preferredListEncoding
,
elementCount
);
char
*
newBytePtr
=
reinterpret_cast
<
char
*>
(
newPtr
);
char
*
oldBytePtr
=
reinterpret_cast
<
char
*>
(
oldPtr
);
ByteCount
newDataByteSize
=
newDataSize
/
BITS_PER_BYTE
;
if
(
oldSize
==
FieldSize
::
BIT
)
{
for
(
uint
i
=
0
;
i
<
elementCount
/
ELEMENTS
;
i
++
)
{
*
newBytePtr
=
(
oldBytePtr
[
i
/
8
]
>>
(
i
%
8
))
&
1
;
newBytePtr
+=
newDataByteSize
/
BYTES
;
}
}
else
{
ByteCount
oldDataByteSize
=
oldDataSize
/
BITS_PER_BYTE
;
for
(
uint
i
=
0
;
i
<
elementCount
/
ELEMENTS
;
i
++
)
{
memcpy
(
newBytePtr
,
oldBytePtr
,
oldDataByteSize
/
BYTES
);
oldBytePtr
+=
oldDataByteSize
/
BYTES
;
newBytePtr
+=
newDataByteSize
/
BYTES
;
}
}
return
ListBuilder
(
origSegment
,
newPtr
,
newDataSize
/
ELEMENTS
,
elementCount
,
newDataSize
,
0
*
POINTERS
);
}
}
}
}
...
...
@@ -1205,9 +1529,15 @@ ListBuilder StructBuilder::initStructListField(
}
ListBuilder
StructBuilder
::
getListField
(
WirePointerCount
ptrIndex
,
const
word
*
defaultValue
)
const
{
WirePointerCount
ptrIndex
,
FieldSize
elementSize
,
const
word
*
defaultValue
)
const
{
return
WireHelpers
::
getWritableListPointer
(
pointers
+
ptrIndex
,
segment
,
defaultValue
);
pointers
+
ptrIndex
,
segment
,
elementSize
,
defaultValue
);
}
ListBuilder
StructBuilder
::
getStructListField
(
WirePointerCount
ptrIndex
,
StructSize
elementSize
,
const
word
*
defaultValue
)
const
{
return
WireHelpers
::
getWritableStructListPointer
(
pointers
+
ptrIndex
,
segment
,
elementSize
,
defaultValue
);
}
template
<>
...
...
@@ -1363,9 +1693,16 @@ ListBuilder ListBuilder::initStructListElement(
segment
,
elementCount
,
elementSize
);
}
ListBuilder
ListBuilder
::
getListElement
(
ElementCount
index
)
const
{
ListBuilder
ListBuilder
::
getListElement
(
ElementCount
index
,
FieldSize
elementSize
)
const
{
return
WireHelpers
::
getWritableListPointer
(
reinterpret_cast
<
WirePointer
*>
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
segment
,
nullptr
);
reinterpret_cast
<
WirePointer
*>
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
segment
,
elementSize
,
nullptr
);
}
ListBuilder
ListBuilder
::
getStructListElement
(
ElementCount
index
,
StructSize
elementSize
)
const
{
return
WireHelpers
::
getWritableStructListPointer
(
reinterpret_cast
<
WirePointer
*>
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
segment
,
elementSize
,
nullptr
);
}
template
<>
...
...
c++/src/capnproto/layout.h
View file @
d43aec91
...
...
@@ -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
;
...
...
c++/src/capnproto/list.h
View file @
d43aec91
...
...
@@ -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
.
get
ListElement
(
index
*
ELEMENTS
);
return
builder
.
get
StructListElement
(
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
.
get
ListField
(
index
,
defaultValue
);
return
builder
.
get
StructListField
(
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
)
{
...
...
c++/src/capnproto/test.capnp
View file @
d43aec91
...
...
@@ -357,14 +357,14 @@ struct TestLateUnion {
struct TestOldVersion {
# A subset of TestNewVersion.
old1 @0 :Int
32
;
old1 @0 :Int
64
;
old2 @1 :Text;
old3 @2 :TestOldVersion;
}
struct TestNewVersion {
# A superset of TestOldVersion.
old1 @0 :Int
32
;
old1 @0 :Int
64
;
old2 @1 :Text;
old3 @2 :TestNewVersion;
new1 @3 :Int64 = 987;
...
...
c++/src/capnproto/type-safety.h
View file @
d43aec91
...
...
@@ -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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment