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
372612cd
Commit
372612cd
authored
Aug 15, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Mostly done with anonymous unions.
parent
248b149a
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
336 additions
and
86 deletions
+336
-86
bootstrap-test.ekam-rule
c++/src/capnp/bootstrap-test.ekam-rule
+2
-0
capnpc-c++.c++
c++/src/capnp/compiler/capnpc-c++.c++
+25
-14
grammar.capnp.c++
c++/src/capnp/compiler/grammar.capnp.c++
+30
-30
dynamic-test.c++
c++/src/capnp/dynamic-test.c++
+69
-9
dynamic.c++
c++/src/capnp/dynamic.c++
+0
-0
dynamic.h
c++/src/capnp/dynamic.h
+3
-0
encoding-test.c++
c++/src/capnp/encoding-test.c++
+3
-2
generated-header-support.h
c++/src/capnp/generated-header-support.h
+3
-7
schema-loader-test.c++
c++/src/capnp/schema-loader-test.c++
+34
-0
schema-loader.c++
c++/src/capnp/schema-loader.c++
+14
-10
schema-test.c++
c++/src/capnp/schema-test.c++
+11
-0
schema.c++
c++/src/capnp/schema.c++
+78
-7
schema.h
c++/src/capnp/schema.h
+6
-0
stringify-test.c++
c++/src/capnp/stringify-test.c++
+28
-0
stringify.c++
c++/src/capnp/stringify.c++
+10
-3
test.capnp
c++/src/capnp/test.capnp
+4
-4
common.h
c++/src/kj/common.h
+4
-0
debug.h
c++/src/kj/debug.h
+12
-0
No files found.
c++/src/capnp/bootstrap-test.ekam-rule
View file @
372612cd
...
...
@@ -73,3 +73,5 @@ for file in $INPUTS; do
diff
-u
$srcfile
tmp/capnp/bootstrap-test-tmp/
$file
.
$ext
>
&2
done
done
echo
passed
c++/src/capnp/compiler/capnpc-c++.c++
View file @
372612cd
...
...
@@ -119,7 +119,7 @@ void enumerateDeps(schema::Node::Reader node, std::set<uint64_t>& deps) {
struct
OrderByName
{
template
<
typename
T
>
inline
bool
operator
()(
const
T
&
a
,
const
T
&
b
)
const
{
return
a
.
getProto
().
getName
()
<
b
.
getProto
().
getName
();
return
a
.
member
.
getProto
().
getName
()
<
b
.
member
.
getProto
().
getName
();
}
};
...
...
@@ -135,11 +135,12 @@ void makeSubMemberInfoTable(const StructSchema::Member& member,
case
schema
:
:
StructNode
::
Member
::
Body
::
UNION_MEMBER
:
// Only create a sub-table if the union is named.
if
(
member
.
getProto
().
getName
().
size
()
>
0
)
{
makeMemberInfoTable
(
1
+
member
.
getIndex
(),
member
.
asUnion
().
getMembers
(),
info
);
makeMemberInfoTable
(
1
+
member
.
getProto
().
getOrdinal
(),
member
.
asUnion
().
getMembers
(),
info
);
}
break
;
case
schema
:
:
StructNode
::
Member
::
Body
::
GROUP_MEMBER
:
makeMemberInfoTable
(
1
+
member
.
get
Index
(),
member
.
asGroup
().
getMembers
(),
info
);
makeMemberInfoTable
(
1
+
member
.
get
Proto
().
getOrdinal
(),
member
.
asGroup
().
getMembers
(),
info
);
break
;
}
}
...
...
@@ -148,29 +149,40 @@ void makeSubMemberInfoTable(const EnumSchema::Enumerant& member,
void
makeSubMemberInfoTable
(
const
InterfaceSchema
::
Method
&
member
,
kj
::
Vector
<
capnp
::
_
::
RawSchema
::
MemberInfo
>&
info
)
{}
template
<
typename
Member
>
struct
MemberAndIndex
{
Member
member
;
uint
index
;
MemberAndIndex
(
Member
member
)
:
member
(
member
),
index
(
member
.
getIndex
())
{}
MemberAndIndex
(
Member
member
,
uint
index
)
:
member
(
member
),
index
(
index
)
{}
};
void
enumerateScope
(
const
StructSchema
::
MemberList
&
members
,
kj
::
Vector
<
StructSchema
::
Member
>&
vec
)
{
kj
::
Vector
<
MemberAndIndex
<
StructSchema
::
Member
>>&
vec
,
uint
offset
=
0
)
{
// Given a member list, flatten all members of the scope into one vector. This basically means
// copying all the members to the vector, except that unnamed unions are flattened.
// copying all the members to the vector, except that unnamed unions are flattened, with their
// members' indexes being offset by the size of the parent scope.
for
(
auto
member
:
members
)
{
vec
.
add
(
member
);
vec
.
add
(
member
,
member
.
getIndex
()
+
offset
);
if
(
member
.
getProto
().
getName
().
size
()
==
0
)
{
// Flatten unnamed union.
enumerateScope
(
member
.
asUnion
().
getMembers
(),
vec
);
enumerateScope
(
member
.
asUnion
().
getMembers
(),
vec
,
offset
+
members
.
size
()
);
}
}
}
void
enumerateScope
(
const
EnumSchema
::
EnumerantList
&
members
,
kj
::
Vector
<
EnumSchema
::
Enumerant
>&
vec
)
{
kj
::
Vector
<
MemberAndIndex
<
EnumSchema
::
Enumerant
>
>&
vec
)
{
for
(
auto
member
:
members
)
{
vec
.
add
(
member
);
}
}
void
enumerateScope
(
const
InterfaceSchema
::
MethodList
&
members
,
kj
::
Vector
<
InterfaceSchema
::
Method
>&
vec
)
{
kj
::
Vector
<
MemberAndIndex
<
InterfaceSchema
::
Method
>
>&
vec
)
{
for
(
auto
member
:
members
)
{
vec
.
add
(
member
);
}
...
...
@@ -179,16 +191,15 @@ void enumerateScope(const InterfaceSchema::MethodList& members,
template
<
typename
MemberList
>
void
makeMemberInfoTable
(
uint
parent
,
MemberList
&&
members
,
kj
::
Vector
<
capnp
::
_
::
RawSchema
::
MemberInfo
>&
info
)
{
kj
::
Vector
<
kj
::
Decay
<
decltype
(
members
[
0
])
>>
sortedMembers
(
members
.
size
());
enumerateScope
(
members
,
sorted
Members
);
kj
::
Vector
<
MemberAndIndex
<
decltype
(
members
[
0
])
>>
sorted
(
members
.
size
());
enumerateScope
(
members
,
sorted
);
auto
sorted
=
KJ_MAP
(
members
,
m
)
{
return
m
;
};
std
::
sort
(
sorted
.
begin
(),
sorted
.
end
(),
OrderByName
());
for
(
auto
&
member
:
sorted
)
{
info
.
add
(
capnp
::
_
::
RawSchema
::
MemberInfo
{
kj
::
implicitCast
<
uint16_t
>
(
parent
),
kj
::
implicitCast
<
uint16_t
>
(
member
.
getIndex
()
)
kj
::
implicitCast
<
uint16_t
>
(
member
.
index
)
});
}
for
(
auto
member
:
members
)
{
...
...
@@ -1063,7 +1074,7 @@ private:
"};
\n
"
"static const ::capnp::_::RawSchema::MemberInfo m_"
,
hexId
,
"[] = {
\n
"
,
KJ_MAP
(
memberInfos
,
info
)
{
return
kj
::
strTree
(
" { "
,
info
.
unionIndex
,
", "
,
info
.
index
,
" },
\n
"
);
return
kj
::
strTree
(
" { "
,
info
.
scopeOrdinal
,
", "
,
info
.
index
,
" },
\n
"
);
},
"};
\n
"
"const ::capnp::_::RawSchema s_"
,
hexId
,
" = {
\n
"
...
...
c++/src/capnp/compiler/grammar.capnp.c++
View file @
372612cd
...
...
@@ -1435,36 +1435,36 @@ static const ::capnp::_::RawSchema::MemberInfo m_96efe787c17e83bb[] = {
{
2
,
2
},
{
2
,
1
},
{
2
,
0
},
{
4
,
9
},
{
4
,
15
},
{
4
,
27
},
{
4
,
24
},
{
4
,
25
},
{
4
,
17
},
{
4
,
18
},
{
4
,
19
},
{
4
,
16
},
{
4
,
28
},
{
4
,
29
},
{
4
,
26
},
{
4
,
21
},
{
4
,
22
},
{
4
,
23
},
{
4
,
20
},
{
4
,
14
},
{
4
,
1
},
{
4
,
2
},
{
4
,
3
},
{
4
,
5
},
{
4
,
13
},
{
4
,
12
},
{
4
,
7
},
{
4
,
8
},
{
4
,
11
},
{
4
,
10
},
{
4
,
4
},
{
4
,
6
},
{
4
,
0
},
{
7
,
9
},
{
7
,
15
},
{
7
,
27
},
{
7
,
24
},
{
7
,
25
},
{
7
,
17
},
{
7
,
18
},
{
7
,
19
},
{
7
,
16
},
{
7
,
28
},
{
7
,
29
},
{
7
,
26
},
{
7
,
21
},
{
7
,
22
},
{
7
,
23
},
{
7
,
20
},
{
7
,
14
},
{
7
,
1
},
{
7
,
2
},
{
7
,
3
},
{
7
,
5
},
{
7
,
13
},
{
7
,
12
},
{
7
,
7
},
{
7
,
8
},
{
7
,
11
},
{
7
,
10
},
{
7
,
4
},
{
7
,
6
},
{
7
,
0
},
};
const
::
capnp
::
_
::
RawSchema
s_96efe787c17e83bb
=
{
0x96efe787c17e83bb
,
b_96efe787c17e83bb
.
words
,
664
,
d_96efe787c17e83bb
,
m_96efe787c17e83bb
,
...
...
c++/src/capnp/dynamic-test.c++
View file @
372612cd
...
...
@@ -293,6 +293,14 @@ TEST(DynamicApi, UnionsRead) {
}
}
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
#define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".")
#define EXPECT_NONFATAL_FAILURE(code) code
#else
#define EXPECT_NONFATAL_FAILURE EXPECT_ANY_THROW
#endif
TEST
(
DynamicApi
,
UnionsWrite
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
DynamicStruct
>
(
Schema
::
from
<
TestUnion
>
());
...
...
@@ -314,29 +322,81 @@ TEST(DynamicApi, UnionsWrite) {
ASSERT_EQ
(
TestUnion
::
Union3
::
U3F0S64
,
reader
.
getUnion3
().
which
());
EXPECT_EQ
(
1234567890123456789ll
,
reader
.
getUnion3
().
getU3f0s64
());
// Can't access union members by name from the root.
EXPECT_ANY_THROW
(
root
.
get
(
"u0f1s32"
));
EXPECT_ANY_THROW
(
root
.
set
(
"u0f1s32"
,
1234567
));
// But can access them by member pointer.
auto
member
=
root
.
get
(
"union0"
).
as
<
DynamicUnion
>
().
getSchema
().
getMemberByName
(
"u0f1s32"
);
EXPECT_EQ
(
1234567
,
root
.
get
(
member
).
as
<
int
>
());
auto
member2
=
root
.
get
(
"union0"
).
as
<
DynamicUnion
>
().
getSchema
().
getMemberByName
(
"u0f1sp"
);
root
.
set
(
member2
,
"foo"
);
EXPECT_EQ
(
"foo"
,
reader
.
getUnion0
().
getU0f1sp
());
}
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
// All exceptions should be non-fatal, so when exceptions are disabled the code should return.
#define EXPECT_ANY_THROW(code) code
#endif
TEST
(
DynamicApi
,
UnnamedUnion
)
{
MallocMessageBuilder
builder
;
StructSchema
schema
=
Schema
::
from
<
test
::
TestUnnamedUnion
>
();
auto
root
=
builder
.
initRoot
<
DynamicStruct
>
(
schema
);
DynamicUnion
::
Builder
unionBuilder
=
root
.
get
(
KJ_ASSERT_NONNULL
(
schema
.
getUnnamedUnion
())).
as
<
DynamicUnion
>
();
EXPECT_EQ
(
schema
.
getMemberByName
(
"foo"
),
KJ_ASSERT_NONNULL
(
unionBuilder
.
which
()));
root
.
set
(
"bar"
,
321
);
EXPECT_EQ
(
schema
.
getMemberByName
(
"bar"
),
KJ_ASSERT_NONNULL
(
unionBuilder
.
which
()));
EXPECT_EQ
(
321u
,
root
.
get
(
"bar"
).
as
<
uint
>
());
EXPECT_EQ
(
321u
,
root
.
asReader
().
get
(
"bar"
).
as
<
uint
>
());
EXPECT_EQ
(
321u
,
unionBuilder
.
get
().
as
<
uint
>
());
EXPECT_EQ
(
321u
,
unionBuilder
.
asReader
().
get
().
as
<
uint
>
());
EXPECT_ANY_THROW
(
root
.
get
(
"foo"
));
EXPECT_ANY_THROW
(
root
.
asReader
().
get
(
"foo"
));
root
.
set
(
"foo"
,
123
);
EXPECT_EQ
(
schema
.
getMemberByName
(
"foo"
),
KJ_ASSERT_NONNULL
(
unionBuilder
.
which
()));
EXPECT_EQ
(
123u
,
root
.
get
(
"foo"
).
as
<
uint
>
());
EXPECT_EQ
(
123u
,
root
.
asReader
().
get
(
"foo"
).
as
<
uint
>
());
EXPECT_EQ
(
123u
,
unionBuilder
.
get
().
as
<
uint
>
());
EXPECT_EQ
(
123u
,
unionBuilder
.
asReader
().
get
().
as
<
uint
>
());
EXPECT_ANY_THROW
(
root
.
get
(
"bar"
));
EXPECT_ANY_THROW
(
root
.
asReader
().
get
(
"bar"
));
unionBuilder
.
set
(
"bar"
,
321
);
EXPECT_EQ
(
schema
.
getMemberByName
(
"bar"
),
KJ_ASSERT_NONNULL
(
unionBuilder
.
which
()));
EXPECT_EQ
(
321u
,
root
.
get
(
"bar"
).
as
<
uint
>
());
EXPECT_EQ
(
321u
,
root
.
asReader
().
get
(
"bar"
).
as
<
uint
>
());
EXPECT_EQ
(
321u
,
unionBuilder
.
get
().
as
<
uint
>
());
EXPECT_EQ
(
321u
,
unionBuilder
.
asReader
().
get
().
as
<
uint
>
());
EXPECT_ANY_THROW
(
root
.
get
(
"foo"
));
EXPECT_ANY_THROW
(
root
.
asReader
().
get
(
"foo"
));
unionBuilder
.
set
(
"foo"
,
123
);
EXPECT_EQ
(
schema
.
getMemberByName
(
"foo"
),
KJ_ASSERT_NONNULL
(
unionBuilder
.
which
()));
EXPECT_EQ
(
123u
,
root
.
get
(
"foo"
).
as
<
uint
>
());
EXPECT_EQ
(
123u
,
root
.
asReader
().
get
(
"foo"
).
as
<
uint
>
());
EXPECT_EQ
(
123u
,
unionBuilder
.
get
().
as
<
uint
>
());
EXPECT_EQ
(
123u
,
unionBuilder
.
asReader
().
get
().
as
<
uint
>
());
EXPECT_ANY_THROW
(
root
.
get
(
"bar"
));
EXPECT_ANY_THROW
(
root
.
asReader
().
get
(
"bar"
));
}
TEST
(
DynamicApi
,
ConversionFailures
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
DynamicStruct
>
(
Schema
::
from
<
TestAllTypes
>
());
root
.
set
(
"int8Field"
,
123
);
EXPECT_
ANY_THROW
(
root
.
set
(
"int8Field"
,
1234
));
EXPECT_
NONFATAL_FAILURE
(
root
.
set
(
"int8Field"
,
1234
));
root
.
set
(
"uInt32Field"
,
1
);
EXPECT_
ANY_THROW
(
root
.
set
(
"uInt32Field"
,
-
1
));
EXPECT_
NONFATAL_FAILURE
(
root
.
set
(
"uInt32Field"
,
-
1
));
root
.
set
(
"int16Field"
,
5
);
EXPECT_
ANY_THROW
(
root
.
set
(
"int16Field"
,
0.5
));
EXPECT_
NONFATAL_FAILURE
(
root
.
set
(
"int16Field"
,
0.5
));
root
.
set
(
"boolField"
,
true
);
EXPECT_
ANY_THROW
(
root
.
set
(
"boolField"
,
1
));
EXPECT_
NONFATAL_FAILURE
(
root
.
set
(
"boolField"
,
1
));
}
TEST
(
DynamicApi
,
LateUnion
)
{
...
...
c++/src/capnp/dynamic.c++
View file @
372612cd
This diff is collapsed.
Click to expand it.
c++/src/capnp/dynamic.h
View file @
372612cd
...
...
@@ -380,6 +380,9 @@ private:
inline
Builder
(
StructSchema
schema
,
_
::
StructBuilder
builder
)
:
schema
(
schema
),
builder
(
builder
)
{}
void
verifySetInUnion
(
StructSchema
::
Member
member
);
void
setInUnion
(
StructSchema
::
Member
member
);
static
DynamicValue
::
Builder
getImpl
(
_
::
StructBuilder
builder
,
StructSchema
::
Member
member
);
static
DynamicStruct
::
Builder
getObjectImpl
(
...
...
c++/src/capnp/encoding-test.c++
View file @
372612cd
...
...
@@ -398,7 +398,7 @@ TEST(Encoding, UnionDefault) {
TEST
(
Encoding
,
UnnamedUnion
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
ge
tRoot
<
test
::
TestUnnamedUnion
>
();
auto
root
=
builder
.
ini
tRoot
<
test
::
TestUnnamedUnion
>
();
EXPECT_EQ
(
test
::
TestUnnamedUnion
::
FOO
,
root
.
which
());
root
.
setBar
(
321
);
...
...
@@ -417,7 +417,8 @@ TEST(Encoding, UnnamedUnion) {
EXPECT_DEBUG_ANY_THROW
(
root
.
getBar
());
EXPECT_DEBUG_ANY_THROW
(
root
.
asReader
().
getBar
());
KJ_IF_MAYBE
(
u
,
Schema
::
from
<
test
::
TestUnnamedUnion
>
().
getUnnamedUnion
())
{
StructSchema
schema
=
Schema
::
from
<
test
::
TestUnnamedUnion
>
();
KJ_IF_MAYBE
(
u
,
schema
.
getUnnamedUnion
())
{
// The discriminant is allocated between allocating the first and second members.
EXPECT_EQ
(
1
,
u
->
getProto
().
getBody
().
getUnionMember
().
getDiscriminantOffset
());
EXPECT_EQ
(
0
,
u
->
getMemberByName
(
"foo"
).
getProto
().
getBody
().
getFieldMember
().
getOffset
());
...
...
c++/src/capnp/generated-header-support.h
View file @
372612cd
...
...
@@ -164,13 +164,9 @@ struct RawSchema {
// TODO(someday): Make this a hashtable.
struct
MemberInfo
{
uint16_t
unionIndex
;
// 0 = not in a union, >0 = one plus the index of the union within the scope indicated by
// scopeOrdinal.
// uint16_t scopeOrdinal;
// // One plus the ordinal number of the parent scope of this member when looking up by name.
// // Zero represents the top-level scope.
uint16_t
scopeOrdinal
;
// One plus the ordinal number of the parent scope of this member when looking up by name.
// Zero represents the top-level scope.
uint16_t
index
;
// Index of the member within its scope. If the index is greater than the number of elements
...
...
c++/src/capnp/schema-loader-test.c++
View file @
372612cd
...
...
@@ -56,6 +56,40 @@ TEST(SchemaLoader, Load) {
EXPECT_EQ
(
0u
,
struct16Schema
.
getProto
().
getBody
().
getStructNode
().
getMembers
().
size
());
}
TEST
(
SchemaLoader
,
LoadLateUnion
)
{
SchemaLoader
loader
;
StructSchema
schema
=
loader
.
load
(
Schema
::
from
<
test
::
TestLateUnion
>
().
getProto
()).
asStruct
();
EXPECT_EQ
(
6
,
schema
.
getMemberByName
(
"theUnion"
).
asUnion
()
.
getMemberByName
(
"grault"
).
getProto
().
getOrdinal
());
EXPECT_EQ
(
9
,
schema
.
getMemberByName
(
"anotherUnion"
).
asUnion
()
.
getMemberByName
(
"corge"
).
getProto
().
getOrdinal
());
EXPECT_TRUE
(
schema
.
findMemberByName
(
"corge"
)
==
nullptr
);
EXPECT_TRUE
(
schema
.
findMemberByName
(
"grault"
)
==
nullptr
);
}
TEST
(
SchemaLoader
,
LoadUnnamedUnion
)
{
SchemaLoader
loader
;
StructSchema
schema
=
loader
.
load
(
Schema
::
from
<
test
::
TestUnnamedUnion
>
().
getProto
()).
asStruct
();
EXPECT_TRUE
(
schema
.
findMemberByName
(
""
)
==
nullptr
);
KJ_IF_MAYBE
(
u
,
schema
.
getUnnamedUnion
())
{
EXPECT_TRUE
(
schema
.
getMemberByName
(
"foo"
)
==
u
->
getMemberByName
(
"foo"
));
EXPECT_TRUE
(
schema
.
getMemberByName
(
"bar"
)
==
u
->
getMemberByName
(
"bar"
));
EXPECT_TRUE
(
u
->
findMemberByName
(
"before"
)
==
nullptr
);
EXPECT_TRUE
(
u
->
findMemberByName
(
"after"
)
==
nullptr
);
EXPECT_TRUE
(
schema
.
findMemberByName
(
"before"
)
!=
nullptr
);
EXPECT_TRUE
(
schema
.
findMemberByName
(
"after"
)
!=
nullptr
);
}
else
{
ADD_FAILURE
()
<<
"getUnnamedUnion() should have returned non-null."
;
}
}
#if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW
#define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".")
...
...
c++/src/capnp/schema-loader.c++
View file @
372612cd
...
...
@@ -148,7 +148,7 @@ private:
bool
isValid
;
std
::
map
<
uint64_t
,
_
::
RawSchema
*>
dependencies
;
// Maps (
unionIndex
, name) -> index for each member.
// Maps (
scopeOrdinal
, name) -> index for each member.
std
::
map
<
std
::
pair
<
uint
,
Text
::
Reader
>
,
uint
>
members
;
#define VALIDATE_SCHEMA(condition, ...) \
...
...
@@ -226,21 +226,22 @@ private:
uint
index
=
0
;
for
(
auto
member
:
members
)
{
KJ_CONTEXT
(
"validating struct member"
,
member
.
getName
());
validate
(
member
,
sawCodeOrder
,
sawOrdinal
,
dataSizeInBits
,
pointerCount
,
0
,
index
++
);
validate
(
member
,
sawCodeOrder
,
sawOrdinal
,
dataSizeInBits
,
pointerCount
,
0
,
members
.
size
(),
index
++
);
}
}
void
validateMemberName
(
kj
::
StringPtr
name
,
uint
unionIndex
,
uint
i
ndex
)
{
void
validateMemberName
(
kj
::
StringPtr
name
,
uint
scopeOrdinal
,
uint
adjustedI
ndex
)
{
bool
isNewName
=
members
.
insert
(
std
::
make_pair
(
std
::
pair
<
uint
,
Text
::
Reader
>
(
unionIndex
,
name
),
i
ndex
)).
second
;
std
::
pair
<
uint
,
Text
::
Reader
>
(
scopeOrdinal
,
name
),
adjustedI
ndex
)).
second
;
VALIDATE_SCHEMA
(
isNewName
,
"duplicate name"
,
name
);
}
void
validate
(
const
schema
::
StructNode
::
Member
::
Reader
&
member
,
kj
::
ArrayPtr
<
bool
>
sawCodeOrder
,
kj
::
ArrayPtr
<
bool
>
sawOrdinal
,
uint
dataSizeInBits
,
uint
pointerCount
,
uint
unionIndex
,
uint
i
ndex
)
{
validateMemberName
(
member
.
getName
(),
unionIndex
,
i
ndex
);
uint
scopeOrdinal
,
uint
scopeMemberCount
,
uint
adjustedI
ndex
)
{
validateMemberName
(
member
.
getName
(),
scopeOrdinal
,
adjustedI
ndex
);
VALIDATE_SCHEMA
(
member
.
getCodeOrder
()
<
sawCodeOrder
.
size
()
&&
!
sawCodeOrder
[
member
.
getCodeOrder
()],
"Invalid codeOrder."
);
...
...
@@ -284,14 +285,17 @@ private:
uMember
.
getBody
().
which
()
==
schema
::
StructNode
::
Member
::
Body
::
FIELD_MEMBER
,
"Union members must be fields."
);
uint
subUnionIndex
;
uint
subScopeOrdinal
;
uint
indexAdjustment
;
if
(
member
.
getName
().
size
()
==
0
)
{
subUnionIndex
=
unionIndex
;
subScopeOrdinal
=
scopeOrdinal
;
indexAdjustment
=
scopeMemberCount
;
}
else
{
subUnionIndex
=
index
+
1
;
subScopeOrdinal
=
member
.
getOrdinal
()
+
1
;
indexAdjustment
=
0
;
}
validate
(
uMember
,
uSawCodeOrder
,
sawOrdinal
,
dataSizeInBits
,
pointerCount
,
sub
UnionIndex
,
subIndex
++
);
sub
ScopeOrdinal
,
uMembers
.
size
(),
subIndex
++
+
indexAdjustment
);
}
// Union ordinal may match the ordinal of its first member, meaning it was unspecified in
...
...
c++/src/capnp/schema-test.c++
View file @
372612cd
...
...
@@ -274,6 +274,17 @@ TEST(Schema, UnnamedUnion) {
StructSchema
schema
=
Schema
::
from
<
test
::
TestUnnamedUnion
>
();
EXPECT_TRUE
(
schema
.
findMemberByName
(
""
)
==
nullptr
);
KJ_IF_MAYBE
(
u
,
schema
.
getUnnamedUnion
())
{
EXPECT_TRUE
(
schema
.
getMemberByName
(
"foo"
)
==
u
->
getMemberByName
(
"foo"
));
EXPECT_TRUE
(
schema
.
getMemberByName
(
"bar"
)
==
u
->
getMemberByName
(
"bar"
));
EXPECT_TRUE
(
u
->
findMemberByName
(
"before"
)
==
nullptr
);
EXPECT_TRUE
(
u
->
findMemberByName
(
"after"
)
==
nullptr
);
EXPECT_TRUE
(
schema
.
findMemberByName
(
"before"
)
!=
nullptr
);
EXPECT_TRUE
(
schema
.
findMemberByName
(
"after"
)
!=
nullptr
);
}
else
{
ADD_FAILURE
()
<<
"getUnnamedUnion() should have returned non-null."
;
}
}
}
// namespace
...
...
c++/src/capnp/schema.c++
View file @
372612cd
...
...
@@ -90,20 +90,74 @@ void Schema::requireUsableAs(const _::RawSchema* expected) const {
namespace
{
inline
StructSchema
::
MemberList
getUnionMembers
(
StructSchema
::
Member
m
)
{
return
m
.
asUnion
().
getMembers
();
}
inline
EnumSchema
::
EnumerantList
getUnionMembers
(
EnumSchema
::
Enumerant
)
{
KJ_FAIL_ASSERT
(
"MemberInfo for enum nonsensically expects unnamed unions."
);
}
inline
InterfaceSchema
::
MethodList
getUnionMembers
(
InterfaceSchema
::
Method
)
{
KJ_FAIL_ASSERT
(
"MemberInfo for interface nonsensically expects unnamed unions."
);
}
template
<
typename
List
>
auto
findUnnamedMemberOfScope
(
const
_
::
RawSchema
*
raw
,
uint
scopeOrdinal
,
List
&&
list
)
->
decltype
(
list
[
0
])
{
uint
lower
=
0
;
uint
upper
=
raw
->
memberCount
;
// Since the empty string sorts before all other strings, we're looking for the first member
// that has the expected scopeOrdinal.
while
(
lower
<
upper
)
{
uint
mid
=
(
lower
+
upper
)
/
2
;
const
_
::
RawSchema
::
MemberInfo
&
member
=
raw
->
membersByName
[
mid
];
if
(
member
.
scopeOrdinal
<
scopeOrdinal
)
{
lower
=
mid
+
1
;
}
else
{
upper
=
mid
;
}
}
const
_
::
RawSchema
::
MemberInfo
&
result
=
raw
->
membersByName
[
lower
];
KJ_DASSERT
(
lower
<
raw
->
memberCount
&&
list
[
result
.
index
].
getProto
().
getName
().
size
()
==
0
,
"Expected to find an unnamed union, but didn't. MemberInfo table must be broken."
);
return
list
[
result
.
index
];
}
template
<
typename
List
>
auto
findSchemaMemberByName
(
const
_
::
RawSchema
*
raw
,
kj
::
StringPtr
name
,
uint
unionIndex
,
List
&&
list
)
->
kj
::
Maybe
<
kj
::
Decay
<
decltype
(
list
[
0
])
>
>
{
uint
scopeOrdinal
,
List
&&
list
)
->
kj
::
Maybe
<
decltype
(
list
[
0
])
>
{
uint
lower
=
0
;
uint
upper
=
raw
->
memberCount
;
List
unnamedUnionMembers
;
while
(
lower
<
upper
)
{
uint
mid
=
(
lower
+
upper
)
/
2
;
const
_
::
RawSchema
::
MemberInfo
&
member
=
raw
->
membersByName
[
mid
];
if
(
member
.
unionIndex
==
unionIndex
)
{
auto
candidate
=
list
[
member
.
index
];
if
(
member
.
scopeOrdinal
==
scopeOrdinal
)
{
decltype
(
list
[
member
.
index
])
candidate
;
if
(
member
.
index
<
list
.
size
())
{
candidate
=
list
[
member
.
index
];
}
else
{
// This looks like it's a member of an unnamed union.
if
(
unnamedUnionMembers
.
size
()
==
0
)
{
// We haven't expanded the unnamed union yet. We have to find it. It should be the very
// first item with the expected ordinal.
unnamedUnionMembers
=
getUnionMembers
(
findUnnamedMemberOfScope
(
raw
,
scopeOrdinal
,
list
));
}
uint
uIndex
=
member
.
index
-
list
.
size
();
KJ_DASSERT
(
uIndex
<
unnamedUnionMembers
.
size
());
candidate
=
unnamedUnionMembers
[
uIndex
];
}
kj
::
StringPtr
candidateName
=
candidate
.
getProto
().
getName
();
if
(
candidateName
==
name
)
{
return
candidate
;
...
...
@@ -112,7 +166,7 @@ auto findSchemaMemberByName(const _::RawSchema* raw, kj::StringPtr name,
}
else
{
upper
=
mid
;
}
}
else
if
(
member
.
unionIndex
<
unionIndex
)
{
}
else
if
(
member
.
scopeOrdinal
<
scopeOrdinal
)
{
lower
=
mid
+
1
;
}
else
{
upper
=
mid
;
...
...
@@ -208,7 +262,24 @@ StructSchema::MemberList StructSchema::Union::getMembers() const {
}
kj
::
Maybe
<
StructSchema
::
Member
>
StructSchema
::
Union
::
findMemberByName
(
kj
::
StringPtr
name
)
const
{
return
findSchemaMemberByName
(
parent
.
raw
,
name
,
index
+
1
,
getMembers
());
auto
proto
=
getProto
();
if
(
proto
.
getName
().
size
()
==
0
)
{
// Unnamed union, so we have to search the parent scope.
KJ_IF_MAYBE
(
result
,
getContainingStruct
().
findMemberByName
(
name
))
{
KJ_IF_MAYBE
(
containingUnion
,
result
->
getContainingUnion
())
{
KJ_ASSERT
(
*
containingUnion
==
*
this
,
"Found a member of some other union? But there can only be one unnamed union!"
);
return
*
result
;
}
else
{
// Oops, we found a member of the parent scope that is *not* also a member of the union.
return
nullptr
;
}
}
else
{
return
nullptr
;
}
}
else
{
return
findSchemaMemberByName
(
parent
.
raw
,
name
,
getProto
().
getOrdinal
()
+
1
,
getMembers
());
}
}
StructSchema
::
Member
StructSchema
::
Union
::
getMemberByName
(
kj
::
StringPtr
name
)
const
{
...
...
@@ -226,7 +297,7 @@ StructSchema::MemberList StructSchema::Group::getMembers() const {
#if 0
// TODO(soon): Implement correctly. Requires some changes to lookup table format.
kj::Maybe<StructSchema::Member> StructSchema::Group::findMemberByName(kj::StringPtr name) const {
return findSchemaMemberByName(parent.raw, name,
index
+ 1, getMembers());
return findSchemaMemberByName(parent.raw, name,
getProto().getOrdinal()
+ 1, getMembers());
}
StructSchema::Member StructSchema::Group::getMemberByName(kj::StringPtr name) const {
...
...
c++/src/capnp/schema.h
View file @
372612cd
...
...
@@ -254,6 +254,8 @@ private:
class
StructSchema
::
MemberList
{
public
:
MemberList
()
=
default
;
// empty list
inline
uint
size
()
const
{
return
list
.
size
();
}
inline
Member
operator
[](
uint
index
)
const
{
return
Member
(
parent
,
unionIndex
,
index
,
list
[
index
]);
}
...
...
@@ -323,6 +325,8 @@ private:
class
EnumSchema
::
EnumerantList
{
public
:
EnumerantList
()
=
default
;
// empty list
inline
uint
size
()
const
{
return
list
.
size
();
}
inline
Enumerant
operator
[](
uint
index
)
const
{
return
Enumerant
(
parent
,
index
,
list
[
index
]);
}
...
...
@@ -391,6 +395,8 @@ private:
class
InterfaceSchema
::
MethodList
{
public
:
MethodList
()
=
default
;
// empty list
inline
uint
size
()
const
{
return
list
.
size
();
}
inline
Method
operator
[](
uint
index
)
const
{
return
Method
(
parent
,
index
,
list
[
index
]);
}
...
...
c++/src/capnp/stringify-test.c++
View file @
372612cd
...
...
@@ -359,6 +359,34 @@ TEST(Stringify, Unions) {
EXPECT_EQ
(
"u3f0s64(123456789012345678)"
,
kj
::
str
(
root
.
getUnion3
()));
}
TEST
(
Stringify
,
UnnamedUnions
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestUnnamedUnion
>
();
root
.
setBar
(
123
);
EXPECT_EQ
(
"(bar(123))"
,
kj
::
str
(
root
));
EXPECT_EQ
(
"(bar(123))"
,
prettyPrint
(
root
).
flatten
());
root
.
setAfter
(
"foooooooooooooooooooooooooooooooo"
);
EXPECT_EQ
(
"(bar(123), after =
\"
foooooooooooooooooooooooooooooooo
\"
)"
,
kj
::
str
(
root
));
EXPECT_EQ
(
"( bar(123),
\n
"
" after =
\"
foooooooooooooooooooooooooooooooo
\"
)"
,
prettyPrint
(
root
).
flatten
());
root
.
setBefore
(
"before"
);
EXPECT_EQ
(
"(before =
\"
before
\"
, bar(123), "
"after =
\"
foooooooooooooooooooooooooooooooo
\"
)"
,
kj
::
str
(
root
));
EXPECT_EQ
(
"( before =
\"
before
\"
,
\n
"
" bar(123),
\n
"
" after =
\"
foooooooooooooooooooooooooooooooo
\"
)"
,
prettyPrint
(
root
).
flatten
());
}
TEST
(
Stringify
,
StructUnions
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestStructUnion
>
();
...
...
c++/src/capnp/stringify.c++
View file @
372612cd
...
...
@@ -197,9 +197,16 @@ static kj::StringTree print(const DynamicValue::Reader& value,
kj
::
Vector
<
kj
::
StringTree
>
printedMembers
(
memberSchemas
.
size
());
for
(
auto
member
:
memberSchemas
)
{
if
(
structValue
.
has
(
member
))
{
printedMembers
.
add
(
kj
::
strTree
(
member
.
getProto
().
getName
(),
" = "
,
print
(
structValue
.
get
(
member
),
whichMemberType
(
member
),
indent
.
next
(),
PREFIXED
)));
auto
name
=
member
.
getProto
().
getName
();
if
(
name
.
size
()
==
0
)
{
// Unnamed union. Just print the content.
printedMembers
.
add
(
kj
::
strTree
(
print
(
structValue
.
get
(
member
),
whichMemberType
(
member
),
indent
.
next
(),
BARE
)));
}
else
{
printedMembers
.
add
(
kj
::
strTree
(
name
,
" = "
,
print
(
structValue
.
get
(
member
),
whichMemberType
(
member
),
indent
.
next
(),
PREFIXED
)));
}
}
}
...
...
c++/src/capnp/test.capnp
View file @
372612cd
...
...
@@ -341,8 +341,8 @@ struct TestListDefaults {
}
struct TestLateUnion {
# Test what happens if the unions are
the first ordinals in the struct. At one point this wa
s
# broken for the dynamic API.
# Test what happens if the unions are
not the first ordinals in the struct. At one point thi
s
#
was
broken for the dynamic API.
foo @0 :Int32;
bar @1 :Text;
...
...
@@ -385,12 +385,12 @@ struct TestStructUnion {
}
struct TestUnnamedUnion {
before @0 :
Void
;
before @0 :
Text
;
union {
foo @1 :UInt16;
bar @2 :UInt32;
}
after @3 :
Void
;
after @3 :
Text
;
}
c++/src/kj/common.h
View file @
372612cd
...
...
@@ -600,6 +600,10 @@ inline T* readMaybe(Maybe<T&>&& maybe) { return maybe.ptr; }
template
<
typename
T
>
inline
T
*
readMaybe
(
const
Maybe
<
T
&>&
maybe
)
{
return
maybe
.
ptr
;
}
template
<
typename
T
>
inline
T
*
readMaybe
(
T
*
ptr
)
{
return
ptr
;
}
// Allow KJ_IF_MAYBE to work on regular pointers.
}
// namespace _ (private)
#define KJ_IF_MAYBE(name, exp) if (auto name = ::kj::_::readMaybe(exp))
...
...
c++/src/kj/debug.h
View file @
372612cd
...
...
@@ -147,6 +147,18 @@ namespace kj {
::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))> \
KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
#define _kJ_NONNULL(nature, value, ...) \
({ \
auto result = ::kj::_::readMaybe(value); \
if (KJ_UNLIKELY(!result)) { \
::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Nature::nature, 0, \
#value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \
} \
*result; \
})
#define KJ_ASSERT_NONNULL(value, ...) _kJ_NONNULL(LOCAL_BUG, value, ##__VA_ARGS__)
#define KJ_REQUIRE_NONNULL(value, ...) _kJ_NONNULL(PRECONDITION, value, ##__VA_ARGS__)
#ifdef NDEBUG
#define KJ_DLOG(...) do {} while (false)
#define KJ_DASSERT(...) do {} while (false)
...
...
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