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
98e6519e
Commit
98e6519e
authored
Aug 26, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor value expression compilation code using new Orphan<DynamicValue>.
parent
c1f3e3ff
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
545 additions
and
277 deletions
+545
-277
node-translator.c++
c++/src/capnp/compiler/node-translator.c++
+276
-227
node-translator.h
c++/src/capnp/compiler/node-translator.h
+15
-6
dynamic.c++
c++/src/capnp/dynamic.c++
+157
-10
dynamic.h
c++/src/capnp/dynamic.h
+44
-12
layout.c++
c++/src/capnp/layout.c++
+37
-14
layout.h
c++/src/capnp/layout.h
+3
-0
orphan-test.c++
c++/src/capnp/orphan-test.c++
+7
-7
exception.c++
c++/src/kj/exception.c++
+6
-1
No files found.
c++/src/capnp/compiler/node-translator.c++
View file @
98e6519e
...
...
@@ -529,6 +529,7 @@ NodeTranslator::NodeTranslator(
const
Declaration
::
Reader
&
decl
,
Orphan
<
schema
::
Node
>
wipNodeParam
,
bool
compileAnnotations
)
:
resolver
(
resolver
),
errorReporter
(
errorReporter
),
orphanage
(
Orphanage
::
getForMessageContaining
(
wipNodeParam
.
get
())),
compileAnnotations
(
compileAnnotations
),
wipNode
(
kj
::
mv
(
wipNodeParam
))
{
compileNode
(
decl
,
wipNode
.
get
());
}
...
...
@@ -1229,8 +1230,7 @@ private:
}
schema
::
Node
::
Builder
newGroupNode
(
schema
::
Node
::
Reader
parent
,
kj
::
StringPtr
name
)
{
auto
orphan
=
Orphanage
::
getForMessageContaining
(
translator
.
wipNode
.
get
())
.
newOrphan
<
schema
::
Node
>
();
auto
orphan
=
translator
.
orphanage
.
newOrphan
<
schema
::
Node
>
();
auto
node
=
orphan
.
get
();
// We'll set the ID and scope ID later.
...
...
@@ -1386,147 +1386,6 @@ void NodeTranslator::compileDefaultDefaultValue(
}
}
class
NodeTranslator
::
DynamicSlot
{
// Acts like a pointer to a field or list element. The target's value can be set or initialized.
// This is useful when recursively compiling values.
//
// TODO(someday): The Dynamic API should support something like this directly.
public
:
DynamicSlot
(
DynamicStruct
::
Builder
structBuilder
,
StructSchema
::
Field
field
)
:
type
(
FIELD
),
struct_
{
structBuilder
,
field
}
{}
DynamicSlot
(
DynamicList
::
Builder
listBuilder
,
uint
index
)
:
type
(
ELEMENT
),
list
{
listBuilder
,
index
}
{}
DynamicSlot
(
DynamicStruct
::
Builder
structBuilder
,
StructSchema
::
Field
field
,
StructSchema
structFieldSchema
)
:
type
(
STRUCT_OBJECT_FIELD
),
struct_
{
structBuilder
,
field
},
structFieldSchema
(
structFieldSchema
)
{}
DynamicSlot
(
DynamicStruct
::
Builder
structBuilder
,
StructSchema
::
Field
field
,
ListSchema
listFieldSchema
)
:
type
(
LIST_OBJECT_FIELD
),
struct_
{
structBuilder
,
field
},
listFieldSchema
(
listFieldSchema
)
{}
DynamicSlot
(
DynamicStruct
::
Builder
structBuilder
,
StructSchema
::
Field
field
,
EnumSchema
enumFieldSchema
)
:
type
(
RAW_ENUM_FIELD
),
struct_
{
structBuilder
,
field
},
enumFieldSchema
(
enumFieldSchema
)
{}
DynamicStruct
::
Builder
initStruct
()
{
switch
(
type
)
{
case
FIELD
:
return
struct_
.
builder
.
init
(
struct_
.
field
).
as
<
DynamicStruct
>
();
case
ELEMENT
:
return
list
.
builder
[
list
.
index
].
as
<
DynamicStruct
>
();
case
STRUCT_OBJECT_FIELD
:
return
struct_
.
builder
.
initObject
(
struct_
.
field
,
structFieldSchema
);
case
LIST_OBJECT_FIELD
:
KJ_FAIL_REQUIRE
(
"Type mismatch."
);
case
RAW_ENUM_FIELD
:
KJ_FAIL_REQUIRE
(
"Type mismatch."
);
}
KJ_FAIL_ASSERT
(
"can't get here"
);
}
DynamicList
::
Builder
initList
(
uint
size
)
{
switch
(
type
)
{
case
FIELD
:
return
struct_
.
builder
.
init
(
struct_
.
field
,
size
).
as
<
DynamicList
>
();
case
ELEMENT
:
return
list
.
builder
.
init
(
list
.
index
,
size
).
as
<
DynamicList
>
();
case
STRUCT_OBJECT_FIELD
:
KJ_FAIL_REQUIRE
(
"Type mismatch."
);
case
LIST_OBJECT_FIELD
:
return
struct_
.
builder
.
initObject
(
struct_
.
field
,
listFieldSchema
,
size
);
case
RAW_ENUM_FIELD
:
KJ_FAIL_REQUIRE
(
"Type mismatch."
);
}
KJ_FAIL_ASSERT
(
"can't get here"
);
}
void
set
(
DynamicValue
::
Reader
value
)
{
switch
(
type
)
{
case
FIELD
:
struct_
.
builder
.
set
(
struct_
.
field
,
value
);
return
;
case
ELEMENT
:
list
.
builder
.
set
(
list
.
index
,
value
);
return
;
case
STRUCT_OBJECT_FIELD
:
struct_
.
builder
.
set
(
struct_
.
field
,
value
);
return
;
case
LIST_OBJECT_FIELD
:
struct_
.
builder
.
set
(
struct_
.
field
,
value
);
return
;
case
RAW_ENUM_FIELD
:
struct_
.
builder
.
set
(
struct_
.
field
,
value
.
as
<
DynamicEnum
>
().
getRaw
());
return
;
}
KJ_FAIL_ASSERT
(
"can't get here"
);
}
kj
::
Maybe
<
uint64_t
>
getEnumType
()
{
// If the slot type is an enum, get its type ID. Otherwise return nullptr.
//
// This is really ugly.
switch
(
type
)
{
case
FIELD
:
return
enumIdForField
(
struct_
.
field
);
case
ELEMENT
:
{
if
(
list
.
builder
.
getSchema
().
whichElementType
()
==
schema
::
Type
::
ENUM
)
{
return
list
.
builder
.
getSchema
().
getEnumElementType
().
getProto
().
getId
();
}
return
nullptr
;
}
case
STRUCT_OBJECT_FIELD
:
return
nullptr
;
case
LIST_OBJECT_FIELD
:
return
nullptr
;
case
RAW_ENUM_FIELD
:
return
enumFieldSchema
.
getProto
().
getId
();
}
KJ_FAIL_ASSERT
(
"can't get here"
);
}
private
:
enum
Type
{
FIELD
,
ELEMENT
,
STRUCT_OBJECT_FIELD
,
LIST_OBJECT_FIELD
,
RAW_ENUM_FIELD
};
Type
type
;
union
{
struct
{
DynamicStruct
::
Builder
builder
;
StructSchema
::
Field
field
;
}
struct_
;
struct
{
DynamicList
::
Builder
builder
;
uint
index
;
}
list
;
};
union
{
StructSchema
structFieldSchema
;
ListSchema
listFieldSchema
;
EnumSchema
enumFieldSchema
;
};
static
kj
::
Maybe
<
uint64_t
>
enumIdForField
(
StructSchema
::
Field
field
)
{
schema
::
Field
::
Reader
proto
=
field
.
getProto
();
if
(
proto
.
isNonGroup
())
{
auto
type
=
proto
.
getNonGroup
().
getType
();
if
(
type
.
isEnum
())
{
return
type
.
getEnum
();
}
}
return
nullptr
;
}
};
static
kj
::
StringPtr
getValueUnionFieldNameFor
(
schema
::
Type
::
Which
type
)
{
switch
(
type
)
{
case
schema
:
:
Type
::
VOID
:
return
"void"
;
case
schema
:
:
Type
::
BOOL
:
return
"bool"
;
case
schema
:
:
Type
::
INT8
:
return
"int8"
;
case
schema
:
:
Type
::
INT16
:
return
"int16"
;
case
schema
:
:
Type
::
INT32
:
return
"int32"
;
case
schema
:
:
Type
::
INT64
:
return
"int64"
;
case
schema
:
:
Type
::
UINT8
:
return
"uint8"
;
case
schema
:
:
Type
::
UINT16
:
return
"uint16"
;
case
schema
:
:
Type
::
UINT32
:
return
"uint32"
;
case
schema
:
:
Type
::
UINT64
:
return
"uint64"
;
case
schema
:
:
Type
::
FLOAT32
:
return
"float32"
;
case
schema
:
:
Type
::
FLOAT64
:
return
"float64"
;
case
schema
:
:
Type
::
TEXT
:
return
"text"
;
case
schema
:
:
Type
::
DATA
:
return
"data"
;
case
schema
:
:
Type
::
LIST
:
return
"list"
;
case
schema
:
:
Type
::
ENUM
:
return
"enum"
;
case
schema
:
:
Type
::
STRUCT
:
return
"struct"
;
case
schema
:
:
Type
::
INTERFACE
:
return
"interface"
;
case
schema
:
:
Type
::
OBJECT
:
return
"object"
;
}
KJ_FAIL_ASSERT
(
"Unknown type."
);
}
void
NodeTranslator
::
compileBootstrapValue
(
ValueExpression
::
Reader
source
,
schema
::
Type
::
Reader
type
,
schema
::
Value
::
Builder
target
)
{
...
...
@@ -1551,154 +1410,345 @@ void NodeTranslator::compileBootstrapValue(ValueExpression::Reader source,
void
NodeTranslator
::
compileValue
(
ValueExpression
::
Reader
source
,
schema
::
Type
::
Reader
type
,
schema
::
Value
::
Builder
target
,
bool
isBootstrap
)
{
auto
valueUnion
=
toDynamic
(
target
);
auto
field
=
valueUnion
.
getSchema
().
getFieldByName
(
getValueUnionFieldNameFor
(
type
.
which
()));
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
LIST
:
KJ_IF_MAYBE
(
listSchema
,
makeListSchemaOf
(
type
.
getList
()))
{
DynamicSlot
slot
(
valueUnion
,
field
,
*
listSchema
);
compileValue
(
source
,
slot
,
isBootstrap
);
kj
::
StringPtr
fieldName
=
KJ_ASSERT_NONNULL
(
toDynamic
(
type
).
which
()).
getProto
().
getName
();
KJ_IF_MAYBE
(
value
,
compileValue
(
source
,
type
,
isBootstrap
))
{
if
(
type
.
isEnum
())
{
target
.
setEnum
(
value
->
getReader
().
as
<
DynamicEnum
>
().
getRaw
());
}
else
{
toDynamic
(
target
).
adopt
(
fieldName
,
kj
::
mv
(
*
value
));
}
}
}
kj
::
Maybe
<
Orphan
<
DynamicValue
>>
NodeTranslator
::
compileValue
(
ValueExpression
::
Reader
src
,
schema
::
Type
::
Reader
type
,
bool
isBootstrap
)
{
Orphan
<
DynamicValue
>
result
=
compileValueInner
(
src
,
type
,
isBootstrap
);
switch
(
result
.
getType
())
{
case
DynamicValue
:
:
UNKNOWN
:
// Error already reported.
return
nullptr
;
case
DynamicValue
:
:
VOID
:
if
(
type
.
isVoid
())
{
return
kj
::
mv
(
result
);
}
break
;
case
schema
:
:
Type
::
STRUCT
:
KJ_IF_MAYBE
(
structSchema
,
resolver
.
resolveBootstrapSchema
(
type
.
getStruct
()))
{
DynamicSlot
slot
(
valueUnion
,
field
,
structSchema
->
asStruct
());
compileValue
(
source
,
slot
,
isBootstrap
);
case
DynamicValue
:
:
BOOL
:
if
(
type
.
isBool
())
{
return
kj
::
mv
(
result
);
}
break
;
case
schema
:
:
Type
::
ENUM
:
KJ_IF_MAYBE
(
enumSchema
,
resolver
.
resolveBootstrapSchema
(
type
.
getEnum
()))
{
DynamicSlot
slot
(
valueUnion
,
field
,
enumSchema
->
asEnum
());
compileValue
(
source
,
slot
,
isBootstrap
);
case
DynamicValue
:
:
INT
:
{
int64_t
value
=
result
.
getReader
().
as
<
int64_t
>
();
if
(
value
<
0
)
{
int64_t
minValue
=
1
;
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
INT8
:
minValue
=
std
::
numeric_limits
<
int8_t
>::
min
();
break
;
case
schema
:
:
Type
::
INT16
:
minValue
=
std
::
numeric_limits
<
int16_t
>::
min
();
break
;
case
schema
:
:
Type
::
INT32
:
minValue
=
std
::
numeric_limits
<
int32_t
>::
min
();
break
;
case
schema
:
:
Type
::
INT64
:
minValue
=
std
::
numeric_limits
<
int64_t
>::
min
();
break
;
case
schema
:
:
Type
::
UINT8
:
minValue
=
std
::
numeric_limits
<
uint8_t
>::
min
();
break
;
case
schema
:
:
Type
::
UINT16
:
minValue
=
std
::
numeric_limits
<
uint16_t
>::
min
();
break
;
case
schema
:
:
Type
::
UINT32
:
minValue
=
std
::
numeric_limits
<
uint32_t
>::
min
();
break
;
case
schema
:
:
Type
::
UINT64
:
minValue
=
std
::
numeric_limits
<
uint64_t
>::
min
();
break
;
case
schema
:
:
Type
::
FLOAT32
:
case
schema
:
:
Type
::
FLOAT64
:
// Any integer is acceptable.
minValue
=
std
::
numeric_limits
<
int64_t
>::
min
();
break
;
default
:
break
;
}
if
(
minValue
==
1
)
break
;
if
(
value
<
minValue
)
{
errorReporter
.
addErrorOn
(
src
,
"Integer value out of range."
);
result
=
minValue
;
}
return
kj
::
mv
(
result
);
}
// No break -- value is positive, so we can just go on to the uint case below.
}
case
DynamicValue
:
:
UINT
:
{
uint64_t
maxValue
=
0
;
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
INT8
:
maxValue
=
std
::
numeric_limits
<
int8_t
>::
max
();
break
;
case
schema
:
:
Type
::
INT16
:
maxValue
=
std
::
numeric_limits
<
int16_t
>::
max
();
break
;
case
schema
:
:
Type
::
INT32
:
maxValue
=
std
::
numeric_limits
<
int32_t
>::
max
();
break
;
case
schema
:
:
Type
::
INT64
:
maxValue
=
std
::
numeric_limits
<
int64_t
>::
max
();
break
;
case
schema
:
:
Type
::
UINT8
:
maxValue
=
std
::
numeric_limits
<
uint8_t
>::
max
();
break
;
case
schema
:
:
Type
::
UINT16
:
maxValue
=
std
::
numeric_limits
<
uint16_t
>::
max
();
break
;
case
schema
:
:
Type
::
UINT32
:
maxValue
=
std
::
numeric_limits
<
uint32_t
>::
max
();
break
;
case
schema
:
:
Type
::
UINT64
:
maxValue
=
std
::
numeric_limits
<
uint64_t
>::
max
();
break
;
case
schema
:
:
Type
::
FLOAT32
:
case
schema
:
:
Type
::
FLOAT64
:
// Any integer is acceptable.
maxValue
=
std
::
numeric_limits
<
uint64_t
>::
max
();
break
;
default
:
break
;
}
if
(
maxValue
==
0
)
break
;
if
(
result
.
getReader
().
as
<
uint64_t
>
()
>
maxValue
)
{
errorReporter
.
addErrorOn
(
src
,
"Integer value out of range."
);
result
=
maxValue
;
}
return
kj
::
mv
(
result
);
}
case
DynamicValue
:
:
FLOAT
:
if
(
type
.
isFloat32
()
||
type
.
isFloat64
())
{
return
kj
::
mv
(
result
);
}
break
;
default
:
DynamicSlot
slot
(
valueUnion
,
field
);
compileValue
(
source
,
slot
,
isBootstrap
);
case
DynamicValue
:
:
TEXT
:
if
(
type
.
isText
())
{
return
kj
::
mv
(
result
);
}
break
;
case
DynamicValue
:
:
DATA
:
if
(
type
.
isData
())
{
return
kj
::
mv
(
result
);
}
break
;
}
}
void
NodeTranslator
::
compileValue
(
ValueExpression
::
Reader
src
,
DynamicSlot
&
dst
,
bool
isBootstrap
)
{
// We rely on the dynamic API to detect type errors and throw exceptions.
//
// TODO(cleanup): We should perhaps ensure that all exceptions that this might throw are
// recoverable, so that this doesn't crash if -fno-exceptions is enabled. Or create a better
// way to test for type compatibility without throwing.
KJ_IF_MAYBE
(
exception
,
kj
::
runCatchingExceptions
(
[
&
]()
{
compileValueInner
(
src
,
dst
,
isBootstrap
);
}))
{
errorReporter
.
addErrorOn
(
src
,
"Type mismatch."
);
case
DynamicValue
:
:
LIST
:
if
(
type
.
isList
())
{
KJ_IF_MAYBE
(
schema
,
makeListSchemaOf
(
type
.
getList
()))
{
if
(
result
.
getReader
().
as
<
DynamicList
>
().
getSchema
()
==
*
schema
)
{
return
kj
::
mv
(
result
);
}
}
else
{
return
nullptr
;
}
}
break
;
case
DynamicValue
:
:
ENUM
:
if
(
type
.
isEnum
())
{
KJ_IF_MAYBE
(
schema
,
resolver
.
resolveBootstrapSchema
(
type
.
getEnum
()))
{
if
(
result
.
getReader
().
as
<
DynamicEnum
>
().
getSchema
()
==
*
schema
)
{
return
kj
::
mv
(
result
);
}
}
else
{
return
nullptr
;
}
}
break
;
case
DynamicValue
:
:
STRUCT
:
if
(
type
.
isStruct
())
{
KJ_IF_MAYBE
(
schema
,
resolver
.
resolveBootstrapSchema
(
type
.
getStruct
()))
{
if
(
result
.
getReader
().
as
<
DynamicStruct
>
().
getSchema
()
==
*
schema
)
{
return
kj
::
mv
(
result
);
}
}
else
{
return
nullptr
;
}
}
break
;
case
DynamicValue
:
:
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces can't have literal values."
);
case
DynamicValue
:
:
OBJECT
:
KJ_FAIL_ASSERT
(
"Objects can't have literal values."
);
}
errorReporter
.
addErrorOn
(
src
,
kj
::
str
(
"Type mismatch; expected "
,
makeTypeName
(
type
),
"."
));
return
nullptr
;
}
void
NodeTranslator
::
compileValueInner
(
ValueExpression
::
Reader
src
,
DynamicSlot
&
dst
,
bool
isBootstrap
)
{
Orphan
<
DynamicValue
>
NodeTranslator
::
compileValueInner
(
ValueExpression
::
Reader
src
,
schema
::
Type
::
Reader
type
,
bool
isBootstrap
)
{
switch
(
src
.
which
())
{
case
ValueExpression
:
:
NAME
:
{
auto
name
=
src
.
getName
();
bool
isBare
=
name
.
getBase
().
isRelativeName
()
&&
name
.
getMemberPath
().
size
()
==
0
;
bool
wasSet
=
false
;
if
(
isBare
)
{
// The name is just a bare identifier. It may be a literal value or an enumerant.
kj
::
StringPtr
id
=
name
.
getBase
().
getRelativeName
().
getValue
();
KJ_IF_MAYBE
(
enumId
,
dst
.
getEnumType
())
{
KJ_IF_MAYBE
(
enumSchema
,
resolver
.
resolveBootstrapSchema
(
*
enumId
))
{
if
(
type
.
isEnum
())
{
KJ_IF_MAYBE
(
enumSchema
,
resolver
.
resolveBootstrapSchema
(
type
.
getEnum
()
))
{
KJ_IF_MAYBE
(
enumerant
,
enumSchema
->
asEnum
().
findEnumerantByName
(
id
))
{
dst
.
set
(
DynamicEnum
(
*
enumerant
));
wasSet
=
true
;
return
DynamicEnum
(
*
enumerant
);
}
}
else
{
// Enum type is broken. We don't want to report a redundant error here, so just assume
// we would have found a matching enumerant.
dst
.
set
(
kj
::
implicitCast
<
uint16_t
>
(
0
));
wasSet
=
true
;
// Enum type is broken.
return
nullptr
;
}
}
else
{
// Interpret known constant values.
if
(
id
==
"void"
)
{
dst
.
set
(
VOID
);
wasSet
=
true
;
return
VOID
;
}
else
if
(
id
==
"true"
)
{
dst
.
set
(
true
);
wasSet
=
true
;
return
true
;
}
else
if
(
id
==
"false"
)
{
dst
.
set
(
false
);
wasSet
=
true
;
return
false
;
}
else
if
(
id
==
"nan"
)
{
dst
.
set
(
std
::
numeric_limits
<
double
>::
quiet_NaN
());
wasSet
=
true
;
return
std
::
numeric_limits
<
double
>::
quiet_NaN
();
}
else
if
(
id
==
"inf"
)
{
dst
.
set
(
std
::
numeric_limits
<
double
>::
infinity
());
wasSet
=
true
;
return
std
::
numeric_limits
<
double
>::
infinity
();
}
}
}
if
(
!
wasSet
)
{
// Haven't resolved the name yet. Try looking up a constant.
KJ_IF_MAYBE
(
constValue
,
readConstant
(
src
.
getName
(),
isBootstrap
,
src
))
{
dst
.
set
(
*
constValue
);
}
// Haven't resolved the name yet. Try looking up a constant.
KJ_IF_MAYBE
(
constValue
,
readConstant
(
src
.
getName
(),
isBootstrap
,
src
))
{
return
orphanage
.
newOrphanCopy
(
*
constValue
);
}
break
;
return
nullptr
;
}
case
ValueExpression
:
:
POSITIVE_INT
:
dst
.
set
(
src
.
getPositiveInt
());
break
;
return
src
.
getPositiveInt
();
case
ValueExpression
:
:
NEGATIVE_INT
:
{
uint64_t
nValue
=
src
.
getNegativeInt
();
if
(
nValue
>
(
std
::
numeric_limits
<
uint64_t
>::
max
()
>>
1
)
+
1
)
{
errorReporter
.
addErrorOn
(
src
,
"Integer is too big to be negative."
);
return
nullptr
;
}
else
{
dst
.
set
(
kj
::
implicitCast
<
int64_t
>
(
-
nValue
)
);
return
kj
::
implicitCast
<
int64_t
>
(
-
nValue
);
}
break
;
}
case
ValueExpression
:
:
FLOAT
:
dst
.
set
(
src
.
getFloat
()
);
return
src
.
getFloat
(
);
break
;
case
ValueExpression
:
:
STRING
:
dst
.
set
(
src
.
getString
());
if
(
type
.
isData
())
{
Text
::
Reader
text
=
src
.
getString
();
return
orphanage
.
newOrphanCopy
(
Data
::
Reader
(
reinterpret_cast
<
const
byte
*>
(
text
.
begin
()),
text
.
size
()));
}
else
{
return
orphanage
.
newOrphanCopy
(
src
.
getString
());
}
break
;
case
ValueExpression
:
:
LIST
:
{
auto
srcList
=
src
.
getList
();
auto
dstList
=
dst
.
initList
(
srcList
.
size
());
for
(
uint
i
=
0
;
i
<
srcList
.
size
();
i
++
)
{
DynamicSlot
slot
(
dstList
,
i
);
compileValue
(
srcList
[
i
],
slot
,
isBootstrap
);
if
(
!
type
.
isList
())
{
errorReporter
.
addErrorOn
(
src
,
"Type mismatch."
);
return
nullptr
;
}
auto
elementType
=
type
.
getList
();
KJ_IF_MAYBE
(
listSchema
,
makeListSchemaOf
(
elementType
))
{
auto
srcList
=
src
.
getList
();
Orphan
<
DynamicList
>
result
=
orphanage
.
newOrphan
(
*
listSchema
,
srcList
.
size
());
auto
dstList
=
result
.
get
();
for
(
uint
i
=
0
;
i
<
srcList
.
size
();
i
++
)
{
KJ_IF_MAYBE
(
value
,
compileValue
(
srcList
[
i
],
elementType
,
isBootstrap
))
{
dstList
.
adopt
(
i
,
kj
::
mv
(
*
value
));
}
}
return
kj
::
mv
(
result
);
}
else
{
return
nullptr
;
}
break
;
}
case
ValueExpression
:
:
STRUCT
:
{
auto
srcStruct
=
src
.
getStruct
();
auto
dstStruct
=
dst
.
initStruct
();
auto
dstSchema
=
dstStruct
.
getSchema
();
for
(
auto
assignment
:
srcStruct
)
{
auto
fieldName
=
assignment
.
getFieldName
();
KJ_IF_MAYBE
(
field
,
dstSchema
.
findFieldByName
(
fieldName
.
getValue
()))
{
DynamicSlot
slot
(
dstStruct
,
*
field
);
compileValue
(
assignment
.
getValue
(),
slot
,
isBootstrap
);
}
else
{
errorReporter
.
addErrorOn
(
fieldName
,
kj
::
str
(
"Struct has no field named '"
,
fieldName
.
getValue
(),
"'."
));
}
if
(
!
type
.
isStruct
())
{
errorReporter
.
addErrorOn
(
src
,
"Type mismatch."
);
return
nullptr
;
}
KJ_IF_MAYBE
(
schema
,
resolver
.
resolveBootstrapSchema
(
type
.
getStruct
()))
{
auto
structSchema
=
schema
->
asStruct
();
Orphan
<
DynamicStruct
>
result
=
orphanage
.
newOrphan
(
structSchema
);
fillStructValue
(
result
.
get
(),
src
.
getStruct
(),
isBootstrap
);
return
kj
::
mv
(
result
);
}
else
{
return
nullptr
;
}
break
;
}
case
ValueExpression
:
:
UNKNOWN
:
// Ignore earlier error.
break
;
return
nullptr
;
}
KJ_UNREACHABLE
;
}
void
NodeTranslator
::
fillStructValue
(
DynamicStruct
::
Builder
builder
,
List
<
ValueExpression
::
FieldAssignment
>::
Reader
assignments
,
bool
isBootstrap
)
{
for
(
auto
assignment
:
assignments
)
{
auto
fieldName
=
assignment
.
getFieldName
();
KJ_IF_MAYBE
(
field
,
builder
.
getSchema
().
findFieldByName
(
fieldName
.
getValue
()))
{
auto
fieldProto
=
field
->
getProto
();
auto
value
=
assignment
.
getValue
();
switch
(
fieldProto
.
which
())
{
case
schema
:
:
Field
::
NON_GROUP
:
KJ_IF_MAYBE
(
compiledValue
,
compileValue
(
value
,
fieldProto
.
getNonGroup
().
getType
(),
isBootstrap
))
{
builder
.
adopt
(
*
field
,
kj
::
mv
(
*
compiledValue
));
}
break
;
case
schema
:
:
Field
::
GROUP
:
if
(
value
.
isStruct
())
{
fillStructValue
(
builder
.
init
(
*
field
).
as
<
DynamicStruct
>
(),
value
.
getStruct
(),
isBootstrap
);
}
else
{
errorReporter
.
addErrorOn
(
value
,
"Type mismatch."
);
}
break
;
}
}
else
{
errorReporter
.
addErrorOn
(
fieldName
,
kj
::
str
(
"Struct has no field named '"
,
fieldName
.
getValue
(),
"'."
));
}
}
}
kj
::
String
NodeTranslator
::
makeNodeName
(
uint64_t
id
)
{
KJ_IF_MAYBE
(
schema
,
resolver
.
resolveBootstrapSchema
(
id
))
{
schema
::
Node
::
Reader
proto
=
schema
->
getProto
();
return
kj
::
str
(
proto
.
getDisplayName
().
slice
(
proto
.
getDisplayNamePrefixLength
()));
}
else
{
return
kj
::
str
(
"@0x"
,
kj
::
hex
(
id
));
}
}
kj
::
String
NodeTranslator
::
makeTypeName
(
schema
::
Type
::
Reader
type
)
{
switch
(
type
.
which
())
{
case
schema
:
:
Type
::
VOID
:
return
kj
::
str
(
"Void"
);
case
schema
:
:
Type
::
BOOL
:
return
kj
::
str
(
"Bool"
);
case
schema
:
:
Type
::
INT8
:
return
kj
::
str
(
"Int8"
);
case
schema
:
:
Type
::
INT16
:
return
kj
::
str
(
"Int16"
);
case
schema
:
:
Type
::
INT32
:
return
kj
::
str
(
"Int32"
);
case
schema
:
:
Type
::
INT64
:
return
kj
::
str
(
"Int64"
);
case
schema
:
:
Type
::
UINT8
:
return
kj
::
str
(
"UInt8"
);
case
schema
:
:
Type
::
UINT16
:
return
kj
::
str
(
"UInt16"
);
case
schema
:
:
Type
::
UINT32
:
return
kj
::
str
(
"UInt32"
);
case
schema
:
:
Type
::
UINT64
:
return
kj
::
str
(
"UInt64"
);
case
schema
:
:
Type
::
FLOAT32
:
return
kj
::
str
(
"Float32"
);
case
schema
:
:
Type
::
FLOAT64
:
return
kj
::
str
(
"Float64"
);
case
schema
:
:
Type
::
TEXT
:
return
kj
::
str
(
"Text"
);
case
schema
:
:
Type
::
DATA
:
return
kj
::
str
(
"Data"
);
case
schema
:
:
Type
::
LIST
:
return
kj
::
str
(
"List("
,
makeTypeName
(
type
.
getList
()),
")"
);
case
schema
:
:
Type
::
ENUM
:
return
makeNodeName
(
type
.
getEnum
());
case
schema
:
:
Type
::
STRUCT
:
return
makeNodeName
(
type
.
getStruct
());
case
schema
:
:
Type
::
INTERFACE
:
return
makeNodeName
(
type
.
getInterface
());
case
schema
:
:
Type
::
OBJECT
:
return
kj
::
str
(
"Object"
);
}
KJ_UNREACHABLE
;
}
kj
::
Maybe
<
DynamicValue
::
Reader
>
NodeTranslator
::
readConstant
(
...
...
@@ -1824,7 +1874,6 @@ Orphan<List<schema::Annotation>> NodeTranslator::compileAnnotationApplications(
return
Orphan
<
List
<
schema
::
Annotation
>>
();
}
Orphanage
orphanage
=
Orphanage
::
getForMessageContaining
(
wipNode
.
get
());
auto
result
=
orphanage
.
newOrphan
<
List
<
schema
::
Annotation
>>
(
annotations
.
size
());
auto
builder
=
result
.
get
();
...
...
c++/src/capnp/compiler/node-translator.h
View file @
98e6519e
...
...
@@ -109,6 +109,7 @@ public:
private
:
const
Resolver
&
resolver
;
const
ErrorReporter
&
errorReporter
;
Orphanage
orphanage
;
bool
compileAnnotations
;
Orphan
<
schema
::
Node
>
wipNode
;
...
...
@@ -168,15 +169,23 @@ private:
schema
::
Value
::
Builder
target
,
bool
isBootstrap
);
// Interprets the value expression and initializes `target` with the result.
class
DynamicSlot
;
kj
::
Maybe
<
Orphan
<
DynamicValue
>>
compileValue
(
ValueExpression
::
Reader
src
,
schema
::
Type
::
Reader
type
,
bool
isBootstrap
);
// Compile the given value as the given type. Returns null if there was an error, including
// if the value doesn't match the type.
void
compileValue
(
ValueExpression
::
Reader
src
,
DynamicSlot
&
dst
,
bool
isBootstrap
);
// Fill in `dst` (which effectively points to a struct field or list element) with the given
// value.
void
compileValueInner
(
ValueExpression
::
Reader
src
,
DynamicSlot
&
dst
,
bool
isBootstrap
);
Orphan
<
DynamicValue
>
compileValueInner
(
ValueExpression
::
Reader
src
,
schema
::
Type
::
Reader
type
,
bool
isBootstrap
);
// Helper for compileValue().
void
fillStructValue
(
DynamicStruct
::
Builder
builder
,
List
<
ValueExpression
::
FieldAssignment
>::
Reader
assignments
,
bool
isBootstrap
);
// Interprets the given assignments and uses them to fill in the given struct builder.
kj
::
String
makeNodeName
(
uint64_t
id
);
kj
::
String
makeTypeName
(
schema
::
Type
::
Reader
type
);
kj
::
Maybe
<
DynamicValue
::
Reader
>
readConstant
(
DeclName
::
Reader
name
,
bool
isBootstrap
,
ValueExpression
::
Reader
errorLocation
);
// Get the value of the given constant. May return null if some error occurs, which will already
...
...
c++/src/capnp/dynamic.c++
View file @
98e6519e
...
...
@@ -558,10 +558,12 @@ void DynamicStruct::Builder::set(StructSchema::Field field, const DynamicValue::
return
;
case
schema
:
:
Type
::
LIST
:
// TODO(soon): Type check.
builder
.
setListField
(
nonGroup
.
getOffset
()
*
POINTERS
,
value
.
as
<
DynamicList
>
().
reader
);
return
;
case
schema
:
:
Type
::
STRUCT
:
// TODO(soon): Type check.
builder
.
setStructField
(
nonGroup
.
getOffset
()
*
POINTERS
,
value
.
as
<
DynamicStruct
>
().
reader
);
return
;
...
...
@@ -697,11 +699,11 @@ void DynamicStruct::Builder::adopt(StructSchema::Field field, Orphan<DynamicValu
return
;
case
schema
:
:
Type
::
TEXT
:
orphan
.
getReader
().
as
<
Text
>
();
// type check
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
TEXT
,
"Value type mismatch."
);
break
;
case
schema
:
:
Type
::
DATA
:
orphan
.
getReader
().
as
<
Data
>
();
// type check
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
DATA
,
"Value type mismatch."
);
break
;
case
schema
:
:
Type
::
LIST
:
{
...
...
@@ -869,7 +871,7 @@ void DynamicStruct::Builder::clear(StructSchema::Field field) {
case
schema
:
:
Type
::
LIST
:
case
schema
:
:
Type
::
STRUCT
:
case
schema
:
:
Type
::
OBJECT
:
builder
.
disown
(
nonGroup
.
getOffset
()
*
POINTERS
);
builder
.
clearPointer
(
nonGroup
.
getOffset
()
*
POINTERS
);
return
;
case
schema
:
:
Type
::
INTERFACE
:
...
...
@@ -1199,17 +1201,16 @@ void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) {
return
;
case
schema
:
:
Type
::
LIST
:
{
// TODO(soon): Type check.
builder
.
setListElement
(
index
*
ELEMENTS
,
value
.
as
<
DynamicList
>
().
reader
);
return
;
}
case
schema
:
:
Type
::
STRUCT
:
// Not supported for the same reason List<struct> doesn't support it -- the space for the
// element is already allocated, and if it's smaller than the input value the copy would
// have to be lossy.
KJ_FAIL_ASSERT
(
"DynamicList of structs does not support set()."
)
{
return
;
}
case
schema
:
:
Type
::
STRUCT
:
{
// TODO(soon): Type check.
builder
.
getStructElement
(
index
*
ELEMENTS
).
copyContentFrom
(
value
.
as
<
DynamicStruct
>
().
reader
);
return
;
}
case
schema
:
:
Type
::
ENUM
:
{
uint16_t
rawValue
;
...
...
@@ -1297,6 +1298,114 @@ DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
return
nullptr
;
}
void
DynamicList
::
Builder
::
adopt
(
uint
index
,
Orphan
<
DynamicValue
>&&
orphan
)
{
switch
(
schema
.
whichElementType
())
{
case
schema
:
:
Type
::
VOID
:
case
schema
:
:
Type
::
BOOL
:
case
schema
:
:
Type
::
INT8
:
case
schema
:
:
Type
::
INT16
:
case
schema
:
:
Type
::
INT32
:
case
schema
:
:
Type
::
INT64
:
case
schema
:
:
Type
::
UINT8
:
case
schema
:
:
Type
::
UINT16
:
case
schema
:
:
Type
::
UINT32
:
case
schema
:
:
Type
::
UINT64
:
case
schema
:
:
Type
::
FLOAT32
:
case
schema
:
:
Type
::
FLOAT64
:
case
schema
:
:
Type
::
ENUM
:
set
(
index
,
orphan
.
getReader
());
return
;
case
schema
:
:
Type
::
TEXT
:
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
TEXT
,
"Value type mismatch."
);
builder
.
adopt
(
index
*
ELEMENTS
,
kj
::
mv
(
orphan
.
builder
));
return
;
case
schema
:
:
Type
::
DATA
:
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
DATA
,
"Value type mismatch."
);
builder
.
adopt
(
index
*
ELEMENTS
,
kj
::
mv
(
orphan
.
builder
));
return
;
case
schema
:
:
Type
::
LIST
:
{
ListSchema
elementType
=
schema
.
getListElementType
();
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
LIST
&&
orphan
.
listSchema
==
elementType
,
"Value type mismatch."
);
builder
.
adopt
(
index
*
ELEMENTS
,
kj
::
mv
(
orphan
.
builder
));
return
;
}
case
schema
:
:
Type
::
STRUCT
:
{
auto
elementType
=
schema
.
getStructElementType
();
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
STRUCT
&&
orphan
.
structSchema
==
elementType
,
"Value type mismatch."
);
builder
.
getStructElement
(
index
*
ELEMENTS
).
transferContentFrom
(
orphan
.
builder
.
asStruct
(
structSizeFromSchema
(
elementType
)));
return
;
}
case
schema
:
:
Type
::
OBJECT
:
KJ_FAIL_ASSERT
(
"List(Object) not supported."
);
case
schema
:
:
Type
::
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not yet implemented."
);
}
KJ_UNREACHABLE
;
}
Orphan
<
DynamicValue
>
DynamicList
::
Builder
::
disown
(
uint
index
)
{
switch
(
schema
.
whichElementType
())
{
case
schema
:
:
Type
::
VOID
:
case
schema
:
:
Type
::
BOOL
:
case
schema
:
:
Type
::
INT8
:
case
schema
:
:
Type
::
INT16
:
case
schema
:
:
Type
::
INT32
:
case
schema
:
:
Type
::
INT64
:
case
schema
:
:
Type
::
UINT8
:
case
schema
:
:
Type
::
UINT16
:
case
schema
:
:
Type
::
UINT32
:
case
schema
:
:
Type
::
UINT64
:
case
schema
:
:
Type
::
FLOAT32
:
case
schema
:
:
Type
::
FLOAT64
:
case
schema
:
:
Type
::
ENUM
:
{
auto
result
=
Orphan
<
DynamicValue
>
(
operator
[](
index
),
_
::
OrphanBuilder
());
switch
(
elementSizeFor
(
schema
.
whichElementType
()))
{
case
_
:
:
FieldSize
::
VOID
:
break
;
case
_
:
:
FieldSize
::
BIT
:
builder
.
setDataElement
<
bool
>
(
index
*
ELEMENTS
,
false
);
break
;
case
_
:
:
FieldSize
::
BYTE
:
builder
.
setDataElement
<
uint8_t
>
(
index
*
ELEMENTS
,
0
);
break
;
case
_
:
:
FieldSize
::
TWO_BYTES
:
builder
.
setDataElement
<
uint16_t
>
(
index
*
ELEMENTS
,
0
);
break
;
case
_
:
:
FieldSize
::
FOUR_BYTES
:
builder
.
setDataElement
<
uint32_t
>
(
index
*
ELEMENTS
,
0
);
break
;
case
_
:
:
FieldSize
::
EIGHT_BYTES
:
builder
.
setDataElement
<
uint64_t
>
(
index
*
ELEMENTS
,
0
);
break
;
case
_
:
:
FieldSize
::
POINTER
:
case
_
:
:
FieldSize
::
INLINE_COMPOSITE
:
KJ_UNREACHABLE
;
}
return
kj
::
mv
(
result
);
}
case
schema
:
:
Type
::
TEXT
:
case
schema
:
:
Type
::
DATA
:
case
schema
:
:
Type
::
LIST
:
case
schema
:
:
Type
::
OBJECT
:
case
schema
:
:
Type
::
INTERFACE
:
{
auto
value
=
operator
[](
index
);
return
Orphan
<
DynamicValue
>
(
value
,
builder
.
disown
(
index
*
ELEMENTS
));
}
case
schema
:
:
Type
::
STRUCT
:
{
// We have to make a copy.
Orphan
<
DynamicStruct
>
result
=
Orphanage
::
getForMessageContaining
(
*
this
).
newOrphan
(
schema
.
getStructElementType
());
auto
element
=
builder
.
getStructElement
(
index
*
ELEMENTS
);
result
.
get
().
builder
.
transferContentFrom
(
element
);
element
.
clearAll
();
return
kj
::
mv
(
result
);
}
}
KJ_UNREACHABLE
;
}
void
DynamicList
::
Builder
::
copyFrom
(
std
::
initializer_list
<
DynamicValue
::
Reader
>
value
)
{
KJ_REQUIRE
(
value
.
size
()
==
size
(),
"DynamicList::copyFrom() argument had different size."
);
uint
i
=
0
;
...
...
@@ -1793,12 +1902,50 @@ DynamicValue::Reader Orphan<DynamicValue>::getReader() const {
template
<>
Orphan
<
DynamicStruct
>
Orphan
<
DynamicValue
>::
releaseAs
<
DynamicStruct
>
()
{
KJ_REQUIRE
(
type
==
DynamicValue
::
STRUCT
,
"Value type mismatch."
);
type
=
DynamicValue
::
UNKNOWN
;
return
Orphan
<
DynamicStruct
>
(
structSchema
,
kj
::
mv
(
builder
));
}
template
<>
Orphan
<
DynamicList
>
Orphan
<
DynamicValue
>::
releaseAs
<
DynamicList
>
()
{
KJ_REQUIRE
(
type
==
DynamicValue
::
LIST
,
"Value type mismatch."
);
type
=
DynamicValue
::
UNKNOWN
;
return
Orphan
<
DynamicList
>
(
listSchema
,
kj
::
mv
(
builder
));
}
template
<>
Orphan
<
DynamicObject
>
Orphanage
::
newOrphanCopy
<
DynamicObject
::
Reader
>
(
const
DynamicObject
::
Reader
&
copyFrom
)
const
{
switch
(
copyFrom
.
reader
.
kind
)
{
case
_
:
:
ObjectKind
::
NULL_POINTER
:
return
Orphan
<
DynamicObject
>
();
case
_
:
:
ObjectKind
::
STRUCT
:
return
Orphan
<
DynamicObject
>
(
_
::
OrphanBuilder
::
copy
(
arena
,
copyFrom
.
reader
.
structReader
));
case
_
:
:
ObjectKind
::
LIST
:
return
Orphan
<
DynamicObject
>
(
_
::
OrphanBuilder
::
copy
(
arena
,
copyFrom
.
reader
.
listReader
));
}
KJ_UNREACHABLE
;
}
template
<>
Orphan
<
DynamicValue
>
Orphanage
::
newOrphanCopy
<
DynamicValue
::
Reader
>
(
const
DynamicValue
::
Reader
&
copyFrom
)
const
{
switch
(
copyFrom
.
getType
())
{
case
DynamicValue
:
:
UNKNOWN
:
return
nullptr
;
case
DynamicValue
:
:
VOID
:
return
copyFrom
.
voidValue
;
case
DynamicValue
:
:
BOOL
:
return
copyFrom
.
boolValue
;
case
DynamicValue
:
:
INT
:
return
copyFrom
.
intValue
;
case
DynamicValue
:
:
UINT
:
return
copyFrom
.
uintValue
;
case
DynamicValue
:
:
FLOAT
:
return
copyFrom
.
floatValue
;
case
DynamicValue
:
:
ENUM
:
return
copyFrom
.
enumValue
;
case
DynamicValue
:
:
TEXT
:
return
newOrphanCopy
(
copyFrom
.
textValue
);
case
DynamicValue
:
:
DATA
:
return
newOrphanCopy
(
copyFrom
.
dataValue
);
case
DynamicValue
:
:
LIST
:
return
newOrphanCopy
(
copyFrom
.
listValue
);
case
DynamicValue
:
:
STRUCT
:
return
newOrphanCopy
(
copyFrom
.
structValue
);
case
DynamicValue
:
:
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not implemented."
);
case
DynamicValue
:
:
OBJECT
:
return
newOrphanCopy
(
copyFrom
.
objectValue
);
}
KJ_UNREACHABLE
;
}
}
// namespace capnp
c++/src/capnp/dynamic.h
View file @
98e6519e
...
...
@@ -150,6 +150,8 @@ class DynamicObject::Reader {
// Represents an "Object" field of unknown type.
public
:
typedef
DynamicObject
Reads
;
Reader
()
=
default
;
template
<
typename
T
>
...
...
@@ -171,6 +173,7 @@ private:
friend
class
DynamicObject
::
Builder
;
friend
class
Orphan
<
DynamicObject
>
;
friend
class
Orphan
<
DynamicValue
>
;
friend
class
Orphanage
;
};
class
DynamicObject
::
Builder
:
public
kj
::
DisallowConstCopy
{
...
...
@@ -182,6 +185,8 @@ class DynamicObject::Builder: public kj::DisallowConstCopy {
// DynamicStruct::Builder::{get,set,init}Object() and pass a type schema to build object fields.
public
:
typedef
DynamicObject
Builds
;
Builder
()
=
default
;
Builder
(
Builder
&
)
=
default
;
Builder
(
Builder
&&
)
=
default
;
...
...
@@ -313,8 +318,6 @@ public:
// Clear a field, setting it to its default value. For pointer fields, this actually makes the
// field null.
// TODO(someday): Implement adopt() and disown().
DynamicStruct
::
Builder
getObject
(
StructSchema
::
Field
field
,
StructSchema
type
);
DynamicList
::
Builder
getObject
(
StructSchema
::
Field
field
,
ListSchema
type
);
Text
::
Builder
getObjectAsText
(
StructSchema
::
Field
field
);
...
...
@@ -437,7 +440,8 @@ public:
DynamicValue
::
Builder
operator
[](
uint
index
);
void
set
(
uint
index
,
const
DynamicValue
::
Reader
&
value
);
DynamicValue
::
Builder
init
(
uint
index
,
uint
size
);
// TODO(someday): Implement adopt() and disown().
void
adopt
(
uint
index
,
Orphan
<
DynamicValue
>&&
orphan
);
Orphan
<
DynamicValue
>
disown
(
uint
index
);
typedef
_
::
IndexingIterator
<
Builder
,
DynamicStruct
::
Builder
>
Iterator
;
inline
Iterator
begin
()
{
return
Iterator
(
this
,
0
);
}
...
...
@@ -484,7 +488,7 @@ class DynamicValue::Reader {
public
:
typedef
DynamicValue
Reads
;
inline
Reader
(
std
::
nullptr_t
n
=
nullptr
);
// UNKNOWN
inline
Reader
(
decltype
(
nullptr
)
n
=
nullptr
);
// UNKNOWN
inline
Reader
(
Void
value
);
inline
Reader
(
bool
value
);
inline
Reader
(
char
value
);
...
...
@@ -557,13 +561,15 @@ private:
template
<
typename
T
,
Kind
kind
=
kind
<
T
>
()
>
struct
AsImpl
;
// Implementation backing the as() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
friend
class
Orphanage
;
// to speed up newOrphanCopy(DynamicValue::Reader)
};
class
DynamicValue
::
Builder
{
public
:
typedef
DynamicValue
Builds
;
inline
Builder
(
std
::
nullptr_t
n
=
nullptr
);
// UNKNOWN
inline
Builder
(
decltype
(
nullptr
)
n
=
nullptr
);
// UNKNOWN
inline
Builder
(
Void
value
);
inline
Builder
(
bool
value
);
inline
Builder
(
char
value
);
...
...
@@ -757,16 +763,34 @@ private:
template
<
typename
,
Kind
>
friend
struct
_
::
PointerHelpers
;
friend
class
Orphan
<
DynamicValue
>
;
friend
class
Orphanage
;
};
template
<>
class
Orphan
<
DynamicValue
>
{
public
:
Orphan
()
=
default
;
KJ_DISALLOW_COPY
(
Orphan
);
inline
Orphan
(
decltype
(
nullptr
)
n
=
nullptr
)
:
type
(
DynamicValue
::
UNKNOWN
)
{}
inline
Orphan
(
Void
value
);
inline
Orphan
(
bool
value
);
inline
Orphan
(
char
value
);
inline
Orphan
(
signed
char
value
);
inline
Orphan
(
short
value
);
inline
Orphan
(
int
value
);
inline
Orphan
(
long
value
);
inline
Orphan
(
long
long
value
);
inline
Orphan
(
unsigned
char
value
);
inline
Orphan
(
unsigned
short
value
);
inline
Orphan
(
unsigned
int
value
);
inline
Orphan
(
unsigned
long
value
);
inline
Orphan
(
unsigned
long
long
value
);
inline
Orphan
(
float
value
);
inline
Orphan
(
double
value
);
inline
Orphan
(
DynamicEnum
value
);
Orphan
(
Orphan
&&
)
=
default
;
template
<
typename
T
>
Orphan
(
Orphan
<
T
>&&
);
KJ_DISALLOW_COPY
(
Orphan
);
Orphan
&
operator
=
(
Orphan
&&
)
=
default
;
inline
DynamicValue
::
Type
getType
()
{
return
type
;
}
...
...
@@ -780,9 +804,6 @@ public:
// the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
// transferred to the returned Orphan<T>.
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
builder
!=
nullptr
;
}
private
:
DynamicValue
::
Type
type
;
union
{
...
...
@@ -851,6 +872,7 @@ Orphan<T> Orphan<DynamicList>::releaseAs() {
template
<
typename
T
>
Orphan
<
T
>
Orphan
<
DynamicValue
>::
releaseAs
()
{
get
().
as
<
T
>
();
// type check
type
=
DynamicValue
::
UNKNOWN
;
return
Orphan
<
T
>
(
kj
::
mv
(
builder
));
}
...
...
@@ -886,6 +908,14 @@ inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>(
return
Orphan
<
DynamicList
>
(
copyFrom
.
getSchema
(),
_
::
OrphanBuilder
::
copy
(
arena
,
copyFrom
.
reader
));
}
template
<>
Orphan
<
DynamicObject
>
Orphanage
::
newOrphanCopy
<
DynamicObject
::
Reader
>
(
const
DynamicObject
::
Reader
&
copyFrom
)
const
;
template
<>
Orphan
<
DynamicValue
>
Orphanage
::
newOrphanCopy
<
DynamicValue
::
Reader
>
(
const
DynamicValue
::
Reader
&
copyFrom
)
const
;
// -------------------------------------------------------------------
// Inject the ability to use DynamicStruct for message roots and Dynamic{Struct,List} for
// generated Object accessors.
...
...
@@ -1001,11 +1031,13 @@ DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
inline
DynamicValue
::
Reader
::
Reader
(
std
::
nullptr_t
n
)
:
type
(
UNKNOWN
)
{}
inline
DynamicValue
::
Builder
::
Builder
(
std
::
nullptr_t
n
)
:
type
(
UNKNOWN
)
{}
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
inline DynamicValue::Reader::Reader(cppType value) \
: type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType value) \
: type(typeTag), fieldName##Value(value) {}
: type(typeTag), fieldName##Value(value) {} \
inline Orphan<DynamicValue>::Orphan(cppType value) \
: type(DynamicValue::typeTag), fieldName##Value(value) {}
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
Void
,
VOID
,
void
);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
(
bool
,
BOOL
,
bool
);
...
...
c++/src/capnp/layout.c++
View file @
98e6519e
...
...
@@ -1558,19 +1558,19 @@ struct WireHelpers {
WirePointer
*
tag
=
reinterpret_cast
<
WirePointer
*>
(
ptr
);
tag
->
setKindAndInlineCompositeListElementCount
(
WirePointer
::
STRUCT
,
value
.
elementCount
);
tag
->
structRef
.
set
(
dataSize
,
pointerCount
);
ptr
+=
POINTER_SIZE_IN_WORDS
;
word
*
dst
=
ptr
+
POINTER_SIZE_IN_WORDS
;
const
word
*
src
=
reinterpret_cast
<
const
word
*>
(
value
.
ptr
);
for
(
uint
i
=
0
;
i
<
value
.
elementCount
/
ELEMENTS
;
i
++
)
{
memcpy
(
ptr
,
src
,
value
.
structDataSize
/
BITS_PER_BYTE
/
BYTES
);
ptr
+=
dataSize
;
memcpy
(
dst
,
src
,
value
.
structDataSize
/
BITS_PER_BYTE
/
BYTES
);
dst
+=
dataSize
;
src
+=
dataSize
;
for
(
uint
j
=
0
;
j
<
pointerCount
/
POINTERS
;
j
++
)
{
setObjectPointer
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
ptr
),
readObjectPointer
(
setObjectPointer
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
dst
),
readObjectPointer
(
value
.
segment
,
reinterpret_cast
<
const
WirePointer
*>
(
src
),
nullptr
,
value
.
nestingLimit
));
ptr
+=
POINTER_SIZE_IN_WORDS
;
dst
+=
POINTER_SIZE_IN_WORDS
;
src
+=
POINTER_SIZE_IN_WORDS
;
}
}
...
...
@@ -2152,6 +2152,19 @@ void StructBuilder::clearPointer(WirePointerCount ptrIndex) {
memset
(
pointers
+
ptrIndex
,
0
,
sizeof
(
WirePointer
));
}
void
StructBuilder
::
clearAll
()
{
if
(
dataSize
==
1
*
BITS
)
{
setDataField
<
bool
>
(
1
*
ELEMENTS
,
false
);
}
else
{
memset
(
data
,
0
,
dataSize
/
BITS_PER_BYTE
/
BYTES
);
}
for
(
uint
i
=
0
;
i
<
pointerCount
/
POINTERS
;
i
++
)
{
WireHelpers
::
zeroObject
(
segment
,
pointers
+
i
);
}
memset
(
pointers
,
0
,
pointerCount
*
BYTES_PER_POINTER
/
BYTES
);
}
void
StructBuilder
::
transferContentFrom
(
StructBuilder
other
)
{
// Determine the amount of data the builders have in common.
BitCount
sharedDataSize
=
kj
::
min
(
dataSize
,
other
.
dataSize
);
...
...
@@ -2679,6 +2692,8 @@ ListBuilder OrphanBuilder::asStructList(StructSize elementSize) {
// Watch out, the pointer could have been updated if the object had to be relocated.
if
(
tagAsPtr
()
->
kind
()
==
WirePointer
::
FAR
)
{
location
=
nullptr
;
}
else
if
(
result
.
step
*
ELEMENTS
<=
BITS_PER_WORD
*
WORDS
)
{
location
=
reinterpret_cast
<
word
*>
(
result
.
ptr
);
}
else
{
location
=
reinterpret_cast
<
word
*>
(
result
.
ptr
)
-
POINTER_SIZE_IN_WORDS
;
}
...
...
@@ -2748,16 +2763,24 @@ ObjectReader OrphanBuilder::asObjectReader() const {
}
void
OrphanBuilder
::
euthanize
()
{
auto
ref
=
reinterpret_cast
<
WirePointer
*>
(
&
tag
);
if
(
ref
->
kind
()
==
WirePointer
::
FAR
)
{
WireHelpers
::
zeroObject
(
segment
,
ref
);
}
else
{
WireHelpers
::
zeroObject
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
&
tag
),
location
);
}
// Carefully catch any exceptions and rethrow them as recoverable exceptions since we may be in
// a destructor.
auto
exception
=
kj
::
runCatchingExceptions
([
&
]()
{
auto
ref
=
reinterpret_cast
<
WirePointer
*>
(
&
tag
);
if
(
ref
->
kind
()
==
WirePointer
::
FAR
)
{
WireHelpers
::
zeroObject
(
segment
,
ref
);
}
else
{
WireHelpers
::
zeroObject
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
&
tag
),
location
);
}
memset
(
ref
,
0
,
sizeof
(
*
ref
));
segment
=
nullptr
;
location
=
nullptr
;
memset
(
ref
,
0
,
sizeof
(
*
ref
));
segment
=
nullptr
;
location
=
nullptr
;
});
KJ_IF_MAYBE
(
e
,
exception
)
{
kj
::
getExceptionCallback
().
onRecoverableException
(
kj
::
mv
(
*
e
));
}
}
}
// namespace _ (private)
...
...
c++/src/capnp/layout.h
View file @
98e6519e
...
...
@@ -376,6 +376,9 @@ public:
void
clearPointer
(
WirePointerCount
ptrIndex
);
// Equivalent to calling disown() and letting the result simply be destroyed.
void
clearAll
();
// Clear all pointers and data.
void
transferContentFrom
(
StructBuilder
other
);
// Adopt all pointers from `other`, and also copy all data. If `other`'s sections are larger
// than this, the extra data is not transferred, meaning there is a risk of data loss when
...
...
c++/src/capnp/orphan-test.c++
View file @
98e6519e
...
...
@@ -446,14 +446,14 @@ TEST(Orphans, DynamicStructAs) {
Orphan
<
DynamicValue
>
orphan
=
root
.
disownObjectField
<
DynamicStruct
>
(
Schema
::
from
<
TestAllTypes
>
());
EXPECT_
FALSE
(
orphan
==
nullptr
);
EXPECT_
EQ
(
DynamicValue
::
STRUCT
,
orphan
.
getType
()
);
checkTestMessage
(
orphan
.
getReader
().
as
<
TestAllTypes
>
());
checkTestMessage
(
orphan
.
get
().
as
<
TestAllTypes
>
());
{
Orphan
<
DynamicStruct
>
structOrphan
=
orphan
.
releaseAs
<
DynamicStruct
>
();
EXPECT_
TRUE
(
orphan
==
nullptr
);
EXPECT_
EQ
(
DynamicValue
::
UNKNOWN
,
orphan
.
getType
()
);
EXPECT_FALSE
(
structOrphan
==
nullptr
);
checkDynamicTestMessage
(
structOrphan
.
getReader
());
checkDynamicTestMessage
(
structOrphan
.
get
());
...
...
@@ -467,7 +467,7 @@ TEST(Orphans, DynamicStructAs) {
checkTestMessage
(
typedOrphan
.
getReader
());
checkTestMessage
(
typedOrphan
.
get
());
orphan
=
kj
::
mv
(
typedOrphan
);
EXPECT_
FALSE
(
orphan
==
nullptr
);
EXPECT_
EQ
(
DynamicValue
::
STRUCT
,
orphan
.
getType
()
);
EXPECT_TRUE
(
typedOrphan
==
nullptr
);
}
}
...
...
@@ -487,14 +487,14 @@ TEST(Orphans, DynamicListAs) {
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
DynamicValue
>
orphan
=
root
.
disownObjectField
<
DynamicList
>
(
Schema
::
from
<
List
<
uint32_t
>>
());
EXPECT_
FALSE
(
orphan
==
nullptr
);
EXPECT_
EQ
(
DynamicValue
::
LIST
,
orphan
.
getType
()
);
checkList
(
orphan
.
getReader
().
as
<
List
<
uint32_t
>>
(),
{
12
,
34
,
56
});
checkList
(
orphan
.
get
().
as
<
List
<
uint32_t
>>
(),
{
12
,
34
,
56
});
{
Orphan
<
DynamicList
>
listOrphan
=
orphan
.
releaseAs
<
DynamicList
>
();
EXPECT_
TRUE
(
orphan
==
nullptr
);
EXPECT_
EQ
(
DynamicValue
::
UNKNOWN
,
orphan
.
getType
()
);
EXPECT_FALSE
(
listOrphan
==
nullptr
);
checkList
<
uint32_t
>
(
listOrphan
.
getReader
(),
{
12
,
34
,
56
});
checkList
<
uint32_t
>
(
listOrphan
.
get
(),
{
12
,
34
,
56
});
...
...
@@ -508,7 +508,7 @@ TEST(Orphans, DynamicListAs) {
checkList
(
typedOrphan
.
getReader
(),
{
12
,
34
,
56
});
checkList
(
typedOrphan
.
get
(),
{
12
,
34
,
56
});
orphan
=
kj
::
mv
(
typedOrphan
);
EXPECT_
FALSE
(
orphan
==
nullptr
);
EXPECT_
EQ
(
DynamicValue
::
LIST
,
orphan
.
getType
()
);
EXPECT_TRUE
(
typedOrphan
==
nullptr
);
}
}
...
...
@@ -528,7 +528,7 @@ TEST(Orphans, DynamicObject) {
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
DynamicValue
>
orphan
=
root
.
disownObjectField
<
DynamicObject
>
();
EXPECT_
FALSE
(
orphan
==
nullptr
);
EXPECT_
EQ
(
DynamicValue
::
OBJECT
,
orphan
.
getType
()
);
checkTestMessage
(
orphan
.
getReader
().
as
<
DynamicObject
>
().
as
<
TestAllTypes
>
());
...
...
c++/src/kj/exception.c++
View file @
98e6519e
...
...
@@ -326,7 +326,12 @@ public:
#if KJ_NO_EXCEPTIONS
logException
(
mv
(
exception
));
#else
throw
ExceptionImpl
(
mv
(
exception
));
if
(
std
::
uncaught_exception
())
{
// Bad time to throw an exception. Just log instead.
logException
(
mv
(
exception
));
}
else
{
throw
ExceptionImpl
(
mv
(
exception
));
}
#endif
}
...
...
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