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
8536e962
Commit
8536e962
authored
Jul 08, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement orphans -- the ability to transfer ownership of sub-objects.
parent
0360b3d1
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1670 additions
and
200 deletions
+1670
-200
Makefile.am
c++/Makefile.am
+2
-0
blob.h
c++/src/capnp/blob.h
+1
-1
common.h
c++/src/capnp/common.h
+78
-0
dynamic.c++
c++/src/capnp/dynamic.c++
+31
-0
dynamic.h
c++/src/capnp/dynamic.h
+137
-4
generated-header-support.h
c++/src/capnp/generated-header-support.h
+19
-0
layout.c++
c++/src/capnp/layout.c++
+402
-37
layout.h
c++/src/capnp/layout.h
+162
-33
list.h
c++/src/capnp/list.h
+47
-80
message.c++
c++/src/capnp/message.c++
+8
-0
message.h
c++/src/capnp/message.h
+2
-0
orphan-test.c++
c++/src/capnp/orphan-test.c++
+421
-0
orphan.h
c++/src/capnp/orphan.h
+262
-0
test-util.c++
c++/src/capnp/test-util.c++
+0
-45
test-util.h
c++/src/capnp/test-util.h
+51
-0
c++-header.mustache
compiler/src/c++-header.mustache
+47
-0
No files found.
c++/Makefile.am
View file @
8536e962
...
...
@@ -119,6 +119,7 @@ includecapnp_HEADERS = \
src/capnp/blob.h
\
src/capnp/endian.h
\
src/capnp/layout.h
\
src/capnp/orphan.h
\
src/capnp/list.h
\
src/capnp/message.h
\
src/capnp/schema.h
\
...
...
@@ -203,6 +204,7 @@ capnp_test_SOURCES = \
src/capnp/dynamic-test.c++
\
src/capnp/stringify-test.c++
\
src/capnp/encoding-test.c++
\
src/capnp/orphan-test.c++
\
src/capnp/serialize-test.c++
\
src/capnp/serialize-packed-test.c++
\
src/capnp/test-util.c++
\
...
...
c++/src/capnp/blob.h
View file @
8536e962
...
...
@@ -104,7 +104,7 @@ public:
KJ_IREQUIRE
(
value
[
size
]
==
'\0'
,
"StringPtr must be NUL-terminated."
);
}
inline
Reader
asReader
()
const
{
return
Reader
(
content
.
begin
(),
content
.
size
());
}
inline
Reader
asReader
()
const
{
return
Reader
(
content
.
begin
(),
content
.
size
()
-
1
);
}
inline
operator
kj
::
ArrayPtr
<
char
>
();
inline
kj
::
ArrayPtr
<
char
>
asArray
();
...
...
c++/src/capnp/common.h
View file @
8536e962
...
...
@@ -43,6 +43,84 @@ enum class Void {
template
<
typename
T
>
inline
T
&
operator
<<
(
T
&
os
,
Void
)
{
return
os
<<
"void"
;
}
struct
Text
;
struct
Data
;
enum
class
Kind
:
uint8_t
{
PRIMITIVE
,
BLOB
,
ENUM
,
STRUCT
,
UNION
,
INTERFACE
,
LIST
,
UNKNOWN
};
namespace
_
{
// private
template
<
typename
T
>
struct
Kind_
{
static
constexpr
Kind
kind
=
Kind
::
UNKNOWN
;
};
template
<>
struct
Kind_
<
Void
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
bool
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
int8_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
int16_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
int32_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
int64_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
uint8_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
uint16_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
uint32_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
uint64_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
float
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
double
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
Text
>
{
static
constexpr
Kind
kind
=
Kind
::
BLOB
;
};
template
<>
struct
Kind_
<
Data
>
{
static
constexpr
Kind
kind
=
Kind
::
BLOB
;
};
}
// namespace _ (private)
template
<
typename
T
>
inline
constexpr
Kind
kind
()
{
return
_
::
Kind_
<
T
>::
kind
;
}
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
List
;
namespace
_
{
// private
template
<
typename
T
,
Kind
k
>
struct
Kind_
<
List
<
T
,
k
>>
{
static
constexpr
Kind
kind
=
Kind
::
LIST
;
};
}
// namespace _ (private)
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
ReaderFor_
{
typedef
typename
T
::
Reader
Type
;
};
template
<
typename
T
>
struct
ReaderFor_
<
T
,
Kind
::
PRIMITIVE
>
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
ReaderFor_
<
T
,
Kind
::
ENUM
>
{
typedef
T
Type
;
};
template
<
typename
T
>
using
ReaderFor
=
typename
ReaderFor_
<
T
>::
Type
;
// The type returned by List<T>::Reader::operator[].
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
BuilderFor_
{
typedef
typename
T
::
Builder
Type
;
};
template
<
typename
T
>
struct
BuilderFor_
<
T
,
Kind
::
PRIMITIVE
>
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
BuilderFor_
<
T
,
Kind
::
ENUM
>
{
typedef
T
Type
;
};
template
<
typename
T
>
using
BuilderFor
=
typename
BuilderFor_
<
T
>::
Type
;
// The type returned by List<T>::Builder::operator[].
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
TypeIfEnum_
;
template
<
typename
T
>
struct
TypeIfEnum_
<
T
,
Kind
::
ENUM
>
{
typedef
T
Type
;
};
template
<
typename
T
>
using
TypeIfEnum
=
typename
TypeIfEnum_
<
kj
::
Decay
<
T
>>::
Type
;
template
<
typename
T
>
using
FromReader
=
typename
kj
::
Decay
<
T
>::
Reads
;
// FromReader<MyType::Reader> = MyType (for any Cap'n Proto type).
template
<
typename
T
>
using
FromBuilder
=
typename
kj
::
Decay
<
T
>::
Builds
;
// FromBuilder<MyType::Builder> = MyType (for any Cap'n Proto type).
namespace
_
{
// private
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
PointerHelpers
;
}
// namespace _ (private)
// =======================================================================================
// Raw memory types and measures
...
...
c++/src/capnp/dynamic.c++
View file @
8536e962
...
...
@@ -1557,4 +1557,35 @@ DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init(
}
// namespace _ (private)
// -------------------------------------------------------------------
Orphan
<
DynamicStruct
>
Orphanage
::
newOrphan
(
StructSchema
schema
)
{
return
Orphan
<
DynamicStruct
>
(
schema
,
_
::
OrphanBuilder
::
initStruct
(
arena
,
structSizeFromSchema
(
schema
)));
}
Orphan
<
DynamicList
>
Orphanage
::
newOrphan
(
ListSchema
schema
,
uint
size
)
{
if
(
schema
.
whichElementType
()
==
schema
::
Type
::
Body
::
STRUCT_TYPE
)
{
return
Orphan
<
DynamicList
>
(
schema
,
_
::
OrphanBuilder
::
initStructList
(
arena
,
size
*
ELEMENTS
,
structSizeFromSchema
(
schema
.
getStructElementType
())));
}
else
{
return
Orphan
<
DynamicList
>
(
schema
,
_
::
OrphanBuilder
::
initList
(
arena
,
size
*
ELEMENTS
,
elementSizeFor
(
schema
.
whichElementType
())));
}
}
DynamicStruct
::
Builder
Orphan
<
DynamicStruct
>::
get
()
{
return
DynamicStruct
::
Builder
(
schema
,
builder
.
asStruct
(
structSizeFromSchema
(
schema
)));
}
DynamicList
::
Builder
Orphan
<
DynamicList
>::
get
()
{
if
(
schema
.
whichElementType
()
==
schema
::
Type
::
Body
::
STRUCT_TYPE
)
{
return
DynamicList
::
Builder
(
schema
,
builder
.
asStructList
(
structSizeFromSchema
(
schema
.
getStructElementType
())));
}
else
{
return
DynamicList
::
Builder
(
schema
,
builder
.
asList
(
elementSizeFor
(
schema
.
whichElementType
())));
}
}
}
// namespace capnp
c++/src/capnp/dynamic.h
View file @
8536e962
...
...
@@ -104,6 +104,14 @@ BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value);
template
<
typename
T
>
DynamicTypeFor
<
TypeIfEnum
<
T
>>
toDynamic
(
T
&&
value
);
template
<
typename
T
>
struct
EnableIfNotDynamic_
{
typedef
T
Type
;
};
template
<>
struct
EnableIfNotDynamic_
<
DynamicUnion
>
{};
template
<>
struct
EnableIfNotDynamic_
<
DynamicStruct
>
{};
template
<>
struct
EnableIfNotDynamic_
<
DynamicList
>
{};
template
<>
struct
EnableIfNotDynamic_
<
DynamicValue
>
{};
template
<
typename
T
>
using
EnableIfNotDynamic
=
typename
EnableIfNotDynamic_
<
T
>::
Type
;
// -------------------------------------------------------------------
class
DynamicEnum
{
...
...
@@ -176,6 +184,8 @@ private:
class
DynamicUnion
::
Reader
{
public
:
typedef
DynamicUnion
Reads
;
Reader
()
=
default
;
inline
StructSchema
::
Union
getSchema
()
const
{
return
schema
;
}
...
...
@@ -203,6 +213,8 @@ private:
class
DynamicUnion
::
Builder
{
public
:
typedef
DynamicUnion
Builds
;
Builder
()
=
default
;
inline
StructSchema
::
Union
getSchema
()
const
{
return
schema
;
}
...
...
@@ -255,9 +267,11 @@ private:
class
DynamicStruct
::
Reader
{
public
:
typedef
DynamicStruct
Reads
;
Reader
()
=
default
;
template
<
typename
T
,
typename
=
FromReader
<
T
>>
template
<
typename
T
,
typename
=
EnableIfNotDynamic
<
FromReader
<
T
>
>>
inline
Reader
(
T
&&
value
)
:
Reader
(
toDynamic
(
value
))
{}
template
<
typename
T
>
...
...
@@ -299,13 +313,16 @@ private:
friend
struct
::
capnp
::
ToDynamic_
;
friend
kj
::
String
_
::
structString
(
_
::
StructReader
reader
,
const
_
::
RawSchema
&
schema
);
friend
class
Orphanage
;
};
class
DynamicStruct
::
Builder
{
public
:
typedef
DynamicStruct
Builds
;
Builder
()
=
default
;
template
<
typename
T
,
typename
=
FromBuilder
<
T
>>
template
<
typename
T
,
typename
=
EnableIfNotDynamic
<
FromBuilder
<
T
>
>>
inline
Builder
(
T
&&
value
)
:
Builder
(
toDynamic
(
value
))
{}
template
<
typename
T
>
...
...
@@ -329,6 +346,8 @@ public:
DynamicValue
::
Builder
init
(
StructSchema
::
Member
member
,
uint
size
);
// Init a struct, list, or blob field.
// TODO(someday): Implement adopt() and disown().
DynamicStruct
::
Builder
getObject
(
StructSchema
::
Member
member
,
StructSchema
type
);
DynamicList
::
Builder
getObject
(
StructSchema
::
Member
member
,
ListSchema
type
);
Text
::
Builder
getObjectAsText
(
StructSchema
::
Member
member
);
...
...
@@ -402,15 +421,19 @@ private:
friend
class
MessageBuilder
;
template
<
typename
T
,
::
capnp
::
Kind
k
>
friend
struct
::
capnp
::
ToDynamic_
;
friend
class
Orphanage
;
friend
class
Orphan
<
DynamicStruct
>
;
};
// -------------------------------------------------------------------
class
DynamicList
::
Reader
{
public
:
typedef
DynamicList
Reads
;
Reader
()
=
default
;
template
<
typename
T
,
typename
=
FromReader
<
T
>>
template
<
typename
T
,
typename
=
EnableIfNotDynamic
<
FromReader
<
T
>
>>
inline
Reader
(
T
&&
value
)
:
Reader
(
toDynamic
(
value
))
{}
template
<
typename
T
>
...
...
@@ -440,13 +463,16 @@ private:
friend
class
DynamicList
::
Builder
;
template
<
typename
T
,
::
capnp
::
Kind
k
>
friend
struct
::
capnp
::
ToDynamic_
;
friend
class
Orphanage
;
};
class
DynamicList
::
Builder
{
public
:
typedef
DynamicList
Builds
;
Builder
()
=
default
;
template
<
typename
T
,
typename
=
FromBuilder
<
T
>>
template
<
typename
T
,
typename
=
EnableIfNotDynamic
<
FromBuilder
<
T
>
>>
inline
Builder
(
T
&&
value
)
:
Builder
(
toDynamic
(
value
))
{}
template
<
typename
T
>
...
...
@@ -460,6 +486,7 @@ 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().
typedef
_
::
IndexingIterator
<
Builder
,
DynamicStruct
::
Builder
>
Iterator
;
inline
Iterator
begin
()
{
return
Iterator
(
this
,
0
);
}
...
...
@@ -480,6 +507,10 @@ private:
friend
struct
DynamicStruct
;
template
<
typename
T
,
::
capnp
::
Kind
k
>
friend
struct
::
capnp
::
ToDynamic_
;
friend
class
Orphanage
;
template
<
typename
T
,
Kind
k
>
friend
struct
_
::
OrphanGetImpl
;
friend
class
Orphan
<
DynamicList
>
;
};
// -------------------------------------------------------------------
...
...
@@ -498,6 +529,8 @@ template <> struct BuilderFor_<DynamicList, Kind::UNKNOWN> { typedef DynamicList
class
DynamicValue
::
Reader
{
public
:
typedef
DynamicValue
Reads
;
inline
Reader
(
std
::
nullptr_t
n
=
nullptr
);
// UNKNOWN
inline
Reader
(
Void
value
);
inline
Reader
(
bool
value
);
...
...
@@ -576,6 +609,8 @@ private:
class
DynamicValue
::
Builder
{
public
:
typedef
DynamicValue
Builds
;
inline
Builder
(
std
::
nullptr_t
n
=
nullptr
);
// UNKNOWN
inline
Builder
(
Void
value
);
inline
Builder
(
bool
value
);
...
...
@@ -646,6 +681,88 @@ kj::String KJ_STRINGIFY(const DynamicStruct::Builder& value);
kj
::
String
KJ_STRINGIFY
(
const
DynamicList
::
Reader
&
value
);
kj
::
String
KJ_STRINGIFY
(
const
DynamicList
::
Builder
&
value
);
// -------------------------------------------------------------------
// Orphan <-> Dynamic glue
template
<>
class
Orphan
<
DynamicStruct
>
{
public
:
Orphan
()
=
default
;
KJ_DISALLOW_COPY
(
Orphan
);
Orphan
(
Orphan
&&
)
=
default
;
Orphan
&
operator
=
(
Orphan
&&
)
=
default
;
DynamicStruct
::
Builder
get
();
inline
bool
operator
==
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
private
:
StructSchema
schema
;
_
::
OrphanBuilder
builder
;
inline
Orphan
(
StructSchema
schema
,
_
::
OrphanBuilder
&&
builder
)
:
schema
(
schema
),
builder
(
kj
::
mv
(
builder
))
{}
template
<
typename
,
Kind
>
friend
struct
_
::
PointerHelpers
;
friend
struct
DynamicList
;
friend
class
Orphanage
;
};
template
<>
class
Orphan
<
DynamicList
>
{
public
:
Orphan
()
=
default
;
KJ_DISALLOW_COPY
(
Orphan
);
Orphan
(
Orphan
&&
)
=
default
;
Orphan
&
operator
=
(
Orphan
&&
)
=
default
;
DynamicList
::
Builder
get
();
inline
bool
operator
==
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
private
:
ListSchema
schema
;
_
::
OrphanBuilder
builder
;
inline
Orphan
(
ListSchema
schema
,
_
::
OrphanBuilder
&&
builder
)
:
schema
(
schema
),
builder
(
kj
::
mv
(
builder
))
{}
template
<
typename
,
Kind
>
friend
struct
_
::
PointerHelpers
;
friend
struct
DynamicList
;
friend
class
Orphanage
;
};
template
<>
struct
Orphanage
::
GetInnerBuilder
<
DynamicStruct
,
Kind
::
UNKNOWN
>
{
static
inline
_
::
StructBuilder
apply
(
DynamicStruct
::
Builder
&
t
)
{
return
t
.
builder
;
}
};
template
<>
struct
Orphanage
::
GetInnerBuilder
<
DynamicList
,
Kind
::
UNKNOWN
>
{
static
inline
_
::
ListBuilder
apply
(
DynamicList
::
Builder
&
t
)
{
return
t
.
builder
;
}
};
template
<>
inline
Orphan
<
DynamicStruct
>
Orphanage
::
newOrphanCopy
<
DynamicStruct
::
Reader
>
(
const
DynamicStruct
::
Reader
&
copyFrom
)
{
return
Orphan
<
DynamicStruct
>
(
copyFrom
.
getSchema
(),
_
::
OrphanBuilder
::
copy
(
arena
,
copyFrom
.
reader
));
}
template
<>
inline
Orphan
<
DynamicList
>
Orphanage
::
newOrphanCopy
<
DynamicList
::
Reader
>
(
const
DynamicList
::
Reader
&
copyFrom
)
{
return
Orphan
<
DynamicList
>
(
copyFrom
.
getSchema
(),
_
::
OrphanBuilder
::
copy
(
arena
,
copyFrom
.
reader
));
}
// -------------------------------------------------------------------
// Inject the ability to use DynamicStruct for message roots and Dynamic{Struct,List} for
// generated Object accessors.
...
...
@@ -672,6 +789,14 @@ struct PointerHelpers<DynamicStruct, Kind::UNKNOWN> {
StructBuilder
builder
,
WirePointerCount
index
,
const
DynamicStruct
::
Reader
&
value
);
static
DynamicStruct
::
Builder
init
(
StructBuilder
builder
,
WirePointerCount
index
,
StructSchema
schema
);
static
inline
void
adopt
(
StructBuilder
builder
,
WirePointerCount
index
,
Orphan
<
DynamicStruct
>&&
value
)
{
builder
.
adopt
(
index
,
kj
::
mv
(
value
.
builder
));
}
static
inline
Orphan
<
DynamicStruct
>
disown
(
StructBuilder
builder
,
WirePointerCount
index
,
StructSchema
schema
)
{
return
Orphan
<
DynamicStruct
>
(
schema
,
builder
.
disown
(
index
));
}
};
template
<>
...
...
@@ -687,6 +812,14 @@ struct PointerHelpers<DynamicList, Kind::UNKNOWN> {
StructBuilder
builder
,
WirePointerCount
index
,
const
DynamicList
::
Reader
&
value
);
static
DynamicList
::
Builder
init
(
StructBuilder
builder
,
WirePointerCount
index
,
ListSchema
schema
,
uint
size
);
static
inline
void
adopt
(
StructBuilder
builder
,
WirePointerCount
index
,
Orphan
<
DynamicList
>&&
value
)
{
builder
.
adopt
(
index
,
kj
::
mv
(
value
.
builder
));
}
static
inline
Orphan
<
DynamicList
>
disown
(
StructBuilder
builder
,
WirePointerCount
index
,
ListSchema
schema
)
{
return
Orphan
<
DynamicList
>
(
schema
,
builder
.
disown
(
index
));
}
};
}
// namespace _ (private)
...
...
c++/src/capnp/generated-header-support.h
View file @
8536e962
...
...
@@ -28,6 +28,7 @@
#include "layout.h"
#include "list.h"
#include "orphan.h"
#include <kj/string.h>
namespace
capnp
{
...
...
@@ -58,6 +59,12 @@ struct PointerHelpers<T, Kind::STRUCT> {
static
inline
typename
T
::
Builder
init
(
StructBuilder
builder
,
WirePointerCount
index
)
{
return
typename
T
::
Builder
(
builder
.
initStructField
(
index
,
structSize
<
T
>
()));
}
static
inline
void
adopt
(
StructBuilder
builder
,
WirePointerCount
index
,
Orphan
<
T
>&&
value
)
{
builder
.
adopt
(
index
,
kj
::
mv
(
value
.
builder
));
}
static
inline
Orphan
<
T
>
disown
(
StructBuilder
builder
,
WirePointerCount
index
)
{
return
Orphan
<
T
>
(
builder
.
disown
(
index
));
}
};
template
<
typename
T
>
...
...
@@ -86,6 +93,12 @@ struct PointerHelpers<List<T>, Kind::LIST> {
StructBuilder
builder
,
WirePointerCount
index
,
uint
size
)
{
return
typename
List
<
T
>::
Builder
(
List
<
T
>::
initAsFieldOf
(
builder
,
index
,
size
));
}
static
inline
void
adopt
(
StructBuilder
builder
,
WirePointerCount
index
,
Orphan
<
List
<
T
>>&&
value
)
{
builder
.
adopt
(
index
,
kj
::
mv
(
value
.
builder
));
}
static
inline
Orphan
<
List
<
T
>>
disown
(
StructBuilder
builder
,
WirePointerCount
index
)
{
return
Orphan
<
List
<
T
>>
(
builder
.
disown
(
index
));
}
};
template
<
typename
T
>
...
...
@@ -106,6 +119,12 @@ struct PointerHelpers<T, Kind::BLOB> {
static
inline
typename
T
::
Builder
init
(
StructBuilder
builder
,
WirePointerCount
index
,
uint
size
)
{
return
builder
.
initBlobField
<
T
>
(
index
,
size
*
BYTES
);
}
static
inline
void
adopt
(
StructBuilder
builder
,
WirePointerCount
index
,
Orphan
<
T
>&&
value
)
{
builder
.
adopt
(
index
,
kj
::
mv
(
value
.
builder
));
}
static
inline
Orphan
<
T
>
disown
(
StructBuilder
builder
,
WirePointerCount
index
)
{
return
Orphan
<
T
>
(
builder
.
disown
(
index
));
}
};
struct
UncheckedMessage
{
...
...
c++/src/capnp/layout.c++
View file @
8536e962
...
...
@@ -195,11 +195,6 @@ static_assert(POINTERS * BITS_PER_POINTER / BITS_PER_BYTE / BYTES == sizeof(Wire
// =======================================================================================
struct
WireHelpers
{
static
KJ_ALWAYS_INLINE
(
WordCount
roundBitsUpToWords
(
BitCount64
bits
))
{
static_assert
(
sizeof
(
word
)
==
8
,
"This code assumes 64-bit words."
);
return
(
bits
+
63
*
BITS
)
/
BITS_PER_WORD
;
}
static
KJ_ALWAYS_INLINE
(
WordCount
roundBytesUpToWords
(
ByteCount
bytes
))
{
static_assert
(
sizeof
(
word
)
==
8
,
"This code assumes 64-bit words."
);
return
(
bytes
+
7
*
BYTES
)
/
BYTES_PER_WORD
;
...
...
@@ -209,6 +204,19 @@ struct WireHelpers {
return
(
bits
+
7
*
BITS
)
/
BITS_PER_BYTE
;
}
// The maximum object size is 4GB - 1 byte. If measured in bits, this would overflow a 32-bit
// counter, so we need to accept BitCount64. However, 32 bits is enough for the returned
// ByteCounts and WordCounts.
static
KJ_ALWAYS_INLINE
(
WordCount
roundBitsUpToWords
(
BitCount64
bits
))
{
static_assert
(
sizeof
(
word
)
==
8
,
"This code assumes 64-bit words."
);
return
(
bits
+
63
*
BITS
)
/
BITS_PER_WORD
;
}
static
KJ_ALWAYS_INLINE
(
ByteCount
roundBitsUpToBytes
(
BitCount64
bits
))
{
return
(
bits
+
7
*
BITS
)
/
BITS_PER_BYTE
;
}
static
KJ_ALWAYS_INLINE
(
bool
boundsCheck
(
SegmentReader
*
segment
,
const
word
*
start
,
const
word
*
end
))
{
// If segment is null, this is an unchecked message, so we don't do bounds checks.
...
...
@@ -246,7 +254,17 @@ struct WireHelpers {
}
}
static
KJ_ALWAYS_INLINE
(
word
*
followFars
(
WirePointer
*&
ref
,
SegmentBuilder
*&
segment
))
{
static
KJ_ALWAYS_INLINE
(
word
*
followFars
(
WirePointer
*&
ref
,
word
*
refTarget
,
SegmentBuilder
*&
segment
))
{
// If `ref` is a far pointer, follow it. On return, `ref` will have been updated to point at
// a WirePointer that contains the type information about the target object, and a pointer to
// the object contents is returned. The caller must NOT use `ref->target()` as this may or may
// not actually return a valid pointer. `segment` is also updated to point at the segment which
// actually contains the object.
//
// If `ref` is not a far pointer, this simply returns `refTarget`. Usually, `refTarget` should
// be the same as `ref->target()`, but may not be in cases where `ref` is only a tag.
if
(
ref
->
kind
()
==
WirePointer
::
FAR
)
{
segment
=
segment
->
getArena
()
->
getSegment
(
ref
->
farRef
.
segmentId
.
get
());
WirePointer
*
pad
=
...
...
@@ -263,12 +281,15 @@ struct WireHelpers {
segment
=
segment
->
getArena
()
->
getSegment
(
pad
->
farRef
.
segmentId
.
get
());
return
segment
->
getPtrUnchecked
(
pad
->
farPositionInSegment
());
}
else
{
return
ref
->
target
()
;
return
ref
Target
;
}
}
static
KJ_ALWAYS_INLINE
(
const
word
*
followFars
(
const
WirePointer
*&
ref
,
SegmentReader
*&
segment
))
{
// Like the other followFars() but operates on readers. There is no `refTarget` parameter
// because `ref->target()` is valid for all use cases of this method.
// If the segment is null, this is an unchecked message, so there are no FAR pointers.
if
(
segment
!=
nullptr
&&
ref
->
kind
()
==
WirePointer
::
FAR
)
{
// Look up the segment containing the landing pad.
...
...
@@ -672,18 +693,33 @@ struct WireHelpers {
SegmentBuilder
*
srcSegment
,
WirePointer
*
src
)
{
// Make *dst point to the same object as *src. Both must reside in the same message, but can
// be in different segments. Not always-inline because this is rarely used.
//
// Caller MUST zero out the source pointer after calling this, to make sure no later code
// mistakenly thinks the source location still owns the object. transferPointer() doesn't do
// this zeroing itself because many callers transfer several pointers in a loop then zero out
// the whole section.
if
(
src
->
isNull
())
{
memset
(
dst
,
0
,
sizeof
(
WirePointer
));
}
else
if
(
src
->
kind
()
==
WirePointer
::
FAR
)
{
// Far pointers are position-independent, so we can just copy.
memcpy
(
dst
,
src
,
sizeof
(
WirePointer
));
}
else
if
(
dstSegment
==
srcSegment
)
{
}
else
{
transferPointer
(
dstSegment
,
dst
,
srcSegment
,
src
,
src
->
target
());
}
}
static
void
transferPointer
(
SegmentBuilder
*
dstSegment
,
WirePointer
*
dst
,
SegmentBuilder
*
srcSegment
,
const
WirePointer
*
srcTag
,
word
*
srcPtr
)
{
// Like the other overload, but splits src into a tag and a target. Particularly useful for
// OrphanBuilder.
if
(
dstSegment
==
srcSegment
)
{
// Same segment, so create a direct pointer.
dst
->
setKindAndTarget
(
src
->
kind
(),
src
->
target
()
);
dst
->
setKindAndTarget
(
src
Tag
->
kind
(),
srcPtr
);
// We can just copy the upper 32 bits. (Use memcpy() to comply with aliasing rules.)
memcpy
(
&
dst
->
upper32Bits
,
&
src
->
upper32Bits
,
sizeof
(
src
->
upper32Bits
));
memcpy
(
&
dst
->
upper32Bits
,
&
src
Tag
->
upper32Bits
,
sizeof
(
srcTag
->
upper32Bits
));
}
else
{
// Need to create a far pointer. Try to allocate it in the same segment as the source, so
// that it doesn't need to be a double-far.
...
...
@@ -697,18 +733,18 @@ struct WireHelpers {
KJ_DASSERT
(
landingPad
!=
nullptr
,
"getSegmentWithAvailable() returned segment without space available."
);
landingPad
[
0
].
setFar
(
false
,
srcSegment
->
getOffsetTo
(
src
->
target
()
));
landingPad
[
0
].
setFar
(
false
,
srcSegment
->
getOffsetTo
(
src
Ptr
));
landingPad
[
0
].
farRef
.
segmentId
.
set
(
srcSegment
->
getSegmentId
());
landingPad
[
1
].
setKindWithZeroOffset
(
src
->
kind
());
memcpy
(
&
landingPad
[
1
].
upper32Bits
,
&
src
->
upper32Bits
,
sizeof
(
src
->
upper32Bits
));
landingPad
[
1
].
setKindWithZeroOffset
(
src
Tag
->
kind
());
memcpy
(
&
landingPad
[
1
].
upper32Bits
,
&
src
Tag
->
upper32Bits
,
sizeof
(
srcTag
->
upper32Bits
));
dst
->
setFar
(
true
,
farSegment
->
getOffsetTo
(
reinterpret_cast
<
word
*>
(
landingPad
)));
dst
->
farRef
.
set
(
farSegment
->
getSegmentId
());
}
else
{
// Simple landing pad is just a pointer.
landingPad
->
setKindAndTarget
(
src
->
kind
(),
src
->
target
()
);
memcpy
(
&
landingPad
->
upper32Bits
,
&
src
->
upper32Bits
,
sizeof
(
src
->
upper32Bits
));
landingPad
->
setKindAndTarget
(
src
Tag
->
kind
(),
srcPtr
);
memcpy
(
&
landingPad
->
upper32Bits
,
&
src
Tag
->
upper32Bits
,
sizeof
(
srcTag
->
upper32Bits
));
dst
->
setFar
(
false
,
srcSegment
->
getOffsetTo
(
reinterpret_cast
<
word
*>
(
landingPad
)));
dst
->
farRef
.
set
(
srcSegment
->
getSegmentId
());
...
...
@@ -733,19 +769,25 @@ struct WireHelpers {
static
KJ_ALWAYS_INLINE
(
StructBuilder
getWritableStructPointer
(
WirePointer
*
ref
,
SegmentBuilder
*
segment
,
StructSize
size
,
const
word
*
defaultValue
))
{
return
getWritableStructPointer
(
ref
,
ref
->
target
(),
segment
,
size
,
defaultValue
);
}
static
KJ_ALWAYS_INLINE
(
StructBuilder
getWritableStructPointer
(
WirePointer
*
ref
,
word
*
refTarget
,
SegmentBuilder
*
segment
,
StructSize
size
,
const
word
*
defaultValue
))
{
if
(
ref
->
isNull
())
{
useDefault
:
if
(
defaultValue
==
nullptr
||
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
)
->
isNull
())
{
return
initStructPointer
(
ref
,
segment
,
size
);
}
copyMessage
(
segment
,
ref
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
refTarget
=
copyMessage
(
segment
,
ref
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
defaultValue
=
nullptr
;
// If the default value is itself invalid, don't use it again.
}
WirePointer
*
oldRef
=
ref
;
SegmentBuilder
*
oldSegment
=
segment
;
word
*
oldPtr
=
followFars
(
oldRef
,
oldSegment
);
word
*
oldPtr
=
followFars
(
oldRef
,
refTarget
,
oldSegment
);
KJ_REQUIRE
(
oldRef
->
kind
()
==
WirePointer
::
STRUCT
,
"Message contains non-struct pointer where struct pointer was expected."
)
{
...
...
@@ -853,6 +895,13 @@ struct WireHelpers {
static
KJ_ALWAYS_INLINE
(
ListBuilder
getWritableListPointer
(
WirePointer
*
origRef
,
SegmentBuilder
*
origSegment
,
FieldSize
elementSize
,
const
word
*
defaultValue
))
{
return
getWritableListPointer
(
origRef
,
origRef
->
target
(),
origSegment
,
elementSize
,
defaultValue
);
}
static
KJ_ALWAYS_INLINE
(
ListBuilder
getWritableListPointer
(
WirePointer
*
origRef
,
word
*
origRefTarget
,
SegmentBuilder
*
origSegment
,
FieldSize
elementSize
,
const
word
*
defaultValue
))
{
KJ_DREQUIRE
(
elementSize
!=
FieldSize
::
INLINE_COMPOSITE
,
"Use getStructList{Element,Field}() for structs."
);
...
...
@@ -862,7 +911,8 @@ struct WireHelpers {
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
)
->
isNull
())
{
return
ListBuilder
();
}
copyMessage
(
origSegment
,
origRef
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
origRefTarget
=
copyMessage
(
origSegment
,
origRef
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
defaultValue
=
nullptr
;
// If the default value is itself invalid, don't use it again.
}
...
...
@@ -873,7 +923,7 @@ struct WireHelpers {
WirePointer
*
ref
=
origRef
;
SegmentBuilder
*
segment
=
origSegment
;
word
*
ptr
=
followFars
(
ref
,
segment
);
word
*
ptr
=
followFars
(
ref
,
origRefTarget
,
segment
);
KJ_REQUIRE
(
ref
->
kind
()
==
WirePointer
::
LIST
,
"Called getList{Field,Element}() but existing pointer is not a list."
)
{
...
...
@@ -956,13 +1006,20 @@ struct WireHelpers {
static
KJ_ALWAYS_INLINE
(
ListBuilder
getWritableStructListPointer
(
WirePointer
*
origRef
,
SegmentBuilder
*
origSegment
,
StructSize
elementSize
,
const
word
*
defaultValue
))
{
return
getWritableStructListPointer
(
origRef
,
origRef
->
target
(),
origSegment
,
elementSize
,
defaultValue
);
}
static
KJ_ALWAYS_INLINE
(
ListBuilder
getWritableStructListPointer
(
WirePointer
*
origRef
,
word
*
origRefTarget
,
SegmentBuilder
*
origSegment
,
StructSize
elementSize
,
const
word
*
defaultValue
))
{
if
(
origRef
->
isNull
())
{
useDefault
:
if
(
defaultValue
==
nullptr
||
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
)
->
isNull
())
{
return
ListBuilder
();
}
copyMessage
(
origSegment
,
origRef
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
origRefTarget
=
copyMessage
(
origSegment
,
origRef
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
defaultValue
=
nullptr
;
// If the default value is itself invalid, don't use it again.
}
...
...
@@ -970,7 +1027,7 @@ struct WireHelpers {
WirePointer
*
oldRef
=
origRef
;
SegmentBuilder
*
oldSegment
=
origSegment
;
word
*
oldPtr
=
followFars
(
oldRef
,
oldSegment
);
word
*
oldPtr
=
followFars
(
oldRef
,
o
rigRefTarget
,
o
ldSegment
);
KJ_REQUIRE
(
oldRef
->
kind
()
==
WirePointer
::
LIST
,
"Called getList{Field,Element}() but existing pointer is not a list."
)
{
...
...
@@ -1233,12 +1290,22 @@ struct WireHelpers {
static
KJ_ALWAYS_INLINE
(
Text
::
Builder
getWritableTextPointer
(
WirePointer
*
ref
,
SegmentBuilder
*
segment
,
const
void
*
defaultValue
,
ByteCount
defaultSize
))
{
return
getWritableTextPointer
(
ref
,
ref
->
target
(),
segment
,
defaultValue
,
defaultSize
);
}
static
KJ_ALWAYS_INLINE
(
Text
::
Builder
getWritableTextPointer
(
WirePointer
*
ref
,
word
*
refTarget
,
SegmentBuilder
*
segment
,
const
void
*
defaultValue
,
ByteCount
defaultSize
))
{
if
(
ref
->
isNull
())
{
Text
::
Builder
builder
=
initTextPointer
(
ref
,
segment
,
defaultSize
);
memcpy
(
builder
.
begin
(),
defaultValue
,
defaultSize
/
BYTES
);
return
builder
;
if
(
defaultSize
==
0
*
BYTES
)
{
return
nullptr
;
}
else
{
Text
::
Builder
builder
=
initTextPointer
(
ref
,
segment
,
defaultSize
);
memcpy
(
builder
.
begin
(),
defaultValue
,
defaultSize
/
BYTES
);
return
builder
;
}
}
else
{
word
*
ptr
=
followFars
(
ref
,
segment
);
word
*
ptr
=
followFars
(
ref
,
refTarget
,
segment
);
KJ_REQUIRE
(
ref
->
kind
()
==
WirePointer
::
LIST
,
"Called getText{Field,Element}() but existing pointer is not a list."
);
...
...
@@ -1271,12 +1338,22 @@ struct WireHelpers {
static
KJ_ALWAYS_INLINE
(
Data
::
Builder
getWritableDataPointer
(
WirePointer
*
ref
,
SegmentBuilder
*
segment
,
const
void
*
defaultValue
,
ByteCount
defaultSize
))
{
return
getWritableDataPointer
(
ref
,
ref
->
target
(),
segment
,
defaultValue
,
defaultSize
);
}
static
KJ_ALWAYS_INLINE
(
Data
::
Builder
getWritableDataPointer
(
WirePointer
*
ref
,
word
*
refTarget
,
SegmentBuilder
*
segment
,
const
void
*
defaultValue
,
ByteCount
defaultSize
))
{
if
(
ref
->
isNull
())
{
Data
::
Builder
builder
=
initDataPointer
(
ref
,
segment
,
defaultSize
);
memcpy
(
builder
.
begin
(),
defaultValue
,
defaultSize
/
BYTES
);
return
builder
;
if
(
defaultSize
==
0
*
BYTES
)
{
return
nullptr
;
}
else
{
Data
::
Builder
builder
=
initDataPointer
(
ref
,
segment
,
defaultSize
);
memcpy
(
builder
.
begin
(),
defaultValue
,
defaultSize
/
BYTES
);
return
builder
;
}
}
else
{
word
*
ptr
=
followFars
(
ref
,
segment
);
word
*
ptr
=
followFars
(
ref
,
refTarget
,
segment
);
KJ_REQUIRE
(
ref
->
kind
()
==
WirePointer
::
LIST
,
"Called getData{Field,Element}() but existing pointer is not a list."
);
...
...
@@ -1289,6 +1366,11 @@ struct WireHelpers {
static
KJ_ALWAYS_INLINE
(
ObjectBuilder
getWritableObjectPointer
(
SegmentBuilder
*
segment
,
WirePointer
*
ref
,
const
word
*
defaultValue
))
{
return
getWritableObjectPointer
(
segment
,
ref
,
ref
->
target
(),
defaultValue
);
}
static
KJ_ALWAYS_INLINE
(
ObjectBuilder
getWritableObjectPointer
(
SegmentBuilder
*
segment
,
WirePointer
*
ref
,
word
*
refTarget
,
const
word
*
defaultValue
))
{
word
*
ptr
;
if
(
ref
->
isNull
())
{
...
...
@@ -1299,7 +1381,7 @@ struct WireHelpers {
ptr
=
copyMessage
(
segment
,
ref
,
reinterpret_cast
<
const
WirePointer
*>
(
defaultValue
));
}
}
else
{
ptr
=
followFars
(
ref
,
segment
);
ptr
=
followFars
(
ref
,
refTarget
,
segment
);
}
if
(
ref
->
kind
()
==
WirePointer
::
LIST
)
{
...
...
@@ -1333,7 +1415,7 @@ struct WireHelpers {
}
}
static
void
setStructPointer
(
SegmentBuilder
*
segment
,
WirePointer
*
ref
,
StructReader
value
)
{
static
word
*
setStructPointer
(
SegmentBuilder
*
segment
,
WirePointer
*
ref
,
StructReader
value
)
{
WordCount
dataSize
=
roundBitsUpToWords
(
value
.
dataSize
);
WordCount
totalSize
=
dataSize
+
value
.
pointerCount
*
WORDS_PER_POINTER
;
...
...
@@ -1351,9 +1433,11 @@ struct WireHelpers {
setObjectPointer
(
segment
,
pointerSection
+
i
,
readObjectPointer
(
value
.
segment
,
value
.
pointers
+
i
,
nullptr
,
value
.
nestingLimit
));
}
return
ptr
;
}
static
void
setListPointer
(
SegmentBuilder
*
segment
,
WirePointer
*
ref
,
ListReader
value
)
{
static
word
*
setListPointer
(
SegmentBuilder
*
segment
,
WirePointer
*
ref
,
ListReader
value
)
{
WordCount
totalSize
=
roundBitsUpToWords
(
value
.
elementCount
*
value
.
step
);
if
(
value
.
step
*
ELEMENTS
<=
BITS_PER_WORD
*
WORDS
)
{
...
...
@@ -1386,6 +1470,8 @@ struct WireHelpers {
ref
->
listRef
.
set
(
elementSize
,
value
.
elementCount
);
memcpy
(
ptr
,
value
.
ptr
,
totalSize
*
BYTES_PER_WORD
/
BYTES
);
}
return
ptr
;
}
else
{
// List of structs.
word
*
ptr
=
allocate
(
ref
,
segment
,
totalSize
+
POINTER_SIZE_IN_WORDS
,
WirePointer
::
LIST
);
...
...
@@ -1413,6 +1499,8 @@ struct WireHelpers {
src
+=
POINTER_SIZE_IN_WORDS
;
}
}
return
ptr
;
}
}
...
...
@@ -1431,6 +1519,37 @@ struct WireHelpers {
}
}
static
void
adopt
(
SegmentBuilder
*
segment
,
WirePointer
*
ref
,
OrphanBuilder
&&
value
)
{
KJ_REQUIRE
(
value
.
segment
->
getArena
()
==
segment
->
getArena
(),
"Adopted object must live in the same message."
);
if
(
!
ref
->
isNull
())
{
zeroObject
(
segment
,
ref
);
}
if
(
value
.
segment
==
nullptr
)
{
// Set null.
memset
(
ref
,
0
,
sizeof
(
*
ref
));
}
else
if
(
value
.
tagAsPtr
()
->
kind
()
==
WirePointer
::
FAR
)
{
// FAR pointers are position-independent, so we can just copy.
memcpy
(
ref
,
value
.
tagAsPtr
(),
sizeof
(
WirePointer
));
}
else
{
WireHelpers
::
transferPointer
(
segment
,
ref
,
value
.
segment
,
value
.
tagAsPtr
(),
value
.
location
);
}
// Take ownership away from the OrphanBuilder.
memset
(
value
.
tagAsPtr
(),
0
,
sizeof
(
WirePointer
));
value
.
location
=
nullptr
;
value
.
segment
=
nullptr
;
}
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
;
}
// -----------------------------------------------------------------
static
KJ_ALWAYS_INLINE
(
StructReader
readStructPointer
(
...
...
@@ -1815,7 +1934,7 @@ StructBuilder StructBuilder::initRoot(
}
void
StructBuilder
::
setRoot
(
SegmentBuilder
*
segment
,
word
*
location
,
StructReader
value
)
{
return
WireHelpers
::
setStructPointer
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
location
),
value
);
WireHelpers
::
setStructPointer
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
location
),
value
);
}
StructBuilder
StructBuilder
::
getRoot
(
...
...
@@ -1896,17 +2015,25 @@ ObjectBuilder StructBuilder::getObjectField(
}
void
StructBuilder
::
setStructField
(
WirePointerCount
ptrIndex
,
StructReader
value
)
{
return
WireHelpers
::
setStructPointer
(
segment
,
pointers
+
ptrIndex
,
value
);
WireHelpers
::
setStructPointer
(
segment
,
pointers
+
ptrIndex
,
value
);
}
void
StructBuilder
::
setListField
(
WirePointerCount
ptrIndex
,
ListReader
value
)
{
return
WireHelpers
::
setListPointer
(
segment
,
pointers
+
ptrIndex
,
value
);
WireHelpers
::
setListPointer
(
segment
,
pointers
+
ptrIndex
,
value
);
}
void
StructBuilder
::
setObjectField
(
WirePointerCount
ptrIndex
,
ObjectReader
value
)
{
return
WireHelpers
::
setObjectPointer
(
segment
,
pointers
+
ptrIndex
,
value
);
}
void
StructBuilder
::
adopt
(
WirePointerCount
ptrIndex
,
OrphanBuilder
&&
value
)
{
WireHelpers
::
adopt
(
segment
,
pointers
+
ptrIndex
,
kj
::
mv
(
value
));
}
OrphanBuilder
StructBuilder
::
disown
(
WirePointerCount
ptrIndex
)
{
return
WireHelpers
::
disown
(
segment
,
pointers
+
ptrIndex
);
}
bool
StructBuilder
::
isPointerFieldNull
(
WirePointerCount
ptrIndex
)
{
return
(
pointers
+
ptrIndex
)
->
isNull
();
}
...
...
@@ -1916,6 +2043,10 @@ StructReader StructBuilder::asReader() const {
dataSize
,
pointerCount
,
bit0Offset
,
std
::
numeric_limits
<
int
>::
max
());
}
BuilderArena
*
StructBuilder
::
getArena
()
{
return
segment
->
getArena
();
}
// =======================================================================================
// StructReader
...
...
@@ -2100,7 +2231,7 @@ ObjectBuilder ListBuilder::getObjectElement(ElementCount index) {
}
void
ListBuilder
::
setListElement
(
ElementCount
index
,
ListReader
value
)
{
return
WireHelpers
::
setListPointer
(
WireHelpers
::
setListPointer
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
value
);
}
...
...
@@ -2109,11 +2240,25 @@ void ListBuilder::setObjectElement(ElementCount index, ObjectReader value) {
segment
,
reinterpret_cast
<
WirePointer
*>
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
value
);
}
void
ListBuilder
::
adopt
(
ElementCount
index
,
OrphanBuilder
&&
value
)
{
WireHelpers
::
adopt
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
kj
::
mv
(
value
));
}
OrphanBuilder
ListBuilder
::
disown
(
ElementCount
index
)
{
return
WireHelpers
::
disown
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
ptr
+
index
*
step
/
BITS_PER_BYTE
));
}
ListReader
ListBuilder
::
asReader
()
const
{
return
ListReader
(
segment
,
ptr
,
elementCount
,
step
,
structDataSize
,
structPointerCount
,
std
::
numeric_limits
<
int
>::
max
());
}
BuilderArena
*
ListBuilder
::
getArena
()
{
return
segment
->
getArena
();
}
// =======================================================================================
// ListReader
...
...
@@ -2202,5 +2347,225 @@ ObjectReader ListReader::getObjectElement(ElementCount index) const {
segment
,
checkAlignment
(
ptr
+
index
*
step
/
BITS_PER_BYTE
),
nullptr
,
nestingLimit
);
}
// =======================================================================================
// OrphanBuilder
// TODO(cleanup): This is hacky. In order to reuse WireHelpers in OrphanBuilder::init*() and
// OrphanBuilder::copy*(), we actually pass them pointers to WirePointers allocated on the stack.
// When this pointer is initialized, the offset may be truncated and thus end up being garbage.
// This is OK because we define the offset to be ignored in this case, but there is a fair amount
// of non-local reasoning going on. Additionally, in order to select a segment, these methods
// manually compute the size that they expect WireHelpers to allocate. This is redundant and
// could theoretically get out-of-sync with the way WireHelpers computes them, leading to subtle
// bugs. Some refactoring could make this cleaner, perhaps, but I couldn't think of a reasonably
// non-invasive approach.
OrphanBuilder
OrphanBuilder
::
initStruct
(
BuilderArena
*
arena
,
StructSize
size
)
{
OrphanBuilder
result
;
result
.
segment
=
arena
->
getSegmentWithAvailable
(
size
.
total
());
StructBuilder
builder
=
WireHelpers
::
initStructPointer
(
result
.
tagAsPtr
(),
result
.
segment
,
size
);
KJ_ASSERT
(
builder
.
segment
==
result
.
segment
,
"Orphan was unexpectedly allocated in a different segment."
);
result
.
location
=
reinterpret_cast
<
word
*>
(
builder
.
data
);
return
result
;
}
OrphanBuilder
OrphanBuilder
::
initList
(
BuilderArena
*
arena
,
ElementCount
elementCount
,
FieldSize
elementSize
)
{
KJ_DREQUIRE
(
elementSize
!=
FieldSize
::
INLINE_COMPOSITE
,
"Use OrphanBuilder::initStructList() instead."
);
decltype
(
BITS
/
ELEMENTS
)
bitsPerElement
=
dataBitsPerElement
(
elementSize
)
+
pointersPerElement
(
elementSize
)
*
BITS_PER_POINTER
;
OrphanBuilder
result
;
result
.
segment
=
arena
->
getSegmentWithAvailable
(
WireHelpers
::
roundBitsUpToWords
(
bitsPerElement
*
ElementCount64
(
elementCount
)));
ListBuilder
builder
=
WireHelpers
::
initListPointer
(
result
.
tagAsPtr
(),
result
.
segment
,
elementCount
,
elementSize
);
KJ_ASSERT
(
builder
.
segment
==
result
.
segment
,
"Orphan was unexpectedly allocated in a different segment."
);
result
.
location
=
reinterpret_cast
<
word
*>
(
builder
.
ptr
);
return
result
;
}
OrphanBuilder
OrphanBuilder
::
initStructList
(
BuilderArena
*
arena
,
ElementCount
elementCount
,
StructSize
elementSize
)
{
if
(
elementSize
.
preferredListEncoding
!=
FieldSize
::
INLINE_COMPOSITE
)
{
// Small data-only struct. Allocate a list of primitives instead.
return
initList
(
arena
,
elementCount
,
elementSize
.
preferredListEncoding
);
}
else
{
OrphanBuilder
result
;
result
.
segment
=
arena
->
getSegmentWithAvailable
(
elementCount
*
(
elementSize
.
total
()
/
ELEMENTS
)
+
POINTER_SIZE_IN_WORDS
);
ListBuilder
builder
=
WireHelpers
::
initStructListPointer
(
result
.
tagAsPtr
(),
result
.
segment
,
elementCount
,
elementSize
);
KJ_ASSERT
(
builder
.
segment
==
result
.
segment
,
"Orphan was unexpectedly allocated in a different segment."
);
result
.
location
=
reinterpret_cast
<
word
*>
(
builder
.
ptr
);
return
result
;
}
}
OrphanBuilder
OrphanBuilder
::
initText
(
BuilderArena
*
arena
,
ByteCount
size
)
{
OrphanBuilder
result
;
result
.
segment
=
arena
->
getSegmentWithAvailable
(
WireHelpers
::
roundBytesUpToWords
(
size
+
1
*
BYTES
));
Text
::
Builder
builder
=
WireHelpers
::
initTextPointer
(
result
.
tagAsPtr
(),
result
.
segment
,
size
);
result
.
location
=
reinterpret_cast
<
word
*>
(
builder
.
begin
());
KJ_ASSERT
(
result
.
segment
->
getOffsetTo
(
result
.
location
)
<=
result
.
segment
->
getSize
(),
"Orphan was unexpectedly allocated in a different segment."
);
return
result
;
}
OrphanBuilder
OrphanBuilder
::
initData
(
BuilderArena
*
arena
,
ByteCount
size
)
{
OrphanBuilder
result
;
result
.
segment
=
arena
->
getSegmentWithAvailable
(
WireHelpers
::
roundBytesUpToWords
(
size
));
Data
::
Builder
builder
=
WireHelpers
::
initDataPointer
(
result
.
tagAsPtr
(),
result
.
segment
,
size
);
result
.
location
=
reinterpret_cast
<
word
*>
(
builder
.
begin
());
KJ_ASSERT
(
result
.
segment
->
getOffsetTo
(
result
.
location
)
<=
result
.
segment
->
getSize
(),
"Orphan was unexpectedly allocated in a different segment."
);
return
result
;
}
OrphanBuilder
OrphanBuilder
::
copy
(
BuilderArena
*
arena
,
StructReader
copyFrom
)
{
OrphanBuilder
result
;
result
.
segment
=
arena
->
getSegmentWithAvailable
(
WireHelpers
::
roundBitsUpToWords
(
copyFrom
.
getDataSectionSize
())
+
copyFrom
.
getPointerSectionSize
()
*
WORDS_PER_POINTER
);
word
*
ptr
=
WireHelpers
::
setStructPointer
(
result
.
segment
,
result
.
tagAsPtr
(),
copyFrom
);
KJ_ASSERT
(
result
.
segment
->
getOffsetTo
(
ptr
)
<=
result
.
segment
->
getSize
(),
"Orphan was unexpectedly allocated in a different segment."
);
result
.
location
=
reinterpret_cast
<
word
*>
(
ptr
);
return
result
;
}
OrphanBuilder
OrphanBuilder
::
copy
(
BuilderArena
*
arena
,
ListReader
copyFrom
)
{
OrphanBuilder
result
;
WordCount
wordCount
=
WireHelpers
::
roundBitsUpToWords
(
copyFrom
.
step
*
ElementCount64
(
copyFrom
.
elementCount
));
if
(
copyFrom
.
step
*
ELEMENTS
>
BITS_PER_WORD
*
WORDS
)
{
// This is a struct list.
wordCount
+=
1
*
WORDS
;
}
result
.
segment
=
arena
->
getSegmentWithAvailable
(
wordCount
);
word
*
ptr
=
WireHelpers
::
setListPointer
(
result
.
segment
,
result
.
tagAsPtr
(),
copyFrom
);
KJ_ASSERT
(
result
.
segment
->
getOffsetTo
(
ptr
)
<=
result
.
segment
->
getSize
(),
"Orphan was unexpectedly allocated in a different segment."
);
result
.
location
=
reinterpret_cast
<
word
*>
(
ptr
);
return
result
;
}
OrphanBuilder
OrphanBuilder
::
copy
(
BuilderArena
*
arena
,
Text
::
Reader
copyFrom
)
{
OrphanBuilder
result
;
result
.
segment
=
arena
->
getSegmentWithAvailable
(
WireHelpers
::
roundBytesUpToWords
((
copyFrom
.
size
()
+
1
)
*
BYTES
));
Text
::
Builder
text
=
WireHelpers
::
initTextPointer
(
result
.
tagAsPtr
(),
result
.
segment
,
copyFrom
.
size
()
*
BYTES
);
result
.
location
=
reinterpret_cast
<
word
*>
(
text
.
begin
());
KJ_ASSERT
(
result
.
segment
->
getOffsetTo
(
result
.
location
)
<=
result
.
segment
->
getSize
(),
"Orphan was unexpectedly allocated in a different segment."
);
memcpy
(
text
.
begin
(),
copyFrom
.
begin
(),
copyFrom
.
size
());
return
result
;
}
OrphanBuilder
OrphanBuilder
::
copy
(
BuilderArena
*
arena
,
Data
::
Reader
copyFrom
)
{
OrphanBuilder
result
;
result
.
segment
=
arena
->
getSegmentWithAvailable
(
WireHelpers
::
roundBytesUpToWords
(
copyFrom
.
size
()
*
BYTES
));
Data
::
Builder
data
=
WireHelpers
::
initDataPointer
(
result
.
tagAsPtr
(),
result
.
segment
,
copyFrom
.
size
()
*
BYTES
);
result
.
location
=
reinterpret_cast
<
word
*>
(
data
.
begin
());
KJ_ASSERT
(
result
.
segment
->
getOffsetTo
(
result
.
location
)
<=
result
.
segment
->
getSize
(),
"Orphan was unexpectedly allocated in a different segment."
);
memcpy
(
data
.
begin
(),
copyFrom
.
begin
(),
copyFrom
.
size
());
return
result
;
}
StructBuilder
OrphanBuilder
::
asStruct
(
StructSize
size
)
{
StructBuilder
result
=
WireHelpers
::
getWritableStructPointer
(
tagAsPtr
(),
location
,
segment
,
size
,
nullptr
);
// Watch out, the pointer could have been updated if the object had to be relocated.
if
(
tagAsPtr
()
->
kind
()
==
WirePointer
::
FAR
)
{
location
=
nullptr
;
}
else
{
location
=
reinterpret_cast
<
word
*>
(
result
.
data
);
}
return
result
;
}
ListBuilder
OrphanBuilder
::
asList
(
FieldSize
elementSize
)
{
ListBuilder
result
=
WireHelpers
::
getWritableListPointer
(
tagAsPtr
(),
location
,
segment
,
elementSize
,
nullptr
);
// Watch out, the pointer could have been updated if the object had to be relocated.
if
(
tagAsPtr
()
->
kind
()
==
WirePointer
::
FAR
)
{
location
=
nullptr
;
}
else
{
location
=
reinterpret_cast
<
word
*>
(
result
.
ptr
);
}
return
result
;
}
ListBuilder
OrphanBuilder
::
asStructList
(
StructSize
elementSize
)
{
ListBuilder
result
=
WireHelpers
::
getWritableStructListPointer
(
tagAsPtr
(),
location
,
segment
,
elementSize
,
nullptr
);
// Watch out, the pointer could have been updated if the object had to be relocated.
if
(
tagAsPtr
()
->
kind
()
==
WirePointer
::
FAR
)
{
location
=
nullptr
;
}
else
{
location
=
reinterpret_cast
<
word
*>
(
result
.
ptr
);
}
return
result
;
}
Text
::
Builder
OrphanBuilder
::
asText
()
{
// Never relocates.
return
WireHelpers
::
getWritableTextPointer
(
tagAsPtr
(),
location
,
segment
,
nullptr
,
0
*
BYTES
);
}
Data
::
Builder
OrphanBuilder
::
asData
()
{
// Never relocates.
return
WireHelpers
::
getWritableDataPointer
(
tagAsPtr
(),
location
,
segment
,
nullptr
,
0
*
BYTES
);
}
ObjectBuilder
OrphanBuilder
::
asObject
()
{
ObjectBuilder
result
=
WireHelpers
::
getWritableObjectPointer
(
segment
,
tagAsPtr
(),
location
,
nullptr
);
// Watch out, the pointer could have been updated if the object had to be relocated.
if
(
tagAsPtr
()
->
kind
()
==
WirePointer
::
FAR
)
{
location
=
nullptr
;
}
else
{
switch
(
result
.
kind
)
{
case
ObjectKind
:
:
STRUCT
:
location
=
reinterpret_cast
<
word
*>
(
result
.
structBuilder
.
data
);
break
;
case
ObjectKind
:
:
LIST
:
location
=
reinterpret_cast
<
word
*>
(
result
.
listBuilder
.
ptr
);
break
;
case
ObjectKind
:
:
NULL_POINTER
:
location
=
nullptr
;
break
;
}
}
return
result
;
}
void
OrphanBuilder
::
euthanize
()
{
WireHelpers
::
zeroObject
(
segment
,
reinterpret_cast
<
WirePointer
*>
(
&
tag
),
location
);
memset
(
&
tag
,
0
,
sizeof
(
tag
));
// Use memset to comply with aliasing rules.
segment
=
nullptr
;
location
=
nullptr
;
}
}
// namespace _ (private)
}
// namespace capnp
c++/src/capnp/layout.h
View file @
8536e962
...
...
@@ -43,12 +43,14 @@ class StructBuilder;
class
StructReader
;
class
ListBuilder
;
class
ListReader
;
class
OrphanBuilder
;
struct
ObjectBuilder
;
struct
ObjectReader
;
struct
WirePointer
;
struct
WireHelpers
;
class
SegmentReader
;
class
SegmentBuilder
;
class
BuilderArena
;
// =============================================================================
...
...
@@ -120,45 +122,40 @@ inline constexpr PointersPerElement pointersPerElement(FieldSize size) {
return
size
==
FieldSize
::
POINTER
?
1
*
POINTERS
/
ELEMENTS
:
0
*
POINTERS
/
ELEMENTS
;
}
}
// namespace _ (private)
enum
class
Kind
:
uint8_t
{
PRIMITIVE
,
BLOB
,
ENUM
,
STRUCT
,
UNION
,
INTERFACE
,
LIST
,
UNKNOWN
template
<
size_t
size
>
struct
ElementSizeForByteSize
;
template
<>
struct
ElementSizeForByteSize
<
1
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
BYTE
;
};
template
<>
struct
ElementSizeForByteSize
<
2
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
TWO_BYTES
;
};
template
<>
struct
ElementSizeForByteSize
<
4
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
FOUR_BYTES
;
};
template
<>
struct
ElementSizeForByteSize
<
8
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
EIGHT_BYTES
;
};
template
<
typename
T
>
struct
ElementSizeForType
{
static
constexpr
FieldSize
value
=
// Primitive types that aren't special-cased below can be determined from sizeof().
kind
<
T
>
()
==
Kind
::
PRIMITIVE
?
ElementSizeForByteSize
<
sizeof
(
T
)
>::
value
:
kind
<
T
>
()
==
Kind
::
ENUM
?
FieldSize
::
TWO_BYTES
:
kind
<
T
>
()
==
Kind
::
STRUCT
?
FieldSize
::
INLINE_COMPOSITE
:
// Everything else is a pointer.
FieldSize
::
POINTER
;
};
namespace
_
{
// private
// Void and bool are special.
template
<>
struct
ElementSizeForType
<
Void
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
VOID
;
};
template
<>
struct
ElementSizeForType
<
bool
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
BIT
;
};
template
<
typename
T
>
struct
Kind_
{
static
constexpr
Kind
kind
=
Kind
::
UNKNOWN
;
};
template
<>
struct
Kind_
<
Void
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
bool
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
int8_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
int16_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
int32_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
int64_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
uint8_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
uint16_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
uint32_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
uint64_t
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
float
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
double
>
{
static
constexpr
Kind
kind
=
Kind
::
PRIMITIVE
;
};
template
<>
struct
Kind_
<
Text
>
{
static
constexpr
Kind
kind
=
Kind
::
BLOB
;
};
template
<>
struct
Kind_
<
Data
>
{
static
constexpr
Kind
kind
=
Kind
::
BLOB
;
};
// Lists and blobs are pointers, not structs.
template
<
typename
T
,
bool
b
>
struct
ElementSizeForType
<
List
<
T
,
b
>>
{
static
constexpr
FieldSize
value
=
FieldSize
::
POINTER
;
};
template
<>
struct
ElementSizeForType
<
Text
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
POINTER
;
};
template
<>
struct
ElementSizeForType
<
Data
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
POINTER
;
};
}
// namespace _ (private)
template
<
typename
T
>
inline
constexpr
Kind
kind
()
{
return
_
::
Kind_
<
T
>::
kind
;
}
// =============================================================================
namespace
_
{
// private
...
...
@@ -359,11 +356,22 @@ public:
void
setObjectField
(
WirePointerCount
ptrIndex
,
ObjectReader
value
);
// Sets a pointer field to a deep copy of the given value.
void
adopt
(
WirePointerCount
ptrIndex
,
OrphanBuilder
&&
orphan
);
// Adopt the orphaned object as the value of the given pointer field. The orphan must reside in
// the same message as the new parent. No copying occurs.
OrphanBuilder
disown
(
WirePointerCount
ptrIndex
);
// Detach the given pointer field from this object. The pointer becomes null, and the child
// object is returned as an orphan.
bool
isPointerFieldNull
(
WirePointerCount
ptrIndex
);
StructReader
asReader
()
const
;
// Gets a StructReader pointing at the same memory.
BuilderArena
*
getArena
();
// Gets the arena in which this object is allocated.
private
:
SegmentBuilder
*
segment
;
// Memory segment in which the struct resides.
void
*
data
;
// Pointer to the encoded data.
...
...
@@ -387,6 +395,7 @@ private:
friend
class
ListBuilder
;
friend
struct
WireHelpers
;
friend
class
OrphanBuilder
;
};
class
StructReader
{
...
...
@@ -553,9 +562,20 @@ public:
void
setObjectElement
(
ElementCount
index
,
ObjectReader
value
);
// Sets a pointer element to a deep copy of the given value.
void
adopt
(
ElementCount
index
,
OrphanBuilder
&&
orphan
);
// Adopt the orphaned object as the value of the given pointer field. The orphan must reside in
// the same message as the new parent. No copying occurs.
OrphanBuilder
disown
(
ElementCount
index
);
// Detach the given pointer field from this object. The pointer becomes null, and the child
// object is returned as an orphan.
ListReader
asReader
()
const
;
// Get a ListReader pointing at the same memory.
BuilderArena
*
getArena
();
// Gets the arena in which this object is allocated.
private
:
SegmentBuilder
*
segment
;
// Memory segment in which the list resides.
...
...
@@ -580,6 +600,7 @@ private:
friend
class
StructBuilder
;
friend
struct
WireHelpers
;
friend
class
OrphanBuilder
;
};
class
ListReader
{
...
...
@@ -642,6 +663,7 @@ private:
friend
class
StructReader
;
friend
class
ListBuilder
;
friend
struct
WireHelpers
;
friend
class
OrphanBuilder
;
};
// -------------------------------------------------------------------
...
...
@@ -686,6 +708,84 @@ struct ObjectReader {
:
kind
(
ObjectKind
::
LIST
),
listReader
(
listReader
)
{}
};
// -------------------------------------------------------------------
class
OrphanBuilder
{
public
:
inline
OrphanBuilder
()
:
segment
(
nullptr
),
location
(
nullptr
)
{
memset
(
&
tag
,
0
,
sizeof
(
tag
));
}
OrphanBuilder
(
const
OrphanBuilder
&
other
)
=
delete
;
inline
OrphanBuilder
(
OrphanBuilder
&&
other
);
inline
~
OrphanBuilder
();
static
OrphanBuilder
initStruct
(
BuilderArena
*
arena
,
StructSize
size
);
static
OrphanBuilder
initList
(
BuilderArena
*
arena
,
ElementCount
elementCount
,
FieldSize
elementSize
);
static
OrphanBuilder
initStructList
(
BuilderArena
*
arena
,
ElementCount
elementCount
,
StructSize
elementSize
);
static
OrphanBuilder
initText
(
BuilderArena
*
arena
,
ByteCount
size
);
static
OrphanBuilder
initData
(
BuilderArena
*
arena
,
ByteCount
size
);
static
OrphanBuilder
copy
(
BuilderArena
*
arena
,
StructReader
copyFrom
);
static
OrphanBuilder
copy
(
BuilderArena
*
arena
,
ListReader
copyFrom
);
static
OrphanBuilder
copy
(
BuilderArena
*
arena
,
Text
::
Reader
copyFrom
);
static
OrphanBuilder
copy
(
BuilderArena
*
arena
,
Data
::
Reader
copyFrom
);
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
;
}
StructBuilder
asStruct
(
StructSize
size
);
// Interpret as a struct, or throw an exception if not a struct.
ListBuilder
asList
(
FieldSize
elementSize
);
// Interpret as a list, or throw an exception if not a list. elementSize cannot be
// INLINE_COMPOSITE -- use asStructList() instead.
ListBuilder
asStructList
(
StructSize
elementSize
);
// Interpret as a struct list, or throw an exception if not a list.
Text
::
Builder
asText
();
Data
::
Builder
asData
();
// Interpret as a blob, or throw an exception if not a blob.
ObjectBuilder
asObject
();
// Interpret as an arbitrary object.
private
:
static_assert
(
1
*
POINTERS
*
WORDS_PER_POINTER
==
1
*
WORDS
,
"This struct assumes a pointer is one word."
);
word
tag
;
// Contains an encoded WirePointer representing this object. WirePointer is defined in
// layout.c++, but fits in a word.
//
// If the pointer is a FAR pointer, then the tag is a complete pointer, `location` is null, and
// `segment` is any arbitrary segment in the message. Otherwise, the tag's offset is garbage,
// `location` points at the actual object, and `segment` points at the segment where `location`
// resides.
SegmentBuilder
*
segment
;
// Segment in which the object resides, or an arbitrary segment in the message if the tag is a
// FAR pointer.
word
*
location
;
// Pointer to the object, or null if the tag is a FAR pointer.
inline
OrphanBuilder
(
const
void
*
tagPtr
,
SegmentBuilder
*
segment
,
word
*
location
)
:
segment
(
segment
),
location
(
location
)
{
memcpy
(
&
tag
,
tagPtr
,
sizeof
(
tag
));
}
inline
WirePointer
*
tagAsPtr
()
{
return
reinterpret_cast
<
WirePointer
*>
(
&
tag
);
}
void
euthanize
();
// Erase the target object, zeroing it out and possibly reclaiming the memory. Called when
// the OrphanBuilder is being destroyed or overwritten and it is non-null.
friend
struct
WireHelpers
;
};
// =======================================================================================
// Internal implementation details...
...
...
@@ -869,6 +969,35 @@ template <> void ListBuilder::setBlobElement<Data>(ElementCount index, typename
template
<>
typename
Data
::
Builder
ListBuilder
::
getBlobElement
<
Data
>
(
ElementCount
index
);
template
<>
typename
Data
::
Reader
ListReader
::
getBlobElement
<
Data
>
(
ElementCount
index
)
const
;
// -------------------------------------------------------------------
inline
OrphanBuilder
::
OrphanBuilder
(
OrphanBuilder
&&
other
)
:
segment
(
other
.
segment
),
location
(
other
.
location
)
{
memcpy
(
&
tag
,
&
other
.
tag
,
sizeof
(
tag
));
// Needs memcpy to comply with aliasing rules.
other
.
segment
=
nullptr
;
other
.
location
=
nullptr
;
}
inline
OrphanBuilder
::~
OrphanBuilder
()
{
if
(
segment
!=
nullptr
)
euthanize
();
}
inline
OrphanBuilder
&
OrphanBuilder
::
operator
=
(
OrphanBuilder
&&
other
)
{
// With normal smart pointers, it's important to handle the case where the incoming pointer
// is actually transitively owned by this one. In this case, euthanize() would destroy `other`
// before we copied it. This isn't possible in the case of `OrphanBuilder` because it only
// owns message objects, and `other` is not itself a message object, therefore cannot possibly
// be transitively owned by `this`.
if
(
segment
!=
nullptr
)
euthanize
();
segment
=
other
.
segment
;
location
=
other
.
location
;
memcpy
(
&
tag
,
&
other
.
tag
,
sizeof
(
tag
));
// Needs memcpy to comply with aliasing rules.
other
.
segment
=
nullptr
;
other
.
location
=
nullptr
;
return
*
this
;
}
}
// namespace _ (private)
}
// namespace capnp
...
...
c++/src/capnp/list.h
View file @
8536e962
...
...
@@ -25,81 +25,12 @@
#define CAPNP_LIST_H_
#include "layout.h"
#include "orphan.h"
#include <initializer_list>
namespace
capnp
{
namespace
_
{
// private
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
PointerHelpers
;
}
// namespace _ (private)
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
List
;
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
ReaderFor_
{
typedef
typename
T
::
Reader
Type
;
};
template
<
typename
T
>
struct
ReaderFor_
<
T
,
Kind
::
PRIMITIVE
>
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
ReaderFor_
<
T
,
Kind
::
ENUM
>
{
typedef
T
Type
;
};
template
<
typename
T
>
using
ReaderFor
=
typename
ReaderFor_
<
T
>::
Type
;
// The type returned by List<T>::Reader::operator[].
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
BuilderFor_
{
typedef
typename
T
::
Builder
Type
;
};
template
<
typename
T
>
struct
BuilderFor_
<
T
,
Kind
::
PRIMITIVE
>
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
BuilderFor_
<
T
,
Kind
::
ENUM
>
{
typedef
T
Type
;
};
template
<
typename
T
>
using
BuilderFor
=
typename
BuilderFor_
<
T
>::
Type
;
// The type returned by List<T>::Builder::operator[].
template
<
typename
T
>
using
FromReader
=
typename
kj
::
Decay
<
T
>::
Reads
;
// FromReader<MyType::Reader> = MyType (for any Cap'n Proto type).
template
<
typename
T
>
using
FromBuilder
=
typename
kj
::
Decay
<
T
>::
Builds
;
// FromBuilder<MyType::Builder> = MyType (for any Cap'n Proto type).
template
<
typename
T
,
Kind
k
=
kind
<
T
>
()
>
struct
TypeIfEnum_
;
template
<
typename
T
>
struct
TypeIfEnum_
<
T
,
Kind
::
ENUM
>
{
typedef
T
Type
;
};
template
<
typename
T
>
using
TypeIfEnum
=
typename
TypeIfEnum_
<
kj
::
Decay
<
T
>>::
Type
;
namespace
_
{
// private
template
<
typename
T
,
Kind
k
>
struct
Kind_
<
List
<
T
,
k
>>
{
static
constexpr
Kind
kind
=
Kind
::
LIST
;
};
template
<
size_t
size
>
struct
FieldSizeForByteSize
;
template
<>
struct
FieldSizeForByteSize
<
1
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
BYTE
;
};
template
<>
struct
FieldSizeForByteSize
<
2
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
TWO_BYTES
;
};
template
<>
struct
FieldSizeForByteSize
<
4
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
FOUR_BYTES
;
};
template
<>
struct
FieldSizeForByteSize
<
8
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
EIGHT_BYTES
;
};
template
<
typename
T
>
struct
FieldSizeForType
{
static
constexpr
FieldSize
value
=
// Primitive types that aren't special-cased below can be determined from sizeof().
kind
<
T
>
()
==
Kind
::
PRIMITIVE
?
FieldSizeForByteSize
<
sizeof
(
T
)
>::
value
:
kind
<
T
>
()
==
Kind
::
ENUM
?
FieldSize
::
TWO_BYTES
:
kind
<
T
>
()
==
Kind
::
STRUCT
?
FieldSize
::
INLINE_COMPOSITE
:
// Everything else is a pointer.
FieldSize
::
POINTER
;
};
// Void and bool are special.
template
<>
struct
FieldSizeForType
<
Void
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
VOID
;
};
template
<>
struct
FieldSizeForType
<
bool
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
BIT
;
};
// Lists and blobs are pointers, not structs.
template
<
typename
T
,
bool
b
>
struct
FieldSizeForType
<
List
<
T
,
b
>>
{
static
constexpr
FieldSize
value
=
FieldSize
::
POINTER
;
};
template
<>
struct
FieldSizeForType
<
Text
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
POINTER
;
};
template
<>
struct
FieldSizeForType
<
Data
>
{
static
constexpr
FieldSize
value
=
FieldSize
::
POINTER
;
};
template
<
typename
T
>
class
TemporaryPointer
{
// This class is a little hack which lets us define operator->() in cases where it needs to
...
...
@@ -193,6 +124,9 @@ struct List<T, Kind::PRIMITIVE> {
friend
struct
_
::
PointerHelpers
;
template
<
typename
U
,
Kind
K
>
friend
struct
List
;
friend
class
Orphanage
;
template
<
typename
U
,
Kind
K
>
friend
struct
ToDynamic_
;
};
class
Builder
{
...
...
@@ -225,34 +159,37 @@ struct List<T, Kind::PRIMITIVE> {
private
:
_
::
ListBuilder
builder
;
friend
class
Orphanage
;
template
<
typename
U
,
Kind
K
>
friend
struct
ToDynamic_
;
};
private
:
inline
static
_
::
ListBuilder
initAsElementOf
(
_
::
ListBuilder
&
builder
,
uint
index
,
uint
size
)
{
return
builder
.
initListElement
(
index
*
ELEMENTS
,
_
::
Field
SizeForType
<
T
>::
value
,
size
*
ELEMENTS
);
index
*
ELEMENTS
,
_
::
Element
SizeForType
<
T
>::
value
,
size
*
ELEMENTS
);
}
inline
static
_
::
ListBuilder
getAsElementOf
(
_
::
ListBuilder
&
builder
,
uint
index
)
{
return
builder
.
getListElement
(
index
*
ELEMENTS
,
_
::
Field
SizeForType
<
T
>::
value
);
return
builder
.
getListElement
(
index
*
ELEMENTS
,
_
::
Element
SizeForType
<
T
>::
value
);
}
inline
static
_
::
ListReader
getAsElementOf
(
const
_
::
ListReader
&
reader
,
uint
index
)
{
return
reader
.
getListElement
(
index
*
ELEMENTS
,
_
::
Field
SizeForType
<
T
>::
value
);
return
reader
.
getListElement
(
index
*
ELEMENTS
,
_
::
Element
SizeForType
<
T
>::
value
);
}
inline
static
_
::
ListBuilder
initAsFieldOf
(
_
::
StructBuilder
&
builder
,
WirePointerCount
index
,
uint
size
)
{
return
builder
.
initListField
(
index
,
_
::
Field
SizeForType
<
T
>::
value
,
size
*
ELEMENTS
);
return
builder
.
initListField
(
index
,
_
::
Element
SizeForType
<
T
>::
value
,
size
*
ELEMENTS
);
}
inline
static
_
::
ListBuilder
getAsFieldOf
(
_
::
StructBuilder
&
builder
,
WirePointerCount
index
,
const
word
*
defaultValue
)
{
return
builder
.
getListField
(
index
,
_
::
Field
SizeForType
<
T
>::
value
,
defaultValue
);
return
builder
.
getListField
(
index
,
_
::
Element
SizeForType
<
T
>::
value
,
defaultValue
);
}
inline
static
_
::
ListReader
getAsFieldOf
(
const
_
::
StructReader
&
reader
,
WirePointerCount
index
,
const
word
*
defaultValue
)
{
return
reader
.
getListField
(
index
,
_
::
Field
SizeForType
<
T
>::
value
,
defaultValue
);
return
reader
.
getListField
(
index
,
_
::
Element
SizeForType
<
T
>::
value
,
defaultValue
);
}
template
<
typename
U
,
Kind
k
>
...
...
@@ -292,6 +229,9 @@ struct List<T, Kind::STRUCT> {
friend
struct
_
::
PointerHelpers
;
template
<
typename
U
,
Kind
K
>
friend
struct
List
;
friend
class
Orphanage
;
template
<
typename
U
,
Kind
K
>
friend
struct
ToDynamic_
;
};
class
Builder
{
...
...
@@ -309,10 +249,10 @@ struct List<T, Kind::STRUCT> {
return
typename
T
::
Builder
(
builder
.
getStructElement
(
index
*
ELEMENTS
));
}
// There are no init()
or set() methods for lists of structs because the elements of the list
//
are inlined and are initialized when the list is initialized. This means that init() would
//
be redundant, and set() would risk data loss if the input struct were from a newer version
//
of teh
protocol.
// There are no init()
, set(), adopt(), or disown() methods for lists of structs because the
//
elements of the list are inlined and are initialized when the list is initialized. This
//
means that init() would be redundant, and set() would risk data loss if the input struct
//
were from a newer version of the
protocol.
typedef
_
::
IndexingIterator
<
Builder
,
typename
T
::
Builder
>
Iterator
;
inline
Iterator
begin
()
{
return
Iterator
(
this
,
0
);
}
...
...
@@ -320,6 +260,9 @@ struct List<T, Kind::STRUCT> {
private
:
_
::
ListBuilder
builder
;
friend
class
Orphanage
;
template
<
typename
U
,
Kind
K
>
friend
struct
ToDynamic_
;
};
private
:
...
...
@@ -384,6 +327,9 @@ struct List<List<T>, Kind::LIST> {
friend
struct
_
::
PointerHelpers
;
template
<
typename
U
,
Kind
K
>
friend
struct
List
;
friend
class
Orphanage
;
template
<
typename
U
,
Kind
K
>
friend
struct
ToDynamic_
;
};
class
Builder
{
...
...
@@ -413,6 +359,12 @@ struct List<List<T>, Kind::LIST> {
l
.
set
(
i
++
,
element
);
}
}
inline
void
adopt
(
uint
index
,
Orphan
<
T
>&&
value
)
{
builder
.
adopt
(
index
*
ELEMENTS
,
kj
::
mv
(
value
));
}
inline
Orphan
<
T
>
disown
(
uint
index
)
{
return
Orphan
<
T
>
(
builder
.
disown
(
index
*
ELEMENTS
));
}
typedef
_
::
IndexingIterator
<
Builder
,
typename
List
<
T
>::
Builder
>
Iterator
;
inline
Iterator
begin
()
{
return
Iterator
(
this
,
0
);
}
...
...
@@ -420,6 +372,9 @@ struct List<List<T>, Kind::LIST> {
private
:
_
::
ListBuilder
builder
;
friend
class
Orphanage
;
template
<
typename
U
,
Kind
K
>
friend
struct
ToDynamic_
;
};
private
:
...
...
@@ -482,6 +437,9 @@ struct List<T, Kind::BLOB> {
friend
struct
_
::
PointerHelpers
;
template
<
typename
U
,
Kind
K
>
friend
struct
List
;
friend
class
Orphanage
;
template
<
typename
U
,
Kind
K
>
friend
struct
ToDynamic_
;
};
class
Builder
{
...
...
@@ -504,6 +462,12 @@ struct List<T, Kind::BLOB> {
inline
typename
T
::
Builder
init
(
uint
index
,
uint
size
)
{
return
builder
.
initBlobElement
<
T
>
(
index
*
ELEMENTS
,
size
*
BYTES
);
}
inline
void
adopt
(
uint
index
,
Orphan
<
T
>&&
value
)
{
builder
.
adopt
(
index
*
ELEMENTS
,
kj
::
mv
(
value
));
}
inline
Orphan
<
T
>
disown
(
uint
index
)
{
return
Orphan
<
T
>
(
builder
.
disown
(
index
*
ELEMENTS
));
}
typedef
_
::
IndexingIterator
<
Builder
,
typename
T
::
Builder
>
Iterator
;
inline
Iterator
begin
()
{
return
Iterator
(
this
,
0
);
}
...
...
@@ -511,6 +475,9 @@ struct List<T, Kind::BLOB> {
private
:
_
::
ListBuilder
builder
;
friend
class
Orphanage
;
template
<
typename
U
,
Kind
K
>
friend
struct
ToDynamic_
;
};
private
:
...
...
c++/src/capnp/message.c++
View file @
8536e962
...
...
@@ -116,6 +116,14 @@ kj::ArrayPtr<const kj::ArrayPtr<const word>> MessageBuilder::getSegmentsForOutpu
}
}
Orphanage
MessageBuilder
::
getOrphanage
()
{
// We must ensure that the arena and root pointer have been allocated before the Orphanage
// can be used.
if
(
!
allocatedArena
)
getRootSegment
();
return
Orphanage
(
arena
());
}
// =======================================================================================
SegmentArrayMessageReader
::
SegmentArrayMessageReader
(
...
...
c++/src/capnp/message.h
View file @
8536e962
...
...
@@ -156,6 +156,8 @@ public:
kj
::
ArrayPtr
<
const
kj
::
ArrayPtr
<
const
word
>>
getSegmentsForOutput
();
Orphanage
getOrphanage
();
private
:
// Space in which we can construct a BuilderArena. We don't use BuilderArena directly here
// because we don't want clients to have to #include arena.h, which itself includes a bunch of
...
...
c++/src/capnp/orphan-test.c++
0 → 100644
View file @
8536e962
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "message.h"
#include <kj/debug.h>
#include <gtest/gtest.h>
#include "test-util.h"
namespace
capnp
{
namespace
_
{
// private
namespace
{
TEST
(
Orphans
,
Structs
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
initTestMessage
(
root
.
initStructField
());
EXPECT_TRUE
(
root
.
hasStructField
());
Orphan
<
TestAllTypes
>
orphan
=
root
.
disownStructField
();
EXPECT_FALSE
(
orphan
==
nullptr
);
checkTestMessage
(
orphan
.
get
().
asReader
());
EXPECT_FALSE
(
root
.
hasStructField
());
root
.
adoptStructField
(
kj
::
mv
(
orphan
));
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
root
.
hasStructField
());
checkTestMessage
(
root
.
asReader
().
getStructField
());
}
TEST
(
Orphans
,
Lists
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
setUInt32List
({
12
,
34
,
56
});
EXPECT_TRUE
(
root
.
hasUInt32List
());
Orphan
<
List
<
uint32_t
>>
orphan
=
root
.
disownUInt32List
();
EXPECT_FALSE
(
orphan
==
nullptr
);
checkList
(
orphan
.
get
().
asReader
(),
{
12
,
34
,
56
});
EXPECT_FALSE
(
root
.
hasUInt32List
());
root
.
adoptUInt32List
(
kj
::
mv
(
orphan
));
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
root
.
hasUInt32List
());
checkList
(
root
.
asReader
().
getUInt32List
(),
{
12
,
34
,
56
});
}
TEST
(
Orphans
,
Text
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
setTextField
(
"foo"
);
EXPECT_TRUE
(
root
.
hasTextField
());
Orphan
<
Text
>
orphan
=
root
.
disownTextField
();
EXPECT_FALSE
(
orphan
==
nullptr
);
EXPECT_EQ
(
"foo"
,
orphan
.
get
());
EXPECT_FALSE
(
root
.
hasTextField
());
root
.
adoptTextField
(
kj
::
mv
(
orphan
));
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
root
.
hasTextField
());
EXPECT_EQ
(
"foo"
,
root
.
getTextField
());
}
TEST
(
Orphans
,
Data
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
setDataField
(
data
(
"foo"
));
EXPECT_TRUE
(
root
.
hasDataField
());
Orphan
<
Data
>
orphan
=
root
.
disownDataField
();
EXPECT_FALSE
(
orphan
==
nullptr
);
EXPECT_EQ
(
data
(
"foo"
),
orphan
.
get
());
EXPECT_FALSE
(
root
.
hasDataField
());
root
.
adoptDataField
(
kj
::
mv
(
orphan
));
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
root
.
hasDataField
());
EXPECT_EQ
(
data
(
"foo"
),
root
.
getDataField
());
}
#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
(
Orphans
,
NoCrossMessageTransfers
)
{
MallocMessageBuilder
builder1
;
MallocMessageBuilder
builder2
;
auto
root1
=
builder1
.
initRoot
<
TestAllTypes
>
();
auto
root2
=
builder2
.
initRoot
<
TestAllTypes
>
();
initTestMessage
(
root1
.
initStructField
());
EXPECT_ANY_THROW
(
root2
.
adoptStructField
(
root1
.
disownStructField
()));
}
TEST
(
Orphans
,
OrphanageStruct
)
{
MallocMessageBuilder
builder
;
Orphan
<
TestAllTypes
>
orphan
=
builder
.
getOrphanage
().
newOrphan
<
TestAllTypes
>
();
initTestMessage
(
orphan
.
get
());
checkTestMessage
(
orphan
.
get
().
asReader
());
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
adoptStructField
(
kj
::
mv
(
orphan
));
}
TEST
(
Orphans
,
OrphanageList
)
{
MallocMessageBuilder
builder
;
Orphan
<
List
<
uint32_t
>>
orphan
=
builder
.
getOrphanage
().
newOrphan
<
List
<
uint32_t
>>
(
2
);
orphan
.
get
().
set
(
0
,
123
);
orphan
.
get
().
set
(
1
,
456
);
List
<
uint32_t
>::
Reader
reader
=
orphan
.
get
().
asReader
();
ASSERT_EQ
(
2u
,
reader
.
size
());
EXPECT_EQ
(
123u
,
reader
[
0
]);
EXPECT_EQ
(
456u
,
reader
[
1
]);
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
adoptUInt32List
(
kj
::
mv
(
orphan
));
}
TEST
(
Orphans
,
OrphanageText
)
{
MallocMessageBuilder
builder
;
Orphan
<
Text
>
orphan
=
builder
.
getOrphanage
().
newOrphan
<
Text
>
(
8
);
ASSERT_EQ
(
8u
,
orphan
.
get
().
size
());
memcpy
(
orphan
.
get
().
begin
(),
"12345678"
,
8
);
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
adoptTextField
(
kj
::
mv
(
orphan
));
EXPECT_EQ
(
"12345678"
,
root
.
getTextField
());
}
TEST
(
Orphans
,
OrphanageData
)
{
MallocMessageBuilder
builder
;
Orphan
<
Data
>
orphan
=
builder
.
getOrphanage
().
newOrphan
<
Data
>
(
2
);
ASSERT_EQ
(
2u
,
orphan
.
get
().
size
());
orphan
.
get
()[
0
]
=
123
;
orphan
.
get
()[
1
]
=
45
;
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
adoptDataField
(
kj
::
mv
(
orphan
));
ASSERT_EQ
(
2u
,
root
.
getDataField
().
size
());
EXPECT_EQ
(
123u
,
root
.
getDataField
()[
0
]);
EXPECT_EQ
(
45u
,
root
.
getDataField
()[
1
]);
}
TEST
(
Orphans
,
OrphanageStructCopy
)
{
MallocMessageBuilder
builder1
;
MallocMessageBuilder
builder2
;
auto
root1
=
builder1
.
initRoot
<
TestAllTypes
>
();
initTestMessage
(
root1
);
Orphan
<
TestAllTypes
>
orphan
=
builder2
.
getOrphanage
().
newOrphanCopy
(
root1
.
asReader
());
checkTestMessage
(
orphan
.
get
().
asReader
());
auto
root2
=
builder2
.
initRoot
<
TestAllTypes
>
();
root2
.
adoptStructField
(
kj
::
mv
(
orphan
));
}
TEST
(
Orphans
,
OrphanageListCopy
)
{
MallocMessageBuilder
builder1
;
MallocMessageBuilder
builder2
;
auto
root1
=
builder1
.
initRoot
<
TestAllTypes
>
();
root1
.
setUInt32List
({
12
,
34
,
56
});
Orphan
<
List
<
uint32_t
>>
orphan
=
builder2
.
getOrphanage
().
newOrphanCopy
(
root1
.
asReader
().
getUInt32List
());
checkList
(
orphan
.
get
().
asReader
(),
{
12
,
34
,
56
});
auto
root2
=
builder2
.
initRoot
<
TestAllTypes
>
();
root2
.
adoptUInt32List
(
kj
::
mv
(
orphan
));
}
TEST
(
Orphans
,
OrphanageTextCopy
)
{
MallocMessageBuilder
builder
;
Orphan
<
Text
>
orphan
=
builder
.
getOrphanage
().
newOrphanCopy
(
Text
::
Reader
(
"foobarba"
));
EXPECT_EQ
(
"foobarba"
,
orphan
.
get
().
asReader
());
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
adoptTextField
(
kj
::
mv
(
orphan
));
}
TEST
(
Orphans
,
OrphanageDataCopy
)
{
MallocMessageBuilder
builder
;
Orphan
<
Data
>
orphan
=
builder
.
getOrphanage
().
newOrphanCopy
(
data
(
"foo"
));
EXPECT_EQ
(
data
(
"foo"
),
orphan
.
get
().
asReader
());
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
root
.
adoptDataField
(
kj
::
mv
(
orphan
));
}
TEST
(
Orphans
,
ZeroOut
)
{
MallocMessageBuilder
builder
;
TestAllTypes
::
Reader
orphanReader
;
{
Orphan
<
TestAllTypes
>
orphan
=
builder
.
getOrphanage
().
newOrphan
<
TestAllTypes
>
();
orphanReader
=
orphan
.
get
().
asReader
();
initTestMessage
(
orphan
.
get
());
checkTestMessage
(
orphan
.
get
().
asReader
());
}
// Once the Orphan destructor is called, the message should be zero'd out.
checkTestMessageAllZero
(
orphanReader
);
}
TEST
(
Orphans
,
StructObject
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
initTestMessage
(
root
.
initObjectField
<
TestAllTypes
>
());
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
TestAllTypes
>
orphan
=
root
.
disownObjectField
<
TestAllTypes
>
();
EXPECT_FALSE
(
orphan
==
nullptr
);
checkTestMessage
(
orphan
.
get
().
asReader
());
EXPECT_FALSE
(
root
.
hasObjectField
());
root
.
adoptObjectField
(
kj
::
mv
(
orphan
));
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
root
.
hasObjectField
());
checkTestMessage
(
root
.
asReader
().
getObjectField
<
TestAllTypes
>
());
}
TEST
(
Orphans
,
ListObject
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
root
.
setObjectField
<
List
<
uint32_t
>>
({
12
,
34
,
56
});
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
List
<
uint32_t
>>
orphan
=
root
.
disownObjectField
<
List
<
uint32_t
>>
();
EXPECT_FALSE
(
orphan
==
nullptr
);
checkList
(
orphan
.
get
().
asReader
(),
{
12
,
34
,
56
});
EXPECT_FALSE
(
root
.
hasObjectField
());
root
.
adoptObjectField
(
kj
::
mv
(
orphan
));
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
root
.
hasObjectField
());
checkList
(
root
.
asReader
().
getObjectField
<
List
<
uint32_t
>>
(),
{
12
,
34
,
56
});
}
TEST
(
Orphans
,
DynamicStruct
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
initTestMessage
(
root
.
initObjectField
<
TestAllTypes
>
());
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
DynamicStruct
>
orphan
=
root
.
disownObjectField
<
DynamicStruct
>
(
Schema
::
from
<
TestAllTypes
>
());
EXPECT_FALSE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
orphan
.
get
().
getSchema
()
==
Schema
::
from
<
TestAllTypes
>
());
checkDynamicTestMessage
(
orphan
.
get
().
asReader
());
EXPECT_FALSE
(
root
.
hasObjectField
());
root
.
adoptObjectField
(
kj
::
mv
(
orphan
));
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
root
.
hasObjectField
());
checkTestMessage
(
root
.
asReader
().
getObjectField
<
TestAllTypes
>
());
}
TEST
(
Orphans
,
DynamicList
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
root
.
setObjectField
<
List
<
uint32_t
>>
({
12
,
34
,
56
});
EXPECT_TRUE
(
root
.
hasObjectField
());
Orphan
<
DynamicList
>
orphan
=
root
.
disownObjectField
<
DynamicList
>
(
Schema
::
from
<
List
<
uint32_t
>>
());
EXPECT_FALSE
(
orphan
==
nullptr
);
checkList
<
uint32_t
>
(
orphan
.
get
().
asReader
(),
{
12
,
34
,
56
});
EXPECT_FALSE
(
root
.
hasObjectField
());
root
.
adoptObjectField
(
kj
::
mv
(
orphan
));
EXPECT_TRUE
(
orphan
==
nullptr
);
EXPECT_TRUE
(
root
.
hasObjectField
());
checkList
(
root
.
asReader
().
getObjectField
<
List
<
uint32_t
>>
(),
{
12
,
34
,
56
});
}
TEST
(
Orphans
,
OrphanageDynamicStruct
)
{
MallocMessageBuilder
builder
;
Orphan
<
DynamicStruct
>
orphan
=
builder
.
getOrphanage
().
newOrphan
(
Schema
::
from
<
TestAllTypes
>
());
initDynamicTestMessage
(
orphan
.
get
());
checkDynamicTestMessage
(
orphan
.
get
().
asReader
());
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
root
.
adoptObjectField
(
kj
::
mv
(
orphan
));
checkTestMessage
(
root
.
asReader
().
getObjectField
<
TestAllTypes
>
());
}
TEST
(
Orphans
,
OrphanageDynamicList
)
{
MallocMessageBuilder
builder
;
Orphan
<
DynamicList
>
orphan
=
builder
.
getOrphanage
().
newOrphan
(
Schema
::
from
<
List
<
uint32_t
>>
(),
2
);
orphan
.
get
().
set
(
0
,
123
);
orphan
.
get
().
set
(
1
,
456
);
checkList
<
uint32_t
>
(
orphan
.
get
().
asReader
(),
{
123
,
456
});
auto
root
=
builder
.
initRoot
<
test
::
TestObject
>
();
root
.
adoptObjectField
(
kj
::
mv
(
orphan
));
checkList
(
root
.
getObjectField
<
List
<
uint32_t
>>
(),
{
123
,
456
});
}
TEST
(
Orphans
,
OrphanageDynamicStructCopy
)
{
MallocMessageBuilder
builder1
;
MallocMessageBuilder
builder2
;
auto
root1
=
builder1
.
initRoot
<
test
::
TestObject
>
();
initTestMessage
(
root1
.
initObjectField
<
TestAllTypes
>
());
Orphan
<
DynamicStruct
>
orphan
=
builder2
.
getOrphanage
().
newOrphanCopy
(
root1
.
asReader
().
getObjectField
<
DynamicStruct
>
(
Schema
::
from
<
TestAllTypes
>
()));
checkDynamicTestMessage
(
orphan
.
get
().
asReader
());
auto
root2
=
builder2
.
initRoot
<
test
::
TestObject
>
();
root2
.
adoptObjectField
(
kj
::
mv
(
orphan
));
checkTestMessage
(
root2
.
asReader
().
getObjectField
<
TestAllTypes
>
());
}
TEST
(
Orphans
,
OrphanageDynamicListCopy
)
{
MallocMessageBuilder
builder1
;
MallocMessageBuilder
builder2
;
auto
root1
=
builder1
.
initRoot
<
test
::
TestObject
>
();
root1
.
setObjectField
<
List
<
uint32_t
>>
({
12
,
34
,
56
});
Orphan
<
DynamicList
>
orphan
=
builder2
.
getOrphanage
().
newOrphanCopy
(
root1
.
asReader
().
getObjectField
<
DynamicList
>
(
Schema
::
from
<
List
<
uint32_t
>>
()));
checkList
<
uint32_t
>
(
orphan
.
get
().
asReader
(),
{
12
,
34
,
56
});
auto
root2
=
builder2
.
initRoot
<
test
::
TestObject
>
();
root2
.
adoptObjectField
(
kj
::
mv
(
orphan
));
checkList
(
root2
.
getObjectField
<
List
<
uint32_t
>>
(),
{
12
,
34
,
56
});
}
TEST
(
Orphans
,
OrphanageFromBuilder
)
{
MallocMessageBuilder
builder
;
auto
root
=
builder
.
initRoot
<
TestAllTypes
>
();
{
Orphanage
orphanage
=
Orphanage
::
getForMessageContaining
(
root
);
Orphan
<
TestAllTypes
>
orphan
=
orphanage
.
newOrphan
<
TestAllTypes
>
();
initTestMessage
(
orphan
.
get
());
root
.
adoptStructField
(
kj
::
mv
(
orphan
));
checkTestMessage
(
root
.
asReader
().
getStructField
());
}
{
Orphanage
orphanage
=
Orphanage
::
getForMessageContaining
(
root
.
initBoolList
(
3
));
Orphan
<
TestAllTypes
>
orphan
=
orphanage
.
newOrphan
<
TestAllTypes
>
();
initTestMessage
(
orphan
.
get
());
root
.
adoptStructField
(
kj
::
mv
(
orphan
));
checkTestMessage
(
root
.
asReader
().
getStructField
());
}
{
Orphanage
orphanage
=
Orphanage
::
getForMessageContaining
(
toDynamic
(
root
));
Orphan
<
TestAllTypes
>
orphan
=
orphanage
.
newOrphan
<
TestAllTypes
>
();
initTestMessage
(
orphan
.
get
());
root
.
adoptStructField
(
kj
::
mv
(
orphan
));
checkTestMessage
(
root
.
asReader
().
getStructField
());
}
{
Orphanage
orphanage
=
Orphanage
::
getForMessageContaining
(
toDynamic
(
root
.
initBoolList
(
3
)));
Orphan
<
TestAllTypes
>
orphan
=
orphanage
.
newOrphan
<
TestAllTypes
>
();
initTestMessage
(
orphan
.
get
());
root
.
adoptStructField
(
kj
::
mv
(
orphan
));
checkTestMessage
(
root
.
asReader
().
getStructField
());
}
}
}
// namespace
}
// namespace _ (private)
}
// namespace capnp
c++/src/capnp/orphan.h
0 → 100644
View file @
8536e962
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CAPNP_ORPHAN_H_
#define CAPNP_ORPHAN_H_
#include "layout.h"
namespace
capnp
{
class
StructSchema
;
class
ListSchema
;
struct
DynamicStruct
;
struct
DynamicList
;
template
<
typename
T
>
class
Orphan
{
// Represents an object which is allocated within some message builder but has no pointers
// pointing at it. An Orphan can later be "adopted" by some other object as one of that object's
// fields, without having to copy the orphan. For a field `foo` of pointer type, the generated
// code will define builder methods `void adoptFoo(Orphan<T>)` and `Orphan<T> disownFoo()`.
// Orphans can also be created independently of any parent using an Orphanage.
//
// `Orphan<T>` can be moved but not copied, like `Own<T>`, so that it is impossible for one
// orphan to be adopted multiple times. If an orphan is destroyed without being adopted, its
// contents are zero'd out (and possibly reused, if we ever implement the ability to reuse space
// in a message arena).
public
:
Orphan
()
=
default
;
KJ_DISALLOW_COPY
(
Orphan
);
Orphan
(
Orphan
&&
)
=
default
;
Orphan
&
operator
=
(
Orphan
&&
)
=
default
;
inline
typename
T
::
Builder
get
();
inline
bool
operator
==
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
{
return
builder
==
nullptr
;
}
private
:
_
::
OrphanBuilder
builder
;
inline
Orphan
(
_
::
OrphanBuilder
&&
builder
)
:
builder
(
kj
::
mv
(
builder
))
{}
template
<
typename
,
Kind
>
friend
struct
_
::
PointerHelpers
;
template
<
typename
,
Kind
>
friend
struct
List
;
friend
class
Orphanage
;
};
class
Orphanage
:
private
kj
::
DisallowConstCopy
{
// Use to directly allocate Orphan objects, without having a parent object allocate and then
// disown the object.
public
:
inline
Orphanage
()
:
arena
(
nullptr
)
{}
template
<
typename
BuilderType
>
static
Orphanage
getForMessageContaining
(
BuilderType
builder
);
// Construct an Orphanage that allocates within the message containing the given Builder. This
// allows the constructed Orphans to be adopted by objects within said message.
//
// This constructor takes the builder rather than having the builder have a getOrphanage() method
// because this is an advanced feature and we don't want to pollute the builder APIs with it.
//
// Note that if you have a direct pointer to the `MessageBuilder`, you can simply call its
// `getOrphanage()` method.
template
<
typename
RootType
>
Orphan
<
RootType
>
newOrphan
();
// Allocate a new orphaned struct.
template
<
typename
RootType
>
Orphan
<
RootType
>
newOrphan
(
uint
size
);
// Allocate a new orphaned list or blob.
Orphan
<
DynamicStruct
>
newOrphan
(
StructSchema
schema
);
// Dynamically create an orphan struct with the given schema. You must
// #include <capnp/dynamic.h> to use this.
Orphan
<
DynamicList
>
newOrphan
(
ListSchema
schema
,
uint
size
);
// Dynamically create an orphan list with the given schema. You must #include <capnp/dynamic.h>
// to use this.
template
<
typename
Reader
>
Orphan
<
FromReader
<
Reader
>>
newOrphanCopy
(
const
Reader
&
copyFrom
);
// Allocate a new orphaned object (struct, list, or blob) and initialize it as a copy of the
// given object.
private
:
_
::
BuilderArena
*
arena
;
inline
explicit
Orphanage
(
_
::
BuilderArena
*
arena
)
:
arena
(
arena
)
{}
template
<
typename
T
,
Kind
=
kind
<
T
>
()
>
struct
GetInnerBuilder
;
template
<
typename
T
,
Kind
=
kind
<
T
>
()
>
struct
GetInnerReader
;
template
<
typename
T
>
struct
NewOrphanListImpl
;
friend
class
MessageBuilder
;
};
// =======================================================================================
// Inline implementation details.
namespace
_
{
// private
template
<
typename
T
,
Kind
=
kind
<
T
>
()
>
struct
OrphanGetImpl
;
template
<
typename
T
>
struct
OrphanGetImpl
<
T
,
Kind
::
STRUCT
>
{
static
inline
typename
T
::
Builder
apply
(
_
::
OrphanBuilder
&
builder
)
{
return
typename
T
::
Builder
(
builder
.
asStruct
(
_
::
structSize
<
T
>
()));
}
};
template
<
typename
T
>
struct
OrphanGetImpl
<
List
<
T
>
,
Kind
::
LIST
>
{
static
inline
typename
List
<
T
>::
Builder
apply
(
_
::
OrphanBuilder
&
builder
)
{
return
typename
List
<
T
>::
Builder
(
builder
.
asList
(
_
::
ElementSizeForType
<
T
>::
value
));
}
};
template
<
typename
T
>
struct
OrphanGetImpl
<
List
<
T
,
Kind
::
STRUCT
>
,
Kind
::
LIST
>
{
static
inline
typename
T
::
Builder
apply
(
_
::
OrphanBuilder
&
builder
)
{
return
typename
List
<
T
>::
Builder
(
builder
.
asStructList
(
_
::
structSize
<
T
>
()));
}
};
template
<>
struct
OrphanGetImpl
<
Text
,
Kind
::
BLOB
>
{
static
inline
Text
::
Builder
apply
(
_
::
OrphanBuilder
&
builder
)
{
return
Text
::
Builder
(
builder
.
asText
());
}
};
template
<>
struct
OrphanGetImpl
<
Data
,
Kind
::
BLOB
>
{
static
inline
Data
::
Builder
apply
(
_
::
OrphanBuilder
&
builder
)
{
return
Data
::
Builder
(
builder
.
asData
());
}
};
}
// namespace _ (private)
template
<
typename
T
>
inline
typename
T
::
Builder
Orphan
<
T
>::
get
()
{
return
_
::
OrphanGetImpl
<
T
>::
apply
(
builder
);
}
template
<
typename
T
>
struct
Orphanage
::
GetInnerBuilder
<
T
,
Kind
::
STRUCT
>
{
static
inline
_
::
StructBuilder
apply
(
typename
T
::
Builder
&
t
)
{
return
t
.
_builder
;
}
};
template
<
typename
T
>
struct
Orphanage
::
GetInnerBuilder
<
T
,
Kind
::
LIST
>
{
static
inline
_
::
ListBuilder
apply
(
typename
T
::
Builder
&
t
)
{
return
t
.
builder
;
}
};
template
<
typename
BuilderType
>
Orphanage
Orphanage
::
getForMessageContaining
(
BuilderType
builder
)
{
return
Orphanage
(
GetInnerBuilder
<
FromBuilder
<
BuilderType
>>::
apply
(
builder
).
getArena
());
}
template
<
typename
RootType
>
Orphan
<
RootType
>
Orphanage
::
newOrphan
()
{
return
Orphan
<
RootType
>
(
_
::
OrphanBuilder
::
initStruct
(
arena
,
_
::
structSize
<
RootType
>
()));
}
template
<
typename
T
,
Kind
k
>
struct
Orphanage
::
NewOrphanListImpl
<
List
<
T
,
k
>>
{
static
inline
_
::
OrphanBuilder
apply
(
_
::
BuilderArena
*
arena
,
uint
size
)
{
return
_
::
OrphanBuilder
::
initList
(
arena
,
size
*
ELEMENTS
,
_
::
ElementSizeForType
<
T
>::
value
);
}
};
template
<
typename
T
>
struct
Orphanage
::
NewOrphanListImpl
<
List
<
T
,
Kind
::
STRUCT
>>
{
static
inline
_
::
OrphanBuilder
apply
(
_
::
BuilderArena
*
arena
,
uint
size
)
{
return
_
::
OrphanBuilder
::
initList
(
arena
,
size
*
ELEMENTS
,
_
::
structSize
<
T
>
());
}
};
template
<>
struct
Orphanage
::
NewOrphanListImpl
<
Text
>
{
static
inline
_
::
OrphanBuilder
apply
(
_
::
BuilderArena
*
arena
,
uint
size
)
{
return
_
::
OrphanBuilder
::
initText
(
arena
,
size
*
BYTES
);
}
};
template
<>
struct
Orphanage
::
NewOrphanListImpl
<
Data
>
{
static
inline
_
::
OrphanBuilder
apply
(
_
::
BuilderArena
*
arena
,
uint
size
)
{
return
_
::
OrphanBuilder
::
initData
(
arena
,
size
*
BYTES
);
}
};
template
<
typename
RootType
>
Orphan
<
RootType
>
Orphanage
::
newOrphan
(
uint
size
)
{
return
Orphan
<
RootType
>
(
NewOrphanListImpl
<
RootType
>::
apply
(
arena
,
size
));
}
template
<
typename
T
>
struct
Orphanage
::
GetInnerReader
<
T
,
Kind
::
STRUCT
>
{
static
inline
_
::
StructReader
apply
(
const
typename
T
::
Reader
&
t
)
{
return
t
.
_reader
;
}
};
template
<
typename
T
>
struct
Orphanage
::
GetInnerReader
<
T
,
Kind
::
LIST
>
{
static
inline
_
::
ListReader
apply
(
const
typename
T
::
Reader
&
t
)
{
return
t
.
reader
;
}
};
template
<
typename
T
>
struct
Orphanage
::
GetInnerReader
<
T
,
Kind
::
BLOB
>
{
static
inline
const
typename
T
::
Reader
&
apply
(
const
typename
T
::
Reader
&
t
)
{
return
t
;
}
};
template
<
typename
Reader
>
Orphan
<
FromReader
<
Reader
>>
Orphanage
::
newOrphanCopy
(
const
Reader
&
copyFrom
)
{
return
Orphan
<
FromReader
<
Reader
>>
(
_
::
OrphanBuilder
::
copy
(
arena
,
GetInnerReader
<
FromReader
<
Reader
>>::
apply
(
copyFrom
)));
}
}
// namespace capnp
#endif // CAPNP_ORPHAN_H_
c++/src/capnp/test-util.c++
View file @
8536e962
...
...
@@ -214,30 +214,6 @@ void dynamicInitTestMessage(DynamicStruct::Builder builder) {
builder
.
set
(
"enumList"
,
{
"foo"
,
"garply"
});
}
template
<
typename
T
,
typename
U
>
void
checkList
(
T
reader
,
std
::
initializer_list
<
U
>
expected
)
{
ASSERT_EQ
(
expected
.
size
(),
reader
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
EXPECT_EQ
(
expected
.
begin
()[
i
],
reader
[
i
]);
}
}
template
<
typename
T
>
void
checkList
(
T
reader
,
std
::
initializer_list
<
float
>
expected
)
{
ASSERT_EQ
(
expected
.
size
(),
reader
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
EXPECT_FLOAT_EQ
(
expected
.
begin
()[
i
],
reader
[
i
]);
}
}
template
<
typename
T
>
void
checkList
(
T
reader
,
std
::
initializer_list
<
double
>
expected
)
{
ASSERT_EQ
(
expected
.
size
(),
reader
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
EXPECT_DOUBLE_EQ
(
expected
.
begin
()[
i
],
reader
[
i
]);
}
}
inline
bool
isNaN
(
float
f
)
{
return
f
!=
f
;
}
inline
bool
isNaN
(
double
f
)
{
return
f
!=
f
;
}
...
...
@@ -347,27 +323,6 @@ void genericCheckTestMessage(Reader reader) {
// Hack because as<>() is a template-parameter-dependent lookup everywhere below...
#define as template as
template
<
typename
T
>
void
expectPrimitiveEq
(
T
a
,
T
b
)
{
EXPECT_EQ
(
a
,
b
);
}
void
expectPrimitiveEq
(
float
a
,
float
b
)
{
EXPECT_FLOAT_EQ
(
a
,
b
);
}
void
expectPrimitiveEq
(
double
a
,
double
b
)
{
EXPECT_DOUBLE_EQ
(
a
,
b
);
}
void
expectPrimitiveEq
(
Text
::
Reader
a
,
Text
::
Builder
b
)
{
EXPECT_EQ
(
a
,
b
);
}
void
expectPrimitiveEq
(
Data
::
Reader
a
,
Data
::
Builder
b
)
{
EXPECT_EQ
(
a
,
b
);
}
template
<
typename
Element
,
typename
T
>
void
checkList
(
T
reader
,
std
::
initializer_list
<
ReaderFor
<
Element
>>
expected
)
{
auto
list
=
reader
.
as
<
DynamicList
>
();
ASSERT_EQ
(
expected
.
size
(),
list
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
expectPrimitiveEq
(
expected
.
begin
()[
i
],
list
[
i
].
as
<
Element
>
());
}
auto
typed
=
reader
.
as
<
List
<
Element
>>
();
ASSERT_EQ
(
expected
.
size
(),
typed
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
expectPrimitiveEq
(
expected
.
begin
()[
i
],
typed
[
i
]);
}
}
Text
::
Reader
name
(
DynamicEnum
e
)
{
KJ_IF_MAYBE
(
schema
,
e
.
getEnumerant
())
{
return
schema
->
getProto
().
getName
();
...
...
c++/src/capnp/test-util.h
View file @
8536e962
...
...
@@ -28,6 +28,7 @@
#include <iostream>
#include "blob.h"
#include "dynamic.h"
#include <gtest/gtest.h>
namespace
capnp
{
...
...
@@ -90,6 +91,56 @@ void checkDynamicTestLists(DynamicStruct::Reader reader);
void
checkDynamicTestMessageAllZero
(
DynamicStruct
::
Builder
builder
);
void
checkDynamicTestMessageAllZero
(
DynamicStruct
::
Reader
reader
);
template
<
typename
T
,
typename
U
>
void
checkList
(
T
reader
,
std
::
initializer_list
<
U
>
expected
)
{
ASSERT_EQ
(
expected
.
size
(),
reader
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
EXPECT_EQ
(
expected
.
begin
()[
i
],
reader
[
i
]);
}
}
template
<
typename
T
>
void
checkList
(
T
reader
,
std
::
initializer_list
<
float
>
expected
)
{
ASSERT_EQ
(
expected
.
size
(),
reader
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
EXPECT_FLOAT_EQ
(
expected
.
begin
()[
i
],
reader
[
i
]);
}
}
template
<
typename
T
>
void
checkList
(
T
reader
,
std
::
initializer_list
<
double
>
expected
)
{
ASSERT_EQ
(
expected
.
size
(),
reader
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
EXPECT_DOUBLE_EQ
(
expected
.
begin
()[
i
],
reader
[
i
]);
}
}
// Hack because as<>() is a template-parameter-dependent lookup everywhere below...
#define as template as
template
<
typename
T
>
void
expectPrimitiveEq
(
T
a
,
T
b
)
{
EXPECT_EQ
(
a
,
b
);
}
inline
void
expectPrimitiveEq
(
float
a
,
float
b
)
{
EXPECT_FLOAT_EQ
(
a
,
b
);
}
inline
void
expectPrimitiveEq
(
double
a
,
double
b
)
{
EXPECT_DOUBLE_EQ
(
a
,
b
);
}
inline
void
expectPrimitiveEq
(
Text
::
Reader
a
,
Text
::
Builder
b
)
{
EXPECT_EQ
(
a
,
b
);
}
inline
void
expectPrimitiveEq
(
Data
::
Reader
a
,
Data
::
Builder
b
)
{
EXPECT_EQ
(
a
,
b
);
}
template
<
typename
Element
,
typename
T
>
void
checkList
(
T
reader
,
std
::
initializer_list
<
ReaderFor
<
Element
>>
expected
)
{
auto
list
=
reader
.
as
<
DynamicList
>
();
ASSERT_EQ
(
expected
.
size
(),
list
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
expectPrimitiveEq
(
expected
.
begin
()[
i
],
list
[
i
].
as
<
Element
>
());
}
auto
typed
=
reader
.
as
<
List
<
Element
>>
();
ASSERT_EQ
(
expected
.
size
(),
typed
.
size
());
for
(
uint
i
=
0
;
i
<
expected
.
size
();
i
++
)
{
expectPrimitiveEq
(
expected
.
begin
()[
i
],
typed
[
i
]);
}
}
#undef as
}
// namespace _ (private)
}
// namespace capnp
...
...
compiler/src/c++-header.mustache
View file @
8536e962
...
...
@@ -190,6 +190,7 @@ private:
template
<typename
T
,
::capnp::Kind
k
>
friend struct ::capnp::_::PointerHelpers;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::String KJ_STRINGIFY(
{{
typeFullName
}}
::Reader reader);
};
...
...
@@ -247,6 +248,8 @@ public:
{{#
fieldIsStruct
}}
inline
{{
fieldType
}}
::Builder init
{{
fieldTitleCase
}}
();
{{/
fieldIsStruct
}}
inline void adopt
{{
fieldTitleCase
}}
(::capnp::Orphan
<
{{
fieldType
}}
>
&&
value);
inline ::capnp::Orphan
<
{{
fieldType
}}
>
disown
{{
fieldTitleCase
}}
();
{{/
fieldIsGenericObject
}}
{{/
fieldIsPrimitive
}}
{{#
fieldIsGenericObject
}}
...
...
@@ -258,12 +261,16 @@ public:
set
{{
fieldTitleCase
}}
(std::initializer_list
<U>
value);
template
<typename
T
,
typename
...
Params
>
inline typename T::Builder
init
{{
fieldTitleCase
}}
(Params
&&
... params);
template
<typename
T
>
void adopt
{{
fieldTitleCase
}}
(::capnp::Orphan
<T>
&&
value);
template
<typename
T
,
typename
...
Params
>
::capnp::Orphan
<T>
disown
{{
fieldTitleCase
}}
(Params
&&
... params);
{{/
fieldIsGenericObject
}}
{{/
typeFields
}}
private:
::capnp::_::StructBuilder _builder;
template
<typename
T
,
::capnp::Kind
k
>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::String KJ_STRINGIFY(
{{
typeFullName
}}
::Builder builder);
};
...
...
@@ -409,6 +416,26 @@ inline {{fieldType}}::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(
}
{{/
fieldIsStruct
}}
inline void
{{
typeFullName
}}
::Builder::adopt
{{
fieldTitleCase
}}
(
::capnp::Orphan
<
{{
fieldType
}}
>
&&
value) {
{{#
fieldUnion
}}
_builder.setDataField
<
{{
unionTitleCase
}}
::Which>
(
{{
unionTagOffset
}}
* ::capnp::ELEMENTS,
{{
unionTitleCase
}}
::
{{
fieldUpperCase
}}
);
{{/
fieldUnion
}}
::capnp::_::PointerHelpers
<
{{
fieldType
}}
>
::adopt(
_builder,
{{
fieldOffset
}}
* ::capnp::POINTERS, kj::mv(value));
}
inline ::capnp::Orphan
<
{{
fieldType
}}
>
{{
typeFullName
}}
::Builder::disown
{{
fieldTitleCase
}}
() {
{{#
fieldUnion
}}
KJ_IREQUIRE(which() ==
{{
unionTitleCase
}}
::
{{
fieldUpperCase
}}
,
"Must check which() before get()ing a union member.");
{{/
fieldUnion
}}
return ::capnp::_::PointerHelpers
<
{{
fieldType
}}
>
::disown(
_builder,
{{
fieldOffset
}}
* ::capnp::POINTERS);
}
{{/
fieldIsGenericObject
}}
{{! ------------------------------------------------------------------------------------------- }}
{{#
fieldIsGenericObject
}}
...
...
@@ -482,6 +509,26 @@ inline typename T::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(Par
_builder,
{{
fieldOffset
}}
* ::capnp::POINTERS, ::kj::fwd
<Params>
(params)...);
}
template
<typename
T
>
void
{{
typeFullName
}}
::Builder::adopt
{{
fieldTitleCase
}}
(::capnp::Orphan
<T>
&&
value) {
{{#
fieldUnion
}}
_builder.setDataField
<
{{
unionTitleCase
}}
::Which>
(
{{
unionTagOffset
}}
* ::capnp::ELEMENTS,
{{
unionTitleCase
}}
::
{{
fieldUpperCase
}}
);
{{/
fieldUnion
}}
::capnp::_::PointerHelpers
<T>
::adopt(
_builder,
{{
fieldOffset
}}
* ::capnp::POINTERS, kj::mv(value));
}
template
<typename
T
,
typename
...
Params
>
::capnp::Orphan
<T>
{{
typeFullName
}}
::Builder::disown
{{
fieldTitleCase
}}
(Params
&&
... params) {
{{#
fieldUnion
}}
KJ_IREQUIRE(which() ==
{{
unionTitleCase
}}
::
{{
fieldUpperCase
}}
,
"Must check which() before get()ing a union member.");
{{/
fieldUnion
}}
return ::capnp::_::PointerHelpers
<T>
::disown(
_builder,
{{
fieldOffset
}}
* ::capnp::POINTERS, ::kj::fwd
<Params>
(params)...);
}
{{/
fieldIsGenericObject
}}
{{/
fieldIsPrimitive
}}
{{/
typeFields
}}
...
...
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