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
c1f3e3ff
Commit
c1f3e3ff
authored
Aug 26, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Flesh out dynamic API for orphans.
parent
55e48fc4
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
700 additions
and
37 deletions
+700
-37
dynamic.c++
c++/src/capnp/dynamic.c++
+307
-1
dynamic.h
c++/src/capnp/dynamic.h
+201
-24
layout.c++
c++/src/capnp/layout.c++
+16
-6
layout.h
c++/src/capnp/layout.h
+4
-4
orphan-test.c++
c++/src/capnp/orphan-test.c++
+168
-0
orphan.h
c++/src/capnp/orphan.h
+4
-2
No files found.
c++/src/capnp/dynamic.c++
View file @
c1f3e3ff
...
...
@@ -669,6 +669,165 @@ DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field, ui
KJ_UNREACHABLE
;
}
void
DynamicStruct
::
Builder
::
adopt
(
StructSchema
::
Field
field
,
Orphan
<
DynamicValue
>&&
orphan
)
{
KJ_REQUIRE
(
field
.
getContainingStruct
()
==
schema
,
"`field` is not a field of this struct."
);
setInUnion
(
field
);
auto
proto
=
field
.
getProto
();
switch
(
proto
.
which
())
{
case
schema
:
:
Field
::
NON_GROUP
:
{
auto
nonGroup
=
proto
.
getNonGroup
();
auto
type
=
nonGroup
.
getType
();
switch
(
type
.
which
())
{
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
(
field
,
orphan
.
getReader
());
return
;
case
schema
:
:
Type
::
TEXT
:
orphan
.
getReader
().
as
<
Text
>
();
// type check
break
;
case
schema
:
:
Type
::
DATA
:
orphan
.
getReader
().
as
<
Data
>
();
// type check
break
;
case
schema
:
:
Type
::
LIST
:
{
ListSchema
listType
=
ListSchema
::
of
(
type
.
getList
(),
field
.
getContainingStruct
());
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
LIST
&&
orphan
.
listSchema
==
listType
,
"Value type mismatch."
);
break
;
}
case
schema
:
:
Type
::
STRUCT
:
{
auto
structType
=
field
.
getContainingStruct
().
getDependency
(
type
.
getStruct
()).
asStruct
();
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
STRUCT
&&
orphan
.
structSchema
==
structType
,
"Value type mismatch."
);
break
;
}
case
schema
:
:
Type
::
OBJECT
:
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
STRUCT
||
orphan
.
getType
()
==
DynamicValue
::
LIST
||
orphan
.
getType
()
==
DynamicValue
::
OBJECT
,
"Value type mismatch."
);
break
;
case
schema
:
:
Type
::
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not yet implemented."
);
break
;
}
builder
.
adopt
(
nonGroup
.
getOffset
()
*
POINTERS
,
kj
::
mv
(
orphan
.
builder
));
return
;
}
case
schema
:
:
Field
::
GROUP
:
// Have to transfer fields.
auto
src
=
orphan
.
get
().
as
<
DynamicStruct
>
();
auto
dst
=
init
(
field
).
as
<
DynamicStruct
>
();
KJ_REQUIRE
(
orphan
.
getType
()
==
DynamicValue
::
STRUCT
&&
orphan
.
structSchema
==
dst
.
getSchema
(),
"Value type mismatch."
);
KJ_IF_MAYBE
(
unionField
,
src
.
which
())
{
dst
.
adopt
(
*
unionField
,
src
.
disown
(
*
unionField
));
}
for
(
auto
field
:
src
.
schema
.
getNonUnionFields
())
{
if
(
src
.
has
(
field
))
{
dst
.
adopt
(
field
,
src
.
disown
(
field
));
}
}
return
;
}
KJ_UNREACHABLE
;
}
Orphan
<
DynamicValue
>
DynamicStruct
::
Builder
::
disown
(
StructSchema
::
Field
field
)
{
// We end up calling get(field) below, so we don't need to validate `field` here.
auto
proto
=
field
.
getProto
();
switch
(
proto
.
which
())
{
case
schema
:
:
Field
::
NON_GROUP
:
{
auto
nonGroup
=
proto
.
getNonGroup
();
switch
(
nonGroup
.
getType
().
which
())
{
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
>
(
get
(
field
),
_
::
OrphanBuilder
());
clear
(
field
);
return
kj
::
mv
(
result
);
}
case
schema
:
:
Type
::
TEXT
:
case
schema
:
:
Type
::
DATA
:
case
schema
:
:
Type
::
LIST
:
case
schema
:
:
Type
::
STRUCT
:
case
schema
:
:
Type
::
OBJECT
:
case
schema
:
:
Type
::
INTERFACE
:
{
auto
value
=
get
(
field
);
return
Orphan
<
DynamicValue
>
(
value
,
builder
.
disown
(
nonGroup
.
getOffset
()
*
POINTERS
));
}
}
KJ_UNREACHABLE
;
}
case
schema
:
:
Field
::
GROUP
:
{
// We have to allocate new space for the group, unfortunately.
auto
src
=
get
(
field
).
as
<
DynamicStruct
>
();
Orphan
<
DynamicStruct
>
result
=
Orphanage
::
getForMessageContaining
(
*
this
).
newOrphan
(
src
.
getSchema
());
auto
dst
=
result
.
get
();
KJ_IF_MAYBE
(
unionField
,
src
.
which
())
{
dst
.
adopt
(
*
unionField
,
src
.
disown
(
*
unionField
));
}
// We need to explicitly reset the union to its default field.
KJ_IF_MAYBE
(
unionField
,
src
.
schema
.
getFieldByDiscriminant
(
0
))
{
src
.
clear
(
*
unionField
);
}
for
(
auto
field
:
src
.
schema
.
getNonUnionFields
())
{
if
(
src
.
has
(
field
))
{
dst
.
adopt
(
field
,
src
.
disown
(
field
));
}
}
return
kj
::
mv
(
result
);
}
}
KJ_UNREACHABLE
;
}
void
DynamicStruct
::
Builder
::
clear
(
StructSchema
::
Field
field
)
{
KJ_REQUIRE
(
field
.
getContainingStruct
()
==
schema
,
"`field` is not a field of this struct."
);
...
...
@@ -723,9 +882,13 @@ void DynamicStruct::Builder::clear(StructSchema::Field field) {
case
schema
:
:
Field
::
GROUP
:
{
DynamicStruct
::
Builder
group
(
schema
.
getDependency
(
proto
.
getGroup
()).
asStruct
(),
builder
);
// We clear the union field with discriminant 0 rather than the one that is set because
// we want the union to end up with its default field active.
KJ_IF_MAYBE
(
unionField
,
group
.
schema
.
getFieldByDiscriminant
(
0
))
{
group
.
clear
(
*
unionField
);
}
for
(
auto
subField
:
group
.
schema
.
getNonUnionFields
())
{
group
.
clear
(
subField
);
}
...
...
@@ -848,6 +1011,12 @@ DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name) {
DynamicValue
::
Builder
DynamicStruct
::
Builder
::
init
(
kj
::
StringPtr
name
,
uint
size
)
{
return
init
(
schema
.
getFieldByName
(
name
),
size
);
}
void
DynamicStruct
::
Builder
::
adopt
(
kj
::
StringPtr
name
,
Orphan
<
DynamicValue
>&&
orphan
)
{
adopt
(
schema
.
getFieldByName
(
name
),
kj
::
mv
(
orphan
));
}
Orphan
<
DynamicValue
>
DynamicStruct
::
Builder
::
disown
(
kj
::
StringPtr
name
)
{
return
disown
(
schema
.
getFieldByName
(
name
));
}
void
DynamicStruct
::
Builder
::
clear
(
kj
::
StringPtr
name
)
{
clear
(
schema
.
getFieldByName
(
name
));
}
...
...
@@ -1447,11 +1616,14 @@ DynamicObject::Reader PointerHelpers<DynamicObject, Kind::UNKNOWN>::get(
StructReader
reader
,
WirePointerCount
index
)
{
return
DynamicObject
::
Reader
(
reader
.
getObjectField
(
index
,
nullptr
));
}
DynamicObject
::
Builder
PointerHelpers
<
DynamicObject
,
Kind
::
UNKNOWN
>::
get
(
StructBuilder
builder
,
WirePointerCount
index
)
{
return
DynamicObject
::
Builder
(
builder
.
getObjectField
(
index
,
nullptr
));
}
void
PointerHelpers
<
DynamicObject
,
Kind
::
UNKNOWN
>::
set
(
StructBuilder
builder
,
WirePointerCount
index
,
const
DynamicObject
::
Reader
&
value
)
{
builder
.
setObjectField
(
index
,
value
.
reader
);
}
}
// namespace _ (private)
...
...
@@ -1495,4 +1667,138 @@ DynamicList::Reader Orphan<DynamicList>::getReader() const {
schema
,
builder
.
asListReader
(
elementSizeFor
(
schema
.
whichElementType
())));
}
DynamicObject
::
Builder
Orphan
<
DynamicObject
>::
get
()
{
return
DynamicObject
::
Builder
(
builder
.
asObject
());
}
DynamicObject
::
Reader
Orphan
<
DynamicObject
>::
getReader
()
const
{
return
DynamicObject
::
Reader
(
builder
.
asObjectReader
());
}
DynamicStruct
::
Builder
Orphan
<
DynamicObject
>::
getAs
(
StructSchema
schema
)
{
return
DynamicStruct
::
Builder
(
schema
,
builder
.
asStruct
(
structSizeFromSchema
(
schema
)));
}
DynamicList
::
Builder
Orphan
<
DynamicObject
>::
getAs
(
ListSchema
schema
)
{
if
(
schema
.
whichElementType
()
==
schema
::
Type
::
STRUCT
)
{
return
DynamicList
::
Builder
(
schema
,
builder
.
asStructList
(
structSizeFromSchema
(
schema
.
getStructElementType
())));
}
else
{
return
DynamicList
::
Builder
(
schema
,
builder
.
asList
(
elementSizeFor
(
schema
.
whichElementType
())));
}
}
template
<>
Text
::
Builder
Orphan
<
DynamicObject
>::
getAs
<
Text
>
()
{
return
builder
.
asText
();
}
template
<>
Data
::
Builder
Orphan
<
DynamicObject
>::
getAs
<
Data
>
()
{
return
builder
.
asData
();
}
Orphan
<
DynamicStruct
>
Orphan
<
DynamicObject
>::
releaseAs
(
StructSchema
schema
)
{
getAs
(
schema
);
// type check
return
Orphan
<
DynamicStruct
>
(
schema
,
kj
::
mv
(
builder
));
}
Orphan
<
DynamicList
>
Orphan
<
DynamicObject
>::
releaseAs
(
ListSchema
schema
)
{
getAs
(
schema
);
// type check
return
Orphan
<
DynamicList
>
(
schema
,
kj
::
mv
(
builder
));
}
template
<>
Orphan
<
Text
>
Orphan
<
DynamicObject
>::
releaseAs
<
Text
>
()
{
getAs
<
Text
>
();
// type check
return
Orphan
<
Text
>
(
kj
::
mv
(
builder
));
}
template
<>
Orphan
<
Data
>
Orphan
<
DynamicObject
>::
releaseAs
<
Data
>
()
{
getAs
<
Data
>
();
// type check
return
Orphan
<
Data
>
(
kj
::
mv
(
builder
));
}
Orphan
<
DynamicValue
>::
Orphan
(
DynamicValue
::
Builder
value
,
_
::
OrphanBuilder
&&
builder
)
:
type
(
value
.
getType
()),
builder
(
kj
::
mv
(
builder
))
{
switch
(
type
)
{
case
DynamicValue
:
:
UNKNOWN
:
break
;
case
DynamicValue
:
:
VOID
:
voidValue
=
value
.
voidValue
;
break
;
case
DynamicValue
:
:
BOOL
:
boolValue
=
value
.
boolValue
;
break
;
case
DynamicValue
:
:
INT
:
intValue
=
value
.
intValue
;
break
;
case
DynamicValue
:
:
UINT
:
uintValue
=
value
.
uintValue
;
break
;
case
DynamicValue
:
:
FLOAT
:
floatValue
=
value
.
floatValue
;
break
;
case
DynamicValue
:
:
ENUM
:
enumValue
=
value
.
enumValue
;
break
;
case
DynamicValue
:
:
TEXT
:
break
;
case
DynamicValue
:
:
DATA
:
break
;
case
DynamicValue
:
:
LIST
:
listSchema
=
value
.
listValue
.
getSchema
();
break
;
case
DynamicValue
:
:
STRUCT
:
structSchema
=
value
.
structValue
.
getSchema
();
break
;
case
DynamicValue
:
:
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not implemented."
);
case
DynamicValue
:
:
OBJECT
:
break
;
}
}
DynamicValue
::
Builder
Orphan
<
DynamicValue
>::
get
()
{
switch
(
type
)
{
case
DynamicValue
:
:
UNKNOWN
:
return
nullptr
;
case
DynamicValue
:
:
VOID
:
return
voidValue
;
case
DynamicValue
:
:
BOOL
:
return
boolValue
;
case
DynamicValue
:
:
INT
:
return
intValue
;
case
DynamicValue
:
:
UINT
:
return
uintValue
;
case
DynamicValue
:
:
FLOAT
:
return
floatValue
;
case
DynamicValue
:
:
ENUM
:
return
enumValue
;
case
DynamicValue
:
:
TEXT
:
return
builder
.
asText
();
case
DynamicValue
:
:
DATA
:
return
builder
.
asData
();
case
DynamicValue
:
:
LIST
:
if
(
listSchema
.
whichElementType
()
==
schema
::
Type
::
STRUCT
)
{
return
DynamicList
::
Builder
(
listSchema
,
builder
.
asStructList
(
structSizeFromSchema
(
listSchema
.
getStructElementType
())));
}
else
{
return
DynamicList
::
Builder
(
listSchema
,
builder
.
asList
(
elementSizeFor
(
listSchema
.
whichElementType
())));
}
case
DynamicValue
:
:
STRUCT
:
return
DynamicStruct
::
Builder
(
structSchema
,
builder
.
asStruct
(
structSizeFromSchema
(
structSchema
)));
case
DynamicValue
:
:
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not implemented."
);
case
DynamicValue
:
:
OBJECT
:
return
DynamicObject
::
Builder
(
builder
.
asObject
());
}
KJ_UNREACHABLE
;
}
DynamicValue
::
Reader
Orphan
<
DynamicValue
>::
getReader
()
const
{
switch
(
type
)
{
case
DynamicValue
:
:
UNKNOWN
:
return
nullptr
;
case
DynamicValue
:
:
VOID
:
return
voidValue
;
case
DynamicValue
:
:
BOOL
:
return
boolValue
;
case
DynamicValue
:
:
INT
:
return
intValue
;
case
DynamicValue
:
:
UINT
:
return
uintValue
;
case
DynamicValue
:
:
FLOAT
:
return
floatValue
;
case
DynamicValue
:
:
ENUM
:
return
enumValue
;
case
DynamicValue
:
:
TEXT
:
return
builder
.
asTextReader
();
case
DynamicValue
:
:
DATA
:
return
builder
.
asDataReader
();
case
DynamicValue
:
:
LIST
:
return
DynamicList
::
Reader
(
listSchema
,
builder
.
asListReader
(
elementSizeFor
(
listSchema
.
whichElementType
())));
case
DynamicValue
:
:
STRUCT
:
return
DynamicStruct
::
Reader
(
structSchema
,
builder
.
asStructReader
(
structSizeFromSchema
(
structSchema
)));
case
DynamicValue
:
:
INTERFACE
:
KJ_FAIL_ASSERT
(
"Interfaces not implemented."
);
case
DynamicValue
:
:
OBJECT
:
return
DynamicObject
::
Reader
(
builder
.
asObjectReader
());
}
KJ_UNREACHABLE
;
}
template
<>
Orphan
<
DynamicStruct
>
Orphan
<
DynamicValue
>::
releaseAs
<
DynamicStruct
>
()
{
KJ_REQUIRE
(
type
==
DynamicValue
::
STRUCT
,
"Value type mismatch."
);
return
Orphan
<
DynamicStruct
>
(
structSchema
,
kj
::
mv
(
builder
));
}
template
<>
Orphan
<
DynamicList
>
Orphan
<
DynamicValue
>::
releaseAs
<
DynamicList
>
()
{
KJ_REQUIRE
(
type
==
DynamicValue
::
LIST
,
"Value type mismatch."
);
return
Orphan
<
DynamicList
>
(
listSchema
,
kj
::
mv
(
builder
));
}
}
// namespace capnp
c++/src/capnp/dynamic.h
View file @
c1f3e3ff
...
...
@@ -86,6 +86,7 @@ struct DynamicList {
class
Reader
;
class
Builder
;
};
template
<>
class
Orphan
<
DynamicValue
>
;
template
<
Kind
k
>
struct
DynamicTypeFor_
;
template
<>
struct
DynamicTypeFor_
<
Kind
::
ENUM
>
{
typedef
DynamicEnum
Type
;
};
...
...
@@ -152,7 +153,7 @@ public:
Reader
()
=
default
;
template
<
typename
T
>
inline
typename
T
::
Reader
as
()
const
{
return
AsImpl
<
T
>::
apply
(
*
this
);
}
typename
T
::
Reader
as
()
const
;
// Convert the object to the given struct, list, or blob type.
DynamicStruct
::
Reader
as
(
StructSchema
schema
)
const
;
...
...
@@ -163,18 +164,16 @@ private:
inline
Reader
(
_
::
ObjectReader
reader
)
:
reader
(
reader
)
{}
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
struct
DynamicStruct
;
friend
struct
DynamicList
;
template
<
typename
T
,
Kind
K
>
friend
struct
_
::
PointerHelpers
;
friend
class
DynamicObject
::
Builder
;
friend
class
Orphan
<
DynamicObject
>
;
friend
class
Orphan
<
DynamicValue
>
;
};
class
DynamicObject
::
Builder
:
kj
::
DisallowConstCopy
{
class
DynamicObject
::
Builder
:
public
kj
::
DisallowConstCopy
{
// Represents an "Object" field of unknown type.
//
// You can't actually do anything with a DynamicObject::Builder except read it. It can't be
...
...
@@ -197,6 +196,8 @@ private:
friend
struct
DynamicList
;
template
<
typename
T
,
Kind
K
>
friend
struct
_
::
PointerHelpers
;
friend
class
Orphan
<
DynamicObject
>
;
friend
class
Orphan
<
DynamicValue
>
;
};
// -------------------------------------------------------------------
...
...
@@ -261,6 +262,7 @@ private:
_
::
StructReader
reader
,
const
_
::
RawSchema
&
schema
);
friend
class
Orphanage
;
friend
class
Orphan
<
DynamicStruct
>
;
friend
class
Orphan
<
DynamicValue
>
;
};
class
DynamicStruct
::
Builder
{
...
...
@@ -302,6 +304,11 @@ public:
DynamicValue
::
Builder
init
(
StructSchema
::
Field
field
,
uint
size
);
// Init a struct, list, or blob field.
void
adopt
(
StructSchema
::
Field
field
,
Orphan
<
DynamicValue
>&&
orphan
);
Orphan
<
DynamicValue
>
disown
(
StructSchema
::
Field
field
);
// Adopt/disown. This works even for non-pointer fields: adopt() becomes equivalent to set()
// and disown() becomes like get() followed by clear().
void
clear
(
StructSchema
::
Field
field
);
// Clear a field, setting it to its default value. For pointer fields, this actually makes the
// field null.
...
...
@@ -326,6 +333,8 @@ public:
void
set
(
kj
::
StringPtr
name
,
std
::
initializer_list
<
DynamicValue
::
Reader
>
value
);
DynamicValue
::
Builder
init
(
kj
::
StringPtr
name
);
DynamicValue
::
Builder
init
(
kj
::
StringPtr
name
,
uint
size
);
void
adopt
(
kj
::
StringPtr
name
,
Orphan
<
DynamicValue
>&&
orphan
);
Orphan
<
DynamicValue
>
disown
(
kj
::
StringPtr
name
);
void
clear
(
kj
::
StringPtr
name
);
DynamicStruct
::
Builder
getObject
(
kj
::
StringPtr
name
,
StructSchema
type
);
DynamicList
::
Builder
getObject
(
kj
::
StringPtr
name
,
ListSchema
type
);
...
...
@@ -361,6 +370,8 @@ private:
friend
struct
::
capnp
::
ToDynamic_
;
friend
class
Orphanage
;
friend
class
Orphan
<
DynamicStruct
>
;
friend
class
Orphan
<
DynamicObject
>
;
friend
class
Orphan
<
DynamicValue
>
;
};
// -------------------------------------------------------------------
...
...
@@ -403,6 +414,7 @@ private:
friend
struct
::
capnp
::
ToDynamic_
;
friend
class
Orphanage
;
friend
class
Orphan
<
DynamicList
>
;
friend
class
Orphan
<
DynamicValue
>
;
};
class
DynamicList
::
Builder
{
...
...
@@ -450,6 +462,8 @@ private:
template
<
typename
T
,
Kind
k
>
friend
struct
_
::
OrphanGetImpl
;
friend
class
Orphan
<
DynamicList
>
;
friend
class
Orphan
<
DynamicObject
>
;
friend
class
Orphan
<
DynamicValue
>
;
};
// -------------------------------------------------------------------
...
...
@@ -611,6 +625,8 @@ 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
Orphan
<
DynamicValue
>
;
};
kj
::
StringTree
KJ_STRINGIFY
(
const
DynamicValue
::
Reader
&
value
);
...
...
@@ -637,8 +653,14 @@ public:
DynamicStruct
::
Builder
get
();
DynamicStruct
::
Reader
getReader
()
const
;
inline
bool
operator
==
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
template
<
typename
T
>
Orphan
<
T
>
releaseAs
();
// Like DynamicStruct::Builder::as(), but coerces the Orphan type. Since Orphans are move-only,
// 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
:
StructSchema
schema
;
...
...
@@ -651,6 +673,8 @@ private:
friend
struct
_
::
PointerHelpers
;
friend
struct
DynamicList
;
friend
class
Orphanage
;
friend
class
Orphan
<
DynamicObject
>
;
friend
class
Orphan
<
DynamicValue
>
;
};
template
<>
...
...
@@ -664,8 +688,14 @@ public:
DynamicList
::
Builder
get
();
DynamicList
::
Reader
getReader
()
const
;
inline
bool
operator
==
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
template
<
typename
T
>
Orphan
<
T
>
releaseAs
();
// Like DynamicList::Builder::as(), but coerces the Orphan type. Since Orphans are move-only,
// 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
:
ListSchema
schema
;
...
...
@@ -678,8 +708,157 @@ private:
friend
struct
_
::
PointerHelpers
;
friend
struct
DynamicList
;
friend
class
Orphanage
;
friend
class
Orphan
<
DynamicObject
>
;
friend
class
Orphan
<
DynamicValue
>
;
};
template
<>
class
Orphan
<
DynamicObject
>
{
public
:
Orphan
()
=
default
;
KJ_DISALLOW_COPY
(
Orphan
);
Orphan
(
Orphan
&&
)
=
default
;
Orphan
&
operator
=
(
Orphan
&&
)
=
default
;
DynamicObject
::
Builder
get
();
DynamicObject
::
Reader
getReader
()
const
;
template
<
typename
T
>
BuilderFor
<
T
>
getAs
();
// Coerce the object to the given type and return a builder for that type. This may relocate
// the object if it was originally created with a previous version of the schema and the sizes
// don't match.
//
// Notice that DynamicObject::Builder does not have an "as<T>()" method, which is why this is
// needed.
template
<
typename
T
>
Orphan
<
T
>
releaseAs
();
// Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only,
// the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
// transferred to the returned Orphan<T>.
DynamicStruct
::
Builder
getAs
(
StructSchema
schema
);
DynamicList
::
Builder
getAs
(
ListSchema
schema
);
// Dynamic versions of 'getAs()'.
Orphan
<
DynamicStruct
>
releaseAs
(
StructSchema
schema
);
Orphan
<
DynamicList
>
releaseAs
(
ListSchema
schema
);
// Dynamic versions of 'releaseAs()'.
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
builder
!=
nullptr
;
}
private
:
_
::
OrphanBuilder
builder
;
explicit
Orphan
(
_
::
OrphanBuilder
&&
builder
)
:
builder
(
kj
::
mv
(
builder
))
{}
template
<
typename
,
Kind
>
friend
struct
_
::
PointerHelpers
;
friend
class
Orphan
<
DynamicValue
>
;
};
template
<>
class
Orphan
<
DynamicValue
>
{
public
:
Orphan
()
=
default
;
KJ_DISALLOW_COPY
(
Orphan
);
Orphan
(
Orphan
&&
)
=
default
;
template
<
typename
T
>
Orphan
(
Orphan
<
T
>&&
);
Orphan
&
operator
=
(
Orphan
&&
)
=
default
;
inline
DynamicValue
::
Type
getType
()
{
return
type
;
}
DynamicValue
::
Builder
get
();
DynamicValue
::
Reader
getReader
()
const
;
template
<
typename
T
>
Orphan
<
T
>
releaseAs
();
// Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only,
// 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
{
Void
voidValue
;
bool
boolValue
;
int64_t
intValue
;
uint64_t
uintValue
;
double
floatValue
;
DynamicEnum
enumValue
;
StructSchema
structSchema
;
ListSchema
listSchema
;
};
_
::
OrphanBuilder
builder
;
// Only used if `type` is a pointer type.
Orphan
(
DynamicValue
::
Builder
value
,
_
::
OrphanBuilder
&&
builder
);
Orphan
(
DynamicValue
::
Type
type
,
_
::
OrphanBuilder
&&
builder
)
:
type
(
type
),
builder
(
kj
::
mv
(
builder
))
{}
Orphan
(
StructSchema
structSchema
,
_
::
OrphanBuilder
&&
builder
)
:
type
(
DynamicValue
::
STRUCT
),
structSchema
(
structSchema
),
builder
(
kj
::
mv
(
builder
))
{}
Orphan
(
ListSchema
listSchema
,
_
::
OrphanBuilder
&&
builder
)
:
type
(
DynamicValue
::
LIST
),
listSchema
(
listSchema
),
builder
(
kj
::
mv
(
builder
))
{}
template
<
typename
,
Kind
>
friend
struct
_
::
PointerHelpers
;
friend
struct
DynamicStruct
;
friend
struct
DynamicList
;
friend
class
Orphanage
;
};
template
<
typename
T
>
BuilderFor
<
T
>
Orphan
<
DynamicObject
>::
getAs
()
{
return
getAs
(
Schema
::
from
<
T
>
()).
template
as
<
T
>
();
}
template
<>
Text
::
Builder
Orphan
<
DynamicObject
>::
getAs
<
Text
>
();
template
<>
Data
::
Builder
Orphan
<
DynamicObject
>::
getAs
<
Data
>
();
template
<
typename
T
>
Orphan
<
T
>
Orphan
<
DynamicObject
>::
releaseAs
()
{
return
releaseAs
(
Schema
::
from
<
T
>
()).
template
releaseAs
<
T
>
();
}
template
<>
Orphan
<
Text
>
Orphan
<
DynamicObject
>::
releaseAs
<
Text
>
();
template
<>
Orphan
<
Data
>
Orphan
<
DynamicObject
>::
releaseAs
<
Data
>
();
template
<
typename
T
>
Orphan
<
DynamicValue
>::
Orphan
(
Orphan
<
T
>&&
other
)
:
Orphan
(
other
.
get
(),
kj
::
mv
(
other
.
builder
))
{}
template
<
typename
T
>
Orphan
<
T
>
Orphan
<
DynamicStruct
>::
releaseAs
()
{
get
().
as
<
T
>
();
// type check
return
Orphan
<
T
>
(
kj
::
mv
(
builder
));
}
template
<
typename
T
>
Orphan
<
T
>
Orphan
<
DynamicList
>::
releaseAs
()
{
get
().
as
<
T
>
();
// type check
return
Orphan
<
T
>
(
kj
::
mv
(
builder
));
}
template
<
typename
T
>
Orphan
<
T
>
Orphan
<
DynamicValue
>::
releaseAs
()
{
get
().
as
<
T
>
();
// type check
return
Orphan
<
T
>
(
kj
::
mv
(
builder
));
}
template
<>
Orphan
<
DynamicStruct
>
Orphan
<
DynamicValue
>::
releaseAs
<
DynamicStruct
>
();
template
<>
Orphan
<
DynamicList
>
Orphan
<
DynamicValue
>::
releaseAs
<
DynamicList
>
();
template
<>
struct
Orphanage
::
GetInnerBuilder
<
DynamicStruct
,
Kind
::
UNKNOWN
>
{
static
inline
_
::
StructBuilder
apply
(
DynamicStruct
::
Builder
&
t
)
{
...
...
@@ -768,10 +947,17 @@ struct PointerHelpers<DynamicList, Kind::UNKNOWN> {
template
<>
struct
PointerHelpers
<
DynamicObject
,
Kind
::
UNKNOWN
>
{
// DynamicObject can only be used with get().
static
DynamicObject
::
Reader
get
(
StructReader
reader
,
WirePointerCount
index
);
static
DynamicObject
::
Builder
get
(
StructBuilder
builder
,
WirePointerCount
index
);
static
void
set
(
StructBuilder
builder
,
WirePointerCount
index
,
const
DynamicObject
::
Reader
&
value
);
static
inline
void
adopt
(
StructBuilder
builder
,
WirePointerCount
index
,
Orphan
<
DynamicObject
>&&
value
)
{
builder
.
adopt
(
index
,
kj
::
mv
(
value
.
builder
));
}
static
inline
Orphan
<
DynamicObject
>
disown
(
StructBuilder
builder
,
WirePointerCount
index
)
{
return
Orphan
<
DynamicObject
>
(
builder
.
disown
(
index
));
}
};
}
// namespace _ (private)
...
...
@@ -939,18 +1125,9 @@ struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
// -------------------------------------------------------------------
template
<
typename
T
>
struct
DynamicObject
::
Reader
::
AsImpl
<
T
,
Kind
::
STRUCT
>
{
static
T
apply
(
DynamicObject
::
Reader
value
)
{
return
value
.
as
(
Schema
::
from
<
T
>
()).
template
as
<
T
>
();
}
};
template
<
typename
T
>
struct
DynamicObject
::
Reader
::
AsImpl
<
T
,
Kind
::
LIST
>
{
static
T
apply
(
DynamicObject
::
Reader
value
)
{
return
value
.
as
(
Schema
::
from
<
T
>
()).
template
as
<
T
>
();
}
};
inline
typename
T
::
Reader
DynamicObject
::
Reader
::
as
()
const
{
return
as
(
Schema
::
from
<
T
>
()).
template
as
<
T
>
();
}
// -------------------------------------------------------------------
...
...
c++/src/capnp/layout.c++
View file @
c1f3e3ff
...
...
@@ -1619,10 +1619,14 @@ struct WireHelpers {
}
static
OrphanBuilder
disown
(
SegmentBuilder
*
segment
,
WirePointer
*
ref
)
{
OrphanBuilder
result
(
ref
,
segment
,
ref
->
kind
()
==
WirePointer
::
FAR
?
nullptr
:
ref
->
target
());
memset
(
ref
,
0
,
sizeof
(
*
ref
));
return
result
;
if
(
ref
->
isNull
())
{
return
OrphanBuilder
();
}
else
{
OrphanBuilder
result
(
ref
,
segment
,
ref
->
kind
()
==
WirePointer
::
FAR
?
nullptr
:
ref
->
target
());
memset
(
ref
,
0
,
sizeof
(
*
ref
));
return
result
;
}
}
// -----------------------------------------------------------------
...
...
@@ -2744,8 +2748,14 @@ ObjectReader OrphanBuilder::asObjectReader() const {
}
void
OrphanBuilder
::
euthanize
()
{
WireHelpers
::
zeroObject
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
&
tag
),
location
);
memset
(
&
tag
,
0
,
sizeof
(
tag
));
// Use memset to comply with aliasing rules.
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
;
}
...
...
c++/src/capnp/layout.h
View file @
c1f3e3ff
...
...
@@ -751,7 +751,7 @@ public:
inline
OrphanBuilder
()
:
segment
(
nullptr
),
location
(
nullptr
)
{
memset
(
&
tag
,
0
,
sizeof
(
tag
));
}
OrphanBuilder
(
const
OrphanBuilder
&
other
)
=
delete
;
inline
OrphanBuilder
(
OrphanBuilder
&&
other
);
inline
~
OrphanBuilder
();
inline
~
OrphanBuilder
()
noexcept
(
false
)
;
static
OrphanBuilder
initStruct
(
BuilderArena
*
arena
,
StructSize
size
);
static
OrphanBuilder
initList
(
BuilderArena
*
arena
,
ElementCount
elementCount
,
...
...
@@ -769,8 +769,8 @@ public:
OrphanBuilder
&
operator
=
(
const
OrphanBuilder
&
other
)
=
delete
;
inline
OrphanBuilder
&
operator
=
(
OrphanBuilder
&&
other
);
inline
bool
operator
==
(
decltype
(
nullptr
))
{
return
location
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
{
return
location
!=
nullptr
;
}
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
segment
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
segment
!=
nullptr
;
}
StructBuilder
asStruct
(
StructSize
size
);
// Interpret as a struct, or throw an exception if not a struct.
...
...
@@ -1041,7 +1041,7 @@ inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other)
other
.
location
=
nullptr
;
}
inline
OrphanBuilder
::~
OrphanBuilder
()
{
inline
OrphanBuilder
::~
OrphanBuilder
()
noexcept
(
false
)
{
if
(
segment
!=
nullptr
)
euthanize
();
}
...
...
c++/src/capnp/orphan-test.c++
View file @
c1f3e3ff
...
...
@@ -437,6 +437,157 @@ TEST(Orphans, OrphanageDynamicListCopy) {
checkList
(
root2
.
getObjectField
<
List
<
uint32_t
>>
(),
{
12u
,
34u
,
56u
});
}
TEST
(
Orphans
,
DynamicStructAs
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
initTestMessage
(
root
.
initObjectField
<
TestAllTypes
>
());
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
DynamicValue
>
orphan
=
root
.
disownObjectField
<
DynamicStruct
>
(
Schema
::
from
<
TestAllTypes
>
());
EXPECT_FALSE
(
orphan
==
nullptr
);
checkTestMessage
(
orphan
.
getReader
().
as
<
TestAllTypes
>
());
checkTestMessage
(
orphan
.
get
().
as
<
TestAllTypes
>
());
{
Orphan
<
DynamicStruct
>
structOrphan
=
orphan
.
releaseAs
<
DynamicStruct
>
();
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_FALSE
(
structOrphan
==
nullptr
);
checkDynamicTestMessage
(
structOrphan
.
getReader
());
checkDynamicTestMessage
(
structOrphan
.
get
());
checkTestMessage
(
structOrphan
.
getReader
().
as
<
TestAllTypes
>
());
checkTestMessage
(
structOrphan
.
get
().
as
<
TestAllTypes
>
());
{
Orphan
<
TestAllTypes
>
typedOrphan
=
structOrphan
.
releaseAs
<
TestAllTypes
>
();
EXPECT_TRUE
(
structOrphan
==
nullptr
);
EXPECT_FALSE
(
typedOrphan
==
nullptr
);
checkTestMessage
(
typedOrphan
.
getReader
());
checkTestMessage
(
typedOrphan
.
get
());
orphan
=
kj
::
mv
(
typedOrphan
);
EXPECT_FALSE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
typedOrphan
==
nullptr
);
}
}
{
Orphan
<
TestAllTypes
>
typedOrphan
=
orphan
.
releaseAs
<
TestAllTypes
>
();
checkTestMessage
(
typedOrphan
.
getReader
());
checkTestMessage
(
typedOrphan
.
get
());
}
}
TEST
(
Orphans
,
DynamicListAs
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
root
.
setObjectField
<
List
<
uint32_t
>>
({
12
,
34
,
56
});
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
DynamicValue
>
orphan
=
root
.
disownObjectField
<
DynamicList
>
(
Schema
::
from
<
List
<
uint32_t
>>
());
EXPECT_FALSE
(
orphan
==
nullptr
);
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_FALSE
(
listOrphan
==
nullptr
);
checkList
<
uint32_t
>
(
listOrphan
.
getReader
(),
{
12
,
34
,
56
});
checkList
<
uint32_t
>
(
listOrphan
.
get
(),
{
12
,
34
,
56
});
checkList
(
listOrphan
.
getReader
().
as
<
List
<
uint32_t
>>
(),
{
12
,
34
,
56
});
checkList
(
listOrphan
.
get
().
as
<
List
<
uint32_t
>>
(),
{
12
,
34
,
56
});
{
Orphan
<
List
<
uint32_t
>>
typedOrphan
=
listOrphan
.
releaseAs
<
List
<
uint32_t
>>
();
EXPECT_TRUE
(
listOrphan
==
nullptr
);
EXPECT_FALSE
(
typedOrphan
==
nullptr
);
checkList
(
typedOrphan
.
getReader
(),
{
12
,
34
,
56
});
checkList
(
typedOrphan
.
get
(),
{
12
,
34
,
56
});
orphan
=
kj
::
mv
(
typedOrphan
);
EXPECT_FALSE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
typedOrphan
==
nullptr
);
}
}
{
Orphan
<
List
<
uint32_t
>>
typedOrphan
=
orphan
.
releaseAs
<
List
<
uint32_t
>>
();
checkList
(
typedOrphan
.
getReader
(),
{
12
,
34
,
56
});
checkList
(
typedOrphan
.
get
(),
{
12
,
34
,
56
});
}
}
TEST
(
Orphans
,
DynamicObject
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
initTestMessage
(
root
.
initObjectField
<
TestAllTypes
>
());
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
DynamicValue
>
orphan
=
root
.
disownObjectField
<
DynamicObject
>
();
EXPECT_FALSE
(
orphan
==
nullptr
);
checkTestMessage
(
orphan
.
getReader
().
as
<
DynamicObject
>
().
as
<
TestAllTypes
>
());
Orphan
<
DynamicObject
>
objectOrphan
=
orphan
.
releaseAs
<
DynamicObject
>
();
checkTestMessage
(
objectOrphan
.
getAs
<
TestAllTypes
>
());
checkDynamicTestMessage
(
objectOrphan
.
getAs
(
Schema
::
from
<
TestAllTypes
>
()));
}
TEST
(
Orphans
,
DynamicDisown
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
initTestMessage
(
root
);
Orphan
<
TestAllTypes
>
dstOrphan
=
Orphanage
::
getForMessageContaining
(
root
).
newOrphan
<
TestAllTypes
>
();
auto
dst
=
dstOrphan
.
get
();
DynamicStruct
::
Builder
dynamic
=
root
;
DynamicStruct
::
Builder
dynamicDst
=
dst
;
for
(
auto
field
:
dynamic
.
getSchema
().
getFields
())
{
dynamicDst
.
adopt
(
field
,
dynamic
.
disown
(
field
));
}
checkTestMessageAllZero
(
root
.
asReader
());
checkTestMessage
(
dst
.
asReader
());
for
(
auto
field
:
dynamic
.
getSchema
().
getFields
())
{
dynamicDst
.
adopt
(
field
,
dynamic
.
disown
(
field
));
}
checkTestMessageAllZero
(
root
.
asReader
());
checkTestMessageAllZero
(
dst
.
asReader
());
}
TEST
(
Orphans
,
DynamicDisownGroup
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestGroups
>
();
auto
bar
=
root
.
initGroups
().
initBar
();
bar
.
setCorge
(
123
);
bar
.
setGrault
(
"foo"
);
bar
.
setGarply
(
9876543210987ll
);
Orphan
<
test
::
TestGroups
>
dstOrphan
=
Orphanage
::
getForMessageContaining
(
root
).
newOrphan
<
test
::
TestGroups
>
();
auto
dst
=
dstOrphan
.
get
();
toDynamic
(
dst
).
adopt
(
"groups"
,
toDynamic
(
root
).
disown
(
"groups"
));
EXPECT_EQ
(
test
::
TestGroups
::
Groups
::
FOO
,
root
.
getGroups
().
which
());
EXPECT_EQ
(
test
::
TestGroups
::
Groups
::
BAR
,
dst
.
getGroups
().
which
());
auto
newBar
=
dst
.
getGroups
().
getBar
();
EXPECT_EQ
(
123
,
newBar
.
getCorge
());
EXPECT_EQ
(
"foo"
,
newBar
.
getGrault
());
EXPECT_EQ
(
9876543210987ll
,
newBar
.
getGarply
());
}
TEST
(
Orphans
,
OrphanageFromBuilder
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
...
...
@@ -619,6 +770,23 @@ TEST(Orphans, DataZerodAfterUse) {
EXPECT_EQ
(
"foo"
,
root
.
getTextField
());
}
TEST
(
Orphans
,
FarPointer
)
{
MallocMessageBuilder
builder
(
0
,
AllocationStrategy
::
FIXED_SIZE
);
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
auto
child
=
root
.
initStructField
();
initTestMessage
(
child
);
auto
orphan
=
root
.
disownStructField
();
EXPECT_FALSE
(
root
.
hasStructField
());
EXPECT_TRUE
(
orphan
!=
nullptr
);
EXPECT_FALSE
(
orphan
==
nullptr
);
KJ_DBG
(
orphan
!=
nullptr
,
orphan
==
nullptr
);
checkTestMessage
(
orphan
.
getReader
());
checkTestMessage
(
orphan
.
get
());
}
}
// namespace
}
// namespace _ (private)
}
// namespace capnp
c++/src/capnp/orphan.h
View file @
c1f3e3ff
...
...
@@ -55,8 +55,8 @@ public:
inline
typename
T
::
Builder
get
();
inline
typename
T
::
Reader
getReader
()
const
;
inline
bool
operator
==
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
{
return
builder
=
=
nullptr
;
}
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
builder
!
=
nullptr
;
}
private
:
_
::
OrphanBuilder
builder
;
...
...
@@ -67,6 +67,8 @@ private:
friend
struct
_
::
PointerHelpers
;
template
<
typename
,
Kind
>
friend
struct
List
;
template
<
typename
U
>
friend
class
Orphan
;
friend
class
Orphanage
;
};
...
...
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