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
7f20d533
Commit
7f20d533
authored
Apr 25, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement inline structs.
parent
9e7acd4b
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1309 additions
and
447 deletions
+1309
-447
encoding-test.c++
c++/src/capnproto/encoding-test.c++
+368
-59
layout.c++
c++/src/capnproto/layout.c++
+21
-31
layout.h
c++/src/capnproto/layout.h
+88
-14
test-util.h
c++/src/capnproto/test-util.h
+3
-0
test.capnp
c++/src/capnproto/test.capnp
+139
-1
type-safety.h
c++/src/capnproto/type-safety.h
+5
-0
capnproto-compiler.cabal
compiler/capnproto-compiler.cabal
+7
-0
Compiler.hs
compiler/src/Compiler.hs
+289
-109
CxxGenerator.hs
compiler/src/CxxGenerator.hs
+27
-9
Grammar.hs
compiler/src/Grammar.hs
+5
-4
Lexer.hs
compiler/src/Lexer.hs
+1
-0
Parser.hs
compiler/src/Parser.hs
+34
-1
Semantics.hs
compiler/src/Semantics.hs
+119
-86
Token.hs
compiler/src/Token.hs
+1
-0
WireFormat.hs
compiler/src/WireFormat.hs
+173
-133
c++-header.mustache
compiler/src/c++-header.mustache
+29
-0
No files found.
c++/src/capnproto/encoding-test.c++
View file @
7f20d533
...
...
@@ -165,19 +165,14 @@ std::ostream& operator<<(std::ostream& os, const UnionState& us) {
return
os
<<
"}, "
<<
us
.
dataOffset
<<
")"
;
}
template
<
typename
T
>
T
one
()
{
return
static_cast
<
T
>
(
1
);
}
template
<>
Text
::
Reader
one
()
{
return
"1"
;
}
template
<>
Void
one
()
{
return
Void
::
VOID
;
}
template
<
typename
T
,
typename
U
>
UnionState
initUnion
(
U
(
TestUnion
::
Builder
::*
unionGetter
)(),
void
(
U
::
Builder
::*
setter
)(
T
value
))
{
template
<
typename
StructType
,
typename
Func
>
UnionState
initUnion
(
Func
&&
initializer
)
{
// Use the given setter to initialize the given union field and then return a struct indicating
// the location of the data that was written as well as the values of the four union
// discriminants.
MallocMessageBuilder
builder
;
((
builder
.
getRoot
<
TestUnion
>
().
*
unionGetter
)().
*
setter
)(
one
<
T
>
());
initializer
(
builder
.
getRoot
<
StructType
>
());
ArrayPtr
<
const
word
>
segment
=
builder
.
getSegmentsForOutput
()[
0
];
CHECK
(
segment
.
size
()
>
2
,
segment
.
size
());
...
...
@@ -204,58 +199,60 @@ found:
offset
);
}
#define INIT_UNION(unionName, fieldName) \
initUnion(&TestUnion::Builder::get##unionName, &TestUnion::unionName::Builder::set##fieldName)
TEST
(
Encoding
,
UnionLayout
)
{
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
Union0
,
U0f0s0
));
EXPECT_EQ
(
UnionState
({
1
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f0s1
));
EXPECT_EQ
(
UnionState
({
2
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f0s8
));
EXPECT_EQ
(
UnionState
({
3
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f0s16
));
EXPECT_EQ
(
UnionState
({
4
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f0s32
));
EXPECT_EQ
(
UnionState
({
5
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f0s64
));
EXPECT_EQ
(
UnionState
({
6
,
0
,
0
,
0
},
448
),
INIT_UNION
(
Union0
,
U0f0sp
));
EXPECT_EQ
(
UnionState
({
7
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
Union0
,
U0f1s0
));
EXPECT_EQ
(
UnionState
({
8
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f1s1
));
EXPECT_EQ
(
UnionState
({
9
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f1s8
));
EXPECT_EQ
(
UnionState
({
10
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f1s16
));
EXPECT_EQ
(
UnionState
({
11
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f1s32
));
EXPECT_EQ
(
UnionState
({
12
,
0
,
0
,
0
},
0
),
INIT_UNION
(
Union0
,
U0f1s64
));
EXPECT_EQ
(
UnionState
({
13
,
0
,
0
,
0
},
448
),
INIT_UNION
(
Union0
,
U0f1sp
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
Union1
,
U1f0s0
));
EXPECT_EQ
(
UnionState
({
0
,
1
,
0
,
0
},
65
),
INIT_UNION
(
Union1
,
U1f0s1
));
EXPECT_EQ
(
UnionState
({
0
,
2
,
0
,
0
},
65
),
INIT_UNION
(
Union1
,
U1f1s1
));
EXPECT_EQ
(
UnionState
({
0
,
3
,
0
,
0
},
72
),
INIT_UNION
(
Union1
,
U1f0s8
));
EXPECT_EQ
(
UnionState
({
0
,
4
,
0
,
0
},
72
),
INIT_UNION
(
Union1
,
U1f1s8
));
EXPECT_EQ
(
UnionState
({
0
,
5
,
0
,
0
},
80
),
INIT_UNION
(
Union1
,
U1f0s16
));
EXPECT_EQ
(
UnionState
({
0
,
6
,
0
,
0
},
80
),
INIT_UNION
(
Union1
,
U1f1s16
));
EXPECT_EQ
(
UnionState
({
0
,
7
,
0
,
0
},
96
),
INIT_UNION
(
Union1
,
U1f0s32
));
EXPECT_EQ
(
UnionState
({
0
,
8
,
0
,
0
},
96
),
INIT_UNION
(
Union1
,
U1f1s32
));
EXPECT_EQ
(
UnionState
({
0
,
9
,
0
,
0
},
128
),
INIT_UNION
(
Union1
,
U1f0s64
));
EXPECT_EQ
(
UnionState
({
0
,
10
,
0
,
0
},
128
),
INIT_UNION
(
Union1
,
U1f1s64
));
EXPECT_EQ
(
UnionState
({
0
,
11
,
0
,
0
},
512
),
INIT_UNION
(
Union1
,
U1f0sp
));
EXPECT_EQ
(
UnionState
({
0
,
12
,
0
,
0
},
512
),
INIT_UNION
(
Union1
,
U1f1sp
));
EXPECT_EQ
(
UnionState
({
0
,
13
,
0
,
0
},
-
1
),
INIT_UNION
(
Union1
,
U1f2s0
));
EXPECT_EQ
(
UnionState
({
0
,
14
,
0
,
0
},
128
),
INIT_UNION
(
Union1
,
U1f2s1
));
EXPECT_EQ
(
UnionState
({
0
,
15
,
0
,
0
},
128
),
INIT_UNION
(
Union1
,
U1f2s8
));
EXPECT_EQ
(
UnionState
({
0
,
16
,
0
,
0
},
128
),
INIT_UNION
(
Union1
,
U1f2s16
));
EXPECT_EQ
(
UnionState
({
0
,
17
,
0
,
0
},
128
),
INIT_UNION
(
Union1
,
U1f2s32
));
EXPECT_EQ
(
UnionState
({
0
,
18
,
0
,
0
},
128
),
INIT_UNION
(
Union1
,
U1f2s64
));
EXPECT_EQ
(
UnionState
({
0
,
19
,
0
,
0
},
512
),
INIT_UNION
(
Union1
,
U1f2sp
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
192
),
INIT_UNION
(
Union2
,
U2f0s1
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
193
),
INIT_UNION
(
Union3
,
U3f0s1
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
1
,
0
},
200
),
INIT_UNION
(
Union2
,
U2f0s8
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
1
},
208
),
INIT_UNION
(
Union3
,
U3f0s8
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
2
,
0
},
224
),
INIT_UNION
(
Union2
,
U2f0s16
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
2
},
240
),
INIT_UNION
(
Union3
,
U3f0s16
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
3
,
0
},
256
),
INIT_UNION
(
Union2
,
U2f0s32
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
3
},
288
),
INIT_UNION
(
Union3
,
U3f0s32
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
4
,
0
},
320
),
INIT_UNION
(
Union2
,
U2f0s64
));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
4
},
384
),
INIT_UNION
(
Union3
,
U3f0s64
));
#define INIT_UNION(setter) \
initUnion<TestUnion>([](TestUnion::Builder b) {b.setter;})
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
getUnion0
().
setU0f0s0
(
Void
::
VOID
)));
EXPECT_EQ
(
UnionState
({
1
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f0s1
(
1
)));
EXPECT_EQ
(
UnionState
({
2
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f0s8
(
1
)));
EXPECT_EQ
(
UnionState
({
3
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f0s16
(
1
)));
EXPECT_EQ
(
UnionState
({
4
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f0s32
(
1
)));
EXPECT_EQ
(
UnionState
({
5
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f0s64
(
1
)));
EXPECT_EQ
(
UnionState
({
6
,
0
,
0
,
0
},
448
),
INIT_UNION
(
getUnion0
().
setU0f0sp
(
"1"
)));
EXPECT_EQ
(
UnionState
({
7
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
getUnion0
().
setU0f1s0
(
Void
::
VOID
)));
EXPECT_EQ
(
UnionState
({
8
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f1s1
(
1
)));
EXPECT_EQ
(
UnionState
({
9
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f1s8
(
1
)));
EXPECT_EQ
(
UnionState
({
10
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f1s16
(
1
)));
EXPECT_EQ
(
UnionState
({
11
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f1s32
(
1
)));
EXPECT_EQ
(
UnionState
({
12
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
setU0f1s64
(
1
)));
EXPECT_EQ
(
UnionState
({
13
,
0
,
0
,
0
},
448
),
INIT_UNION
(
getUnion0
().
setU0f1sp
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
getUnion1
().
setU1f0s0
(
Void
::
VOID
)));
EXPECT_EQ
(
UnionState
({
0
,
1
,
0
,
0
},
65
),
INIT_UNION
(
getUnion1
().
setU1f0s1
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
2
,
0
,
0
},
65
),
INIT_UNION
(
getUnion1
().
setU1f1s1
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
3
,
0
,
0
},
72
),
INIT_UNION
(
getUnion1
().
setU1f0s8
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
4
,
0
,
0
},
72
),
INIT_UNION
(
getUnion1
().
setU1f1s8
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
5
,
0
,
0
},
80
),
INIT_UNION
(
getUnion1
().
setU1f0s16
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
6
,
0
,
0
},
80
),
INIT_UNION
(
getUnion1
().
setU1f1s16
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
7
,
0
,
0
},
96
),
INIT_UNION
(
getUnion1
().
setU1f0s32
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
8
,
0
,
0
},
96
),
INIT_UNION
(
getUnion1
().
setU1f1s32
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
9
,
0
,
0
},
128
),
INIT_UNION
(
getUnion1
().
setU1f0s64
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
10
,
0
,
0
},
128
),
INIT_UNION
(
getUnion1
().
setU1f1s64
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
11
,
0
,
0
},
512
),
INIT_UNION
(
getUnion1
().
setU1f0sp
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
12
,
0
,
0
},
512
),
INIT_UNION
(
getUnion1
().
setU1f1sp
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
13
,
0
,
0
},
-
1
),
INIT_UNION
(
getUnion1
().
setU1f2s0
(
Void
::
VOID
)));
EXPECT_EQ
(
UnionState
({
0
,
14
,
0
,
0
},
128
),
INIT_UNION
(
getUnion1
().
setU1f2s1
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
15
,
0
,
0
},
128
),
INIT_UNION
(
getUnion1
().
setU1f2s8
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
16
,
0
,
0
},
128
),
INIT_UNION
(
getUnion1
().
setU1f2s16
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
17
,
0
,
0
},
128
),
INIT_UNION
(
getUnion1
().
setU1f2s32
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
18
,
0
,
0
},
128
),
INIT_UNION
(
getUnion1
().
setU1f2s64
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
19
,
0
,
0
},
512
),
INIT_UNION
(
getUnion1
().
setU1f2sp
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
192
),
INIT_UNION
(
getUnion2
().
setU2f0s1
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
193
),
INIT_UNION
(
getUnion3
().
setU3f0s1
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
1
,
0
},
200
),
INIT_UNION
(
getUnion2
().
setU2f0s8
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
1
},
208
),
INIT_UNION
(
getUnion3
().
setU3f0s8
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
2
,
0
},
224
),
INIT_UNION
(
getUnion2
().
setU2f0s16
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
2
},
240
),
INIT_UNION
(
getUnion3
().
setU3f0s16
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
3
,
0
},
256
),
INIT_UNION
(
getUnion2
().
setU2f0s32
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
3
},
288
),
INIT_UNION
(
getUnion3
().
setU3f0s32
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
4
,
0
},
320
),
INIT_UNION
(
getUnion2
().
setU2f0s64
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
4
},
384
),
INIT_UNION
(
getUnion3
().
setU3f0s64
(
1
)));
#undef INIT_UNION
}
TEST
(
Encoding
,
UnionDefault
)
{
...
...
@@ -287,6 +284,318 @@ TEST(Encoding, UnionDefault) {
}
}
// =======================================================================================
TEST
(
Encoding
,
InlineStructUnionLayout
)
{
uint
ptrOffset
=
TestInlineUnions
::
STRUCT_SIZE
.
data
*
BITS_PER_WORD
/
BITS
-
64
;
auto
ptr
=
[
=
](
uint
i
)
{
return
ptrOffset
+
i
*
64
;
};
#define INIT_UNION(setter) \
initUnion<TestInlineUnions>([](TestInlineUnions::Builder b) {b.setter;})
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
getUnion0
().
initF0
()));
EXPECT_EQ
(
UnionState
({
1
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF1
().
setF
(
1
)));
EXPECT_EQ
(
UnionState
({
2
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF8
().
setF0
(
true
)));
EXPECT_EQ
(
UnionState
({
3
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF16
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
4
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF32
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
5
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF64
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
6
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF128
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
7
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF192
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
8
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
getUnion0
().
initF0p
().
initF
()));
EXPECT_EQ
(
UnionState
({
9
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF1p
().
initF
().
setF
(
1
)));
EXPECT_EQ
(
UnionState
({
10
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF8p
().
initF
().
setF0
(
true
)));
EXPECT_EQ
(
UnionState
({
11
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF16p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
12
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF32p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
13
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF64p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
14
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF128p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
15
,
0
,
0
,
0
},
0
),
INIT_UNION
(
getUnion0
().
initF192p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
8
,
0
,
0
,
0
},
ptr
(
0
)),
INIT_UNION
(
getUnion0
().
initF0p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
9
,
0
,
0
,
0
},
ptr
(
0
)),
INIT_UNION
(
getUnion0
().
initF1p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
10
,
0
,
0
,
0
},
ptr
(
0
)),
INIT_UNION
(
getUnion0
().
initF8p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
11
,
0
,
0
,
0
},
ptr
(
0
)),
INIT_UNION
(
getUnion0
().
initF16p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
12
,
0
,
0
,
0
},
ptr
(
0
)),
INIT_UNION
(
getUnion0
().
initF32p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
13
,
0
,
0
,
0
},
ptr
(
0
)),
INIT_UNION
(
getUnion0
().
initF64p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
14
,
0
,
0
,
0
},
ptr
(
0
)),
INIT_UNION
(
getUnion0
().
initF128p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
15
,
0
,
0
,
0
},
ptr
(
0
)),
INIT_UNION
(
getUnion0
().
initF192p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
-
1
),
INIT_UNION
(
getUnion1
().
initF0
()));
EXPECT_EQ
(
UnionState
({
0
,
1
,
0
,
0
},
193
),
INIT_UNION
(
getUnion1
().
initF1
().
setF
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
2
,
0
,
0
},
200
),
INIT_UNION
(
getUnion1
().
initF8
().
setF0
(
true
)));
EXPECT_EQ
(
UnionState
({
0
,
3
,
0
,
0
},
208
),
INIT_UNION
(
getUnion1
().
initF16
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
4
,
0
,
0
},
224
),
INIT_UNION
(
getUnion1
().
initF32
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
5
,
0
,
0
},
256
),
INIT_UNION
(
getUnion1
().
initF64
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
6
,
0
,
0
},
256
),
INIT_UNION
(
getUnion1
().
initF128
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
7
,
0
,
0
},
256
),
INIT_UNION
(
getUnion1
().
initF192
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
448
),
INIT_UNION
(
getUnion2
().
initF1p
().
initF
().
setF
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
449
),
INIT_UNION
(
getUnion3
().
initF1p
().
initF
().
setF
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
1
,
0
},
456
),
INIT_UNION
(
getUnion2
().
initF8p
().
initF
().
setF0
(
true
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
1
},
464
),
INIT_UNION
(
getUnion3
().
initF8p
().
initF
().
setF0
(
true
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
2
,
0
},
480
),
INIT_UNION
(
getUnion2
().
initF16p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
2
},
496
),
INIT_UNION
(
getUnion3
().
initF16p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
3
,
0
},
512
),
INIT_UNION
(
getUnion2
().
initF32p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
3
},
544
),
INIT_UNION
(
getUnion3
().
initF32p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
4
,
0
},
576
),
INIT_UNION
(
getUnion2
().
initF64p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
4
},
640
),
INIT_UNION
(
getUnion3
().
initF64p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
5
,
0
},
704
),
INIT_UNION
(
getUnion2
().
initF128p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
5
},
832
),
INIT_UNION
(
getUnion3
().
initF128p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
6
,
0
},
960
),
INIT_UNION
(
getUnion2
().
initF192p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
6
},
1152
),
INIT_UNION
(
getUnion3
().
initF192p
().
initF
().
setF0
(
1
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
ptr
(
3
)),
INIT_UNION
(
getUnion2
().
initF1p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
0
},
ptr
(
4
)),
INIT_UNION
(
getUnion3
().
initF1p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
1
,
0
},
ptr
(
3
)),
INIT_UNION
(
getUnion2
().
initF8p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
1
},
ptr
(
4
)),
INIT_UNION
(
getUnion3
().
initF8p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
2
,
0
},
ptr
(
5
)),
INIT_UNION
(
getUnion2
().
initF16p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
2
},
ptr
(
7
)),
INIT_UNION
(
getUnion3
().
initF16p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
3
,
0
},
ptr
(
5
)),
INIT_UNION
(
getUnion2
().
initF32p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
3
},
ptr
(
7
)),
INIT_UNION
(
getUnion3
().
initF32p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
4
,
0
},
ptr
(
5
)),
INIT_UNION
(
getUnion2
().
initF64p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
4
},
ptr
(
7
)),
INIT_UNION
(
getUnion3
().
initF64p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
5
,
0
},
ptr
(
9
)),
INIT_UNION
(
getUnion2
().
initF128p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
5
},
ptr
(
12
)),
INIT_UNION
(
getUnion3
().
initF128p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
6
,
0
},
ptr
(
9
)),
INIT_UNION
(
getUnion2
().
initF192p
().
setP0
(
"1"
)));
EXPECT_EQ
(
UnionState
({
0
,
0
,
0
,
6
},
ptr
(
12
)),
INIT_UNION
(
getUnion3
().
initF192p
().
setP0
(
"1"
)));
#undef INIT_UNION
}
TEST
(
Encoding
,
InitInlineStruct
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
getRoot
<
TestInlineLayout
>
();
// Set as many bits as we can.
root
.
initF1
().
setF
(
true
);
root
.
initF1Offset
().
setF
(
true
);
root
.
setBit
(
true
);
root
.
initF8
().
setF0
(
true
);
root
.
getF8
().
setF1
(
true
);
root
.
getF8
().
setF2
(
true
);
root
.
initF16
().
setF0
(
0xffu
);
root
.
getF16
().
setF1
(
0xffu
);
root
.
initF32
().
setF0
(
0xffu
);
root
.
getF32
().
setF1
(
0xffffu
);
root
.
initF64
().
setF0
(
0xffu
);
root
.
getF64
().
setF1
(
0xffffffffu
);
root
.
initF128
().
setF0
(
0xffffffffffffffffull
);
root
.
getF128
().
setF1
(
0xffffffffffffffffull
);
root
.
initF192
().
setF0
(
0xffffffffffffffffull
);
root
.
getF192
().
setF1
(
0xffffffffffffffffull
);
root
.
getF192
().
setF2
(
0xffffffffffffffffull
);
root
.
initF0p
().
setP0
(
"foo"
);
root
.
initF1p
().
setP0
(
"foo"
);
root
.
getF1p
().
initF
().
setF
(
true
);
root
.
initF8p
().
setP0
(
"foo"
);
root
.
initF16p
().
setP0
(
"foo"
);
root
.
getF16p
().
setP1
(
"foo"
);
root
.
initF32p
().
setP0
(
"foo"
);
root
.
getF32p
().
setP1
(
"foo"
);
root
.
initF64p
().
setP0
(
"foo"
);
root
.
getF64p
().
setP1
(
"foo"
);
root
.
initF128p
().
setP0
(
"foo"
);
root
.
getF128p
().
setP1
(
"foo"
);
root
.
getF128p
().
setP2
(
"foo"
);
root
.
initF192p
().
setP0
(
"foo"
);
root
.
getF192p
().
setP1
(
"foo"
);
root
.
getF192p
().
setP2
(
"foo"
);
// Now try re-initializing each thing and making sure the surrounding things aren't modified.
EXPECT_FALSE
(
root
.
initF1
().
getF
());
EXPECT_TRUE
(
root
.
getF1Offset
().
getF
());
root
.
getF1
().
setF
(
true
);
EXPECT_FALSE
(
root
.
initF1Offset
().
getF
());
EXPECT_TRUE
(
root
.
getF1
().
getF
());
EXPECT_TRUE
(
root
.
getBit
());
EXPECT_TRUE
(
root
.
getF8
().
getF0
());
root
.
getF1Offset
().
setF
(
true
);
EXPECT_FALSE
(
root
.
initF8
().
getF0
());
EXPECT_FALSE
(
root
.
getF8
().
getF1
());
EXPECT_FALSE
(
root
.
getF8
().
getF2
());
EXPECT_TRUE
(
root
.
getF1
().
getF
());
EXPECT_TRUE
(
root
.
getBit
());
EXPECT_EQ
(
0xffu
,
root
.
getF16
().
getF0
());
root
.
initF8
().
setF0
(
true
);
root
.
getF8
().
setF1
(
true
);
root
.
getF8
().
setF2
(
true
);
EXPECT_EQ
(
0u
,
root
.
initF16
().
getF0
());
EXPECT_EQ
(
0u
,
root
.
getF16
().
getF1
());
EXPECT_TRUE
(
root
.
getF8
().
getF0
());
EXPECT_TRUE
(
root
.
getF8
().
getF1
());
EXPECT_TRUE
(
root
.
getF8
().
getF2
());
EXPECT_EQ
(
0xffu
,
root
.
getF32
().
getF0
());
root
.
getF16
().
setF0
(
0xffu
);
root
.
getF16
().
setF1
(
0xffu
);
EXPECT_EQ
(
0u
,
root
.
initF32
().
getF0
());
EXPECT_EQ
(
0u
,
root
.
getF32
().
getF1
());
EXPECT_EQ
(
0xffu
,
root
.
getF16
().
getF0
());
EXPECT_EQ
(
0xffu
,
root
.
getF16
().
getF1
());
EXPECT_EQ
(
0xffu
,
root
.
getF64
().
getF0
());
root
.
getF32
().
setF0
(
0xffu
);
root
.
getF32
().
setF1
(
0xffffu
);
EXPECT_EQ
(
0u
,
root
.
initF64
().
getF0
());
EXPECT_EQ
(
0u
,
root
.
getF64
().
getF1
());
EXPECT_EQ
(
0xffu
,
root
.
getF32
().
getF0
());
EXPECT_EQ
(
0xffffu
,
root
.
getF32
().
getF1
());
EXPECT_EQ
(
0xffffffffffffffffull
,
root
.
getF128
().
getF0
());
root
.
getF64
().
setF0
(
0xffu
);
root
.
getF64
().
setF1
(
0xffffffffu
);
EXPECT_EQ
(
0u
,
root
.
initF128
().
getF0
());
EXPECT_EQ
(
0u
,
root
.
getF128
().
getF1
());
EXPECT_EQ
(
0xffu
,
root
.
getF64
().
getF0
());
EXPECT_EQ
(
0xffffffffu
,
root
.
getF64
().
getF1
());
EXPECT_EQ
(
0xffffffffffffffffull
,
root
.
getF192
().
getF0
());
root
.
getF128
().
setF0
(
0xffffffffffffffffull
);
root
.
getF128
().
setF1
(
0xffffffffffffffffull
);
EXPECT_EQ
(
0u
,
root
.
initF192
().
getF0
());
EXPECT_EQ
(
0u
,
root
.
getF192
().
getF1
());
EXPECT_EQ
(
0u
,
root
.
getF192
().
getF2
());
EXPECT_EQ
(
0xffffffffffffffffull
,
root
.
getF128
().
getF0
());
EXPECT_EQ
(
0xffffffffffffffffull
,
root
.
getF128
().
getF1
());
EXPECT_TRUE
(
root
.
getF1p
().
getF
().
getF
());
root
.
getF192
().
setF0
(
0xffffffffffffffffull
);
root
.
getF192
().
setF1
(
0xffffffffffffffffull
);
root
.
getF192
().
setF2
(
0xffffffffffffffffull
);
EXPECT_EQ
(
""
,
root
.
initF0p
().
getP0
());
EXPECT_EQ
(
"foo"
,
root
.
getF1p
().
getP0
());
root
.
getF0p
().
setP0
(
"foo"
);
EXPECT_EQ
(
""
,
root
.
initF1p
().
getP0
());
EXPECT_EQ
(
"foo"
,
root
.
getF0p
().
getP0
());
EXPECT_EQ
(
"foo"
,
root
.
getF8p
().
getP0
());
root
.
getF1p
().
setP0
(
"foo"
);
EXPECT_EQ
(
""
,
root
.
initF8p
().
getP0
());
EXPECT_EQ
(
"foo"
,
root
.
getF1p
().
getP0
());
EXPECT_EQ
(
"foo"
,
root
.
getF16p
().
getP0
());
root
.
initF8p
().
setP0
(
"foo"
);
EXPECT_EQ
(
""
,
root
.
initF16p
().
getP0
());
EXPECT_EQ
(
""
,
root
.
getF16p
().
getP1
());
EXPECT_EQ
(
"foo"
,
root
.
getF8p
().
getP0
());
EXPECT_EQ
(
"foo"
,
root
.
getF32p
().
getP0
());
root
.
initF16p
().
setP0
(
"foo"
);
root
.
getF16p
().
setP1
(
"foo"
);
EXPECT_EQ
(
""
,
root
.
initF32p
().
getP0
());
EXPECT_EQ
(
""
,
root
.
getF32p
().
getP1
());
EXPECT_EQ
(
"foo"
,
root
.
getF16p
().
getP1
());
EXPECT_EQ
(
"foo"
,
root
.
getF64p
().
getP0
());
root
.
initF32p
().
setP0
(
"foo"
);
root
.
getF32p
().
setP1
(
"foo"
);
EXPECT_EQ
(
""
,
root
.
initF64p
().
getP0
());
EXPECT_EQ
(
""
,
root
.
getF64p
().
getP1
());
EXPECT_EQ
(
"foo"
,
root
.
getF32p
().
getP1
());
EXPECT_EQ
(
"foo"
,
root
.
getF128p
().
getP0
());
root
.
initF64p
().
setP0
(
"foo"
);
root
.
getF64p
().
setP1
(
"foo"
);
EXPECT_EQ
(
""
,
root
.
initF128p
().
getP0
());
EXPECT_EQ
(
""
,
root
.
getF128p
().
getP1
());
EXPECT_EQ
(
""
,
root
.
getF128p
().
getP2
());
EXPECT_EQ
(
"foo"
,
root
.
getF64p
().
getP1
());
EXPECT_EQ
(
"foo"
,
root
.
getF192p
().
getP0
());
root
.
initF128p
().
setP0
(
"foo"
);
root
.
getF128p
().
setP1
(
"foo"
);
root
.
getF128p
().
setP2
(
"foo"
);
EXPECT_EQ
(
""
,
root
.
initF192p
().
getP0
());
EXPECT_EQ
(
""
,
root
.
getF192p
().
getP1
());
EXPECT_EQ
(
""
,
root
.
getF192p
().
getP2
());
EXPECT_EQ
(
"foo"
,
root
.
getF128p
().
getP2
());
root
.
initF192p
().
setP0
(
"foo"
);
root
.
getF192p
().
setP1
(
"foo"
);
root
.
getF192p
().
setP2
(
"foo"
);
}
TEST
(
Encoding
,
InlineDefaults
)
{
MallocMessageBuilder
builder
;
TestInlineDefaults
::
Reader
reader
=
builder
.
getRoot
<
TestInlineDefaults
>
().
asReader
();
{
auto
normal
=
reader
.
getNormal
();
EXPECT_TRUE
(
normal
.
getF1
().
getF
());
EXPECT_TRUE
(
normal
.
getF8
().
getF0
());
EXPECT_FALSE
(
normal
.
getF8
().
getF1
());
EXPECT_TRUE
(
normal
.
getF8
().
getF2
());
EXPECT_EQ
(
123u
,
normal
.
getF16
().
getF0
());
EXPECT_EQ
(
45u
,
normal
.
getF16
().
getF1
());
EXPECT_EQ
(
67u
,
normal
.
getF32
().
getF0
());
EXPECT_EQ
(
8901u
,
normal
.
getF32
().
getF1
());
EXPECT_EQ
(
234u
,
normal
.
getF64
().
getF0
());
EXPECT_EQ
(
567890123u
,
normal
.
getF64
().
getF1
());
EXPECT_EQ
(
1234567890123ull
,
normal
.
getF128
().
getF0
());
EXPECT_EQ
(
4567890123456ull
,
normal
.
getF128
().
getF1
());
EXPECT_EQ
(
7890123456789ull
,
normal
.
getF192
().
getF0
());
EXPECT_EQ
(
2345678901234ull
,
normal
.
getF192
().
getF1
());
EXPECT_EQ
(
5678901234567ull
,
normal
.
getF192
().
getF2
());
EXPECT_FALSE
(
normal
.
getF1p
().
getF
().
getF
());
EXPECT_TRUE
(
normal
.
getF8p
().
getF
().
getF0
());
EXPECT_TRUE
(
normal
.
getF8p
().
getF
().
getF1
());
EXPECT_FALSE
(
normal
.
getF8p
().
getF
().
getF2
());
EXPECT_EQ
(
98u
,
normal
.
getF16p
().
getF
().
getF0
());
EXPECT_EQ
(
76u
,
normal
.
getF16p
().
getF
().
getF1
());
EXPECT_EQ
(
54u
,
normal
.
getF32p
().
getF
().
getF0
());
EXPECT_EQ
(
32109u
,
normal
.
getF32p
().
getF
().
getF1
());
EXPECT_EQ
(
87u
,
normal
.
getF64p
().
getF
().
getF0
());
EXPECT_EQ
(
654321098u
,
normal
.
getF64p
().
getF
().
getF1
());
EXPECT_EQ
(
7654321098765ull
,
normal
.
getF128p
().
getF
().
getF0
());
EXPECT_EQ
(
4321098765432ull
,
normal
.
getF128p
().
getF
().
getF1
());
EXPECT_EQ
(
1098765432109ull
,
normal
.
getF192p
().
getF
().
getF0
());
EXPECT_EQ
(
8765432109876ull
,
normal
.
getF192p
().
getF
().
getF1
());
EXPECT_EQ
(
5432109876543ull
,
normal
.
getF192p
().
getF
().
getF2
());
EXPECT_EQ
(
"foo"
,
normal
.
getF0p
().
getP0
());
EXPECT_EQ
(
"bar"
,
normal
.
getF1p
().
getP0
());
EXPECT_EQ
(
"baz"
,
normal
.
getF8p
().
getP0
());
EXPECT_EQ
(
"qux"
,
normal
.
getF16p
().
getP0
());
EXPECT_EQ
(
"quux"
,
normal
.
getF16p
().
getP1
());
EXPECT_EQ
(
"corge"
,
normal
.
getF32p
().
getP0
());
EXPECT_EQ
(
"grault"
,
normal
.
getF32p
().
getP1
());
EXPECT_EQ
(
"garply"
,
normal
.
getF64p
().
getP0
());
EXPECT_EQ
(
"waldo"
,
normal
.
getF64p
().
getP1
());
EXPECT_EQ
(
"fred"
,
normal
.
getF128p
().
getP0
());
EXPECT_EQ
(
"plugh"
,
normal
.
getF128p
().
getP1
());
EXPECT_EQ
(
"xyzzy"
,
normal
.
getF128p
().
getP2
());
EXPECT_EQ
(
"thud"
,
normal
.
getF192p
().
getP0
());
EXPECT_EQ
(
"foobar"
,
normal
.
getF192p
().
getP1
());
EXPECT_EQ
(
"barbaz"
,
normal
.
getF192p
().
getP2
());
}
{
auto
unions
=
reader
.
getUnions
();
ASSERT_EQ
(
TestInlineUnions
::
Union0
::
F32
,
unions
.
getUnion0
().
which
());
EXPECT_EQ
(
67u
,
unions
.
getUnion0
().
getF32
().
getF0
());
EXPECT_EQ
(
8901u
,
unions
.
getUnion0
().
getF32
().
getF1
());
ASSERT_EQ
(
TestInlineUnions
::
Union1
::
F128
,
unions
.
getUnion1
().
which
());
EXPECT_EQ
(
1234567890123ull
,
unions
.
getUnion1
().
getF128
().
getF0
());
EXPECT_EQ
(
4567890123456ull
,
unions
.
getUnion1
().
getF128
().
getF1
());
ASSERT_EQ
(
TestInlineUnions
::
Union2
::
F1P
,
unions
.
getUnion2
().
which
());
EXPECT_EQ
(
"foo"
,
unions
.
getUnion2
().
getF1p
().
getP0
());
ASSERT_EQ
(
TestInlineUnions
::
Union3
::
F16P
,
unions
.
getUnion3
().
which
());
EXPECT_EQ
(
98u
,
unions
.
getUnion3
().
getF16p
().
getF
().
getF0
());
EXPECT_EQ
(
76u
,
unions
.
getUnion3
().
getF16p
().
getF
().
getF1
());
EXPECT_EQ
(
"qux"
,
unions
.
getUnion3
().
getF16p
().
getP0
());
EXPECT_EQ
(
"quux"
,
unions
.
getUnion3
().
getF16p
().
getP1
());
}
}
// =======================================================================================
// Tests of generated code, not really of the encoding.
// TODO(cleanup): Move to a different test?
...
...
c++/src/capnproto/layout.c++
View file @
7f20d533
...
...
@@ -415,7 +415,7 @@ struct WireHelpers {
ref
->
structRef
.
set
(
size
);
// Build the StructBuilder.
return
StructBuilder
(
segment
,
ptr
,
reinterpret_cast
<
WireReference
*>
(
ptr
+
size
.
data
));
return
StructBuilder
(
segment
,
ptr
,
reinterpret_cast
<
WireReference
*>
(
ptr
+
size
.
data
)
,
0
*
BITS
);
}
static
CAPNPROTO_ALWAYS_INLINE
(
StructBuilder
getWritableStructReference
(
...
...
@@ -442,7 +442,7 @@ struct WireHelpers {
"Trying to update struct with incorrect reference count."
);
}
return
StructBuilder
(
segment
,
ptr
,
reinterpret_cast
<
WireReference
*>
(
ptr
+
size
.
data
));
return
StructBuilder
(
segment
,
ptr
,
reinterpret_cast
<
WireReference
*>
(
ptr
+
size
.
data
)
,
0
*
BITS
);
}
static
CAPNPROTO_ALWAYS_INLINE
(
ListBuilder
initListReference
(
...
...
@@ -603,7 +603,7 @@ struct WireHelpers {
if
(
ref
==
nullptr
||
ref
->
isNull
())
{
useDefault
:
if
(
defaultValue
==
nullptr
)
{
return
StructReader
(
nullptr
,
nullptr
,
nullptr
,
0
*
WORD
S
,
0
*
REFERENCES
,
0
*
BITS
,
return
StructReader
(
nullptr
,
nullptr
,
nullptr
,
0
*
BIT
S
,
0
*
REFERENCES
,
0
*
BITS
,
std
::
numeric_limits
<
int
>::
max
());
}
segment
=
nullptr
;
...
...
@@ -637,7 +637,7 @@ struct WireHelpers {
return
StructReader
(
segment
,
ptr
,
reinterpret_cast
<
const
WireReference
*>
(
ptr
+
ref
->
structRef
.
dataSize
.
get
()),
ref
->
structRef
.
dataSize
.
get
(),
ref
->
structRef
.
dataSize
.
get
()
*
BITS_PER_WORD
,
ref
->
structRef
.
refCount
.
get
(),
0
*
BITS
,
nestingLimit
-
1
);
}
...
...
@@ -752,7 +752,8 @@ struct WireHelpers {
}
return
ListReader
(
segment
,
ptr
,
size
,
wordsPerElement
*
BITS_PER_WORD
,
tag
->
structRef
.
dataSize
.
get
(),
tag
->
structRef
.
refCount
.
get
(),
nestingLimit
-
1
);
tag
->
structRef
.
dataSize
.
get
()
*
BITS_PER_WORD
,
tag
->
structRef
.
refCount
.
get
(),
nestingLimit
-
1
);
}
else
{
// The elements of the list are NOT structs.
...
...
@@ -774,28 +775,17 @@ struct WireHelpers {
// old version of the protocol. We need to verify that the struct's first field matches
// what the sender sent us.
WordCount
dataSize
;
WireReferenceCount
referenceCount
;
BitCount
dataSize
=
0
*
BITS
;
WireReferenceCount
referenceCount
=
0
*
REFERENCES
;
switch
(
ref
->
listRef
.
elementSize
())
{
case
FieldSize
:
:
VOID
:
dataSize
=
0
*
WORDS
;
referenceCount
=
0
*
REFERENCES
;
break
;
case
FieldSize
:
:
BIT
:
case
FieldSize
:
:
BYTE
:
case
FieldSize
:
:
TWO_BYTES
:
case
FieldSize
:
:
FOUR_BYTES
:
case
FieldSize
:
:
EIGHT_BYTES
:
dataSize
=
1
*
WORDS
;
referenceCount
=
0
*
REFERENCES
;
break
;
case
FieldSize
:
:
REFERENCE
:
dataSize
=
0
*
WORDS
;
referenceCount
=
1
*
REFERENCES
;
break
;
case
FieldSize
:
:
VOID
:
break
;
case
FieldSize
:
:
BIT
:
dataSize
=
1
*
BITS
;
break
;
case
FieldSize
:
:
BYTE
:
dataSize
=
8
*
BITS
;
break
;
case
FieldSize
:
:
TWO_BYTES
:
dataSize
=
16
*
BITS
;
break
;
case
FieldSize
:
:
FOUR_BYTES
:
dataSize
=
32
*
BITS
;
break
;
case
FieldSize
:
:
EIGHT_BYTES
:
dataSize
=
64
*
BITS
;
break
;
case
FieldSize
:
:
REFERENCE
:
referenceCount
=
1
*
REFERENCES
;
break
;
case
FieldSize
:
:
INLINE_COMPOSITE
:
FAIL_CHECK
();
...
...
@@ -978,7 +968,7 @@ StructReader StructBuilder::asReader() const {
static_assert
(
sizeof
(
WireReference
::
structRef
.
refCount
)
==
2
,
"Has the maximum reference count changed?"
);
return
StructReader
(
segment
,
data
,
references
,
0xffff
*
WORD
S
,
0xffff
*
REFERENCES
,
0
*
BITS
,
std
::
numeric_limits
<
int
>::
max
());
0xffff
ffff
*
BIT
S
,
0xffff
*
REFERENCES
,
0
*
BITS
,
std
::
numeric_limits
<
int
>::
max
());
}
StructReader
StructReader
::
readRootTrusted
(
const
word
*
location
)
{
...
...
@@ -998,7 +988,7 @@ StructReader StructReader::readRoot(
}
StructReader
StructReader
::
readEmpty
()
{
return
StructReader
(
nullptr
,
nullptr
,
nullptr
,
0
*
WORD
S
,
0
*
REFERENCES
,
0
*
BITS
,
return
StructReader
(
nullptr
,
nullptr
,
nullptr
,
0
*
BIT
S
,
0
*
REFERENCES
,
0
*
BITS
,
std
::
numeric_limits
<
int
>::
max
());
}
...
...
@@ -1031,7 +1021,7 @@ StructBuilder ListBuilder::getStructElement(
ElementCount
index
,
decltype
(
WORDS
/
ELEMENTS
)
elementSize
,
WordCount
structDataSize
)
const
{
word
*
structPtr
=
ptr
+
elementSize
*
index
;
return
StructBuilder
(
segment
,
structPtr
,
reinterpret_cast
<
WireReference
*>
(
structPtr
+
structDataSize
));
reinterpret_cast
<
WireReference
*>
(
structPtr
+
structDataSize
)
,
0
*
BITS
);
}
ListBuilder
ListBuilder
::
initListElement
(
...
...
@@ -1087,9 +1077,9 @@ ListReader ListBuilder::asReader(FieldSize elementSize) const {
std
::
numeric_limits
<
int
>::
max
());
}
ListReader
ListBuilder
::
asReader
(
Word
Count
dataSize
,
WireReferenceCount
referenceCount
)
const
{
ListReader
ListBuilder
::
asReader
(
Bit
Count
dataSize
,
WireReferenceCount
referenceCount
)
const
{
return
ListReader
(
segment
,
ptr
,
elementCount
,
(
dataSize
+
referenceCount
*
WORDS_PER_REFERENCE
)
*
BITS_PER_WORD
/
ELEMENTS
,
(
dataSize
+
referenceCount
*
WORDS_PER_REFERENCE
*
BITS_PER_WORD
)
/
ELEMENTS
,
dataSize
,
referenceCount
,
std
::
numeric_limits
<
int
>::
max
());
}
...
...
@@ -1103,7 +1093,7 @@ StructReader ListReader::getStructElement(ElementCount index) const {
const
byte
*
structPtr
=
reinterpret_cast
<
const
byte
*>
(
ptr
)
+
indexBit
/
BITS_PER_BYTE
;
return
StructReader
(
segment
,
structPtr
,
reinterpret_cast
<
const
WireReference
*>
(
structPtr
+
structDataSize
*
BYTES_PER_WORD
),
reinterpret_cast
<
const
WireReference
*>
(
structPtr
+
structDataSize
/
BITS_PER_BYTE
),
structDataSize
,
structReferenceCount
,
indexBit
%
BITS_PER_BYTE
,
nestingLimit
-
1
);
}
...
...
c++/src/capnproto/layout.h
View file @
7f20d533
...
...
@@ -28,6 +28,11 @@
// as does other parts of the Cap'n proto library which provide a higher-level interface for
// dynamic introspection.
#ifdef __CDT_PARSER__
// Eclipse keeps thinking this is pre-defined for no apparent reason.
#undef CAPNPROTO_LAYOUT_H_
#endif
#ifndef CAPNPROTO_LAYOUT_H_
#define CAPNPROTO_LAYOUT_H_
...
...
@@ -91,8 +96,8 @@ enum class FieldSize: uint8_t {
// 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
.
// struct, new fields cannot be added to it.
The field's struct type is therefore required to
//
be declared "inline" with a fixed width
.
};
typedef
decltype
(
BITS
/
ELEMENTS
)
BitsPerElement
;
...
...
@@ -276,6 +281,17 @@ public:
// initialized, it is initialized as a deep copy of the given default value (a trusted message),
// or to the empty state if defaultValue is nullptr.
CAPNPROTO_ALWAYS_INLINE
(
StructBuilder
initInlineStructField
(
BitCount
dataOffset
,
BitCount
inlineDataSize
,
WireReferenceCount
refIndex
,
WireReferenceCount
inlineRefCount
)
const
);
// Initialize an inlined struct field, given the position and size of the data and pointer
// sections.
CAPNPROTO_ALWAYS_INLINE
(
StructBuilder
getInlineStructField
(
BitCount
dataOffset
,
BitCount
inlineDataSize
,
WireReferenceCount
refIndex
,
WireReferenceCount
inlineRefCount
)
const
);
// Gets an inlined struct field, given the position and size of the data and pointer sections.
ListBuilder
initListField
(
WireReferenceCount
refIndex
,
FieldSize
elementSize
,
ElementCount
elementCount
)
const
;
// Allocates a new list of the given size for the field at the given index in the reference
...
...
@@ -313,11 +329,16 @@ public:
private
:
SegmentBuilder
*
segment
;
// Memory segment in which the struct resides.
wor
d
*
data
;
// Pointer to the encoded data.
voi
d
*
data
;
// Pointer to the encoded data.
WireReference
*
references
;
// Pointer to the encoded references.
inline
StructBuilder
(
SegmentBuilder
*
segment
,
word
*
data
,
WireReference
*
references
)
:
segment
(
segment
),
data
(
data
),
references
(
references
)
{}
BitCount8
bit0Offset
;
// A special hack: When accessing a boolean with field number zero, pretend its offset is this
// instead of the usual zero. This is needed to support 1-bit inline structs.
inline
StructBuilder
(
SegmentBuilder
*
segment
,
void
*
data
,
WireReference
*
references
,
BitCount8
bit0Offset
)
:
segment
(
segment
),
data
(
data
),
references
(
references
),
bit0Offset
(
bit0Offset
)
{}
friend
class
ListBuilder
;
friend
struct
WireHelpers
;
...
...
@@ -351,6 +372,11 @@ public:
// struct reference, which in turn points at the struct value. The default value is allowed to
// be null, in which case an empty struct is used.
CAPNPROTO_ALWAYS_INLINE
(
StructReader
getInlineStructField
(
BitCount
dataOffset
,
BitCount
inlineDataSize
,
WireReferenceCount
refIndex
,
WireReferenceCount
inlineRefCount
)
const
);
// Gets an inlined struct field, given the position and size of the data and pointer sections.
ListReader
getListField
(
WireReferenceCount
refIndex
,
FieldSize
expectedElementSize
,
const
word
*
defaultValue
)
const
;
// Get the list field at the given index in the reference segment, or the default value if not
...
...
@@ -370,20 +396,21 @@ private:
const
void
*
data
;
const
WireReference
*
references
;
WordCount8
dataSize
;
// Size of data segment.
WireReferenceCount
8
referenceCount
;
// Size of the reference segment.
BitCount32
dataSize
;
// Size of data segment.
WireReferenceCount
16
referenceCount
;
// Size of the reference segment.
BitCount8
bit0Offset
;
// A special hack: When accessing a boolean with field number zero, pretend its offset is this
// instead of the usual zero. This is needed to allow a boolean list to be upgraded to a list
// of structs.
// of structs
, and to support 1-bit inline structs
.
int
nestingLimit
;
// Limits the depth of message structures to guard against stack-overflow-based DoS attacks.
// Once this reaches zero, further pointers will be pruned.
// TODO: Limit to 8 bits for better alignment?
inline
StructReader
(
SegmentReader
*
segment
,
const
void
*
data
,
const
WireReference
*
references
,
Word
Count
dataSize
,
WireReferenceCount
referenceCount
,
Bit
Count
dataSize
,
WireReferenceCount
referenceCount
,
BitCount
bit0Offset
,
int
nestingLimit
)
:
segment
(
segment
),
data
(
data
),
references
(
references
),
dataSize
(
dataSize
),
referenceCount
(
referenceCount
),
bit0Offset
(
bit0Offset
),
...
...
@@ -448,7 +475,7 @@ public:
ListReader
asReader
(
FieldSize
elementSize
)
const
;
// Get a ListReader pointing at the same memory. Use this version only for non-struct lists.
ListReader
asReader
(
Word
Count
dataSize
,
WireReferenceCount
referenceCount
)
const
;
ListReader
asReader
(
Bit
Count
dataSize
,
WireReferenceCount
referenceCount
)
const
;
// Get a ListReader pointing at the same memory. Use this version only for struct lists.
private
:
...
...
@@ -503,7 +530,7 @@ private:
// if the sender upgraded a data list to a struct list. It will always be aligned properly for
// the type. Unsigned so that division by a constant power of 2 is efficient.
Word
Count
structDataSize
;
Bit
Count
structDataSize
;
WireReferenceCount
structReferenceCount
;
// If the elements are structs, the properties of the struct. The reference count is
// only used to check for field presence; the data size is also used to compute the reference
...
...
@@ -519,7 +546,7 @@ private:
structDataSize
(
0
),
structReferenceCount
(
0
),
nestingLimit
(
nestingLimit
)
{}
inline
ListReader
(
SegmentReader
*
segment
,
const
void
*
ptr
,
ElementCount
elementCount
,
decltype
(
BITS
/
ELEMENTS
)
stepBits
,
Word
Count
structDataSize
,
decltype
(
BITS
/
ELEMENTS
)
stepBits
,
Bit
Count
structDataSize
,
WireReferenceCount
structReferenceCount
,
int
nestingLimit
)
:
segment
(
segment
),
ptr
(
ptr
),
elementCount
(
elementCount
),
stepBits
(
stepBits
),
structDataSize
(
structDataSize
),
structReferenceCount
(
structReferenceCount
),
...
...
@@ -541,6 +568,10 @@ inline T StructBuilder::getDataField(ElementCount offset) const {
template
<>
inline
bool
StructBuilder
::
getDataField
<
bool
>
(
ElementCount
offset
)
const
{
BitCount
boffset
=
offset
*
(
1
*
BITS
/
ELEMENTS
);
// This branch should always be optimized away when inlining.
if
(
boffset
==
0
*
BITS
)
boffset
=
bit0Offset
;
byte
*
b
=
reinterpret_cast
<
byte
*>
(
data
)
+
boffset
/
BITS_PER_BYTE
;
return
(
*
reinterpret_cast
<
uint8_t
*>
(
b
)
&
(
1
<<
(
boffset
%
BITS_PER_BYTE
/
BITS
)))
!=
0
;
}
...
...
@@ -564,6 +595,10 @@ inline void StructBuilder::setDataField(
template
<>
inline
void
StructBuilder
::
setDataField
<
bool
>
(
ElementCount
offset
,
bool
value
)
const
{
BitCount
boffset
=
offset
*
(
1
*
BITS
/
ELEMENTS
);
// This branch should always be optimized away when inlining.
if
(
boffset
==
0
*
BITS
)
boffset
=
bit0Offset
;
byte
*
b
=
reinterpret_cast
<
byte
*>
(
data
)
+
boffset
/
BITS_PER_BYTE
;
uint
bitnum
=
boffset
%
BITS_PER_BYTE
/
BITS
;
*
reinterpret_cast
<
uint8_t
*>
(
b
)
=
(
*
reinterpret_cast
<
uint8_t
*>
(
b
)
&
~
(
1
<<
bitnum
))
...
...
@@ -579,11 +614,37 @@ inline void StructBuilder::setDataField(
setDataField
<
typename
MaskType
<
T
>::
Type
>
(
offset
,
mask
<
T
>
(
value
,
m
));
}
inline
StructBuilder
StructBuilder
::
initInlineStructField
(
BitCount
dataOffset
,
BitCount
inlineDataSize
,
WireReferenceCount
refIndex
,
WireReferenceCount
inlineRefCount
)
const
{
// This branch should be optimized away.
if
(
inlineDataSize
==
1
*
BITS
)
{
setDataField
<
bool
>
(
dataOffset
/
(
1
*
BITS
/
ELEMENTS
),
false
);
}
else
{
memset
(
reinterpret_cast
<
byte
*>
(
data
)
+
dataOffset
/
BITS_PER_BYTE
/
BYTES
,
0
,
inlineDataSize
/
BITS_PER_BYTE
/
BYTES
);
}
memset
(
reinterpret_cast
<
word
*>
(
references
)
+
refIndex
*
WORDS_PER_REFERENCE
,
0
,
inlineRefCount
*
WORDS_PER_REFERENCE
*
BYTES_PER_WORD
/
BYTES
);
return
getInlineStructField
(
dataOffset
,
inlineDataSize
,
refIndex
,
inlineRefCount
);
}
inline
StructBuilder
StructBuilder
::
getInlineStructField
(
BitCount
dataOffset
,
BitCount
inlineDataSize
,
WireReferenceCount
refIndex
,
WireReferenceCount
inlineRefCount
)
const
{
return
StructBuilder
(
segment
,
reinterpret_cast
<
byte
*>
(
data
)
+
dataOffset
/
BITS_PER_BYTE
,
// WireReference is incomplete here so we have to cast around... Bah.
reinterpret_cast
<
WireReference
*>
(
reinterpret_cast
<
word
*>
(
references
)
+
refIndex
*
WORDS_PER_REFERENCE
),
dataOffset
==
0
*
BITS
?
BitCount
(
bit0Offset
)
:
dataOffset
%
BITS_PER_BYTE
);
}
// -------------------------------------------------------------------
template
<
typename
T
>
T
StructReader
::
getDataField
(
ElementCount
offset
)
const
{
if
(
offset
*
bytesPerElement
<
T
>
()
<
dataSize
*
BYTES_PER_WORD
)
{
if
(
offset
*
capnproto
::
bitsPerElement
<
T
>
()
<
dataSize
)
{
return
reinterpret_cast
<
const
WireValue
<
T
>*>
(
data
)[
offset
/
ELEMENTS
].
get
();
}
else
{
return
static_cast
<
T
>
(
0
);
...
...
@@ -597,7 +658,7 @@ inline bool StructReader::getDataField<bool>(ElementCount offset) const {
// This branch should always be optimized away when inlining.
if
(
boffset
==
0
*
BITS
)
boffset
=
bit0Offset
;
if
(
boffset
<
dataSize
*
BITS_PER_WORD
)
{
if
(
boffset
<
dataSize
)
{
const
byte
*
b
=
reinterpret_cast
<
const
byte
*>
(
data
)
+
boffset
/
BITS_PER_BYTE
;
return
(
*
reinterpret_cast
<
const
uint8_t
*>
(
b
)
&
(
1
<<
(
boffset
%
BITS_PER_BYTE
/
BITS
)))
!=
0
;
}
else
{
...
...
@@ -615,6 +676,19 @@ T StructReader::getDataField(ElementCount offset, typename MaskType<T>::Type mas
return
unmask
<
T
>
(
getDataField
<
typename
MaskType
<
T
>::
Type
>
(
offset
),
mask
);
}
inline
StructReader
StructReader
::
getInlineStructField
(
BitCount
dataOffset
,
BitCount
inlineDataSize
,
WireReferenceCount
refIndex
,
WireReferenceCount
inlineRefCount
)
const
{
return
StructReader
(
segment
,
reinterpret_cast
<
const
byte
*>
(
data
)
+
dataOffset
/
BITS_PER_BYTE
,
// WireReference is incomplete here so we have to cast around... Bah.
reinterpret_cast
<
const
WireReference
*>
(
reinterpret_cast
<
const
word
*>
(
references
)
+
refIndex
*
WORDS_PER_REFERENCE
),
dataSize
,
inlineRefCount
,
dataOffset
==
0
*
BITS
?
BitCount
(
bit0Offset
)
:
dataOffset
%
BITS_PER_BYTE
,
nestingLimit
);
}
// -------------------------------------------------------------------
inline
ElementCount
ListBuilder
::
size
()
{
return
elementCount
;
}
...
...
c++/src/capnproto/test-util.h
View file @
7f20d533
...
...
@@ -57,6 +57,9 @@ using ::capnproto::test::TestUnion;
using
::
capnproto
::
test
::
TestUnionDefaults
;
using
::
capnproto
::
test
::
TestNestedTypes
;
using
::
capnproto
::
test
::
TestUsing
;
using
::
capnproto
::
test
::
TestInlineLayout
;
using
::
capnproto
::
test
::
TestInlineUnions
;
using
::
capnproto
::
test
::
TestInlineDefaults
;
void
initTestMessage
(
test
::
TestAllTypes
::
Builder
builder
);
void
initTestMessage
(
test
::
TestDefaults
::
Builder
builder
);
...
...
c++/src/capnproto/test.capnp
View file @
7f20d533
...
...
@@ -213,7 +213,6 @@ struct TestUnion {
bit5 @42: Bool;
bit6 @43: Bool;
bit7 @44: Bool;
byte0 @49: UInt8;
# Interleave two unions to be really annoying.
# Also declare in reverse order to make sure union discriminant values are sorted by field number
...
...
@@ -233,6 +232,8 @@ struct TestUnion {
u3f0s8 @48: Int8;
u3f0s1 @46: Bool;
}
byte0 @49: UInt8;
}
struct TestUnionDefaults {
...
...
@@ -274,3 +275,140 @@ struct TestUsing {
outerNestedEnum @1 :OuterNestedEnum = bar;
innerNestedEnum @0 :NestedEnum = quux;
}
struct TestInline0 fixed(0 bits) {}
struct TestInline1 fixed(1 bits) { f @0: Bool; }
struct TestInline8 fixed(8 bits) { f0 @0: Bool; f1 @1: Bool; f2 @2: Bool; }
struct TestInline16 fixed(16 bits) { f0 @0: UInt8; f1 @1: UInt8; }
struct TestInline32 fixed(32 bits) { f0 @0: UInt8; f1 @1: UInt16; }
struct TestInline64 fixed(64 bits) { f0 @0: UInt8; f1 @1: UInt32; }
struct TestInline128 fixed(2 words) { f0 @0: UInt64; f1 @1: UInt64; }
struct TestInline192 fixed(3 words) { f0 @0: UInt64; f1 @1: UInt64; f2 @2: UInt64; }
struct TestInline0p fixed(0 bits, 1 pointers) { f @0 :Inline(TestInline0); p0 @1 :Text; }
struct TestInline1p fixed(1 bits, 1 pointers) { f @0 :Inline(TestInline1); p0 @1 :Text; }
struct TestInline8p fixed(8 bits, 1 pointers) { f @0 :Inline(TestInline8); p0 @1 :Text; }
struct TestInline16p fixed(16 bits, 2 pointers) { f @0 :Inline(TestInline16); p0 @1 :Text; p1 @2 :Text; }
struct TestInline32p fixed(32 bits, 2 pointers) { f @0 :Inline(TestInline32); p0 @1 :Text; p1 @2 :Text; }
struct TestInline64p fixed(64 bits, 2 pointers) { f @0 :Inline(TestInline64); p0 @1 :Text; p1 @2 :Text; }
struct TestInline128p fixed(2 words, 3 pointers) { f @0 :Inline(TestInline128); p0 @1 :Text; p1 @2 :Text; p2 @3 :Text; }
struct TestInline192p fixed(3 words, 3 pointers) { f @0 :Inline(TestInline192); p0 @1 :Text; p1 @2 :Text; p2 @3 :Text; }
struct TestInlineLayout {
f0 @0 :Inline(TestInline0);
f1 @1 :Inline(TestInline1);
f8 @2 :Inline(TestInline8);
f16 @3 :Inline(TestInline16);
f32 @4 :Inline(TestInline32);
f64 @5 :Inline(TestInline64);
f128 @6 :Inline(TestInline128);
f192 @7 :Inline(TestInline192);
f0p @8 :Inline(TestInline0p);
f1p @9 :Inline(TestInline1p);
f8p @10 :Inline(TestInline8p);
f16p @11 :Inline(TestInline16p);
f32p @12 :Inline(TestInline32p);
f64p @13 :Inline(TestInline64p);
f128p @14 :Inline(TestInline128p);
f192p @15 :Inline(TestInline192p);
f1Offset @16 :Inline(TestInline1);
bit @17 :Bool;
}
struct TestInlineUnions {
union0 @0 union {
f0 @4 :Inline(TestInline0);
f1 @5 :Inline(TestInline1);
f8 @6 :Inline(TestInline8);
f16 @7 :Inline(TestInline16);
f32 @8 :Inline(TestInline32);
f64 @9 :Inline(TestInline64);
f128 @10 :Inline(TestInline128);
f192 @11 :Inline(TestInline192);
f0p @12 :Inline(TestInline0p);
f1p @13 :Inline(TestInline1p);
f8p @14 :Inline(TestInline8p);
f16p @15 :Inline(TestInline16p);
f32p @16 :Inline(TestInline32p);
f64p @17 :Inline(TestInline64p);
f128p @18 :Inline(TestInline128p);
f192p @19 :Inline(TestInline192p);
}
# Pack one bit in order to make pathological situation for union1.
bit0 @20: Bool;
union1 @1 union {
f0 @21 :Inline(TestInline0);
f1 @22 :Inline(TestInline1);
f8 @23 :Inline(TestInline8);
f16 @24 :Inline(TestInline16);
f32 @25 :Inline(TestInline32);
f64 @26 :Inline(TestInline64);
f128 @27 :Inline(TestInline128);
f192 @28 :Inline(TestInline192);
}
# Fill in the rest of that bitfield from earlier.
bit2 @29: Bool;
bit3 @30: Bool;
bit4 @31: Bool;
bit5 @32: Bool;
bit6 @33: Bool;
bit7 @34: Bool;
# Interleave two unions to be really annoying.
union2 @2 union {
f1p @35 :Inline(TestInline1p);
f8p @37 :Inline(TestInline8p);
f16p @40 :Inline(TestInline16p);
f32p @42 :Inline(TestInline32p);
f64p @44 :Inline(TestInline64p);
f128p @46 :Inline(TestInline128p);
f192p @48 :Inline(TestInline192p);
}
union3 @3 union {
f1p @36 :Inline(TestInline1p);
f8p @38 :Inline(TestInline8p);
f16p @41 :Inline(TestInline16p);
f32p @43 :Inline(TestInline32p);
f64p @45 :Inline(TestInline64p);
f128p @47 :Inline(TestInline128p);
f192p @49 :Inline(TestInline192p);
}
byte0 @39: UInt8;
}
struct TestInlineDefaults {
normal @0 :TestInlineLayout = (
f0 = (),
f1 = (f = true),
f8 = (f0 = true, f1 = false, f2 = true),
f16 = (f0 = 123, f1 = 45),
f32 = (f0 = 67, f1 = 8901),
f64 = (f0 = 234, f1 = 567890123),
f128 = (f0 = 1234567890123, f1 = 4567890123456),
f192 = (f0 = 7890123456789, f1 = 2345678901234, f2 = 5678901234567),
f0p = (p0 = "foo"),
f1p = (f = (f = false), p0 = "bar"),
f8p = (f = (f0 = true, f1 = true, f2 = false), p0 = "baz"),
f16p = (f = (f0 = 98, f1 = 76), p0 = "qux", p1 = "quux"),
f32p = (f = (f0 = 54, f1 = 32109), p0 = "corge", p1 = "grault"),
f64p = (f = (f0 = 87, f1 = 654321098), p0 = "garply", p1 = "waldo"),
f128p = (f = (f0 = 7654321098765, f1 = 4321098765432),
p0 = "fred", p1 = "plugh", p2 = "xyzzy"),
f192p = (f = (f0 = 1098765432109, f1 = 8765432109876, f2 = 5432109876543),
p0 = "thud", p1 = "foobar", p2 = "barbaz"));
unions @1 :TestInlineUnions = (
union0 = f32(f0 = 67, f1 = 8901),
union1 = f128(f0 = 1234567890123, f1 = 4567890123456),
union2 = f1p(p0 = "foo"),
union3 = f16p(f = (f0 = 98, f1 = 76), p0 = "qux", p1 = "quux"));
}
c++/src/capnproto/type-safety.h
View file @
7f20d533
...
...
@@ -651,6 +651,11 @@ inline constexpr decltype(BYTES / ELEMENTS) bytesPerElement() {
return
sizeof
(
T
)
*
BYTES
/
ELEMENTS
;
}
template
<
typename
T
>
inline
constexpr
decltype
(
BITS
/
ELEMENTS
)
bitsPerElement
()
{
return
sizeof
(
T
)
*
8
*
BITS
/
ELEMENTS
;
}
#ifndef __CDT_PARSER__
template
<
typename
T
,
typename
U
>
...
...
compiler/capnproto-compiler.cabal
View file @
7f20d533
...
...
@@ -4,6 +4,13 @@ cabal-version: >=1.2
build-type: Simple
author: kenton
-- How to get stack traces:
-- 1. Compile normally and do not clean.
-- 2. Add "-prof -fprof-auto -osuf .prof.o" to ghc-options and compile again.
-- (TODO: Figure out how to add these through "cabal configure" instead of by editing
-- this file. --enable-executable-profiling alone doesn't appear to get the job done.)
-- 3. Run with +RTS -xc -RTS on the command line.
executable capnpc
hs-source-dirs: src
main-is: Main.hs
...
...
compiler/src/Compiler.hs
View file @
7f20d533
...
...
@@ -27,12 +27,12 @@ import Grammar
import
Semantics
import
Token
(
Located
(
Located
),
locatedPos
,
locatedValue
)
import
Parser
(
parseFile
)
import
Control.Monad
(
unless
)
import
Control.Monad
(
when
,
unless
)
import
qualified
Data.Map
as
Map
import
Data.Map
((
!
))
import
qualified
Data.Set
as
Set
import
qualified
Data.List
as
List
import
Data.Maybe
(
mapMaybe
,
fromMaybe
,
listToMaybe
,
catMaybes
)
import
Data.Maybe
(
mapMaybe
,
fromMaybe
,
listToMaybe
,
catMaybes
,
isJust
)
import
Text.Parsec.Pos
(
SourcePos
,
newPos
)
import
Text.Parsec.Error
(
ParseError
,
newErrorMessage
,
Message
(
Message
,
Expect
))
import
Text.Printf
(
printf
)
...
...
@@ -67,9 +67,16 @@ instance Monad Status where
return
x
=
Active
x
[]
fail
=
makeError
(
newPos
"?"
0
0
)
-- Recovers from Failed status by using a fallback result, but keeps the errors.
--
-- This function is carefully written such that the runtime can see that it returns Active without
-- actually evaluating the parameters. The parameters are only evaluated when the returned value
-- or errors are examined.
recover
::
a
->
Status
a
->
Status
a
recover
_
(
Active
x
e
)
=
Active
x
e
recover
x
(
Failed
e
)
=
Active
x
e
recover
fallback
status
=
Active
value
errs
where
(
value
,
errs
)
=
case
status
of
Active
v
e
->
(
v
,
e
)
Failed
e
->
(
fallback
,
e
)
succeed
::
a
->
Status
a
succeed
x
=
Active
x
[]
...
...
@@ -154,7 +161,7 @@ lookupDesc scope name = lookupDesc (descParent scope) name
builtinTypeMap
::
Map
.
Map
String
Desc
builtinTypeMap
=
Map
.
fromList
([(
builtinTypeName
t
,
DescBuiltinType
t
)
|
t
<-
builtinTypes
]
++
[(
"List"
,
DescBuiltinList
),
(
"id"
,
DescBuiltinId
)])
[(
"List"
,
DescBuiltinList
),
(
"
Inline"
,
DescBuiltinInline
),
(
"
id"
,
DescBuiltinId
)])
------------------------------------------------------------------------------------------
...
...
@@ -234,6 +241,8 @@ compileValue pos (StructType desc) (RecordFieldValue fields) = do
return
(
StructValueDesc
assignments
)
compileValue
pos
(
InlineStructType
desc
)
v
=
compileValue
pos
(
StructType
desc
)
v
compileValue
_
(
ListType
t
)
(
ListFieldValue
l
)
=
fmap
ListDesc
(
doAll
[
compileValue
vpos
t
v
|
Located
vpos
v
<-
l
])
...
...
@@ -254,6 +263,7 @@ compileValue pos (BuiltinType BuiltinData) _ = makeExpectError pos "string"
compileValue
pos
(
EnumType
_
)
_
=
makeExpectError
pos
"enumerant name"
compileValue
pos
(
StructType
_
)
_
=
makeExpectError
pos
"parenthesized list of field assignments"
compileValue
pos
(
InlineStructType
_
)
_
=
makeExpectError
pos
"parenthesized list of field assignments"
compileValue
pos
(
InterfaceType
_
)
_
=
makeError
pos
"Interfaces can't have default values."
compileValue
pos
(
ListType
_
)
_
=
makeExpectError
pos
"list"
...
...
@@ -264,6 +274,8 @@ descAsType _ (DescBuiltinType desc) = succeed (BuiltinType desc)
descAsType
name
(
DescUsing
desc
)
=
descAsType
name
(
usingTarget
desc
)
descAsType
name
DescBuiltinList
=
makeError
(
declNamePos
name
)
message
where
message
=
printf
"'List' requires exactly one type parameter."
(
declNameString
name
)
descAsType
name
DescBuiltinInline
=
makeError
(
declNamePos
name
)
message
where
message
=
printf
"'Inline' requires exactly one type parameter."
(
declNameString
name
)
descAsType
name
_
=
makeError
(
declNamePos
name
)
message
where
message
=
printf
"'%s' is not a type."
(
declNameString
name
)
...
...
@@ -278,6 +290,18 @@ compileType scope (TypeExpression n (param:moreParams)) = do
if
null
moreParams
then
fmap
ListType
(
compileType
scope
param
)
else
makeError
(
declNamePos
n
)
"'List' requires exactly one type parameter."
DescBuiltinInline
->
if
null
moreParams
then
do
inner
<-
compileType
scope
param
case
inner
of
StructType
s
->
if
structIsFixedWidth
s
then
return
(
InlineStructType
s
)
else
makeError
(
declNamePos
n
)
$
printf
"'%s' cannot be inlined because it is not fixed-width."
(
structName
s
)
_
->
makeError
(
declNamePos
n
)
"'Inline' parameter must be a struct type."
else
makeError
(
declNamePos
n
)
"'Inline' requires exactly one type parameter."
_
->
makeError
(
declNamePos
n
)
"Only the type 'List' can have type parameters."
compileAnnotation
::
Desc
->
AnnotationTarget
->
Annotation
...
...
@@ -378,10 +402,6 @@ requireNoDuplicateNames decls = Active () (loop (List.sort locatedNames)) where
dupError
val
=
newErrorMessage
(
Message
message
)
where
message
=
printf
"Duplicate declaration
\"
%s
\"
."
val
fieldInUnion
name
f
=
case
fieldUnion
f
of
Nothing
->
False
Just
(
x
,
_
)
->
unionName
x
==
name
requireNoMoreThanOneFieldNumberLessThan
name
pos
num
fields
=
Active
()
errors
where
retroFields
=
[
fieldName
f
|
f
<-
fields
,
fieldNumber
f
<
num
]
message
=
printf
"No more than one field in a union may have a number less than the
\
...
...
@@ -399,102 +419,217 @@ extractFieldNumbers decls = concat
------------------------------------------------------------------------------------------
initialPackingState
=
PackingState
0
0
0
0
0
0
data
PackingState
=
PackingState
{
packingHoles
::
Map
.
Map
DataSize
Integer
,
packingDataSize
::
Integer
,
packingReferenceCount
::
Integer
}
packValue
::
FieldSize
->
PackingState
->
(
Integer
,
PackingState
)
packValue
Size64
s
@
(
PackingState
{
packingDataSize
=
ds
})
=
(
ds
,
s
{
packingDataSize
=
ds
+
1
})
initialPackingState
=
PackingState
Map
.
empty
0
0
packValue
::
FieldSize
->
PackingState
->
(
FieldOffset
,
PackingState
)
packValue
SizeVoid
s
=
(
VoidOffset
,
s
)
packValue
SizeReference
s
@
(
PackingState
{
packingReferenceCount
=
rc
})
=
(
rc
,
s
{
packingReferenceCount
=
rc
+
1
})
packValue
(
SizeInlineComposite
_
_
)
_
=
error
"Inline fields not yet supported."
packValue
Size32
s
@
(
PackingState
{
packingHole32
=
0
})
=
case
packValue
Size64
s
of
(
o64
,
s2
)
->
(
o64
*
2
,
s2
{
packingHole32
=
o64
*
2
+
1
})
packValue
Size32
s
@
(
PackingState
{
packingHole32
=
h32
})
=
(
h32
,
s
{
packingHole32
=
0
})
packValue
Size16
s
@
(
PackingState
{
packingHole16
=
0
})
=
case
packValue
Size32
s
of
(
o32
,
s2
)
->
(
o32
*
2
,
s2
{
packingHole16
=
o32
*
2
+
1
})
packValue
Size16
s
@
(
PackingState
{
packingHole16
=
h16
})
=
(
h16
,
s
{
packingHole16
=
0
})
packValue
Size8
s
@
(
PackingState
{
packingHole8
=
0
})
=
case
packValue
Size16
s
of
(
o16
,
s2
)
->
(
o16
*
2
,
s2
{
packingHole8
=
o16
*
2
+
1
})
packValue
Size8
s
@
(
PackingState
{
packingHole8
=
h8
})
=
(
h8
,
s
{
packingHole8
=
0
})
packValue
Size1
s
@
(
PackingState
{
packingHole1
=
0
})
=
case
packValue
Size8
s
of
(
o8
,
s2
)
->
(
o8
*
8
,
s2
{
packingHole1
=
o8
*
8
+
1
})
packValue
Size1
s
@
(
PackingState
{
packingHole1
=
h1
})
=
(
h1
,
s
{
packingHole1
=
if
mod
(
h1
+
1
)
8
==
0
then
0
else
h1
+
1
})
packValue
Size0
s
=
(
0
,
s
)
initialUnionPackingState
=
UnionPackingState
Nothing
Nothing
(
PointerOffset
rc
,
s
{
packingReferenceCount
=
rc
+
1
})
packValue
(
SizeInlineComposite
(
DataSectionWords
inlineDs
)
inlineRc
)
s
@
(
PackingState
{
packingDataSize
=
ds
,
packingReferenceCount
=
rc
})
=
(
InlineCompositeOffset
ds
rc
(
DataSectionWords
inlineDs
)
inlineRc
,
s
{
packingDataSize
=
ds
+
inlineDs
,
packingReferenceCount
=
rc
+
inlineRc
})
packValue
(
SizeInlineComposite
inlineDs
inlineRc
)
s
@
(
PackingState
{
packingReferenceCount
=
rc
})
=
let
size
=
(
dataSectionAlignment
inlineDs
)
(
offset
,
s2
)
=
packData
size
s
in
(
InlineCompositeOffset
offset
rc
inlineDs
inlineRc
,
s2
{
packingReferenceCount
=
rc
+
inlineRc
})
packValue
(
SizeData
size
)
s
=
let
(
o
,
s2
)
=
packData
size
s
in
(
DataOffset
size
o
,
s2
)
packData
::
DataSize
->
PackingState
->
(
Integer
,
PackingState
)
packData
Size64
s
@
(
PackingState
{
packingDataSize
=
ds
})
=
(
ds
,
s
{
packingDataSize
=
ds
+
1
})
packData
size
s
=
let
-- updateLookupWithKey doesn't quite work here because it returns the new value if updated, or
-- the old value if not. We really always want the old value and have no way to distinguish.
-- There appears to be no function that does this, AFAICT.
hole
=
Map
.
lookup
size
$
packingHoles
s
newHoles
=
Map
.
update
splitHole
size
$
packingHoles
s
splitHole
off
=
case
size
of
Size1
->
if
mod
off
8
==
7
then
Nothing
else
Just
(
off
+
1
)
_
->
Nothing
in
case
hole
of
-- If there was a hole of the correct size, use it.
Just
off
->
(
off
,
s
{
packingHoles
=
newHoles
})
-- Otherwise, try to pack a value of the next size up, and then split it.
Nothing
->
let
nextSize
=
succ
size
(
nextOff
,
s2
)
=
packData
nextSize
s
off
=
demoteOffset
nextSize
nextOff
newHoles2
=
Map
.
insert
size
(
off
+
1
)
$
packingHoles
s2
in
(
off
,
s2
{
packingHoles
=
newHoles2
})
-- Convert an offset of one data size to an offset of the next smaller size.
demoteOffset
::
DataSize
->
Integer
->
Integer
demoteOffset
Size1
_
=
error
"can't split bit"
demoteOffset
Size8
i
=
i
*
8
demoteOffset
_
i
=
i
*
2
data
UnionSlot
sizeType
=
UnionSlot
{
unionSlotSize
::
sizeType
,
unionSlotOffset
::
Integer
}
data
UnionPackingState
=
UnionPackingState
{
unionDataSlot
::
UnionSlot
DataSectionSize
,
unionPointerSlot
::
UnionSlot
Integer
}
initialUnionPackingState
=
UnionPackingState
(
UnionSlot
(
DataSectionWords
0
)
0
)
(
UnionSlot
0
0
)
packUnionizedValue
::
FieldSize
-- Size of field to pack.
->
UnionPackingState
-- Current layout of the union
->
PackingState
-- Current layout of the struct.
->
(
Integer
,
UnionPackingState
,
PackingState
)
packUnionizedValue
(
SizeInlineComposite
_
_
)
_
_
=
error
"Can't put inline composite into union."
packUnionizedValue
Size0
u
s
=
(
0
,
u
,
s
)
-- Pack reference when we already have a reference slot allocated.
packUnionizedValue
SizeReference
u
@
(
UnionPackingState
_
(
Just
offset
))
s
=
(
offset
,
u
,
s
)
->
(
FieldOffset
,
UnionPackingState
,
PackingState
)
packUnionizedValue
SizeVoid
u
s
=
(
VoidOffset
,
u
,
s
)
-- Pack data when there is no existing slot.
packUnionizedValue
(
SizeData
size
)
(
UnionPackingState
(
UnionSlot
(
DataSectionWords
0
)
_
)
p
)
s
=
let
(
offset
,
s2
)
=
packData
size
s
in
(
DataOffset
size
offset
,
UnionPackingState
(
UnionSlot
(
dataSizeToSectionSize
size
)
offset
)
p
,
s2
)
-- Pack data when there is a word-sized slot. All data fits in a word.
packUnionizedValue
(
SizeData
size
)
ups
@
(
UnionPackingState
(
UnionSlot
(
DataSectionWords
_
)
offset
)
_
)
s
=
(
DataOffset
size
(
offset
*
div
64
(
dataSizeInBits
size
)),
ups
,
s
)
-- Pack data when there is a non-word-sized slot.
packUnionizedValue
(
SizeData
size
)
(
UnionPackingState
(
UnionSlot
slotSize
slotOffset
)
p
)
s
=
case
tryExpandSubWordDataSlot
(
dataSectionAlignment
slotSize
,
slotOffset
)
s
size
of
Just
(
offset
,
(
newSlotSize
,
newSlotOffset
),
s2
)
->
(
DataOffset
size
offset
,
UnionPackingState
(
UnionSlot
(
dataSizeToSectionSize
newSlotSize
)
newSlotOffset
)
p
,
s2
)
-- If the slot wasn't big enough, pack as if there were no slot.
Nothing
->
packUnionizedValue
(
SizeData
size
)
(
UnionPackingState
(
UnionSlot
(
DataSectionWords
0
)
0
)
p
)
s
-- Pack reference when we don't have a reference slot.
packUnionizedValue
SizeReference
(
UnionPackingState
d
Nothing
)
s
=
(
offset
,
u2
,
s2
)
where
(
offset
,
s2
)
=
packValue
SizeReference
s
u2
=
UnionPackingState
d
(
Just
offset
)
-- Pack data.
packUnionizedValue
size
(
UnionPackingState
d
r
)
s
=
case
packUnionizedData
(
fromMaybe
(
0
,
Size0
)
d
)
s
size
of
Just
(
offset
,
slotOffset
,
slotSize
,
s2
)
->
(
offset
,
UnionPackingState
(
Just
(
slotOffset
,
slotSize
))
r
,
s2
)
Nothing
->
let
(
offset
,
s2
)
=
packValue
size
s
in
(
offset
,
UnionPackingState
(
Just
(
offset
,
size
))
r
,
s2
)
packUnionizedValue
SizeReference
u
@
(
UnionPackingState
_
(
UnionSlot
0
_
))
s
=
let
(
PointerOffset
offset
,
s2
)
=
packValue
SizeReference
s
u2
=
u
{
unionPointerSlot
=
UnionSlot
1
offset
}
in
(
PointerOffset
offset
,
u2
,
s2
)
packUnionizedData
::
(
Integer
,
FieldSize
)
-- existing slot to expand
->
PackingState
-- existing packing state
->
FieldSize
-- desired field size
->
Maybe
(
Integer
,
-- Offset of the new field (in multiples of field size).
Integer
,
-- New offset of the slot (in multiples of slot size).
FieldSize
,
-- New size of the slot.
PackingState
)
-- New struct packing state.
-- Pack reference when we already have a reference slot allocated.
packUnionizedValue
SizeReference
u
@
(
UnionPackingState
_
(
UnionSlot
_
offset
))
s
=
(
PointerOffset
offset
,
u
,
s
)
-- Pack inline composite.
packUnionizedValue
(
SizeInlineComposite
dataSize
pointerCount
)
u
@
(
UnionPackingState
{
unionDataSlot
=
UnionSlot
dataSlotSize
dataSlotOffset
,
unionPointerSlot
=
UnionSlot
pointerSlotSize
pointerSlotOffset
})
s
=
let
-- Pack the data section.
(
dataOffset
,
u2
,
s2
)
=
case
dataSize
of
DataSectionWords
0
->
(
0
,
u
,
s
)
DataSectionWords
requestedWordSize
->
let
maybeExpanded
=
case
dataSlotSize
of
-- Try to expand existing n-word slot to fit.
DataSectionWords
existingWordSize
->
tryExpandUnionizedDataWords
u
s
dataSlotOffset
existingWordSize
requestedWordSize
-- Try to expand the existing sub-word slot into a word, then from there to a slot
-- of the size we need.
_
->
do
(
expandedSlotOffset
,
_
,
expandedPackingState
)
<-
tryExpandSubWordDataSlot
(
dataSectionAlignment
dataSlotSize
,
dataSlotOffset
)
s
Size64
let
newU
=
u
{
unionDataSlot
=
UnionSlot
(
DataSectionWords
1
)
expandedSlotOffset
}
tryExpandUnionizedDataWords
newU
expandedPackingState
expandedSlotOffset
1
requestedWordSize
-- If expanding fails, fall back to appending the new words to the end of the struct.
atEnd
=
(
packingDataSize
s
,
u
{
unionDataSlot
=
UnionSlot
(
DataSectionWords
requestedWordSize
)
(
packingDataSize
s
)
},
s
{
packingDataSize
=
packingDataSize
s
+
requestedWordSize
})
in
fromMaybe
atEnd
maybeExpanded
_
->
let
(
DataOffset
_
result
,
newU
,
newS
)
=
packUnionizedValue
(
SizeData
(
dataSectionAlignment
dataSize
))
u
s
in
(
result
,
newU
,
newS
)
-- Pack the pointer section.
(
pointerOffset
,
u3
,
s3
)
|
pointerCount
<=
pointerSlotSize
=
(
pointerSlotOffset
,
u2
,
s2
)
|
pointerSlotOffset
+
pointerSlotSize
==
packingReferenceCount
s2
=
(
pointerSlotOffset
,
u2
{
unionPointerSlot
=
UnionSlot
pointerCount
pointerSlotOffset
},
s2
{
packingReferenceCount
=
pointerSlotOffset
+
pointerCount
})
|
otherwise
=
(
packingReferenceCount
s2
,
u2
{
unionPointerSlot
=
UnionSlot
pointerCount
(
packingReferenceCount
s2
)
},
s2
{
packingReferenceCount
=
packingReferenceCount
s2
+
pointerCount
})
combinedOffset
=
InlineCompositeOffset
{
inlineCompositeDataOffset
=
dataOffset
,
inlineCompositePointerOffset
=
pointerOffset
,
inlineCompositeDataSize
=
dataSize
,
inlineCompositePointerSize
=
pointerCount
}
-- Don't try to allocate space for voids.
packUnionizedData
(
slotOffset
,
slotSize
)
state
Size0
=
Just
(
0
,
slotOffset
,
slotSize
,
state
)
in
(
combinedOffset
,
u3
,
s3
)
tryExpandUnionizedDataWords
unionState
packingState
existingOffset
existingSize
requestedSize
-- Is the existing multi-word slot big enough?
|
requestedSize
<=
existingSize
=
-- Yes, use it.
Just
(
existingOffset
,
unionState
,
packingState
)
-- Is the slot at the end of the struct?
|
existingOffset
+
existingSize
==
packingDataSize
packingState
=
-- Yes, expand it.
Just
(
existingOffset
,
unionState
{
unionDataSlot
=
UnionSlot
(
DataSectionWords
requestedSize
)
existingOffset
},
packingState
{
packingDataSize
=
packingDataSize
packingState
+
requestedSize
-
existingSize
})
|
otherwise
=
Nothing
-- Try to expand an existing data slot to be big enough for a data field.
tryExpandSubWordDataSlot
::
(
DataSize
,
Integer
)
-- existing slot to expand
->
PackingState
-- existing packing state
->
DataSize
-- desired field size
->
Maybe
(
Integer
,
-- Offset of the new field.
(
DataSize
,
Integer
),
-- New offset of the slot.
PackingState
)
-- New struct packing state.
-- If slot is bigger than desired size, no expansion is needed.
packUnionizedData
(
slotOffset
,
slotSize
)
state
desiredSize
|
sizeInBits
slotSize
>=
sizeInBits
desiredSize
=
Just
(
div
(
sizeInBits
slotSize
)
(
sizeInBits
desiredSize
)
*
slotOffset
,
slotOffset
,
slotSize
,
state
)
-- If slot is a bit, and it is the first bit in its byte, and the bit hole immediately follows
-- expand it to a byte.
packUnionizedData
(
slotOffset
,
Size1
)
p
@
(
PackingState
{
packingHole1
=
hole
})
desiredSize
|
mod
slotOffset
8
==
0
&&
hole
==
slotOffset
+
1
=
packUnionizedData
(
div
slotOffset
8
,
Size8
)
(
p
{
packingHole1
=
0
})
desiredSize
-- If slot is size N, and the next N bits are padding, expand.
packUnionizedData
(
slotOffset
,
Size8
)
p
@
(
PackingState
{
packingHole8
=
hole
})
desiredSize
|
hole
==
slotOffset
+
1
=
packUnionizedData
(
div
slotOffset
2
,
Size16
)
(
p
{
packingHole8
=
0
})
desiredSize
packUnionizedData
(
slotOffset
,
Size16
)
p
@
(
PackingState
{
packingHole16
=
hole
})
desiredSize
|
hole
==
slotOffset
+
1
=
packUnionizedData
(
div
slotOffset
2
,
Size32
)
(
p
{
packingHole16
=
0
})
desiredSize
packUnionizedData
(
slotOffset
,
Size32
)
p
@
(
PackingState
{
packingHole32
=
hole
})
desiredSize
|
hole
==
slotOffset
+
1
=
packUnionizedData
(
div
slotOffset
2
,
Size64
)
(
p
{
packingHole32
=
0
})
desiredSize
-- Otherwise, we fail.
packUnionizedData
_
_
_
=
Nothing
tryExpandSubWordDataSlot
(
slotSize
,
slotOffset
)
state
desiredSize
|
dataSizeInBits
slotSize
>=
dataSizeInBits
desiredSize
=
Just
(
div
(
dataSizeInBits
slotSize
)
(
dataSizeInBits
desiredSize
)
*
slotOffset
,
(
slotSize
,
slotOffset
),
state
)
-- Try expanding the slot by combining it with subsequent padding.
tryExpandSubWordDataSlot
(
slotSize
,
slotOffset
)
state
desiredSize
=
let
nextSize
=
succ
slotSize
ratio
=
div
(
dataSizeInBits
nextSize
)
(
dataSizeInBits
slotSize
)
isAligned
=
mod
slotOffset
ratio
==
0
nextOffset
=
div
slotOffset
ratio
deleteHole
_
_
=
Nothing
(
maybeHole
,
newHoles
)
=
Map
.
updateLookupWithKey
deleteHole
slotSize
$
packingHoles
state
newState
=
state
{
packingHoles
=
newHoles
}
in
if
not
isAligned
then
Nothing
-- Existing slot is not aligned properly.
else
case
maybeHole
of
Just
holeOffset
|
holeOffset
==
slotOffset
+
1
->
tryExpandSubWordDataSlot
(
nextSize
,
nextOffset
)
newState
desiredSize
_
->
Nothing
-- Determine the offset for the given field, and update the packing states to include the field.
packField
::
FieldDesc
->
PackingState
->
Map
.
Map
Integer
UnionPackingState
->
(
Integer
,
PackingState
,
Map
.
Map
Integer
UnionPackingState
)
->
(
FieldOffset
,
PackingState
,
Map
.
Map
Integer
UnionPackingState
)
packField
fieldDesc
state
unionState
=
case
fieldUnion
fieldDesc
of
Nothing
->
let
...
...
@@ -511,13 +646,19 @@ packField fieldDesc state unionState =
-- Determine the offset for the given union, and update the packing states to include the union.
-- Specifically, this packs the union tag, *not* the fields of the union.
packUnion
::
UnionDesc
->
PackingState
->
Map
.
Map
Integer
UnionPackingState
->
(
Integer
,
PackingState
,
Map
.
Map
Integer
UnionPackingState
)
packUnion
_
state
unionState
=
(
offset
,
newState
,
unionState
)
where
(
offset
,
newState
)
=
packValue
Size16
state
packFields
::
[
FieldDesc
]
->
[
UnionDesc
]
->
(
PackingState
,
Map
.
Map
Integer
UnionPackingState
,
Map
.
Map
Integer
(
Integer
,
PackingState
))
packFields
fields
unions
=
(
finalState
,
finalUnionState
,
Map
.
fromList
packedItems
)
where
->
(
FieldOffset
,
PackingState
,
Map
.
Map
Integer
UnionPackingState
)
packUnion
_
state
unionState
=
(
DataOffset
Size16
offset
,
newState
,
unionState
)
where
(
offset
,
newState
)
=
packData
Size16
state
stripHolesFromFirstWord
Size1
_
=
Size1
-- Nothing left to strip.
stripHolesFromFirstWord
size
holes
=
let
nextSize
=
pred
size
in
case
Map
.
lookup
nextSize
holes
of
Just
1
->
stripHolesFromFirstWord
nextSize
holes
_
->
size
packFields
::
[
FieldDesc
]
->
[
UnionDesc
]
->
(
DataSectionSize
,
Integer
,
Map
.
Map
Integer
FieldOffset
)
packFields
fields
unions
=
let
items
=
concat
(
[(
fieldNumber
d
,
packField
d
)
|
d
<-
fields
]
:
[(
unionNumber
d
,
packUnion
d
)
:
[(
fieldNumber
d2
,
packField
d2
)
|
d2
<-
unionFields
d
]
...
...
@@ -526,13 +667,45 @@ packFields fields unions = (finalState, finalUnionState, Map.fromList packedItem
itemsByNumber
=
List
.
sortBy
compareNumbers
items
compareNumbers
(
a
,
_
)
(
b
,
_
)
=
compare
a
b
(
finalState
,
finalUnionState
,
packedItems
)
=
(
finalState
,
_
,
packedItems
)
=
foldl
packItem
(
initialPackingState
,
Map
.
empty
,
[]
)
itemsByNumber
packItem
(
state
,
unionState
,
packed
)
(
n
,
item
)
=
(
newState
,
newUnionState
,
(
n
,
(
offset
,
newState
)
)
:
packed
)
where
(
newState
,
newUnionState
,
(
n
,
offset
)
:
packed
)
where
(
offset
,
newState
,
newUnionState
)
=
item
state
unionState
dataSectionSize
=
if
packingDataSize
finalState
==
1
then
dataSizeToSectionSize
$
stripHolesFromFirstWord
Size64
$
packingHoles
finalState
else
DataSectionWords
$
packingDataSize
finalState
in
(
dataSectionSize
,
packingReferenceCount
finalState
,
Map
.
fromList
packedItems
)
enforceFixed
Nothing
sizes
=
return
sizes
enforceFixed
(
Just
(
Located
pos
(
requestedDataSize
,
requestedPointerCount
)))
(
actualDataSize
,
actualPointerCount
)
=
do
validatedRequestedDataSize
<-
case
requestedDataSize
of
1
->
return
DataSection1
8
->
return
DataSection8
16
->
return
DataSection16
32
->
return
DataSection32
s
|
mod
s
64
==
0
->
return
$
DataSectionWords
$
div
s
64
_
->
makeError
pos
$
printf
"Struct data section size must be a whole number of words
\
\
or 0, 1, 8, 16, or 32 bits."
recover
()
$
when
(
dataSectionBits
actualDataSize
>
dataSectionBits
validatedRequestedDataSize
)
$
makeError
pos
$
printf
"Struct data section size is %s which exceeds specified maximum of
\
\
%s. WARNING: Increasing the maximum will break backwards-compatibility."
(
dataSectionSizeString
actualDataSize
)
(
dataSectionSizeString
validatedRequestedDataSize
)
recover
()
$
when
(
actualPointerCount
>
requestedPointerCount
)
$
makeError
pos
$
printf
"Struct pointer section size is %d pointers which exceeds specified
\
\
maximum of %d pointers. WARNING: Increasing the maximum will break
\
\
backwards-compatibility."
actualPointerCount
requestedPointerCount
return
(
validatedRequestedDataSize
,
requestedPointerCount
)
------------------------------------------------------------------------------------------
data
CompiledStatementStatus
=
CompiledStatementStatus
String
(
Status
Desc
)
...
...
@@ -604,7 +777,7 @@ compileDecl scope@(DescEnum parent)
compileDecl
_
(
EnumerantDecl
(
Located
pos
name
)
_
_
)
=
CompiledStatementStatus
name
(
makeError
pos
"Enumerants can only appear inside enums."
)
compileDecl
scope
(
StructDecl
(
Located
_
name
)
annotations
decls
)
=
compileDecl
scope
(
StructDecl
(
Located
_
name
)
isFixed
annotations
decls
)
=
CompiledStatementStatus
name
(
feedback
(
\
desc
->
do
(
members
,
memberMap
)
<-
compileChildDecls
desc
decls
requireNoDuplicateNames
decls
...
...
@@ -612,15 +785,19 @@ compileDecl scope (StructDecl (Located _ name) annotations decls) =
requireSequentialNumbering
"Fields"
fieldNums
requireOrdinalsInRange
fieldNums
(
theId
,
compiledAnnotations
)
<-
compileAnnotations
scope
StructAnnotation
annotations
return
(
let
let
(
dataSize
,
pointerCount
,
fieldPackingMap
)
=
packFields
fields
unions
fields
=
[
d
|
DescField
d
<-
members
]
unions
=
[
d
|
DescUnion
d
<-
members
]
(
packing
,
_
,
fieldPackingMap
)
=
packFields
fields
unions
(
finalDataSize
,
finalPointerCount
)
<-
recover
(
dataSize
,
pointerCount
)
$
enforceFixed
isFixed
(
dataSize
,
pointerCount
)
return
(
let
in
DescStruct
StructDesc
{
structName
=
name
,
structId
=
theId
,
structParent
=
scope
,
structPacking
=
packing
,
structDataSize
=
finalDataSize
,
structPointerCount
=
finalPointerCount
,
structIsFixedWidth
=
isJust
isFixed
,
structFields
=
fields
,
structUnions
=
unions
,
structAnnotations
=
compiledAnnotations
...
...
@@ -639,14 +816,13 @@ compileDecl scope@(DescStruct parent)
requireNoMoreThanOneFieldNumberLessThan
name
numPos
number
fields
(
theId
,
compiledAnnotations
)
<-
compileAnnotations
scope
UnionAnnotation
annotations
return
(
let
(
tagOffset
,
tagPacking
)
=
structFieldPackingMap
parent
!
number
DataOffset
Size16
tagOffset
=
structFieldPackingMap
parent
!
number
in
DescUnion
UnionDesc
{
unionName
=
name
,
unionId
=
theId
,
unionParent
=
parent
,
unionNumber
=
number
,
unionTagOffset
=
tagOffset
,
unionTagPacking
=
tagPacking
,
unionFields
=
fields
,
unionAnnotations
=
compiledAnnotations
,
unionMemberMap
=
memberMap
...
...
@@ -668,18 +844,22 @@ compileDecl scope
_
->
Nothing
typeDesc
<-
compileType
scope
typeExp
defaultDesc
<-
case
defaultValue
of
Just
(
Located
defaultPos
value
)
->
fmap
Just
(
compileValue
defaultPos
typeDesc
value
)
Just
(
Located
defaultPos
value
)
->
do
result
<-
fmap
Just
(
compileValue
defaultPos
typeDesc
value
)
recover
()
(
case
typeDesc
of
InlineStructType
_
->
makeError
defaultPos
"Inline fields cannot have default values."
_
->
return
()
)
return
result
Nothing
->
return
Nothing
(
theId
,
compiledAnnotations
)
<-
compileAnnotations
scope
FieldAnnotation
annotations
return
(
let
(
offset
,
packing
)
=
structFieldPackingMap
parent
!
number
in
DescField
FieldDesc
{
fieldName
=
name
,
fieldId
=
theId
,
fieldParent
=
parent
,
fieldNumber
=
number
,
fieldOffset
=
offset
,
fieldPacking
=
packing
,
fieldOffset
=
structFieldPackingMap
parent
!
number
,
fieldUnion
=
unionDesc
,
fieldType
=
typeDesc
,
fieldDefaultValue
=
defaultDesc
...
...
compiler/src/CxxGenerator.hs
View file @
7f20d533
...
...
@@ -88,6 +88,7 @@ hashString str =
isPrimitive
t
@
(
BuiltinType
_
)
=
not
$
isBlob
t
isPrimitive
(
EnumType
_
)
=
True
isPrimitive
(
StructType
_
)
=
False
isPrimitive
(
InlineStructType
_
)
=
False
isPrimitive
(
InterfaceType
_
)
=
False
isPrimitive
(
ListType
_
)
=
False
...
...
@@ -96,8 +97,12 @@ isBlob (BuiltinType BuiltinData) = True
isBlob
_
=
False
isStruct
(
StructType
_
)
=
True
isStruct
(
InlineStructType
_
)
=
True
isStruct
_
=
False
isInlineStruct
(
InlineStructType
_
)
=
True
isInlineStruct
_
=
False
isList
(
ListType
_
)
=
True
isList
_
=
False
...
...
@@ -130,18 +135,30 @@ cxxTypeString (BuiltinType BuiltinText) = " ::capnproto::Text"
cxxTypeString
(
BuiltinType
BuiltinData
)
=
" ::capnproto::Data"
cxxTypeString
(
EnumType
desc
)
=
globalName
$
DescEnum
desc
cxxTypeString
(
StructType
desc
)
=
globalName
$
DescStruct
desc
cxxTypeString
(
InlineStructType
desc
)
=
globalName
$
DescStruct
desc
cxxTypeString
(
InterfaceType
desc
)
=
globalName
$
DescInterface
desc
cxxTypeString
(
ListType
t
)
=
concat
[
" ::capnproto::List<"
,
cxxTypeString
t
,
">"
]
cxxFieldSizeString
Size
0
=
"VOID"
;
cxxFieldSizeString
Size1
=
"BIT"
;
cxxFieldSizeString
Size8
=
"BYTE"
;
cxxFieldSizeString
Size16
=
"TWO_BYTES"
;
cxxFieldSizeString
Size32
=
"FOUR_BYTES"
;
cxxFieldSizeString
Size64
=
"EIGHT_BYTES"
;
cxxFieldSizeString
Size
Void
=
"VOID"
;
cxxFieldSizeString
(
SizeData
Size1
)
=
"BIT"
;
cxxFieldSizeString
(
SizeData
Size8
)
=
"BYTE"
;
cxxFieldSizeString
(
SizeData
Size16
)
=
"TWO_BYTES"
;
cxxFieldSizeString
(
SizeData
Size32
)
=
"FOUR_BYTES"
;
cxxFieldSizeString
(
SizeData
Size64
)
=
"EIGHT_BYTES"
;
cxxFieldSizeString
SizeReference
=
"REFERENCE"
;
cxxFieldSizeString
(
SizeInlineComposite
_
_
)
=
"INLINE_COMPOSITE"
;
fieldOffsetInteger
VoidOffset
=
"0"
fieldOffsetInteger
(
DataOffset
_
o
)
=
show
o
fieldOffsetInteger
(
PointerOffset
o
)
=
show
o
fieldOffsetInteger
(
InlineCompositeOffset
d
p
ds
ps
)
=
let
bitSize
=
dataSectionBits
ds
bitOffset
=
case
ds
of
DataSectionWords
_
->
d
*
64
_
->
d
*
bitSize
in
printf
"%d * ::capnproto::BITS, %d * ::capnproto::BITS,
\
\
%d * ::capnproto::REFERENCES, %d * ::capnproto::REFERENCES"
bitOffset
bitSize
p
ps
isDefaultZero
VoidDesc
=
True
isDefaultZero
(
BoolDesc
b
)
=
not
b
isDefaultZero
(
Int8Desc
i
)
=
i
==
0
...
...
@@ -221,6 +238,7 @@ fieldContext parent desc = mkStrContext context where
context
"fieldIsPrimitive"
=
MuBool
$
isPrimitive
$
fieldType
desc
context
"fieldIsBlob"
=
MuBool
$
isBlob
$
fieldType
desc
context
"fieldIsStruct"
=
MuBool
$
isStruct
$
fieldType
desc
context
"fieldIsInlineStruct"
=
MuBool
$
isInlineStruct
$
fieldType
desc
context
"fieldIsList"
=
MuBool
$
isList
$
fieldType
desc
context
"fieldIsNonStructList"
=
MuBool
$
isNonStructList
$
fieldType
desc
context
"fieldIsPrimitiveList"
=
MuBool
$
isPrimitiveList
$
fieldType
desc
...
...
@@ -231,7 +249,7 @@ fieldContext parent desc = mkStrContext context where
Nothing
->
muNull
context
"fieldType"
=
MuVariable
$
cxxTypeString
$
fieldType
desc
context
"fieldBlobType"
=
MuVariable
$
blobTypeString
$
fieldType
desc
context
"fieldOffset"
=
MuVariable
$
fieldOffset
desc
context
"fieldOffset"
=
MuVariable
$
fieldOffset
Integer
$
fieldOffset
desc
context
"fieldDefaultMask"
=
case
fieldDefaultValue
desc
of
Nothing
->
MuVariable
""
Just
v
->
MuVariable
(
if
isDefaultZero
v
then
""
else
", "
++
defaultMask
v
)
...
...
@@ -283,8 +301,8 @@ structContext parent desc = mkStrContext context where
context
"structFullName"
=
MuVariable
$
fullName
(
DescStruct
desc
)
context
"structFields"
=
MuList
$
map
(
fieldContext
context
)
$
structFields
desc
context
"structUnions"
=
MuList
$
map
(
unionContext
context
)
$
structUnions
desc
context
"structDataSize"
=
MuVariable
$
packingDataSize
$
structPacking
desc
context
"structReferenceCount"
=
MuVariable
$
packingReferenceCount
$
structPacking
desc
context
"structDataSize"
=
MuVariable
$
dataSectionWordSize
$
structDataSize
desc
context
"structReferenceCount"
=
MuVariable
$
structPointerCount
desc
context
"structNestedEnums"
=
MuList
$
map
(
enumContext
context
)
[
m
|
DescEnum
m
<-
structMembers
desc
]
context
"structNestedStructs"
=
...
...
compiler/src/Grammar.hs
View file @
7f20d533
...
...
@@ -95,7 +95,8 @@ data Declaration = UsingDecl (Located String) DeclName
|
ConstantDecl
(
Located
String
)
TypeExpression
[
Annotation
]
(
Located
FieldValue
)
|
EnumDecl
(
Located
String
)
[
Annotation
]
[
Declaration
]
|
EnumerantDecl
(
Located
String
)
(
Located
Integer
)
[
Annotation
]
|
StructDecl
(
Located
String
)
[
Annotation
]
[
Declaration
]
|
StructDecl
(
Located
String
)
(
Maybe
(
Located
(
Integer
,
Integer
)))
[
Annotation
]
[
Declaration
]
|
FieldDecl
(
Located
String
)
(
Located
Integer
)
TypeExpression
[
Annotation
]
(
Maybe
(
Located
FieldValue
))
|
UnionDecl
(
Located
String
)
(
Located
Integer
)
[
Annotation
]
[
Declaration
]
...
...
@@ -110,7 +111,7 @@ declarationName (UsingDecl n _) = Just n
declarationName
(
ConstantDecl
n
_
_
_
)
=
Just
n
declarationName
(
EnumDecl
n
_
_
)
=
Just
n
declarationName
(
EnumerantDecl
n
_
_
)
=
Just
n
declarationName
(
StructDecl
n
_
_
)
=
Just
n
declarationName
(
StructDecl
n
_
_
_
)
=
Just
n
declarationName
(
FieldDecl
n
_
_
_
_
)
=
Just
n
declarationName
(
UnionDecl
n
_
_
_
)
=
Just
n
declarationName
(
InterfaceDecl
n
_
_
)
=
Just
n
...
...
@@ -122,8 +123,8 @@ declImports (UsingDecl _ name) = maybeToList (declNameImport name)
declImports
(
ConstantDecl
_
t
ann
_
)
=
typeImports
t
++
concatMap
annotationImports
ann
declImports
(
EnumDecl
_
ann
decls
)
=
concatMap
annotationImports
ann
++
concatMap
declImports
decls
declImports
(
EnumerantDecl
_
_
ann
)
=
concatMap
annotationImports
ann
declImports
(
StructDecl
_
ann
decls
)
=
concatMap
annotationImports
ann
++
concatMap
declImports
decls
declImports
(
StructDecl
_
_
ann
decls
)
=
concatMap
annotationImports
ann
++
concatMap
declImports
decls
declImports
(
FieldDecl
_
_
t
ann
_
)
=
typeImports
t
++
concatMap
annotationImports
ann
declImports
(
UnionDecl
_
_
ann
decls
)
=
concatMap
annotationImports
ann
++
concatMap
declImports
decls
...
...
compiler/src/Lexer.hs
View file @
7f20d533
...
...
@@ -49,6 +49,7 @@ keywords =
,
(
UnionKeyword
,
"union"
)
,
(
InterfaceKeyword
,
"interface"
)
,
(
AnnotationKeyword
,
"annotation"
)
,
(
FixedKeyword
,
"fixed"
)
]
languageDef
::
T
.
LanguageDef
st
...
...
compiler/src/Parser.hs
View file @
7f20d533
...
...
@@ -24,6 +24,7 @@
module
Parser
(
parseFile
)
where
import
Data.Generics
import
Data.Maybe
(
fromMaybe
)
import
Text.Parsec
hiding
(
tokens
)
import
Token
import
Grammar
...
...
@@ -65,6 +66,7 @@ tokenErrorString StructKeyword = "keyword \"struct\""
tokenErrorString
UnionKeyword
=
"keyword
\"
union
\"
"
tokenErrorString
InterfaceKeyword
=
"keyword
\"
interface
\"
"
tokenErrorString
AnnotationKeyword
=
"keyword
\"
annotation
\"
"
tokenErrorString
FixedKeyword
=
"keyword
\"
fixed
\"
"
type
TokenParser
=
Parsec
[
Located
Token
]
[
ParseError
]
...
...
@@ -120,6 +122,7 @@ structKeyword = tokenParser (matchSimpleToken StructKeyword) <?> "\"struct\""
unionKeyword
=
tokenParser
(
matchSimpleToken
UnionKeyword
)
<?>
"
\"
union
\"
"
interfaceKeyword
=
tokenParser
(
matchSimpleToken
InterfaceKeyword
)
<?>
"
\"
interface
\"
"
annotationKeyword
=
tokenParser
(
matchSimpleToken
AnnotationKeyword
)
<?>
"
\"
annotation
\"
"
fixedKeyword
=
tokenParser
(
matchSimpleToken
FixedKeyword
)
<?>
"
\"
fixed
\"
"
exactIdentifier
s
=
tokenParser
(
matchSimpleToken
$
Identifier
s
)
<?>
"
\"
"
++
s
++
"
\"
"
...
...
@@ -223,9 +226,39 @@ enumerantDecl = do
structDecl
statements
=
do
structKeyword
name
<-
located
typeIdentifier
fixed
<-
optionMaybe
fixedSpec
annotations
<-
many
annotation
children
<-
parseBlock
structLine
statements
return
(
StructDecl
name
annotations
children
)
return
(
StructDecl
name
fixed
annotations
children
)
fixedSpec
=
do
fixedKeyword
Located
pos
sizes
<-
located
$
parenthesizedList
fixedSize
(
dataSize
,
pointerSize
)
<-
foldM
combineFixedSizes
(
Nothing
,
Nothing
)
sizes
return
$
Located
pos
(
fromMaybe
0
dataSize
,
fromMaybe
0
pointerSize
)
data
FixedSize
=
FixedData
Integer
|
FixedPointers
Integer
combineFixedSizes
::
(
Maybe
Integer
,
Maybe
Integer
)
->
FixedSize
->
TokenParser
(
Maybe
Integer
,
Maybe
Integer
)
combineFixedSizes
(
Nothing
,
p
)
(
FixedData
d
)
=
return
(
Just
d
,
p
)
combineFixedSizes
(
Just
_
,
_
)
(
FixedData
_
)
=
fail
"Multiple data section size specifications."
combineFixedSizes
(
d
,
Nothing
)
(
FixedPointers
p
)
=
return
(
d
,
Just
p
)
combineFixedSizes
(
_
,
Just
_
)
(
FixedPointers
_
)
=
fail
"Multiple pointer section size specifications."
fixedSize
=
do
size
<-
literalInt
(
exactIdentifier
"bit"
>>
return
(
FixedData
size
))
<|>
(
exactIdentifier
"bits"
>>
return
(
FixedData
size
))
<|>
(
exactIdentifier
"byte"
>>
return
(
FixedData
(
8
*
size
)))
<|>
(
exactIdentifier
"bytes"
>>
return
(
FixedData
(
8
*
size
)))
<|>
(
exactIdentifier
"word"
>>
return
(
FixedData
(
64
*
size
)))
<|>
(
exactIdentifier
"words"
>>
return
(
FixedData
(
64
*
size
)))
<|>
(
exactIdentifier
"pointer"
>>
return
(
FixedPointers
size
))
<|>
(
exactIdentifier
"pointers"
>>
return
(
FixedPointers
size
))
<?>
"
\"
bits
\"
,
\"
bytes
\"
,
\"
words
\"
, or
\"
pointers
\"
"
structLine
::
Maybe
[
Located
Statement
]
->
TokenParser
Declaration
structLine
Nothing
=
usingDecl
<|>
constantDecl
<|>
fieldDecl
<|>
annotationDecl
...
...
compiler/src/Semantics.hs
View file @
7f20d533
...
...
@@ -55,6 +55,7 @@ data Desc = DescFile FileDesc
|
DescAnnotation
AnnotationDesc
|
DescBuiltinType
BuiltinType
|
DescBuiltinList
|
DescBuiltinInline
|
DescBuiltinId
descName
(
DescFile
_
)
=
"(top-level)"
...
...
@@ -71,6 +72,7 @@ descName (DescParam d) = paramName d
descName
(
DescAnnotation
d
)
=
annotationName
d
descName
(
DescBuiltinType
d
)
=
builtinTypeName
d
descName
DescBuiltinList
=
"List"
descName
DescBuiltinInline
=
"Inline"
descName
DescBuiltinId
=
"id"
descId
(
DescFile
d
)
=
fileId
d
...
...
@@ -87,6 +89,7 @@ descId (DescParam d) = paramId d
descId
(
DescAnnotation
d
)
=
annotationId
d
descId
(
DescBuiltinType
_
)
=
Nothing
descId
DescBuiltinList
=
Nothing
descId
DescBuiltinInline
=
Nothing
descId
DescBuiltinId
=
Just
"0U0T3e_SnatEfk6UcH2tcjTt1E0"
-- Gets the ID if explicitly defined, or generates it by appending ".name" to the parent's ID.
...
...
@@ -111,6 +114,7 @@ descParent (DescParam d) = DescMethod (paramParent d)
descParent
(
DescAnnotation
d
)
=
annotationParent
d
descParent
(
DescBuiltinType
_
)
=
error
"Builtin type has no parent."
descParent
DescBuiltinList
=
error
"Builtin type has no parent."
descParent
DescBuiltinInline
=
error
"Builtin type has no parent."
descParent
DescBuiltinId
=
error
"Builtin annotation has no parent."
descFile
(
DescFile
d
)
=
d
...
...
@@ -130,9 +134,10 @@ descAnnotations (DescParam d) = paramAnnotations d
descAnnotations
(
DescAnnotation
d
)
=
annotationAnnotations
d
descAnnotations
(
DescBuiltinType
_
)
=
Map
.
empty
descAnnotations
DescBuiltinList
=
Map
.
empty
descAnnotations
DescBuiltinInline
=
Map
.
empty
descAnnotations
DescBuiltinId
=
Map
.
empty
descRuntimeImports
(
DescFile
d
)
=
error
"Not to be called on files."
descRuntimeImports
(
DescFile
_
)
=
error
"Not to be called on files."
descRuntimeImports
(
DescUsing
d
)
=
usingRuntimeImports
d
descRuntimeImports
(
DescConstant
d
)
=
constantRuntimeImports
d
descRuntimeImports
(
DescEnum
d
)
=
enumRuntimeImports
d
...
...
@@ -146,6 +151,7 @@ descRuntimeImports (DescParam d) = paramRuntimeImports d
descRuntimeImports
(
DescAnnotation
d
)
=
annotationRuntimeImports
d
descRuntimeImports
(
DescBuiltinType
_
)
=
[]
descRuntimeImports
DescBuiltinList
=
[]
descRuntimeImports
DescBuiltinInline
=
[]
descRuntimeImports
DescBuiltinId
=
[]
type
MemberMap
=
Map
.
Map
String
(
Maybe
Desc
)
...
...
@@ -212,101 +218,118 @@ valueString (ListDesc l) = "[" ++ delimit ", " (map valueString l) ++ "]" where
data
TypeDesc
=
BuiltinType
BuiltinType
|
EnumType
EnumDesc
|
StructType
StructDesc
|
InlineStructType
StructDesc
|
InterfaceType
InterfaceDesc
|
ListType
TypeDesc
typeRuntimeImports
(
BuiltinType
_
)
=
[]
typeRuntimeImports
(
EnumType
d
)
=
[
descFile
(
DescEnum
d
)]
typeRuntimeImports
(
StructType
d
)
=
[
descFile
(
DescStruct
d
)]
typeRuntimeImports
(
InlineStructType
d
)
=
[
descFile
(
DescStruct
d
)]
typeRuntimeImports
(
InterfaceType
d
)
=
[
descFile
(
DescInterface
d
)]
typeRuntimeImports
(
ListType
d
)
=
typeRuntimeImports
d
data
PackingState
=
PackingState
{
packingHole1
::
Integer
,
packingHole8
::
Integer
,
packingHole16
::
Integer
,
packingHole32
::
Integer
,
packingDataSize
::
Integer
,
packingReferenceCount
::
Integer
}
packingSize
PackingState
{
packingDataSize
=
ds
,
packingReferenceCount
=
rc
}
=
ds
+
rc
-- Represents the current packing state of a union. The parameters are:
-- - The offset of a 64-bit word in the data segment allocated to the union.
-- - The offset of a reference allocated to the union.
-- - The offset of a smaller piece of the data segment allocated to the union. Such a smaller
-- piece exists if one field in the union has lower number than the union itself -- in this case,
-- this is the piece that had been allocated to that field, and is now retroactively part of the
-- union.
data
UnionPackingState
=
UnionPackingState
{
unionPackDataOffset
::
Maybe
(
Integer
,
FieldSize
)
,
unionPackReferenceOffset
::
Maybe
Integer
}
data
FieldSize
=
Size0
|
Size1
|
Size8
|
Size16
|
Size32
|
Size64
|
SizeReference
|
SizeInlineComposite
Integer
Integer
isDataFieldSize
SizeReference
=
False
isDataFieldSize
(
SizeInlineComposite
_
_
)
=
False
isDataFieldSize
_
=
True
fieldSize
(
BuiltinType
BuiltinVoid
)
=
Size0
fieldSize
(
BuiltinType
BuiltinBool
)
=
Size1
fieldSize
(
BuiltinType
BuiltinInt8
)
=
Size8
fieldSize
(
BuiltinType
BuiltinInt16
)
=
Size16
fieldSize
(
BuiltinType
BuiltinInt32
)
=
Size32
fieldSize
(
BuiltinType
BuiltinInt64
)
=
Size64
fieldSize
(
BuiltinType
BuiltinUInt8
)
=
Size8
fieldSize
(
BuiltinType
BuiltinUInt16
)
=
Size16
fieldSize
(
BuiltinType
BuiltinUInt32
)
=
Size32
fieldSize
(
BuiltinType
BuiltinUInt64
)
=
Size64
fieldSize
(
BuiltinType
BuiltinFloat32
)
=
Size32
fieldSize
(
BuiltinType
BuiltinFloat64
)
=
Size64
data
DataSectionSize
=
DataSection1
|
DataSection8
|
DataSection16
|
DataSection32
|
DataSectionWords
Integer
dataSectionWordSize
ds
=
case
ds
of
DataSectionWords
w
->
w
_
->
1
dataSectionAlignment
DataSection1
=
Size1
dataSectionAlignment
DataSection8
=
Size8
dataSectionAlignment
DataSection16
=
Size16
dataSectionAlignment
DataSection32
=
Size32
dataSectionAlignment
(
DataSectionWords
_
)
=
Size64
dataSectionBits
DataSection1
=
1
dataSectionBits
DataSection8
=
8
dataSectionBits
DataSection16
=
16
dataSectionBits
DataSection32
=
32
dataSectionBits
(
DataSectionWords
w
)
=
w
*
64
dataSizeToSectionSize
Size1
=
DataSection1
dataSizeToSectionSize
Size8
=
DataSection8
dataSizeToSectionSize
Size16
=
DataSection16
dataSizeToSectionSize
Size32
=
DataSection32
dataSizeToSectionSize
Size64
=
DataSectionWords
1
dataSectionSizeString
DataSection1
=
"1 bits"
dataSectionSizeString
DataSection8
=
"8 bits"
dataSectionSizeString
DataSection16
=
"16 bits"
dataSectionSizeString
DataSection32
=
"32 bits"
dataSectionSizeString
(
DataSectionWords
n
)
=
show
n
++
" words"
data
DataSize
=
Size1
|
Size8
|
Size16
|
Size32
|
Size64
deriving
(
Eq
,
Ord
,
Enum
)
dataSizeInBits
::
DataSize
->
Integer
dataSizeInBits
Size1
=
1
dataSizeInBits
Size8
=
8
dataSizeInBits
Size16
=
16
dataSizeInBits
Size32
=
32
dataSizeInBits
Size64
=
64
data
FieldSize
=
SizeVoid
|
SizeData
DataSize
|
SizeReference
|
SizeInlineComposite
DataSectionSize
Integer
data
FieldOffset
=
VoidOffset
|
DataOffset
DataSize
Integer
|
PointerOffset
Integer
|
InlineCompositeOffset
{
inlineCompositeDataOffset
::
Integer
,
inlineCompositePointerOffset
::
Integer
,
inlineCompositeDataSize
::
DataSectionSize
,
inlineCompositePointerSize
::
Integer
}
offsetToSize
::
FieldOffset
->
FieldSize
offsetToSize
VoidOffset
=
SizeVoid
offsetToSize
(
DataOffset
s
_
)
=
SizeData
s
offsetToSize
(
PointerOffset
_
)
=
SizeReference
offsetToSize
(
InlineCompositeOffset
_
_
d
p
)
=
SizeInlineComposite
d
p
fieldSize
(
BuiltinType
BuiltinVoid
)
=
SizeVoid
fieldSize
(
BuiltinType
BuiltinBool
)
=
SizeData
Size1
fieldSize
(
BuiltinType
BuiltinInt8
)
=
SizeData
Size8
fieldSize
(
BuiltinType
BuiltinInt16
)
=
SizeData
Size16
fieldSize
(
BuiltinType
BuiltinInt32
)
=
SizeData
Size32
fieldSize
(
BuiltinType
BuiltinInt64
)
=
SizeData
Size64
fieldSize
(
BuiltinType
BuiltinUInt8
)
=
SizeData
Size8
fieldSize
(
BuiltinType
BuiltinUInt16
)
=
SizeData
Size16
fieldSize
(
BuiltinType
BuiltinUInt32
)
=
SizeData
Size32
fieldSize
(
BuiltinType
BuiltinUInt64
)
=
SizeData
Size64
fieldSize
(
BuiltinType
BuiltinFloat32
)
=
SizeData
Size32
fieldSize
(
BuiltinType
BuiltinFloat64
)
=
SizeData
Size64
fieldSize
(
BuiltinType
BuiltinText
)
=
SizeReference
fieldSize
(
BuiltinType
BuiltinData
)
=
SizeReference
fieldSize
(
EnumType
_
)
=
Size
16
-- TODO: ??
fieldSize
(
EnumType
_
)
=
Size
Data
Size16
fieldSize
(
StructType
_
)
=
SizeReference
fieldSize
(
InlineStructType
StructDesc
{
structDataSize
=
ds
,
structPointerCount
=
ps
})
=
SizeInlineComposite
ds
ps
fieldSize
(
InterfaceType
_
)
=
SizeReference
fieldSize
(
ListType
_
)
=
SizeReference
fieldValueSize
VoidDesc
=
Size0
fieldValueSize
(
BoolDesc
_
)
=
Size1
fieldValueSize
(
Int8Desc
_
)
=
Size8
fieldValueSize
(
Int16Desc
_
)
=
Size16
fieldValueSize
(
Int32Desc
_
)
=
Size32
fieldValueSize
(
Int64Desc
_
)
=
Size64
fieldValueSize
(
UInt8Desc
_
)
=
Size8
fieldValueSize
(
UInt16Desc
_
)
=
Size16
fieldValueSize
(
UInt32Desc
_
)
=
Size32
fieldValueSize
(
UInt64Desc
_
)
=
Size64
fieldValueSize
(
Float32Desc
_
)
=
Size32
fieldValueSize
(
Float64Desc
_
)
=
Size64
fieldValueSize
(
TextDesc
_
)
=
SizeReference
fieldValueSize
(
DataDesc
_
)
=
SizeReference
fieldValueSize
(
EnumerantValueDesc
_
)
=
Size16
fieldValueSize
(
StructValueDesc
_
)
=
SizeReference
fieldValueSize
(
ListDesc
_
)
=
SizeReference
elementSize
(
StructType
StructDesc
{
structPacking
=
PackingState
{
packingDataSize
=
ds
,
packingReferenceCount
=
rc
}
})
=
SizeInlineComposite
ds
rc
elementSize
(
StructType
StructDesc
{
structDataSize
=
DataSection1
,
structPointerCount
=
0
})
=
SizeData
Size1
elementSize
(
StructType
StructDesc
{
structDataSize
=
DataSection8
,
structPointerCount
=
0
})
=
SizeData
Size8
elementSize
(
StructType
StructDesc
{
structDataSize
=
DataSection16
,
structPointerCount
=
0
})
=
SizeData
Size16
elementSize
(
StructType
StructDesc
{
structDataSize
=
DataSection32
,
structPointerCount
=
0
})
=
SizeData
Size32
elementSize
(
StructType
StructDesc
{
structDataSize
=
ds
,
structPointerCount
=
pc
})
=
SizeInlineComposite
ds
pc
elementSize
(
InlineStructType
s
)
=
elementSize
(
StructType
s
)
elementSize
t
=
fieldSize
t
sizeInBits
Size0
=
0
sizeInBits
Size1
=
1
sizeInBits
Size8
=
8
sizeInBits
Size16
=
16
sizeInBits
Size32
=
32
sizeInBits
Size64
=
64
sizeInBits
SizeReference
=
64
sizeInBits
(
SizeInlineComposite
d
r
)
=
(
d
+
r
)
*
64
-- Render the type descriptor's name as a string, appropriate for use in the given scope.
typeName
::
Desc
->
TypeDesc
->
String
typeName
_
(
BuiltinType
t
)
=
builtinTypeName
t
-- TODO: Check for shadowing.
typeName
scope
(
EnumType
desc
)
=
descQualifiedName
scope
(
DescEnum
desc
)
typeName
scope
(
StructType
desc
)
=
descQualifiedName
scope
(
DescStruct
desc
)
typeName
scope
(
InlineStructType
desc
)
=
descQualifiedName
scope
(
DescStruct
desc
)
typeName
scope
(
InterfaceType
desc
)
=
descQualifiedName
scope
(
DescInterface
desc
)
typeName
scope
(
ListType
t
)
=
"List("
++
typeName
scope
t
++
")"
...
...
@@ -386,7 +409,9 @@ data StructDesc = StructDesc
{
structName
::
String
,
structId
::
Maybe
String
,
structParent
::
Desc
,
structPacking
::
PackingState
,
structDataSize
::
DataSectionSize
,
structPointerCount
::
Integer
,
structIsFixedWidth
::
Bool
,
structFields
::
[
FieldDesc
]
,
structUnions
::
[
UnionDesc
]
,
structAnnotations
::
AnnotationMap
...
...
@@ -396,7 +421,7 @@ data StructDesc = StructDesc
-- Don't use this directly, use the members of FieldDesc and UnionDesc.
-- This field is exposed here only because I was too lazy to create a way to pass it on
-- the side when compiling members of a struct.
,
structFieldPackingMap
::
Map
.
Map
Integer
(
Integer
,
PackingState
)
,
structFieldPackingMap
::
Map
.
Map
Integer
FieldOffset
}
structRuntimeImports
desc
=
concatMap
descRuntimeImports
$
structMembers
desc
...
...
@@ -407,7 +432,6 @@ data UnionDesc = UnionDesc
,
unionParent
::
StructDesc
,
unionNumber
::
Integer
,
unionTagOffset
::
Integer
,
unionTagPacking
::
PackingState
,
unionFields
::
[
FieldDesc
]
,
unionAnnotations
::
AnnotationMap
,
unionMemberMap
::
MemberMap
...
...
@@ -424,8 +448,7 @@ data FieldDesc = FieldDesc
,
fieldId
::
Maybe
String
,
fieldParent
::
StructDesc
,
fieldNumber
::
Integer
,
fieldOffset
::
Integer
,
fieldPacking
::
PackingState
-- PackingState for the struct *if* this were the final field.
,
fieldOffset
::
FieldOffset
,
fieldUnion
::
Maybe
(
UnionDesc
,
Integer
)
-- Integer is value of union discriminant.
,
fieldType
::
TypeDesc
,
fieldDefaultValue
::
Maybe
ValueDesc
...
...
@@ -508,8 +531,13 @@ descToCode indent self@(DescEnum desc) = printf "%senum %s%s {\n%s%s}\n" indent
descToCode
indent
self
@
(
DescEnumerant
desc
)
=
printf
"%s%s @%d%s;
\n
"
indent
(
enumerantName
desc
)
(
enumerantNumber
desc
)
(
annotationsCode
self
)
descToCode
indent
self
@
(
DescStruct
desc
)
=
printf
"%sstruct %s%s {
\n
%s%s}
\n
"
indent
descToCode
indent
self
@
(
DescStruct
desc
)
=
printf
"%sstruct %s%s
%s
{
\n
%s%s}
\n
"
indent
(
structName
desc
)
(
if
structIsFixedWidth
desc
then
printf
" fixed(%s, %d pointers) "
(
dataSectionSizeString
$
structDataSize
desc
)
(
structPointerCount
desc
)
else
""
)
(
annotationsCode
self
)
(
blockCode
indent
(
structMembers
desc
))
indent
...
...
@@ -519,12 +547,16 @@ descToCode indent self@(DescField desc) = printf "%s%s@%d%s: %s%s%s; # %s\n" in
(
typeName
(
descParent
self
)
(
fieldType
desc
))
(
case
fieldDefaultValue
desc
of
{
Nothing
->
""
;
Just
v
->
" = "
++
valueString
v
;
})
(
annotationsCode
self
)
(
case
fieldSize
$
fieldType
desc
of
SizeReference
->
printf
"ref[%d]"
$
fieldOffset
desc
SizeInlineComposite
_
_
->
"??"
s
->
let
bits
=
sizeInBits
s
offset
=
fieldOffset
desc
(
case
fieldOffset
desc
of
PointerOffset
o
->
printf
"ptr[%d]"
o
InlineCompositeOffset
dataOffset
pointerOffset
dataSize
pointerSize
->
let
dataBitOffset
=
dataOffset
*
dataSizeInBits
(
dataSectionAlignment
dataSize
)
in
printf
"bits[%d, %d), ptrs[%d, %d)"
dataBitOffset
(
dataBitOffset
+
dataSectionBits
dataSize
)
pointerOffset
(
pointerOffset
+
pointerSize
)
VoidOffset
->
"(none)"
DataOffset
dataSize
offset
->
let
bits
=
dataSizeInBits
dataSize
in
printf
"bits[%d, %d)"
(
offset
*
bits
)
((
offset
+
1
)
*
bits
))
descToCode
indent
self
@
(
DescUnion
desc
)
=
printf
"%sunion %s@%d%s { # [%d, %d)
\n
%s%s}
\n
"
indent
(
unionName
desc
)
(
unionNumber
desc
)
...
...
@@ -556,6 +588,7 @@ descToCode indent self@(DescAnnotation desc) = printf "%sannotation %s: %s on(%s
(
annotationsCode
self
)
descToCode
_
(
DescBuiltinType
_
)
=
error
"Can't print code for builtin type."
descToCode
_
DescBuiltinList
=
error
"Can't print code for builtin type."
descToCode
_
DescBuiltinInline
=
error
"Can't print code for builtin type."
descToCode
_
DescBuiltinId
=
error
"Can't print code for builtin annotation."
maybeBlockCode
::
String
->
[
Desc
]
->
String
...
...
compiler/src/Token.hs
View file @
7f20d533
...
...
@@ -74,6 +74,7 @@ data Token = Identifier String
|
UnionKeyword
|
InterfaceKeyword
|
AnnotationKeyword
|
FixedKeyword
deriving
(
Data
,
Typeable
,
Show
,
Eq
)
data
Statement
=
Line
TokenSequence
...
...
compiler/src/WireFormat.hs
View file @
7f20d533
...
...
@@ -26,11 +26,11 @@ module WireFormat(encodeMessage) where
import
Data.List
(
sortBy
,
genericLength
,
genericReplicate
)
import
Data.Word
import
Data.Bits
(
shiftL
,
shiftR
,
Bits
,
setBit
,
xor
)
import
Data.Function
(
on
)
import
Semantics
import
Data.Binary.IEEE754
(
floatToWord
,
doubleToWord
)
import
qualified
Codec.Binary.UTF8.String
as
UTF8
--
byte
::
(
Integral
a
,
Bits
a
)
=>
a
->
Int
->
Word8
byte
i
amount
=
fromIntegral
(
shiftR
i
(
amount
*
8
))
...
...
@@ -43,119 +43,112 @@ padToWord b = let
then
b
else
b
++
replicate
(
8
-
trailing
)
0
roundUpToMultiple
factor
n
=
let
remainder
=
mod
n
factor
in
if
remainder
==
0
then
n
else
n
+
(
factor
-
remainder
)
encodeDataValue
::
ValueDesc
->
[
Word8
]
encodeDataValue
VoidDesc
=
[]
encodeDataValue
(
BoolDesc
_
)
=
error
"Bools must be handled specially."
encodeDataValue
(
Int8Desc
v
)
=
bytes
v
1
encodeDataValue
(
Int16Desc
v
)
=
bytes
v
2
encodeDataValue
(
Int32Desc
v
)
=
bytes
v
4
encodeDataValue
(
Int64Desc
v
)
=
bytes
v
8
encodeDataValue
(
UInt8Desc
v
)
=
bytes
v
1
encodeDataValue
(
UInt16Desc
v
)
=
bytes
v
2
encodeDataValue
(
UInt32Desc
v
)
=
bytes
v
4
encodeDataValue
(
UInt64Desc
v
)
=
bytes
v
8
encodeDataValue
(
Float32Desc
v
)
=
bytes
(
floatToWord
v
)
4
encodeDataValue
(
Float64Desc
v
)
=
bytes
(
doubleToWord
v
)
8
encodeDataValue
(
TextDesc
_
)
=
error
"Not fixed-width data."
encodeDataValue
(
DataDesc
_
)
=
error
"Not fixed-width data."
encodeDataValue
(
EnumerantValueDesc
v
)
=
bytes
(
enumerantNumber
v
)
2
encodeDataValue
(
StructValueDesc
_
)
=
error
"Not fixed-width data."
encodeDataValue
(
ListDesc
_
)
=
error
"Not fixed-width data."
encodeMaskedDataValue
v
Nothing
=
encodeDataValue
v
encodeMaskedDataValue
v
(
Just
d
)
=
zipWith
xor
(
encodeDataValue
v
)
(
encodeDataValue
d
)
packBits
::
Bits
a
=>
Int
->
[(
Bool
,
Maybe
Bool
)]
->
a
packBits
_
[]
=
0
packBits
offset
((
True
,
Nothing
)
:
bits
)
=
setBit
(
packBits
(
offset
+
1
)
bits
)
offset
packBits
offset
((
False
,
Nothing
)
:
bits
)
=
packBits
(
offset
+
1
)
bits
packBits
offset
((
b
,
Just
d
)
:
bits
)
=
packBits
offset
((
b
/=
d
,
Nothing
)
:
bits
)
-- The tuples are (offsetInBits, type, value, defaultValue) for each field to encode.
encodeData
::
Integer
->
[(
Integer
,
TypeDesc
,
ValueDesc
,
Maybe
ValueDesc
)]
->
[
Word8
]
encodeData
size
=
loop
0
where
loop
bit
[]
|
bit
==
size
=
[]
data
EncodedData
=
EncodedBit
Bool
|
EncodedBytes
[
Word8
]
xorData
(
EncodedBit
a
)
(
EncodedBit
b
)
=
EncodedBit
(
a
/=
b
)
xorData
(
EncodedBytes
a
)
(
EncodedBytes
b
)
=
EncodedBytes
(
zipWith
xor
a
b
)
xorData
_
_
=
error
"Value type mismatch when xor'ing."
encodeDataValue
::
TypeDesc
->
ValueDesc
->
EncodedData
encodeDataValue
_
VoidDesc
=
EncodedBytes
[]
encodeDataValue
_
(
BoolDesc
v
)
=
EncodedBit
v
encodeDataValue
_
(
Int8Desc
v
)
=
EncodedBytes
$
bytes
v
1
encodeDataValue
_
(
Int16Desc
v
)
=
EncodedBytes
$
bytes
v
2
encodeDataValue
_
(
Int32Desc
v
)
=
EncodedBytes
$
bytes
v
4
encodeDataValue
_
(
Int64Desc
v
)
=
EncodedBytes
$
bytes
v
8
encodeDataValue
_
(
UInt8Desc
v
)
=
EncodedBytes
$
bytes
v
1
encodeDataValue
_
(
UInt16Desc
v
)
=
EncodedBytes
$
bytes
v
2
encodeDataValue
_
(
UInt32Desc
v
)
=
EncodedBytes
$
bytes
v
4
encodeDataValue
_
(
UInt64Desc
v
)
=
EncodedBytes
$
bytes
v
8
encodeDataValue
_
(
Float32Desc
v
)
=
EncodedBytes
$
bytes
(
floatToWord
v
)
4
encodeDataValue
_
(
Float64Desc
v
)
=
EncodedBytes
$
bytes
(
doubleToWord
v
)
8
encodeDataValue
_
(
TextDesc
_
)
=
error
"Not fixed-width data."
encodeDataValue
_
(
DataDesc
_
)
=
error
"Not fixed-width data."
encodeDataValue
_
(
EnumerantValueDesc
v
)
=
EncodedBytes
$
bytes
(
enumerantNumber
v
)
2
encodeDataValue
(
StructType
desc
)
(
StructValueDesc
assignments
)
=
let
(
dataBytes
,
refBytes
,
childBytes
)
=
encodeStruct
desc
assignments
0
in
if
null
refBytes
&&
null
childBytes
then
EncodedBytes
dataBytes
else
error
"encodeDataValue called on struct that wasn't plain data."
encodeDataValue
(
InlineStructType
desc
)
v
=
encodeDataValue
(
StructType
desc
)
v
encodeDataValue
_
(
StructValueDesc
_
)
=
error
"Type/value mismatch."
encodeDataValue
_
(
ListDesc
_
)
=
error
"Not fixed-width data."
encodeMaskedDataValue
t
v
Nothing
=
encodeDataValue
t
v
encodeMaskedDataValue
t
v
(
Just
d
)
=
xorData
(
encodeDataValue
t
v
)
(
encodeDataValue
t
d
)
encodePointerValue
::
TypeDesc
->
ValueDesc
->
(
Integer
->
[
Word8
],
[
Word8
])
encodePointerValue
_
(
TextDesc
text
)
=
let
encoded
=
UTF8
.
encode
text
++
[
0
]
in
(
encodeListReference
(
SizeData
Size8
)
(
genericLength
encoded
),
padToWord
encoded
)
encodePointerValue
_
(
DataDesc
d
)
=
(
encodeListReference
(
SizeData
Size8
)
(
genericLength
d
),
padToWord
d
)
encodePointerValue
(
StructType
desc
)
(
StructValueDesc
assignments
)
=
let
(
dataBytes
,
refBytes
,
childBytes
)
=
encodeStruct
desc
assignments
0
in
(
encodeStructReference
desc
,
concat
[
padToWord
dataBytes
,
refBytes
,
childBytes
])
encodePointerValue
(
InlineStructType
desc
)
v
=
encodePointerValue
(
StructType
desc
)
v
encodePointerValue
(
ListType
elementType
)
(
ListDesc
items
)
=
(
encodeListReference
(
elementSize
elementType
)
(
genericLength
items
),
encodeList
elementType
items
)
encodePointerValue
_
_
=
error
"Unknown pointer type."
-- Given a sorted list of (bitOffset, data), pack into a byte array.
packBytes
::
Integer
-- Total size of array to pack, in bits.
->
[(
Integer
,
EncodedData
)]
-- (offset, data) pairs to pack. Must be in order.
->
[
Word8
]
packBytes
size
=
loop
0
where
loop
::
Integer
->
[(
Integer
,
EncodedData
)]
->
[
Word8
]
loop
bit
[]
|
bit
<=
size
=
genericReplicate
(
div
(
size
-
bit
+
7
)
8
)
0
loop
bit
[]
|
bit
>
size
=
error
"Data values overran size."
loop
bit
[]
=
0
:
loop
(
bit
+
8
)
[]
loop
bit
rest
@
((
valuePos
,
_
,
BoolDesc
_
,
_
)
:
_
)
|
valuePos
==
bit
=
let
(
bits
,
rest2
)
=
popBits
(
bit
+
8
)
rest
in
packBits
0
bits
:
loop
(
bit
+
8
)
rest2
loop
bit
((
valuePos
,
_
,
value
,
defaultValue
)
:
rest
)
|
valuePos
==
bit
=
encodeMaskedDataValue
value
defaultValue
++
loop
(
bit
+
sizeInBits
(
fieldValueSize
value
))
rest
loop
bit
rest
@
((
valuePos
,
_
,
_
,
_
)
:
_
)
|
valuePos
>
bit
=
0
:
loop
(
bit
+
8
)
rest
loop
_
_
=
error
"Data values were out-of-order."
popBits
limit
((
valuePos
,
_
,
BoolDesc
b
,
d
)
:
rest
)
|
valuePos
<
limit
=
let
(
restBits
,
rest2
)
=
popBits
limit
rest
defaultB
=
fmap
(
\
(
BoolDesc
b2
)
->
b2
)
d
in
((
b
,
defaultB
)
:
restBits
,
rest2
)
popBits
_
rest
=
(
[]
,
rest
)
encodeReferences
::
Integer
->
Integer
->
[(
Integer
,
TypeDesc
,
ValueDesc
)]
->
([
Word8
],
[
Word8
])
encodeReferences
o
size
=
loop
0
(
o
+
size
-
1
)
where
loop
idx
offset
((
pos
,
t
,
v
)
:
rest
)
|
idx
==
pos
=
let
(
ref
,
obj
)
=
case
(
t
,
v
)
of
(
StructType
desc
,
StructValueDesc
assignments
)
->
let
(
dataBytes
,
refBytes
,
childBytes
)
=
encodeStruct
desc
assignments
0
in
(
encodeStructReference
desc
offset
,
concat
[
dataBytes
,
refBytes
,
childBytes
])
(
ListType
elementType
,
ListDesc
items
)
->
(
encodeListReference
(
elementSize
elementType
)
(
genericLength
items
)
offset
,
encodeList
elementType
items
)
(
BuiltinType
BuiltinText
,
TextDesc
text
)
->
let
encoded
=
(
UTF8
.
encode
text
++
[
0
])
in
(
encodeListReference
Size8
(
genericLength
encoded
)
offset
,
padToWord
encoded
)
(
BuiltinType
BuiltinData
,
DataDesc
d
)
->
let
in
(
encodeListReference
Size8
(
genericLength
d
)
offset
,
padToWord
d
)
_
->
error
"Unknown reference type."
len
=
genericLength
obj
wordLen
=
if
mod
len
8
==
0
then
div
len
8
else
error
"Child not word-aligned."
(
refs
,
objects
)
=
loop
(
idx
+
1
)
(
offset
+
wordLen
-
1
)
rest
in
(
ref
++
refs
,
obj
++
objects
)
loop
idx
offset
rest
@
((
pos
,
_
,
_
)
:
_
)
=
let
loop
bit
values
@
((
offset
,
_
)
:
_
)
|
offset
>=
bit
+
8
=
0
:
loop
(
bit
+
8
)
values
loop
bit
((
offset
,
EncodedBit
True
)
:
rest
)
=
let
firstByte
:
restBytes
=
loop
bit
rest
in
setBit
firstByte
(
fromIntegral
(
offset
-
bit
))
:
restBytes
loop
bit
((
_
,
EncodedBit
False
)
:
rest
)
=
loop
bit
rest
loop
bit
((
offset
,
EncodedBytes
encoded
)
:
rest
)
|
offset
==
bit
=
encoded
++
loop
(
bit
+
genericLength
encoded
*
8
)
rest
loop
_
_
=
error
"Data values overlapped."
bytesToWords
i
=
if
mod
i
8
==
0
then
div
i
8
else
error
"Byte count did not divide evenly into words."
packPointers
::
Integer
-- Total number of pointers to pack.
->
[(
Integer
,
(
Integer
->
[
Word8
],
[
Word8
]))]
->
Integer
-- Word offset from end of pointer array to child area.
->
([
Word8
],
[
Word8
])
packPointers
size
items
o
=
loop
0
items
(
o
+
size
-
1
)
where
loop
::
Integer
->
[(
Integer
,
(
Integer
->
[
Word8
],
[
Word8
]))]
->
Integer
->
([
Word8
],
[
Word8
])
loop
idx
((
pos
,
(
mkptrs
,
child
))
:
rest
)
childOff
|
idx
==
pos
=
let
ptrs
=
mkptrs
childOff
ptrCount
=
bytesToWords
(
genericLength
ptrs
)
newChildOff
=
childOff
-
ptrCount
+
bytesToWords
(
genericLength
child
)
(
restPtrs
,
restChildren
)
=
loop
(
idx
+
ptrCount
)
rest
newChildOff
in
(
ptrs
++
restPtrs
,
child
++
restChildren
)
loop
idx
rest
@
((
pos
,
_
)
:
_
)
childOff
=
let
padCount
=
pos
-
idx
(
refs
,
objects
)
=
loop
pos
(
offset
-
padCount
)
rest
in
(
genericReplicate
(
padCount
*
8
)
0
++
refs
,
objects
)
loop
idx
_
[]
=
(
genericReplicate
((
size
-
idx
)
*
8
)
0
,
[]
)
encodeStructList
::
Integer
->
StructDesc
->
[[(
FieldDesc
,
ValueDesc
)]]
->
([
Word8
],
[
Word8
])
encodeStructList
o
desc
elements
=
loop
(
o
+
eSize
*
genericLength
elements
)
elements
where
eSize
=
packingSize
$
structPacking
desc
loop
_
[]
=
(
[]
,
[]
)
loop
offset
(
element
:
rest
)
=
let
offsetFromElementEnd
=
offset
-
eSize
(
dataBytes
,
refBytes
,
childBytes
)
=
encodeStruct
desc
element
offsetFromElementEnd
childLen
=
genericLength
childBytes
childWordLen
=
if
mod
childLen
8
==
0
then
div
childLen
8
else
error
"Child not word-aligned."
(
restBytes
,
restChildren
)
=
loop
(
offsetFromElementEnd
+
childWordLen
)
rest
in
(
dataBytes
++
refBytes
++
restBytes
,
childBytes
++
restChildren
)
(
restPtrs
,
restChildren
)
=
loop
pos
rest
(
childOff
-
padCount
)
in
(
genericReplicate
(
padCount
*
8
)
0
++
restPtrs
,
restChildren
)
loop
idx
[]
_
=
(
genericReplicate
((
size
-
idx
)
*
8
)
0
,
[]
)
encodeStructReference
desc
offset
=
bytes
(
offset
*
4
+
structTag
)
4
++
bytes
(
packingDataSize
$
structPacking
desc
)
2
++
bytes
(
packingReferenceCount
$
structPacking
desc
)
2
bytes
(
dataSectionWordSize
$
structDataSize
desc
)
2
++
bytes
(
structPointerCount
desc
)
2
encodeListReference
elemSize
@
(
SizeInlineComposite
ds
rc
)
elementCount
offset
=
bytes
(
offset
*
4
+
listTag
)
4
++
bytes
(
fieldSizeEnum
elemSize
+
shiftL
(
elementCount
*
(
ds
+
rc
))
3
)
4
bytes
(
fieldSizeEnum
elemSize
+
shiftL
(
elementCount
*
(
d
ataSectionWordSize
d
s
+
rc
))
3
)
4
encodeListReference
elemSize
elementCount
offset
=
bytes
(
offset
*
4
+
listTag
)
4
++
bytes
(
fieldSizeEnum
elemSize
+
shiftL
elementCount
3
)
4
fieldSizeEnum
Size
0
=
0
fieldSizeEnum
Size1
=
1
fieldSizeEnum
Size8
=
2
fieldSizeEnum
Size16
=
3
fieldSizeEnum
Size32
=
4
fieldSizeEnum
Size64
=
5
fieldSizeEnum
Size
Void
=
0
fieldSizeEnum
(
SizeData
Size1
)
=
1
fieldSizeEnum
(
SizeData
Size8
)
=
2
fieldSizeEnum
(
SizeData
Size16
)
=
3
fieldSizeEnum
(
SizeData
Size32
)
=
4
fieldSizeEnum
(
SizeData
Size64
)
=
5
fieldSizeEnum
SizeReference
=
6
fieldSizeEnum
(
SizeInlineComposite
_
_
)
=
7
...
...
@@ -164,47 +157,94 @@ listTag = 1
-- childOffset = number of words between the last reference and the location where children will
-- be allocated.
encodeStruct
desc
assignments
childOffset
=
(
dataBytes
,
referenceBytes
,
children
)
where
-- Values explicitly assigned.
explicitValues
=
[(
fieldOffset
f
,
fieldType
f
,
v
,
fieldDefaultValue
f
)
|
(
f
,
v
)
<-
assignments
]
-- Values of union tags.
unionValues
=
[(
unionTagOffset
u
,
BuiltinType
BuiltinUInt16
,
UInt16Desc
$
fromIntegral
n
,
Nothing
)
|
(
FieldDesc
{
fieldUnion
=
Just
(
u
,
n
)},
_
)
<-
assignments
]
allValues
=
explicitValues
++
unionValues
allData
=
[
(
o
*
sizeInBits
(
fieldValueSize
v
),
t
,
v
,
d
)
|
(
o
,
t
,
v
,
d
)
<-
allValues
,
isDataFieldSize
$
fieldValueSize
v
]
allReferences
=
[
(
o
,
t
,
v
)
|
(
o
,
t
,
v
,
_
)
<-
allValues
,
not
$
isDataFieldSize
$
fieldValueSize
v
]
sortedData
=
sortBy
compareDataValues
allData
compareDataValues
(
o1
,
_
,
_
,
_
)
(
o2
,
_
,
_
,
_
)
=
compare
o1
o2
sortedReferences
=
sortBy
compareReferenceValues
allReferences
compareReferenceValues
(
o1
,
_
,
_
)
(
o2
,
_
,
_
)
=
compare
o1
o2
dataBytes
=
encodeData
(
packingDataSize
(
structPacking
desc
)
*
64
)
sortedData
(
referenceBytes
,
children
)
=
encodeReferences
childOffset
(
packingReferenceCount
$
structPacking
desc
)
sortedReferences
encodeStruct
desc
assignments
childOffset
=
let
dataSize
=
dataSectionBits
$
structDataSize
desc
dataSection
=
packBytes
dataSize
$
sortBy
(
compare
`
on
`
fst
)
$
structDataSectionValues
assignments
pointerCount
=
structPointerCount
desc
(
pointerSection
,
children
)
=
packPointers
pointerCount
(
sortBy
(
compare
`
on
`
fst
)
$
structPointerSectionValues
assignments
)
childOffset
in
(
dataSection
,
pointerSection
,
children
)
dataBitOffset
(
DataOffset
size
off
)
=
dataSizeInBits
size
*
off
dataBitOffset
(
InlineCompositeOffset
off
_
dataSectionSize
_
)
=
off
*
dataSizeInBits
(
dataSectionAlignment
dataSectionSize
)
dataBitOffset
_
=
error
"Not a data field."
structDataSectionValues
assignments
=
let
simpleValues
=
[(
dataBitOffset
$
fieldOffset
f
,
encodeMaskedDataValue
(
fieldType
f
)
v
(
fieldDefaultValue
f
))
|
(
f
@
FieldDesc
{
fieldOffset
=
DataOffset
_
_
},
v
)
<-
assignments
]
inlineStructValues
=
do
-- List monad!
(
FieldDesc
{
fieldOffset
=
InlineCompositeOffset
off
_
sectionSize
_
},
StructValueDesc
v
)
<-
assignments
let
bitOffset
=
off
*
dataSizeInBits
(
dataSectionAlignment
sectionSize
)
(
pos
,
v2
)
<-
structDataSectionValues
v
return
(
pos
+
bitOffset
,
v2
)
unionTags
=
[(
unionTagOffset
u
*
16
,
encodeDataValue
(
BuiltinType
BuiltinUInt16
)
(
UInt16Desc
$
fromIntegral
n
))
|
(
FieldDesc
{
fieldUnion
=
Just
(
u
,
n
)},
_
)
<-
assignments
]
in
simpleValues
++
inlineStructValues
++
unionTags
structPointerSectionValues
::
[(
FieldDesc
,
ValueDesc
)]
->
[(
Integer
,
(
Integer
->
[
Word8
],
[
Word8
]))]
structPointerSectionValues
assignments
=
let
simpleValues
=
[(
off
,
encodePointerValue
(
fieldType
f
)
v
)
|
(
f
@
FieldDesc
{
fieldOffset
=
PointerOffset
off
},
v
)
<-
assignments
]
inlineStructValues
=
do
-- List monad!
(
FieldDesc
{
fieldOffset
=
InlineCompositeOffset
_
off
_
_
},
StructValueDesc
v
)
<-
assignments
(
pos
,
v2
)
<-
structPointerSectionValues
v
return
(
pos
+
off
,
v2
)
in
simpleValues
++
inlineStructValues
encodeList
elementType
elements
=
case
elementSize
elementType
of
SizeInlineComposite
_
_
->
case
elementType
of
StructType
desc
->
let
SizeVoid
->
[]
SizeInlineComposite
_
_
->
let
handleStructType
desc
=
let
count
=
genericLength
elements
tag
=
encodeStructReference
desc
count
(
elemBytes
,
childBytes
)
=
encodeStructList
0
desc
[
v
|
StructValueDesc
v
<-
elements
]
in
concat
[
tag
,
elemBytes
,
childBytes
]
_
->
error
"Only structs can be inline composites."
in
case
elementType
of
StructType
desc
->
handleStructType
desc
InlineStructType
desc
->
handleStructType
desc
_
->
error
"Only structs can be inline composites."
SizeReference
->
refBytes
++
childBytes
where
(
refBytes
,
childBytes
)
=
encodeReferences
0
(
genericLength
elements
)
$
zipWith
(
\
i
v
->
(
i
,
elementType
,
v
))
[
0
..
]
elements
size
->
encodeData
(
roundUpToMultiple
64
(
genericLength
elements
*
sizeInBits
size
))
$
zipWith
(
\
i
v
->
(
i
*
sizeInBits
size
,
elementType
,
v
,
Nothing
))
[
0
..
]
elements
encodedElements
=
zip
[
0
..
]
$
map
(
encodePointerValue
elementType
)
elements
(
refBytes
,
childBytes
)
=
packPointers
(
genericLength
elements
)
encodedElements
0
SizeData
size
->
let
bits
=
dataSizeInBits
size
encodedElements
=
zip
[
0
,
bits
..
]
$
map
(
encodeDataValue
elementType
)
elements
in
padToWord
$
packBytes
(
genericLength
elements
*
bits
)
encodedElements
-- Encode an inline-composite struct list. Not used in cases where the struct is data-only and
-- fits into 32 bits or less.
encodeStructList
::
Integer
->
StructDesc
->
[[(
FieldDesc
,
ValueDesc
)]]
->
([
Word8
],
[
Word8
])
encodeStructList
o
desc
elements
=
loop
(
o
+
eSize
*
genericLength
elements
)
elements
where
eSize
=
dataSectionWordSize
(
structDataSize
desc
)
+
structPointerCount
desc
loop
_
[]
=
(
[]
,
[]
)
loop
offset
(
element
:
rest
)
=
let
offsetFromElementEnd
=
offset
-
eSize
(
dataBytes
,
refBytes
,
childBytes
)
=
encodeStruct
desc
element
offsetFromElementEnd
childLen
=
genericLength
childBytes
childWordLen
=
if
mod
childLen
8
==
0
then
div
childLen
8
else
error
"Child not word-aligned."
(
restBytes
,
restChildren
)
=
loop
(
offsetFromElementEnd
+
childWordLen
)
rest
in
(
padToWord
dataBytes
++
refBytes
++
restBytes
,
childBytes
++
restChildren
)
encodeMessage
(
StructType
desc
)
(
StructValueDesc
assignments
)
=
let
(
dataBytes
,
refBytes
,
childBytes
)
=
encodeStruct
desc
assignments
0
in
concat
[
encodeStructReference
desc
(
0
::
Integer
),
dataBytes
,
refBytes
,
childBytes
]
in
concat
[
encodeStructReference
desc
(
0
::
Integer
),
padToWord
dataBytes
,
refBytes
,
childBytes
]
encodeMessage
(
InlineStructType
desc
)
val
=
encodeMessage
(
StructType
desc
)
val
encodeMessage
(
ListType
elementType
)
(
ListDesc
elements
)
=
encodeListReference
(
elementSize
elementType
)
(
genericLength
elements
)
(
0
::
Integer
)
++
encodeList
elementType
elements
...
...
compiler/src/c++-header.mustache
View file @
7f20d533
...
...
@@ -295,6 +295,7 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(
{{/
fieldIsBlob
}}
{{! ------------------------------------------------------------------------------------------- }}
{{#
fieldIsStruct
}}
{{^
fieldIsInlineStruct
}}
inline
{{
fieldType
}}
::Reader
{{
typeFullName
}}
::Reader::get
{{
fieldTitleCase
}}
() {
{{#
fieldUnion
}}
CAPNPROTO_INLINE_DPRECOND(which() ==
{{
unionTitleCase
}}
::
{{
fieldUpperCase
}}
,
...
...
@@ -324,6 +325,34 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}()
{{#
fieldDefaultBytes
}}
DEFAULT_
{{
fieldUpperCase
}}
.words
{{/
fieldDefaultBytes
}}
{{^
fieldDefaultBytes
}}
nullptr
{{/
fieldDefaultBytes
}}
));
}
{{/
fieldIsInlineStruct
}}
{{#
fieldIsInlineStruct
}}
inline
{{
fieldType
}}
::Reader
{{
typeFullName
}}
::Reader::get
{{
fieldTitleCase
}}
() {
{{#
fieldUnion
}}
CAPNPROTO_INLINE_DPRECOND(which() ==
{{
unionTitleCase
}}
::
{{
fieldUpperCase
}}
,
"Must check which() before get()ing a union member.");
{{/
fieldUnion
}}
return
{{
fieldType
}}
::Reader(_reader.getInlineStructField(
{{
fieldOffset
}}
));
}
inline
{{
fieldType
}}
::Builder
{{
typeFullName
}}
::Builder::init
{{
fieldTitleCase
}}
() {
{{#
fieldUnion
}}
_builder.setDataField
<
{{
unionTitleCase
}}
::Which>
(
{{
unionTagOffset
}}
* ::capnproto::ELEMENTS,
{{
unionTitleCase
}}
::
{{
fieldUpperCase
}}
);
{{/
fieldUnion
}}
return
{{
fieldType
}}
::Builder(_builder.initInlineStructField(
{{
fieldOffset
}}
));
}
inline
{{
fieldType
}}
::Builder
{{
typeFullName
}}
::Builder::get
{{
fieldTitleCase
}}
() {
{{#
fieldUnion
}}
CAPNPROTO_INLINE_DPRECOND(which() ==
{{
unionTitleCase
}}
::
{{
fieldUpperCase
}}
,
"Must check which() before get()ing a union member.");
{{/
fieldUnion
}}
return
{{
fieldType
}}
::Builder(_builder.getInlineStructField(
{{
fieldOffset
}}
));
}
{{/
fieldIsInlineStruct
}}
{{/
fieldIsStruct
}}
{{! ------------------------------------------------------------------------------------------- }}
{{#
fieldIsList
}}
...
...
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