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
203a16cc
Commit
203a16cc
authored
Mar 19, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Basic serialization.
parent
9c3cb05f
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1404 additions
and
220 deletions
+1404
-220
encoding-test.c++
c++/src/capnproto/encoding-test.c++
+24
-220
serialize-test.c++
c++/src/capnproto/serialize-test.c++
+388
-0
serialize.c++
c++/src/capnproto/serialize.c++
+371
-0
serialize.h
c++/src/capnproto/serialize.h
+337
-0
test-util.c++
c++/src/capnproto/test-util.c++
+240
-0
test-util.h
c++/src/capnproto/test-util.h
+44
-0
No files found.
c++/src/capnproto/encoding-test.c++
View file @
203a16cc
...
...
@@ -24,234 +24,38 @@
#include "test.capnp.h"
#include "message.h"
#include <gtest/gtest.h>
#include
<initializer_list>
#include
"test-util.h"
namespace
capnproto
{
namespace
internal
{
namespace
{
template
<
typename
Builder
>
void
initMessage
(
Builder
builder
)
{
builder
.
setVoidField
(
Void
::
VOID
);
builder
.
setBoolField
(
true
);
builder
.
setInt8Field
(
-
123
);
builder
.
setInt16Field
(
-
12345
);
builder
.
setInt32Field
(
-
12345678
);
builder
.
setInt64Field
(
-
123456789012345ll
);
builder
.
setUInt8Field
(
234u
);
builder
.
setUInt16Field
(
45678u
);
builder
.
setUInt32Field
(
3456789012u
);
builder
.
setUInt64Field
(
12345678901234567890ull
);
builder
.
setFloat32Field
(
1234.5
);
builder
.
setFloat64Field
(
-
123e45
);
builder
.
setTextField
(
"foo"
);
builder
.
setDataField
(
"bar"
);
{
auto
subBuilder
=
builder
.
initStructField
();
subBuilder
.
setVoidField
(
Void
::
VOID
);
subBuilder
.
setBoolField
(
true
);
subBuilder
.
setInt8Field
(
-
12
);
subBuilder
.
setInt16Field
(
3456
);
subBuilder
.
setInt32Field
(
-
78901234
);
subBuilder
.
setInt64Field
(
56789012345678ll
);
subBuilder
.
setUInt8Field
(
90u
);
subBuilder
.
setUInt16Field
(
1234u
);
subBuilder
.
setUInt32Field
(
56789012u
);
subBuilder
.
setUInt64Field
(
345678901234567890ull
);
subBuilder
.
setFloat32Field
(
-
1.25e-10
);
subBuilder
.
setFloat64Field
(
345
);
subBuilder
.
setTextField
(
"baz"
);
subBuilder
.
setDataField
(
"qux"
);
{
auto
subSubBuilder
=
subBuilder
.
initStructField
();
subSubBuilder
.
setTextField
(
"nested"
);
subSubBuilder
.
initStructField
().
setTextField
(
"really nested"
);
}
subBuilder
.
setVoidList
({
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
subBuilder
.
setBoolList
({
false
,
true
,
false
,
true
,
true
});
subBuilder
.
setInt8List
({
12
,
-
34
,
-
0x80
,
0x7f
});
subBuilder
.
setInt16List
({
1234
,
-
5678
,
-
0x8000
,
0x7fff
});
subBuilder
.
setInt32List
({
12345678
,
-
90123456
,
-
0x8000000
,
0x7ffffff
});
// gcc warns on -0x800...ll and the only work-around I could find was to do -0x7ff...ll-1.
subBuilder
.
setInt64List
({
123456789012345ll
,
-
678901234567890ll
,
-
0x7fffffffffffffffll
-
1
,
0x7fffffffffffffffll
});
subBuilder
.
setUInt8List
({
12u
,
34u
,
0u
,
0xffu
});
subBuilder
.
setUInt16List
({
1234u
,
5678u
,
0u
,
0xffffu
});
subBuilder
.
setUInt32List
({
12345678u
,
90123456u
,
0u
,
0xffffffffu
});
subBuilder
.
setUInt64List
({
123456789012345ull
,
678901234567890ull
,
0ull
,
0xffffffffffffffffull
});
subBuilder
.
setFloat32List
({
0
,
1234567
,
1e37
,
-
1e37
,
1e-37
,
-
1e-37
});
subBuilder
.
setFloat64List
({
0
,
123456789012345
,
1e306
,
-
1e306
,
1e-306
,
-
1e-306
});
subBuilder
.
setTextList
({
"quux"
,
"corge"
,
"grault"
});
subBuilder
.
setDataList
({
"garply"
,
"waldo"
,
"fred"
});
{
auto
listBuilder
=
subBuilder
.
initStructList
(
3
);
listBuilder
[
0
].
setTextField
(
"x structlist 1"
);
listBuilder
[
1
].
setTextField
(
"x structlist 2"
);
listBuilder
[
2
].
setTextField
(
"x structlist 3"
);
}
}
builder
.
initVoidList
(
6
);
builder
.
setBoolList
({
true
,
false
,
false
,
true
});
builder
.
setInt8List
({
111
,
-
111
});
builder
.
setInt16List
({
11111
,
-
11111
});
builder
.
setInt32List
({
111111111
,
-
111111111
});
builder
.
setInt64List
({
1111111111111111111ll
,
-
1111111111111111111ll
});
builder
.
setUInt8List
({
111u
,
222u
});
builder
.
setUInt16List
({
33333u
,
44444u
});
builder
.
setUInt32List
({
3333333333u
});
builder
.
setUInt64List
({
11111111111111111111ull
});
builder
.
setFloat32List
({
5555.5
,
2222.25
});
builder
.
setFloat64List
({
7777.75
,
1111.125
});
builder
.
setTextList
({
"plugh"
,
"xyzzy"
,
"thud"
});
builder
.
setDataList
({
"oops"
,
"exhausted"
,
"rfc3092"
});
{
auto
listBuilder
=
builder
.
initStructList
(
3
);
listBuilder
[
0
].
setTextField
(
"structlist 1"
);
listBuilder
[
1
].
setTextField
(
"structlist 2"
);
listBuilder
[
2
].
setTextField
(
"structlist 3"
);
}
}
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
]);
}
}
template
<
typename
Reader
>
void
checkMessage
(
Reader
reader
)
{
EXPECT_EQ
(
Void
::
VOID
,
reader
.
getVoidField
());
EXPECT_EQ
(
true
,
reader
.
getBoolField
());
EXPECT_EQ
(
-
123
,
reader
.
getInt8Field
());
EXPECT_EQ
(
-
12345
,
reader
.
getInt16Field
());
EXPECT_EQ
(
-
12345678
,
reader
.
getInt32Field
());
EXPECT_EQ
(
-
123456789012345ll
,
reader
.
getInt64Field
());
EXPECT_EQ
(
234u
,
reader
.
getUInt8Field
());
EXPECT_EQ
(
45678u
,
reader
.
getUInt16Field
());
EXPECT_EQ
(
3456789012u
,
reader
.
getUInt32Field
());
EXPECT_EQ
(
12345678901234567890ull
,
reader
.
getUInt64Field
());
EXPECT_FLOAT_EQ
(
1234.5
f
,
reader
.
getFloat32Field
());
EXPECT_DOUBLE_EQ
(
-
123e45
,
reader
.
getFloat64Field
());
EXPECT_EQ
(
"foo"
,
reader
.
getTextField
());
EXPECT_EQ
(
"bar"
,
reader
.
getDataField
());
{
auto
subReader
=
reader
.
getStructField
();
EXPECT_EQ
(
Void
::
VOID
,
subReader
.
getVoidField
());
EXPECT_EQ
(
true
,
subReader
.
getBoolField
());
EXPECT_EQ
(
-
12
,
subReader
.
getInt8Field
());
EXPECT_EQ
(
3456
,
subReader
.
getInt16Field
());
EXPECT_EQ
(
-
78901234
,
subReader
.
getInt32Field
());
EXPECT_EQ
(
56789012345678ll
,
subReader
.
getInt64Field
());
EXPECT_EQ
(
90u
,
subReader
.
getUInt8Field
());
EXPECT_EQ
(
1234u
,
subReader
.
getUInt16Field
());
EXPECT_EQ
(
56789012u
,
subReader
.
getUInt32Field
());
EXPECT_EQ
(
345678901234567890ull
,
subReader
.
getUInt64Field
());
EXPECT_FLOAT_EQ
(
-
1.25e-10
f
,
subReader
.
getFloat32Field
());
EXPECT_DOUBLE_EQ
(
345
,
subReader
.
getFloat64Field
());
EXPECT_EQ
(
"baz"
,
subReader
.
getTextField
());
EXPECT_EQ
(
"qux"
,
subReader
.
getDataField
());
{
auto
subSubReader
=
subReader
.
getStructField
();
EXPECT_EQ
(
"nested"
,
subSubReader
.
getTextField
());
EXPECT_EQ
(
"really nested"
,
subSubReader
.
getStructField
().
getTextField
());
}
checkList
(
subReader
.
getVoidList
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
checkList
(
subReader
.
getBoolList
(),
{
false
,
true
,
false
,
true
,
true
});
checkList
(
subReader
.
getInt8List
(),
{
12
,
-
34
,
-
0x80
,
0x7f
});
checkList
(
subReader
.
getInt16List
(),
{
1234
,
-
5678
,
-
0x8000
,
0x7fff
});
checkList
(
subReader
.
getInt32List
(),
{
12345678
,
-
90123456
,
-
0x8000000
,
0x7ffffff
});
// gcc warns on -0x800...ll and the only work-around I could find was to do -0x7ff...ll-1.
checkList
(
subReader
.
getInt64List
(),
{
123456789012345ll
,
-
678901234567890ll
,
-
0x7fffffffffffffffll
-
1
,
0x7fffffffffffffffll
});
checkList
(
subReader
.
getUInt8List
(),
{
12u
,
34u
,
0u
,
0xffu
});
checkList
(
subReader
.
getUInt16List
(),
{
1234u
,
5678u
,
0u
,
0xffffu
});
checkList
(
subReader
.
getUInt32List
(),
{
12345678u
,
90123456u
,
0u
,
0xffffffffu
});
checkList
(
subReader
.
getUInt64List
(),
{
123456789012345ull
,
678901234567890ull
,
0ull
,
0xffffffffffffffffull
});
checkList
(
subReader
.
getFloat32List
(),
{
0.0
f
,
1234567.0
f
,
1e37
f
,
-
1e37
f
,
1e-37
f
,
-
1e-37
f
});
checkList
(
subReader
.
getFloat64List
(),
{
0.0
,
123456789012345.0
,
1e306
,
-
1e306
,
1e-306
,
-
1e-306
});
checkList
(
subReader
.
getTextList
(),
{
"quux"
,
"corge"
,
"grault"
});
checkList
(
subReader
.
getDataList
(),
{
"garply"
,
"waldo"
,
"fred"
});
{
auto
listReader
=
subReader
.
getStructList
();
ASSERT_EQ
(
3u
,
listReader
.
size
());
EXPECT_EQ
(
"x structlist 1"
,
listReader
[
0
].
getTextField
());
EXPECT_EQ
(
"x structlist 2"
,
listReader
[
1
].
getTextField
());
EXPECT_EQ
(
"x structlist 3"
,
listReader
[
2
].
getTextField
());
}
}
EXPECT_EQ
(
6u
,
reader
.
getVoidList
().
size
());
checkList
(
reader
.
getBoolList
(),
{
true
,
false
,
false
,
true
});
checkList
(
reader
.
getInt8List
(),
{
111
,
-
111
});
checkList
(
reader
.
getInt16List
(),
{
11111
,
-
11111
});
checkList
(
reader
.
getInt32List
(),
{
111111111
,
-
111111111
});
checkList
(
reader
.
getInt64List
(),
{
1111111111111111111ll
,
-
1111111111111111111ll
});
checkList
(
reader
.
getUInt8List
(),
{
111u
,
222u
});
checkList
(
reader
.
getUInt16List
(),
{
33333u
,
44444u
});
checkList
(
reader
.
getUInt32List
(),
{
3333333333u
});
checkList
(
reader
.
getUInt64List
(),
{
11111111111111111111ull
});
checkList
(
reader
.
getFloat32List
(),
{
5555.5
f
,
2222.25
f
});
checkList
(
reader
.
getFloat64List
(),
{
7777.75
,
1111.125
});
checkList
(
reader
.
getTextList
(),
{
"plugh"
,
"xyzzy"
,
"thud"
});
checkList
(
reader
.
getDataList
(),
{
"oops"
,
"exhausted"
,
"rfc3092"
});
{
auto
listReader
=
reader
.
getStructList
();
ASSERT_EQ
(
3u
,
listReader
.
size
());
EXPECT_EQ
(
"structlist 1"
,
listReader
[
0
].
getTextField
());
EXPECT_EQ
(
"structlist 2"
,
listReader
[
1
].
getTextField
());
EXPECT_EQ
(
"structlist 3"
,
listReader
[
2
].
getTextField
());
}
}
TEST
(
Encoding
,
AllTypes
)
{
MallocMessageBuilder
builder
;
initMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
checkMessage
(
builder
.
getRoot
<
TestAllTypes
>
());
checkMessage
(
builder
.
getRoot
<
TestAllTypes
>
().
asReader
());
init
Test
Message
(
builder
.
initRoot
<
TestAllTypes
>
());
check
Test
Message
(
builder
.
getRoot
<
TestAllTypes
>
());
check
Test
Message
(
builder
.
getRoot
<
TestAllTypes
>
().
asReader
());
SegmentArrayMessageReader
reader
(
builder
.
getSegmentsForOutput
());
checkMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
check
Test
Message
(
reader
.
getRoot
<
TestAllTypes
>
());
ASSERT_EQ
(
1u
,
builder
.
getSegmentsForOutput
().
size
());
checkMessage
(
readMessageTrusted
<
TestAllTypes
>
(
builder
.
getSegmentsForOutput
()[
0
].
begin
()));
check
Test
Message
(
readMessageTrusted
<
TestAllTypes
>
(
builder
.
getSegmentsForOutput
()[
0
].
begin
()));
}
TEST
(
Encoding
,
AllTypesMultiSegment
)
{
MallocMessageBuilder
builder
(
0
,
AllocationStrategy
::
FIXED_SIZE
);
initMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
checkMessage
(
builder
.
getRoot
<
TestAllTypes
>
());
checkMessage
(
builder
.
getRoot
<
TestAllTypes
>
().
asReader
());
init
Test
Message
(
builder
.
initRoot
<
TestAllTypes
>
());
check
Test
Message
(
builder
.
getRoot
<
TestAllTypes
>
());
check
Test
Message
(
builder
.
getRoot
<
TestAllTypes
>
().
asReader
());
SegmentArrayMessageReader
reader
(
builder
.
getSegmentsForOutput
());
checkMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
check
Test
Message
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Encoding
,
Defaults
)
{
...
...
@@ -259,38 +63,38 @@ TEST(Encoding, Defaults) {
ArrayPtr
<
const
word
>
segments
[
1
]
=
{
arrayPtr
(
nullRoot
.
words
,
1
)};
SegmentArrayMessageReader
reader
(
arrayPtr
(
segments
,
1
));
checkMessage
(
reader
.
getRoot
<
TestDefaults
>
());
checkMessage
(
readMessageTrusted
<
TestDefaults
>
(
nullRoot
.
words
));
check
Test
Message
(
reader
.
getRoot
<
TestDefaults
>
());
check
Test
Message
(
readMessageTrusted
<
TestDefaults
>
(
nullRoot
.
words
));
}
TEST
(
Encoding
,
DefaultInitialization
)
{
MallocMessageBuilder
builder
;
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
());
// first pass initializes to defaults
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
check
Test
Message
(
builder
.
getRoot
<
TestDefaults
>
());
// first pass initializes to defaults
check
Test
Message
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
());
// second pass just reads the initialized structure
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
check
Test
Message
(
builder
.
getRoot
<
TestDefaults
>
());
// second pass just reads the initialized structure
check
Test
Message
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
SegmentArrayMessageReader
reader
(
builder
.
getSegmentsForOutput
());
checkMessage
(
reader
.
getRoot
<
TestDefaults
>
());
check
Test
Message
(
reader
.
getRoot
<
TestDefaults
>
());
}
TEST
(
Encoding
,
DefaultInitializationMultiSegment
)
{
MallocMessageBuilder
builder
(
0
,
AllocationStrategy
::
FIXED_SIZE
);
// first pass initializes to defaults
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
());
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
check
Test
Message
(
builder
.
getRoot
<
TestDefaults
>
());
check
Test
Message
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
// second pass just reads the initialized structure
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
());
checkMessage
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
check
Test
Message
(
builder
.
getRoot
<
TestDefaults
>
());
check
Test
Message
(
builder
.
getRoot
<
TestDefaults
>
().
asReader
());
SegmentArrayMessageReader
reader
(
builder
.
getSegmentsForOutput
());
checkMessage
(
reader
.
getRoot
<
TestDefaults
>
());
check
Test
Message
(
reader
.
getRoot
<
TestDefaults
>
());
}
TEST
(
Encoding
,
DefaultsFromEmptyMessage
)
{
...
...
@@ -299,8 +103,8 @@ TEST(Encoding, DefaultsFromEmptyMessage) {
ArrayPtr
<
const
word
>
segments
[
1
]
=
{
arrayPtr
(
emptyMessage
.
words
,
1
)};
SegmentArrayMessageReader
reader
(
arrayPtr
(
segments
,
1
));
checkMessage
(
reader
.
getRoot
<
TestDefaults
>
());
checkMessage
(
readMessageTrusted
<
TestDefaults
>
(
emptyMessage
.
words
));
check
Test
Message
(
reader
.
getRoot
<
TestDefaults
>
());
check
Test
Message
(
readMessageTrusted
<
TestDefaults
>
(
emptyMessage
.
words
));
}
}
// namespace
...
...
c++/src/capnproto/serialize-test.c++
0 → 100644
View file @
203a16cc
// 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 "test.capnp.h"
#include "serialize.h"
#include <gtest/gtest.h>
#include <string>
#include <stdlib.h>
#include "test-util.h"
namespace
capnproto
{
namespace
internal
{
namespace
{
class
TestMessageBuilder
:
public
MallocMessageBuilder
{
// A MessageBuilder that tries to allocate an exact number of total segments, by allocating
// minimum-size segments until it reaches the number, then allocating one large segment to
// finish.
public
:
explicit
TestMessageBuilder
(
uint
desiredSegmentCount
)
:
MallocMessageBuilder
(
0
,
AllocationStrategy
::
FIXED_SIZE
),
desiredSegmentCount
(
desiredSegmentCount
)
{}
~
TestMessageBuilder
()
{
EXPECT_EQ
(
0u
,
desiredSegmentCount
);
}
ArrayPtr
<
word
>
allocateSegment
(
uint
minimumSize
)
override
{
if
(
desiredSegmentCount
<=
1
)
{
if
(
desiredSegmentCount
<
1
)
{
ADD_FAILURE
()
<<
"Allocated more segments than desired."
;
}
else
{
--
desiredSegmentCount
;
}
return
MallocMessageBuilder
::
allocateSegment
(
SUGGESTED_FIRST_SEGMENT_WORDS
);
}
else
{
--
desiredSegmentCount
;
return
MallocMessageBuilder
::
allocateSegment
(
minimumSize
);
}
}
private
:
uint
desiredSegmentCount
;
};
TEST
(
Serialize
,
FlatArray
)
{
TestMessageBuilder
builder
(
1
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
FlatArrayMessageReader
reader
(
serialized
.
asPtr
());
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
FlatArrayOddSegmentCount
)
{
TestMessageBuilder
builder
(
7
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
FlatArrayMessageReader
reader
(
serialized
.
asPtr
());
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
FlatArrayEventSegmentCount
)
{
TestMessageBuilder
builder
(
10
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
FlatArrayMessageReader
reader
(
serialized
.
asPtr
());
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
class
TestInputStream
:
public
InputStream
{
public
:
TestInputStream
(
ArrayPtr
<
const
word
>
data
)
:
pos
(
reinterpret_cast
<
const
char
*>
(
data
.
begin
())),
end
(
reinterpret_cast
<
const
char
*>
(
data
.
end
()))
{}
~
TestInputStream
()
{}
bool
read
(
void
*
buffer
,
size_t
size
)
override
{
if
(
size_t
(
end
-
pos
)
<
size
)
{
ADD_FAILURE
()
<<
"Overran end of stream."
;
return
false
;
}
else
{
memcpy
(
buffer
,
pos
,
size
);
pos
+=
size
;
return
true
;
}
}
private
:
const
char
*
pos
;
const
char
*
end
;
};
TEST
(
Serialize
,
InputStream
)
{
TestMessageBuilder
builder
(
1
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputStream
stream
(
serialized
.
asPtr
());
InputStreamMessageReader
reader
(
&
stream
,
ReaderOptions
(),
InputStrategy
::
EAGER
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputStreamLazy
)
{
TestMessageBuilder
builder
(
1
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputStream
stream
(
serialized
.
asPtr
());
InputStreamMessageReader
reader
(
&
stream
,
ReaderOptions
(),
InputStrategy
::
LAZY
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputStreamOddSegmentCount
)
{
TestMessageBuilder
builder
(
7
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputStream
stream
(
serialized
.
asPtr
());
InputStreamMessageReader
reader
(
&
stream
,
ReaderOptions
(),
InputStrategy
::
EAGER
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputStreamOddSegmentCountLazy
)
{
TestMessageBuilder
builder
(
7
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputStream
stream
(
serialized
.
asPtr
());
InputStreamMessageReader
reader
(
&
stream
,
ReaderOptions
(),
InputStrategy
::
LAZY
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputStreamEventSegmentCount
)
{
TestMessageBuilder
builder
(
10
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputStream
stream
(
serialized
.
asPtr
());
InputStreamMessageReader
reader
(
&
stream
,
ReaderOptions
(),
InputStrategy
::
EAGER
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputStreamEventSegmentCountLazy
)
{
TestMessageBuilder
builder
(
10
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputStream
stream
(
serialized
.
asPtr
());
InputStreamMessageReader
reader
(
&
stream
,
ReaderOptions
(),
InputStrategy
::
LAZY
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
class
TestInputFile
:
public
InputFile
{
public
:
TestInputFile
(
ArrayPtr
<
const
word
>
data
)
:
begin
(
reinterpret_cast
<
const
char
*>
(
data
.
begin
())),
size_
(
data
.
size
()
*
sizeof
(
word
))
{}
~
TestInputFile
()
{}
bool
read
(
size_t
offset
,
void
*
buffer
,
size_t
size
)
override
{
if
(
size_
<
offset
+
size
)
{
ADD_FAILURE
()
<<
"Overran end of file."
;
return
false
;
}
else
{
memcpy
(
buffer
,
begin
+
offset
,
size
);
return
true
;
}
}
private
:
const
char
*
begin
;
size_t
size_
;
};
TEST
(
Serialize
,
InputFile
)
{
TestMessageBuilder
builder
(
1
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputFile
file
(
serialized
.
asPtr
());
InputFileMessageReader
reader
(
&
file
,
ReaderOptions
(),
InputStrategy
::
EAGER
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputFileLazy
)
{
TestMessageBuilder
builder
(
1
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputFile
file
(
serialized
.
asPtr
());
InputFileMessageReader
reader
(
&
file
,
ReaderOptions
(),
InputStrategy
::
LAZY
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputFileOddSegmentCount
)
{
TestMessageBuilder
builder
(
7
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputFile
file
(
serialized
.
asPtr
());
InputFileMessageReader
reader
(
&
file
,
ReaderOptions
(),
InputStrategy
::
EAGER
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputFileOddSegmentCountLazy
)
{
TestMessageBuilder
builder
(
7
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputFile
file
(
serialized
.
asPtr
());
InputFileMessageReader
reader
(
&
file
,
ReaderOptions
(),
InputStrategy
::
LAZY
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputFileEventSegmentCount
)
{
TestMessageBuilder
builder
(
10
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputFile
file
(
serialized
.
asPtr
());
InputFileMessageReader
reader
(
&
file
,
ReaderOptions
(),
InputStrategy
::
EAGER
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
TEST
(
Serialize
,
InputFileEventSegmentCountLazy
)
{
TestMessageBuilder
builder
(
10
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestInputFile
file
(
serialized
.
asPtr
());
InputFileMessageReader
reader
(
&
file
,
ReaderOptions
(),
InputStrategy
::
LAZY
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
class
TestOutputStream
:
public
OutputStream
{
public
:
TestOutputStream
()
{}
~
TestOutputStream
()
{}
void
write
(
const
void
*
buffer
,
size_t
size
)
override
{
data
.
append
(
reinterpret_cast
<
const
char
*>
(
buffer
),
size
);
}
const
bool
dataEquals
(
ArrayPtr
<
const
word
>
other
)
{
return
data
==
std
::
string
(
reinterpret_cast
<
const
char
*>
(
other
.
begin
()),
other
.
size
()
*
sizeof
(
word
));
}
private
:
std
::
string
data
;
};
TEST
(
Serialize
,
WriteMessage
)
{
TestMessageBuilder
builder
(
1
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestOutputStream
output
;
writeMessage
(
output
,
builder
);
EXPECT_TRUE
(
output
.
dataEquals
(
serialized
.
asPtr
()));
}
TEST
(
Serialize
,
WriteMessageOddSegmentCount
)
{
TestMessageBuilder
builder
(
7
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestOutputStream
output
;
writeMessage
(
output
,
builder
);
EXPECT_TRUE
(
output
.
dataEquals
(
serialized
.
asPtr
()));
}
TEST
(
Serialize
,
WriteMessageEventSegmentCount
)
{
TestMessageBuilder
builder
(
10
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
Array
<
word
>
serialized
=
messageToFlatArray
(
builder
);
TestOutputStream
output
;
writeMessage
(
output
,
builder
);
EXPECT_TRUE
(
output
.
dataEquals
(
serialized
.
asPtr
()));
}
TEST
(
Serialize
,
FileDescriptors
)
{
char
filename
[]
=
"/tmp/capnproto-serialize-test-XXXXXX"
;
AutoCloseFd
tmpfile
(
mkstemp
(
filename
));
ASSERT_GE
(
tmpfile
.
get
(),
0
);
// Unlink the file so that it will be deleted on close.
EXPECT_EQ
(
0
,
unlink
(
filename
));
{
TestMessageBuilder
builder
(
7
);
initTestMessage
(
builder
.
initRoot
<
TestAllTypes
>
());
writeMessageToFd
(
tmpfile
.
get
(),
builder
);
}
{
TestMessageBuilder
builder
(
1
);
builder
.
initRoot
<
TestAllTypes
>
().
setTextField
(
"second message in file"
);
writeMessageToFd
(
tmpfile
.
get
(),
builder
);
}
lseek
(
tmpfile
,
0
,
SEEK_SET
);
{
StreamFdMessageReader
reader
(
tmpfile
.
get
());
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
{
FileFdMessageReader
reader
(
tmpfile
.
get
(),
0
);
checkTestMessage
(
reader
.
getRoot
<
TestAllTypes
>
());
}
size_t
secondStart
=
lseek
(
tmpfile
,
0
,
SEEK_CUR
);
{
StreamFdMessageReader
reader
(
tmpfile
.
get
());
EXPECT_EQ
(
"second message in file"
,
reader
.
getRoot
<
TestAllTypes
>
().
getTextField
());
}
{
FileFdMessageReader
reader
(
move
(
tmpfile
),
secondStart
);
EXPECT_EQ
(
"second message in file"
,
reader
.
getRoot
<
TestAllTypes
>
().
getTextField
());
}
}
// TODO: Test error cases.
}
// namespace
}
// namespace internal
}
// namespace capnproto
c++/src/capnproto/serialize.c++
0 → 100644
View file @
203a16cc
// 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 "serialize.h"
#include "wire-format.h"
#include <string.h>
#include <errno.h>
#include <unistd.h>
namespace
capnproto
{
FlatArrayMessageReader
::
FlatArrayMessageReader
(
ArrayPtr
<
const
word
>
array
,
ReaderOptions
options
)
:
MessageReader
(
options
)
{
if
(
array
.
size
()
<
1
)
{
// Assume empty message.
return
;
}
const
internal
::
WireValue
<
uint32_t
>*
table
=
reinterpret_cast
<
const
internal
::
WireValue
<
uint32_t
>*>
(
array
.
begin
());
uint
segmentCount
=
table
[
0
].
get
();
size_t
offset
=
segmentCount
/
2u
+
1u
;
if
(
array
.
size
()
<
offset
)
{
options
.
errorReporter
->
reportError
(
"Message ends prematurely in segment table."
);
return
;
}
if
(
segmentCount
==
0
)
{
return
;
}
uint
segmentSize
=
table
[
1
].
get
();
if
(
array
.
size
()
<
offset
+
segmentSize
)
{
options
.
errorReporter
->
reportError
(
"Message ends prematurely in first segment."
);
return
;
}
segment0
=
array
.
slice
(
offset
,
offset
+
segmentSize
);
offset
+=
segmentSize
;
if
(
segmentCount
>
1
)
{
moreSegments
=
newArray
<
ArrayPtr
<
const
word
>>
(
segmentCount
-
1
);
for
(
uint
i
=
1
;
i
<
segmentCount
;
i
++
)
{
uint
segmentSize
=
table
[
i
+
1
].
get
();
if
(
array
.
size
()
<
offset
+
segmentSize
)
{
moreSegments
=
nullptr
;
options
.
errorReporter
->
reportError
(
"Message ends prematurely."
);
return
;
}
moreSegments
[
i
-
1
]
=
array
.
slice
(
offset
,
offset
+
segmentSize
);
offset
+=
segmentSize
;
}
}
}
ArrayPtr
<
const
word
>
FlatArrayMessageReader
::
getSegment
(
uint
id
)
{
if
(
id
==
0
)
{
return
segment0
;
}
else
if
(
id
<=
moreSegments
.
size
())
{
return
moreSegments
[
id
-
1
];
}
else
{
return
nullptr
;
}
}
Array
<
word
>
messageToFlatArray
(
ArrayPtr
<
const
ArrayPtr
<
const
word
>>
segments
)
{
size_t
totalSize
=
segments
.
size
()
/
2
+
1
;
for
(
auto
&
segment
:
segments
)
{
totalSize
+=
segment
.
size
();
}
Array
<
word
>
result
=
newArray
<
word
>
(
totalSize
);
internal
::
WireValue
<
uint32_t
>*
table
=
reinterpret_cast
<
internal
::
WireValue
<
uint32_t
>*>
(
result
.
begin
());
table
[
0
].
set
(
segments
.
size
());
for
(
uint
i
=
0
;
i
<
segments
.
size
();
i
++
)
{
table
[
i
+
1
].
set
(
segments
[
i
].
size
());
}
if
(
segments
.
size
()
%
2
==
0
)
{
// Set padding byte.
table
[
segments
.
size
()
+
1
].
set
(
0
);
}
word
*
dst
=
result
.
begin
()
+
segments
.
size
()
/
2
+
1
;
for
(
auto
&
segment
:
segments
)
{
memcpy
(
dst
,
segment
.
begin
(),
segment
.
size
()
*
sizeof
(
word
));
dst
+=
segment
.
size
();
}
CAPNPROTO_DEBUG_ASSERT
(
dst
==
result
.
end
(),
"Buffer overrun/underrun bug in code above."
);
return
move
(
result
);
}
// =======================================================================================
InputStream
::~
InputStream
()
{}
InputFile
::~
InputFile
()
{}
OutputStream
::~
OutputStream
()
{}
// -------------------------------------------------------------------
InputStreamMessageReader
::
InputStreamMessageReader
(
InputStream
*
inputStream
,
ReaderOptions
options
,
InputStrategy
inputStrategy
)
:
MessageReader
(
options
),
inputStream
(
inputStream
),
segmentsReadSoFar
(
0
)
{
internal
::
WireValue
<
uint32_t
>
firstWord
[
2
];
if
(
!
inputStream
->
read
(
firstWord
,
sizeof
(
firstWord
)))
return
;
uint
segmentCount
=
firstWord
[
0
].
get
();
segment0
.
size
=
segmentCount
==
0
?
0
:
firstWord
[
1
].
get
();
if
(
segmentCount
>
1
)
{
internal
::
WireValue
<
uint32_t
>
sizes
[
segmentCount
-
1
];
if
(
!
inputStream
->
read
(
sizes
,
sizeof
(
sizes
)))
return
;
moreSegments
=
newArray
<
LazySegment
>
(
segmentCount
-
1
);
for
(
uint
i
=
1
;
i
<
segmentCount
;
i
++
)
{
moreSegments
[
i
-
1
].
size
=
sizes
[
i
-
1
].
get
();
}
}
if
(
segmentCount
%
2
==
0
)
{
// Read the padding.
uint32_t
pad
;
if
(
!
inputStream
->
read
(
&
pad
,
sizeof
(
pad
)))
return
;
}
if
(
inputStrategy
==
InputStrategy
::
EAGER
)
{
getSegment
(
segmentCount
-
1
);
inputStream
=
nullptr
;
}
}
ArrayPtr
<
const
word
>
InputStreamMessageReader
::
getSegment
(
uint
id
)
{
if
(
id
>
moreSegments
.
size
())
{
return
nullptr
;
}
while
(
segmentsReadSoFar
<=
id
&&
inputStream
!=
nullptr
)
{
LazySegment
&
segment
=
segmentsReadSoFar
==
0
?
segment0
:
moreSegments
[
segmentsReadSoFar
-
1
];
Array
<
word
>
words
=
newArray
<
word
>
(
segment
.
size
);
if
(
!
inputStream
->
read
(
words
.
begin
(),
words
.
size
()
*
sizeof
(
word
)))
{
// There was an error but no exception was thrown, so we're supposed to plod along with
// default values. Discard the broken stream.
inputStream
=
nullptr
;
break
;
}
segment
.
words
=
move
(
words
);
++
segmentsReadSoFar
;
}
return
id
==
0
?
segment0
.
words
.
asPtr
()
:
moreSegments
[
id
-
1
].
words
.
asPtr
();
}
// -------------------------------------------------------------------
InputFileMessageReader
::
InputFileMessageReader
(
InputFile
*
inputFile
,
ReaderOptions
options
,
InputStrategy
inputStrategy
)
:
MessageReader
(
options
),
inputFile
(
inputFile
)
{
internal
::
WireValue
<
uint32_t
>
firstWord
[
2
];
if
(
!
inputFile
->
read
(
0
,
firstWord
,
sizeof
(
firstWord
)))
return
;
uint
segmentCount
=
firstWord
[
0
].
get
();
segment0
.
size
=
segmentCount
==
0
?
0
:
firstWord
[
1
].
get
();
if
(
segmentCount
>
1
)
{
internal
::
WireValue
<
uint32_t
>
sizes
[
segmentCount
-
1
];
if
(
!
inputFile
->
read
(
sizeof
(
firstWord
),
sizes
,
sizeof
(
sizes
)))
return
;
uint64_t
offset
=
(
segmentCount
/
2
+
1
)
*
sizeof
(
word
);
segment0
.
offset
=
offset
;
offset
+=
segment0
.
size
*
sizeof
(
word
);
moreSegments
=
newArray
<
LazySegment
>
(
segmentCount
-
1
);
for
(
uint
i
=
1
;
i
<
segmentCount
;
i
++
)
{
uint
segmentSize
=
sizes
[
i
-
1
].
get
();
moreSegments
[
i
-
1
].
size
=
segmentSize
;
moreSegments
[
i
-
1
].
offset
=
offset
;
offset
+=
segmentSize
*
sizeof
(
word
);
}
}
else
{
segment0
.
offset
=
sizeof
(
firstWord
);
}
if
(
inputStrategy
==
InputStrategy
::
EAGER
)
{
for
(
uint
i
=
0
;
i
<
segmentCount
;
i
++
)
{
getSegment
(
segmentCount
);
}
inputFile
=
nullptr
;
}
}
ArrayPtr
<
const
word
>
InputFileMessageReader
::
getSegment
(
uint
id
)
{
if
(
id
>
moreSegments
.
size
())
{
return
nullptr
;
}
LazySegment
&
segment
=
id
==
0
?
segment0
:
moreSegments
[
id
-
1
];
if
(
segment
.
words
==
nullptr
&&
segment
.
size
>
0
&&
inputFile
!=
nullptr
)
{
Array
<
word
>
words
=
newArray
<
word
>
(
segment
.
size
);
if
(
!
inputFile
->
read
(
segment
.
offset
,
words
.
begin
(),
words
.
size
()
*
sizeof
(
word
)))
{
// There was an error but no exception was thrown, so we're supposed to plod along with
// default values. Discard the broken stream.
inputFile
=
nullptr
;
}
else
{
segment
.
words
=
move
(
words
);
}
}
return
segment
.
words
.
asPtr
();
}
// -------------------------------------------------------------------
void
writeMessage
(
OutputStream
&
output
,
ArrayPtr
<
const
ArrayPtr
<
const
word
>>
segments
)
{
internal
::
WireValue
<
uint32_t
>
table
[(
segments
.
size
()
+
2
)
&
~
size_t
(
1
)];
table
[
0
].
set
(
segments
.
size
());
for
(
uint
i
=
0
;
i
<
segments
.
size
();
i
++
)
{
table
[
i
+
1
].
set
(
segments
[
i
].
size
());
}
if
(
segments
.
size
()
%
2
==
0
)
{
// Set padding byte.
table
[
segments
.
size
()
+
1
].
set
(
0
);
}
output
.
write
(
table
,
sizeof
(
table
));
for
(
auto
&
segment
:
segments
)
{
output
.
write
(
segment
.
begin
(),
segment
.
size
()
*
sizeof
(
word
));
}
}
// =======================================================================================
class
OsException
:
public
std
::
exception
{
public
:
OsException
(
int
error
)
:
error
(
error
)
{}
~
OsException
()
noexcept
{}
const
char
*
what
()
const
noexcept
override
{
// TODO: Use strerror_r or whatever for thread-safety. Ugh.
return
strerror
(
error
);
}
private
:
int
error
;
};
AutoCloseFd
::~
AutoCloseFd
()
{
if
(
fd
>=
0
&&
close
(
fd
)
<
0
)
{
if
(
std
::
uncaught_exception
())
{
// TODO: Devise some way to report secondary errors during unwind.
}
else
{
throw
OsException
(
errno
);
}
}
}
FdInputStream
::~
FdInputStream
()
{}
bool
FdInputStream
::
read
(
void
*
buffer
,
size_t
size
)
{
char
*
pos
=
reinterpret_cast
<
char
*>
(
buffer
);
while
(
size
>
0
)
{
ssize_t
n
=
::
read
(
fd
,
pos
,
size
);
if
(
n
<=
0
)
{
if
(
n
<
0
)
{
// TODO: Use strerror_r or whatever for thread-safety. Ugh.
errorReporter
->
reportError
(
strerror
(
errno
));
}
else
if
(
n
==
0
)
{
errorReporter
->
reportError
(
"Stream ended prematurely."
);
}
return
false
;
}
pos
+=
n
;
size
-=
n
;
}
return
true
;
}
FdInputFile
::~
FdInputFile
()
{}
bool
FdInputFile
::
read
(
size_t
offset
,
void
*
buffer
,
size_t
size
)
{
char
*
pos
=
reinterpret_cast
<
char
*>
(
buffer
);
offset
+=
this
->
offset
;
while
(
size
>
0
)
{
ssize_t
n
=
::
pread
(
fd
,
pos
,
size
,
offset
);
if
(
n
<=
0
)
{
if
(
n
<
0
)
{
// TODO: Use strerror_r or whatever for thread-safety. Ugh.
errorReporter
->
reportError
(
strerror
(
errno
));
}
else
if
(
n
==
0
)
{
errorReporter
->
reportError
(
"Stream ended prematurely."
);
}
return
false
;
}
pos
+=
n
;
offset
+=
n
;
size
-=
n
;
}
return
true
;
}
FdOutputStream
::~
FdOutputStream
()
{}
void
FdOutputStream
::
write
(
const
void
*
buffer
,
size_t
size
)
{
const
char
*
pos
=
reinterpret_cast
<
const
char
*>
(
buffer
);
while
(
size
>
0
)
{
ssize_t
n
=
::
write
(
fd
,
pos
,
size
);
if
(
n
<=
0
)
{
throw
OsException
(
n
==
0
?
EIO
:
errno
);
}
pos
+=
n
;
size
-=
n
;
}
}
StreamFdMessageReader
::~
StreamFdMessageReader
()
{}
FileFdMessageReader
::~
FileFdMessageReader
()
{}
void
writeMessageToFd
(
int
fd
,
ArrayPtr
<
const
ArrayPtr
<
const
word
>>
segments
)
{
FdOutputStream
stream
(
fd
);
writeMessage
(
stream
,
segments
);
}
}
// namespace capnproto
c++/src/capnproto/serialize.h
0 → 100644
View file @
203a16cc
// 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.
// This file implements a simple serialization format for Cap'n Proto messages. The format
// is as follows:
//
// * 32-bit little-endian segment count (4 bytes).
// * 32-bit little-endian size of each segment (4*(segment count) bytes).
// * Padding so that subsequent data is 64-bit-aligned (0 or 4 bytes). (I.e., if there are an even
// number of segments, there are 4 bytes of zeros here, otherwise there is no padding.)
// * Data from each segment, in order (8*sum(segment sizes) bytes)
//
// This format has some important properties:
// - It is self-delimiting, so multiple messages may be written to a stream without any external
// delimiter.
// - The total size and position of each segment can be determined by reading only the first part
// of the message, allowing lazy and random-access reading of the segment data.
// - A message is always at least 8 bytes.
// - A single-segment message can be read entirely in two system calls with no buffering.
// - A multi-segment message can be read entirely in three system calls with no buffering.
// - The format is appropriate for mmap()ing since all data is aligned.
#ifndef CAPNPROTO_SERIALIZE_H_
#define CAPNPROTO_SERIALIZE_H_
#include "message.h"
namespace
capnproto
{
class
FlatArrayMessageReader
:
public
MessageReader
{
// Parses a message from a flat array. Note that it makes sense to use this together with mmap()
// for extremely fast parsing.
public
:
FlatArrayMessageReader
(
ArrayPtr
<
const
word
>
array
,
ReaderOptions
options
=
ReaderOptions
());
// The array must remain valid until the MessageReader is destroyed.
ArrayPtr
<
const
word
>
getSegment
(
uint
id
)
override
;
private
:
// Optimize for single-segment case.
ArrayPtr
<
const
word
>
segment0
;
Array
<
ArrayPtr
<
const
word
>>
moreSegments
;
};
Array
<
word
>
messageToFlatArray
(
MessageBuilder
&
builder
);
// Constructs a flat array containing the entire content of the given message.
Array
<
word
>
messageToFlatArray
(
ArrayPtr
<
const
ArrayPtr
<
const
word
>>
segments
);
// Version of messageToFlatArray that takes a raw segment array.
// =======================================================================================
class
InputStream
{
public
:
virtual
~
InputStream
();
virtual
bool
read
(
void
*
buffer
,
size_t
size
)
=
0
;
// Always reads the full size requested. Returns true if successful. May throw an exception
// on failure, or report the error through some side channel and return false.
};
class
InputFile
{
public
:
virtual
~
InputFile
();
virtual
bool
read
(
size_t
offset
,
void
*
buffer
,
size_t
size
)
=
0
;
// Always reads the full size requested. Returns true if successful. May throw an exception
// on failure, or report the error through some side channel and return false.
};
class
OutputStream
{
public
:
virtual
~
OutputStream
();
virtual
void
write
(
const
void
*
buffer
,
size_t
size
)
=
0
;
// Throws exception on error, or reports errors via some side channel and returns.
};
enum
class
InputStrategy
{
EAGER
,
// Read the whole message into RAM upfront, in the MessageReader constructor. When reading from
// an InputStream, the stream will then be positioned at the byte immediately after the end of
// the message, and will not be accessed again.
LAZY
// Read segments of the message into RAM as needed while the message structure is being traversed.
// When reading from an InputStream, segments must be read in order, so segments up to the
// required segment will also be read. No guarantee is made about the position of the InputStream
// after reading. When using an InputFile, only the exact segments desired are read.
};
class
InputStreamMessageReader
:
public
MessageReader
{
public
:
InputStreamMessageReader
(
InputStream
*
inputStream
,
ReaderOptions
options
=
ReaderOptions
(),
InputStrategy
inputStrategy
=
InputStrategy
::
EAGER
);
// implements MessageReader ----------------------------------------
ArrayPtr
<
const
word
>
getSegment
(
uint
id
)
override
;
private
:
InputStream
*
inputStream
;
uint
segmentsReadSoFar
;
struct
LazySegment
{
uint
size
;
Array
<
word
>
words
;
// null until actually read
inline
LazySegment
()
:
size
(
0
),
words
(
nullptr
)
{}
};
// Optimize for single-segment case.
LazySegment
segment0
;
Array
<
LazySegment
>
moreSegments
;
};
class
InputFileMessageReader
:
public
MessageReader
{
public
:
InputFileMessageReader
(
InputFile
*
inputFile
,
ReaderOptions
options
=
ReaderOptions
(),
InputStrategy
inputStrategy
=
InputStrategy
::
EAGER
);
// implements MessageReader ----------------------------------------
ArrayPtr
<
const
word
>
getSegment
(
uint
id
)
override
;
private
:
InputFile
*
inputFile
;
struct
LazySegment
{
uint
size
;
size_t
offset
;
Array
<
word
>
words
;
// null until actually read
inline
LazySegment
()
:
size
(
0
),
offset
(
0
),
words
(
nullptr
)
{}
};
// Optimize for single-segment case.
LazySegment
segment0
;
Array
<
LazySegment
>
moreSegments
;
};
void
writeMessage
(
OutputStream
&
output
,
MessageBuilder
&
builder
);
// Write the message to the given output stream.
void
writeMessage
(
OutputStream
&
output
,
ArrayPtr
<
const
ArrayPtr
<
const
word
>>
segments
);
// Write the segment array to the given output stream.
// =======================================================================================
// Specializations for reading from / writing to file descriptors.
class
AutoCloseFd
{
// A wrapper around a file descriptor which automatically closes the descriptor when destroyed.
// The wrapper supports move construction for transferring ownership of the descriptor. If
// close() returns an error, the destructor throws an exception, UNLESS the destructor is being
// called during unwind from another exception, in which case the close error is ignored.
//
// If your code is not exception-safe, you should not use AutoCloseFd. In this case you will
// have to call close() yourself and handle errors appropriately.
//
// TODO: Create a general helper library for reporting/detecting secondary exceptions that
// occurred during unwind of some primary exception.
public
:
inline
AutoCloseFd
()
:
fd
(
-
1
)
{}
inline
AutoCloseFd
(
std
::
nullptr_t
)
:
fd
(
-
1
)
{}
inline
explicit
AutoCloseFd
(
int
fd
)
:
fd
(
fd
)
{}
inline
AutoCloseFd
(
AutoCloseFd
&&
other
)
:
fd
(
other
.
fd
)
{
other
.
fd
=
-
1
;
}
CAPNPROTO_DISALLOW_COPY
(
AutoCloseFd
);
~
AutoCloseFd
();
inline
operator
int
()
{
return
fd
;
}
inline
int
get
()
{
return
fd
;
}
inline
bool
operator
==
(
std
::
nullptr_t
)
{
return
fd
<
0
;
}
inline
bool
operator
!=
(
std
::
nullptr_t
)
{
return
fd
>=
0
;
}
private
:
int
fd
;
};
class
FdInputStream
:
public
InputStream
{
// An InputStream wrapping a file descriptor.
public
:
FdInputStream
(
int
fd
,
ErrorReporter
*
errorReporter
=
getThrowingErrorReporter
())
:
fd
(
fd
),
errorReporter
(
errorReporter
)
{};
FdInputStream
(
AutoCloseFd
fd
,
ErrorReporter
*
errorReporter
=
getThrowingErrorReporter
())
:
fd
(
fd
),
autoclose
(
move
(
fd
)),
errorReporter
(
errorReporter
)
{}
~
FdInputStream
();
bool
read
(
void
*
buffer
,
size_t
size
)
override
;
private
:
int
fd
;
AutoCloseFd
autoclose
;
ErrorReporter
*
errorReporter
;
};
class
FdInputFile
:
public
InputFile
{
// An InputFile wrapping a file descriptor. The file descriptor must be seekable. This
// implementation uses pread(), so the stream pointer will not be modified.
public
:
FdInputFile
(
int
fd
,
size_t
offset
,
ErrorReporter
*
errorReporter
=
getThrowingErrorReporter
())
:
fd
(
fd
),
offset
(
offset
),
errorReporter
(
errorReporter
)
{};
FdInputFile
(
AutoCloseFd
fd
,
size_t
offset
,
ErrorReporter
*
errorReporter
=
getThrowingErrorReporter
())
:
fd
(
fd
),
autoclose
(
move
(
fd
)),
offset
(
offset
),
errorReporter
(
errorReporter
)
{}
~
FdInputFile
();
bool
read
(
size_t
offset
,
void
*
buffer
,
size_t
size
)
override
;
private
:
int
fd
;
AutoCloseFd
autoclose
;
size_t
offset
;
ErrorReporter
*
errorReporter
;
};
class
FdOutputStream
:
public
OutputStream
{
// An OutputStream wrapping a file descriptor.
public
:
FdOutputStream
(
int
fd
)
:
fd
(
fd
)
{};
FdOutputStream
(
AutoCloseFd
fd
)
:
fd
(
fd
),
autoclose
(
move
(
fd
))
{}
~
FdOutputStream
();
void
write
(
const
void
*
buffer
,
size_t
size
)
override
;
private
:
int
fd
;
AutoCloseFd
autoclose
;
};
class
StreamFdMessageReader
:
private
FdInputStream
,
public
InputStreamMessageReader
{
// A MessageReader that reads from a steam-based file descriptor. For seekable file descriptors
// (e.g. actual disk files), FdFileMessageReader is better, but this will still work.
public
:
StreamFdMessageReader
(
int
fd
,
ReaderOptions
options
=
ReaderOptions
(),
InputStrategy
inputStrategy
=
InputStrategy
::
EAGER
)
:
FdInputStream
(
fd
),
InputStreamMessageReader
(
this
,
options
,
inputStrategy
)
{}
// Read message from a file descriptor, without taking ownership of the descriptor.
//
// Since this version implies that the caller intends to read more data from the fd later on, the
// default is to read the entire message eagerly in the constructor, so that the fd will be
// deterministically positioned just past the end of the message.
StreamFdMessageReader
(
AutoCloseFd
fd
,
ReaderOptions
options
=
ReaderOptions
(),
InputStrategy
inputStrategy
=
InputStrategy
::
LAZY
)
:
FdInputStream
(
move
(
fd
)),
InputStreamMessageReader
(
this
,
options
,
inputStrategy
)
{}
// Read a message from a file descriptor, taking ownership of the descriptor.
//
// Since this version implies that the caller does not intend to read any more data from the fd,
// the default is to read the message lazily as needed.
~
StreamFdMessageReader
();
};
class
FileFdMessageReader
:
private
FdInputFile
,
public
InputFileMessageReader
{
// A MessageReader that reads from a seekable file descriptor, e.g. disk files. For non-seekable
// file descriptors, use FdStreamMessageReader. This implementation uses pread(), so the file
// descriptor's stream pointer will not be modified.
public
:
FileFdMessageReader
(
int
fd
,
size_t
offset
,
ReaderOptions
options
=
ReaderOptions
(),
InputStrategy
inputStrategy
=
InputStrategy
::
LAZY
)
:
FdInputFile
(
fd
,
offset
,
options
.
errorReporter
),
InputFileMessageReader
(
this
,
options
,
inputStrategy
)
{}
// Read message from a file descriptor, without taking ownership of the descriptor.
//
// All reads use pread(), so the file descriptor's stream pointer will not be modified.
FileFdMessageReader
(
AutoCloseFd
fd
,
size_t
offset
,
ReaderOptions
options
=
ReaderOptions
(),
InputStrategy
inputStrategy
=
InputStrategy
::
LAZY
)
:
FdInputFile
(
move
(
fd
),
offset
,
options
.
errorReporter
),
InputFileMessageReader
(
this
,
options
,
inputStrategy
)
{}
// Read a message from a file descriptor, taking ownership of the descriptor.
//
// All reads use pread(), so the file descriptor's stream pointer will not be modified.
~
FileFdMessageReader
();
};
void
writeMessageToFd
(
int
fd
,
MessageBuilder
&
builder
);
// Write the message to the given file descriptor.
//
// This function throws an exception on any I/O error. If your code is not exception-safe, be sure
// you catch this exception at the call site. If throwing an exception is not acceptable, you
// can implement your own OutputStream with arbitrary error handling and then use writeMessage().
void
writeMessageToFd
(
int
fd
,
ArrayPtr
<
const
ArrayPtr
<
const
word
>>
segments
);
// Write the segment array to the given file descriptor.
//
// This function throws an exception on any I/O error. If your code is not exception-safe, be sure
// you catch this exception at the call site. If throwing an exception is not acceptable, you
// can implement your own OutputStream with arbitrary error handling and then use writeMessage().
// =======================================================================================
// inline stuff
inline
Array
<
word
>
messageToFlatArray
(
MessageBuilder
&
builder
)
{
return
messageToFlatArray
(
builder
.
getSegmentsForOutput
());
}
inline
void
writeMessage
(
OutputStream
&
output
,
MessageBuilder
&
builder
)
{
writeMessage
(
output
,
builder
.
getSegmentsForOutput
());
}
inline
void
writeMessageToFd
(
int
fd
,
MessageBuilder
&
builder
)
{
writeMessageToFd
(
fd
,
builder
.
getSegmentsForOutput
());
}
}
// namespace capnproto
#endif // SERIALIZE_H_
c++/src/capnproto/test-util.c++
0 → 100644
View file @
203a16cc
// 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 "test-util.h"
#include <gtest/gtest.h>
namespace
capnproto
{
namespace
internal
{
namespace
{
template
<
typename
Builder
>
void
genericInitTestMessage
(
Builder
builder
)
{
builder
.
setVoidField
(
Void
::
VOID
);
builder
.
setBoolField
(
true
);
builder
.
setInt8Field
(
-
123
);
builder
.
setInt16Field
(
-
12345
);
builder
.
setInt32Field
(
-
12345678
);
builder
.
setInt64Field
(
-
123456789012345ll
);
builder
.
setUInt8Field
(
234u
);
builder
.
setUInt16Field
(
45678u
);
builder
.
setUInt32Field
(
3456789012u
);
builder
.
setUInt64Field
(
12345678901234567890ull
);
builder
.
setFloat32Field
(
1234.5
);
builder
.
setFloat64Field
(
-
123e45
);
builder
.
setTextField
(
"foo"
);
builder
.
setDataField
(
"bar"
);
{
auto
subBuilder
=
builder
.
initStructField
();
subBuilder
.
setVoidField
(
Void
::
VOID
);
subBuilder
.
setBoolField
(
true
);
subBuilder
.
setInt8Field
(
-
12
);
subBuilder
.
setInt16Field
(
3456
);
subBuilder
.
setInt32Field
(
-
78901234
);
subBuilder
.
setInt64Field
(
56789012345678ll
);
subBuilder
.
setUInt8Field
(
90u
);
subBuilder
.
setUInt16Field
(
1234u
);
subBuilder
.
setUInt32Field
(
56789012u
);
subBuilder
.
setUInt64Field
(
345678901234567890ull
);
subBuilder
.
setFloat32Field
(
-
1.25e-10
);
subBuilder
.
setFloat64Field
(
345
);
subBuilder
.
setTextField
(
"baz"
);
subBuilder
.
setDataField
(
"qux"
);
{
auto
subSubBuilder
=
subBuilder
.
initStructField
();
subSubBuilder
.
setTextField
(
"nested"
);
subSubBuilder
.
initStructField
().
setTextField
(
"really nested"
);
}
subBuilder
.
setVoidList
({
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
subBuilder
.
setBoolList
({
false
,
true
,
false
,
true
,
true
});
subBuilder
.
setInt8List
({
12
,
-
34
,
-
0x80
,
0x7f
});
subBuilder
.
setInt16List
({
1234
,
-
5678
,
-
0x8000
,
0x7fff
});
subBuilder
.
setInt32List
({
12345678
,
-
90123456
,
-
0x8000000
,
0x7ffffff
});
// gcc warns on -0x800...ll and the only work-around I could find was to do -0x7ff...ll-1.
subBuilder
.
setInt64List
({
123456789012345ll
,
-
678901234567890ll
,
-
0x7fffffffffffffffll
-
1
,
0x7fffffffffffffffll
});
subBuilder
.
setUInt8List
({
12u
,
34u
,
0u
,
0xffu
});
subBuilder
.
setUInt16List
({
1234u
,
5678u
,
0u
,
0xffffu
});
subBuilder
.
setUInt32List
({
12345678u
,
90123456u
,
0u
,
0xffffffffu
});
subBuilder
.
setUInt64List
({
123456789012345ull
,
678901234567890ull
,
0ull
,
0xffffffffffffffffull
});
subBuilder
.
setFloat32List
({
0
,
1234567
,
1e37
,
-
1e37
,
1e-37
,
-
1e-37
});
subBuilder
.
setFloat64List
({
0
,
123456789012345
,
1e306
,
-
1e306
,
1e-306
,
-
1e-306
});
subBuilder
.
setTextList
({
"quux"
,
"corge"
,
"grault"
});
subBuilder
.
setDataList
({
"garply"
,
"waldo"
,
"fred"
});
{
auto
listBuilder
=
subBuilder
.
initStructList
(
3
);
listBuilder
[
0
].
setTextField
(
"x structlist 1"
);
listBuilder
[
1
].
setTextField
(
"x structlist 2"
);
listBuilder
[
2
].
setTextField
(
"x structlist 3"
);
}
}
builder
.
initVoidList
(
6
);
builder
.
setBoolList
({
true
,
false
,
false
,
true
});
builder
.
setInt8List
({
111
,
-
111
});
builder
.
setInt16List
({
11111
,
-
11111
});
builder
.
setInt32List
({
111111111
,
-
111111111
});
builder
.
setInt64List
({
1111111111111111111ll
,
-
1111111111111111111ll
});
builder
.
setUInt8List
({
111u
,
222u
});
builder
.
setUInt16List
({
33333u
,
44444u
});
builder
.
setUInt32List
({
3333333333u
});
builder
.
setUInt64List
({
11111111111111111111ull
});
builder
.
setFloat32List
({
5555.5
,
2222.25
});
builder
.
setFloat64List
({
7777.75
,
1111.125
});
builder
.
setTextList
({
"plugh"
,
"xyzzy"
,
"thud"
});
builder
.
setDataList
({
"oops"
,
"exhausted"
,
"rfc3092"
});
{
auto
listBuilder
=
builder
.
initStructList
(
3
);
listBuilder
[
0
].
setTextField
(
"structlist 1"
);
listBuilder
[
1
].
setTextField
(
"structlist 2"
);
listBuilder
[
2
].
setTextField
(
"structlist 3"
);
}
}
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
]);
}
}
template
<
typename
Reader
>
void
genericCheckTestMessage
(
Reader
reader
)
{
EXPECT_EQ
(
Void
::
VOID
,
reader
.
getVoidField
());
EXPECT_EQ
(
true
,
reader
.
getBoolField
());
EXPECT_EQ
(
-
123
,
reader
.
getInt8Field
());
EXPECT_EQ
(
-
12345
,
reader
.
getInt16Field
());
EXPECT_EQ
(
-
12345678
,
reader
.
getInt32Field
());
EXPECT_EQ
(
-
123456789012345ll
,
reader
.
getInt64Field
());
EXPECT_EQ
(
234u
,
reader
.
getUInt8Field
());
EXPECT_EQ
(
45678u
,
reader
.
getUInt16Field
());
EXPECT_EQ
(
3456789012u
,
reader
.
getUInt32Field
());
EXPECT_EQ
(
12345678901234567890ull
,
reader
.
getUInt64Field
());
EXPECT_FLOAT_EQ
(
1234.5
f
,
reader
.
getFloat32Field
());
EXPECT_DOUBLE_EQ
(
-
123e45
,
reader
.
getFloat64Field
());
EXPECT_EQ
(
"foo"
,
reader
.
getTextField
());
EXPECT_EQ
(
"bar"
,
reader
.
getDataField
());
{
auto
subReader
=
reader
.
getStructField
();
EXPECT_EQ
(
Void
::
VOID
,
subReader
.
getVoidField
());
EXPECT_EQ
(
true
,
subReader
.
getBoolField
());
EXPECT_EQ
(
-
12
,
subReader
.
getInt8Field
());
EXPECT_EQ
(
3456
,
subReader
.
getInt16Field
());
EXPECT_EQ
(
-
78901234
,
subReader
.
getInt32Field
());
EXPECT_EQ
(
56789012345678ll
,
subReader
.
getInt64Field
());
EXPECT_EQ
(
90u
,
subReader
.
getUInt8Field
());
EXPECT_EQ
(
1234u
,
subReader
.
getUInt16Field
());
EXPECT_EQ
(
56789012u
,
subReader
.
getUInt32Field
());
EXPECT_EQ
(
345678901234567890ull
,
subReader
.
getUInt64Field
());
EXPECT_FLOAT_EQ
(
-
1.25e-10
f
,
subReader
.
getFloat32Field
());
EXPECT_DOUBLE_EQ
(
345
,
subReader
.
getFloat64Field
());
EXPECT_EQ
(
"baz"
,
subReader
.
getTextField
());
EXPECT_EQ
(
"qux"
,
subReader
.
getDataField
());
{
auto
subSubReader
=
subReader
.
getStructField
();
EXPECT_EQ
(
"nested"
,
subSubReader
.
getTextField
());
EXPECT_EQ
(
"really nested"
,
subSubReader
.
getStructField
().
getTextField
());
}
checkList
(
subReader
.
getVoidList
(),
{
Void
::
VOID
,
Void
::
VOID
,
Void
::
VOID
});
checkList
(
subReader
.
getBoolList
(),
{
false
,
true
,
false
,
true
,
true
});
checkList
(
subReader
.
getInt8List
(),
{
12
,
-
34
,
-
0x80
,
0x7f
});
checkList
(
subReader
.
getInt16List
(),
{
1234
,
-
5678
,
-
0x8000
,
0x7fff
});
checkList
(
subReader
.
getInt32List
(),
{
12345678
,
-
90123456
,
-
0x8000000
,
0x7ffffff
});
// gcc warns on -0x800...ll and the only work-around I could find was to do -0x7ff...ll-1.
checkList
(
subReader
.
getInt64List
(),
{
123456789012345ll
,
-
678901234567890ll
,
-
0x7fffffffffffffffll
-
1
,
0x7fffffffffffffffll
});
checkList
(
subReader
.
getUInt8List
(),
{
12u
,
34u
,
0u
,
0xffu
});
checkList
(
subReader
.
getUInt16List
(),
{
1234u
,
5678u
,
0u
,
0xffffu
});
checkList
(
subReader
.
getUInt32List
(),
{
12345678u
,
90123456u
,
0u
,
0xffffffffu
});
checkList
(
subReader
.
getUInt64List
(),
{
123456789012345ull
,
678901234567890ull
,
0ull
,
0xffffffffffffffffull
});
checkList
(
subReader
.
getFloat32List
(),
{
0.0
f
,
1234567.0
f
,
1e37
f
,
-
1e37
f
,
1e-37
f
,
-
1e-37
f
});
checkList
(
subReader
.
getFloat64List
(),
{
0.0
,
123456789012345.0
,
1e306
,
-
1e306
,
1e-306
,
-
1e-306
});
checkList
(
subReader
.
getTextList
(),
{
"quux"
,
"corge"
,
"grault"
});
checkList
(
subReader
.
getDataList
(),
{
"garply"
,
"waldo"
,
"fred"
});
{
auto
listReader
=
subReader
.
getStructList
();
ASSERT_EQ
(
3u
,
listReader
.
size
());
EXPECT_EQ
(
"x structlist 1"
,
listReader
[
0
].
getTextField
());
EXPECT_EQ
(
"x structlist 2"
,
listReader
[
1
].
getTextField
());
EXPECT_EQ
(
"x structlist 3"
,
listReader
[
2
].
getTextField
());
}
}
EXPECT_EQ
(
6u
,
reader
.
getVoidList
().
size
());
checkList
(
reader
.
getBoolList
(),
{
true
,
false
,
false
,
true
});
checkList
(
reader
.
getInt8List
(),
{
111
,
-
111
});
checkList
(
reader
.
getInt16List
(),
{
11111
,
-
11111
});
checkList
(
reader
.
getInt32List
(),
{
111111111
,
-
111111111
});
checkList
(
reader
.
getInt64List
(),
{
1111111111111111111ll
,
-
1111111111111111111ll
});
checkList
(
reader
.
getUInt8List
(),
{
111u
,
222u
});
checkList
(
reader
.
getUInt16List
(),
{
33333u
,
44444u
});
checkList
(
reader
.
getUInt32List
(),
{
3333333333u
});
checkList
(
reader
.
getUInt64List
(),
{
11111111111111111111ull
});
checkList
(
reader
.
getFloat32List
(),
{
5555.5
f
,
2222.25
f
});
checkList
(
reader
.
getFloat64List
(),
{
7777.75
,
1111.125
});
checkList
(
reader
.
getTextList
(),
{
"plugh"
,
"xyzzy"
,
"thud"
});
checkList
(
reader
.
getDataList
(),
{
"oops"
,
"exhausted"
,
"rfc3092"
});
{
auto
listReader
=
reader
.
getStructList
();
ASSERT_EQ
(
3u
,
listReader
.
size
());
EXPECT_EQ
(
"structlist 1"
,
listReader
[
0
].
getTextField
());
EXPECT_EQ
(
"structlist 2"
,
listReader
[
1
].
getTextField
());
EXPECT_EQ
(
"structlist 3"
,
listReader
[
2
].
getTextField
());
}
}
}
// namespace
void
initTestMessage
(
TestAllTypes
::
Builder
builder
)
{
genericInitTestMessage
(
builder
);
}
void
initTestMessage
(
TestDefaults
::
Builder
builder
)
{
genericInitTestMessage
(
builder
);
}
void
checkTestMessage
(
TestAllTypes
::
Builder
builder
)
{
genericCheckTestMessage
(
builder
);
}
void
checkTestMessage
(
TestDefaults
::
Builder
builder
)
{
genericCheckTestMessage
(
builder
);
}
void
checkTestMessage
(
TestAllTypes
::
Reader
reader
)
{
genericCheckTestMessage
(
reader
);
}
void
checkTestMessage
(
TestDefaults
::
Reader
reader
)
{
genericCheckTestMessage
(
reader
);
}
}
// namespace internal
}
// namespace capnproto
c++/src/capnproto/test-util.h
0 → 100644
View file @
203a16cc
// 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 CAPNPROTO_TEST_UTIL_H_
#define CAPNPROTO_TEST_UTIL_H_
#include "test.capnp.h"
namespace
capnproto
{
namespace
internal
{
void
initTestMessage
(
TestAllTypes
::
Builder
builder
);
void
initTestMessage
(
TestDefaults
::
Builder
builder
);
void
checkTestMessage
(
TestAllTypes
::
Builder
builder
);
void
checkTestMessage
(
TestDefaults
::
Builder
builder
);
void
checkTestMessage
(
TestAllTypes
::
Reader
reader
);
void
checkTestMessage
(
TestDefaults
::
Reader
reader
);
}
// namespace internal
}
// namespace capnproto
#endif // TEST_UTIL_H_
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