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
dd46a758
Commit
dd46a758
authored
Mar 01, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Type-safe quantities catch bugs.
parent
92a64de2
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
848 additions
and
261 deletions
+848
-261
descriptor-test.c++
c++/src/capnproto/descriptor-test.c++
+79
-0
descriptor.h
c++/src/capnproto/descriptor.h
+22
-9
macros.h
c++/src/capnproto/macros.h
+167
-0
message.h
c++/src/capnproto/message.h
+71
-58
unit-test.c++
c++/src/capnproto/unit-test.c++
+67
-0
unit.c++
c++/src/capnproto/unit.c++
+28
-0
unit.h
c++/src/capnproto/unit.h
+178
-0
wire-format.c++
c++/src/capnproto/wire-format.c++
+127
-116
wire-format.h
c++/src/capnproto/wire-format.h
+109
-78
No files found.
c++/src/capnproto/descriptor-test.c++
0 → 100644
View file @
dd46a758
// 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 "descriptor.h"
#include <gtest/gtest.h>
namespace
capnproto
{
namespace
internal
{
namespace
{
const
int
READONLY_SEGMENT_START
=
123
;
const
FieldDescriptor
TEST_FIELDS
[
2
]
=
{
{
WordCount8
(
1
*
WORDS
),
0
,
0
,
FieldSize
::
FOUR_BYTES
,
1
,
0
,
0
,
0
},
{
WordCount8
(
1
*
WORDS
),
1
,
0
,
FieldSize
::
REFERENCE
,
1
,
0
,
0
,
0
}
};
extern
const
StructDescriptor
TEST_STRUCT
;
extern
const
Descriptor
*
const
TEST_STRUCT_DEFAULT_REFS
[
1
]
=
{
&
TEST_STRUCT
.
base
};
const
AlignedData
<
1
>
TEST_STRUCT_DEFAULT_DATA
=
{
{
0x12
,
0x34
,
0x56
,
0x78
,
0x9a
,
0xbc
,
0xde
,
0xf0
}
};
const
StructDescriptor
TEST_STRUCT
=
{
{
Descriptor
::
Kind
::
STRUCT
},
2
,
WordCount8
(
1
*
WORDS
),
1
,
TEST_FIELDS
,
TEST_STRUCT_DEFAULT_DATA
.
bytes
,
TEST_STRUCT_DEFAULT_REFS
};
const
int
READONLY_SEGMENT_END
=
321
;
TEST
(
Descriptors
,
InReadOnlySegment
)
{
// It's extremely important that statically-initialized descriptors end up in the read-only
// segment, proving that they will not require any dynamic initialization at startup. We hackily
// assume that variables will be placed in each segment in the order that they appear, therefore
// if our test declarations above do in fact land in the read-only segment, they should appear
// between READONLY_SEGMENT_START and READONLY_SEGMENT_END.
EXPECT_LE
((
const
void
*
)
&
READONLY_SEGMENT_START
,
(
const
void
*
)
&
TEST_FIELDS
);
EXPECT_GE
((
const
void
*
)
&
READONLY_SEGMENT_END
,
(
const
void
*
)
&
TEST_FIELDS
);
EXPECT_LE
((
const
void
*
)
&
READONLY_SEGMENT_START
,
(
const
void
*
)
&
TEST_STRUCT_DEFAULT_DATA
);
EXPECT_GE
((
const
void
*
)
&
READONLY_SEGMENT_END
,
(
const
void
*
)
&
TEST_STRUCT_DEFAULT_DATA
);
EXPECT_LE
((
const
void
*
)
&
READONLY_SEGMENT_START
,
(
const
void
*
)
&
TEST_STRUCT_DEFAULT_REFS
);
EXPECT_GE
((
const
void
*
)
&
READONLY_SEGMENT_END
,
(
const
void
*
)
&
TEST_STRUCT_DEFAULT_REFS
);
EXPECT_LE
((
const
void
*
)
&
READONLY_SEGMENT_START
,
(
const
void
*
)
&
TEST_STRUCT
);
EXPECT_GE
((
const
void
*
)
&
READONLY_SEGMENT_END
,
(
const
void
*
)
&
TEST_STRUCT
);
}
}
// namespace
}
// namespace internal
}
// namespace capnproto
c++/src/capnproto/descriptor.h
View file @
dd46a758
...
...
@@ -46,6 +46,15 @@ struct ListDescriptor;
struct
StructDescriptor
;
struct
FieldDescriptor
;
template
<
int
wordCount
>
union
AlignedData
{
// Useful for declaring static constant data blobs as an array of bytes, but forcing those
// bytes to be word-aligned.
uint8_t
bytes
[
wordCount
*
sizeof
(
word
)];
word
words
[
wordCount
];
};
struct
Descriptor
{
// This is the "base type" for descriptors that describe the target of a reference.
// StructDescriptor and ListDescriptor should be treated as if they subclass this type. However,
...
...
@@ -79,17 +88,19 @@ enum class FieldSize: uint8_t {
// fields, since a struct cannot embed another struct inline.
};
inline
int
sizeInBits
(
FieldSize
s
)
{
static
const
int
table
[]
=
{
1
,
8
,
16
,
32
,
64
,
64
,
128
,
-
1
};
inline
BitCount
sizeInBits
(
FieldSize
s
)
{
static
constexpr
BitCount
table
[]
=
{
1
*
BITS
,
8
*
BITS
,
16
*
BITS
,
32
*
BITS
,
64
*
BITS
,
64
*
BITS
,
128
*
BITS
,
0
*
BITS
};
return
table
[
static_cast
<
int
>
(
s
)];
}
inline
i
nt
byteOffsetForFieldZero
(
FieldSize
s
)
{
inline
ByteCou
nt
byteOffsetForFieldZero
(
FieldSize
s
)
{
// For the given field size, get the offset, in bytes, between a struct pointer and the location
// of the struct's first field, if the struct's first field is of the given type. We use this
// to adjust pointers when non-struct lists are converted to struct lists or vice versa.
static
const
int
table
[]
=
{
1
,
1
,
2
,
4
,
8
,
0
,
8
,
0
};
static
constexpr
ByteCount
table
[]
=
{
1
*
BYTES
,
1
*
BYTES
,
2
*
BYTES
,
4
*
BYTES
,
8
*
BYTES
,
0
*
BYTES
,
8
*
BYTES
,
0
*
BYTES
};
return
table
[
static_cast
<
int
>
(
s
)];
}
...
...
@@ -131,8 +142,9 @@ struct StructDescriptor {
uint8_t
fieldCount
;
// Number of fields in this type -- that we were aware of at compile time, of course.
uint8_t
dataSize
;
WordCount8
dataSize
;
// Size of the data segment, in 64-bit words.
// TODO: Can we use WordCount here and still get static init?
uint8_t
referenceCount
;
// Number of references in the reference segment.
...
...
@@ -146,9 +158,10 @@ struct StructDescriptor {
const
Descriptor
*
const
*
defaultReferences
;
// Array of descriptors describing the references.
inline
uint32_
t
wordSize
()
const
{
inline
WordCoun
t
wordSize
()
const
{
// Size of the struct in words.
return
static_cast
<
uint32_t
>
(
fieldCount
)
+
static_cast
<
uint32_t
>
(
referenceCount
);
// TODO: Somehow use WORDS_PER_REFERENCE here.
return
WordCount
(
dataSize
)
+
referenceCount
*
WORDS
;
}
};
static_assert
(
__builtin_offsetof
(
StructDescriptor
,
base
)
==
0
,
...
...
@@ -158,12 +171,12 @@ static_assert(__builtin_offsetof(StructDescriptor, base) == 0,
struct
FieldDescriptor
{
// Describes one field of a struct.
uint8_t
requiredDataSize
;
WordCount8
requiredDataSize
;
// The minimum size of the data segment of any object which includes this field. This is always
// offset * size / 64 bits, rounded up. This value is useful for validating object references
// received on the wire -- if dataSize is insufficient to support fieldCount, don't trust it!
uint8_t
requiredReference
Size
;
uint8_t
requiredReference
Count
;
// The minimum size of the reference segment of any object which includes this field. Same deal
// as with requiredDataSize.
...
...
c++/src/capnproto/macros.h
View file @
dd46a758
...
...
@@ -24,7 +24,174 @@
#ifndef CAPNPROTO_MACROS_H_
#define CAPNPROTO_MACROS_H_
#include <inttypes.h>
#include "unit.h"
namespace
capnproto
{
// TODO: Rename file "common.h" since it's no longer just macros.
#define CAPNPROTO_DISALLOW_COPY(classname) \
classname(const classname&) = delete; \
classname& operator=(const classname&) = delete
typedef
unsigned
int
uint
;
class
byte
{
uint8_t
content
;
CAPNPROTO_DISALLOW_COPY
(
byte
);
};
class
word
{
uint64_t
content
;
CAPNPROTO_DISALLOW_COPY
(
word
);
};
// byte and word are opaque types with sizes of 8 and 64 bits, respectively. These types are useful
// only to make pointer arithmetic clearer. Since the contents are private, the only way to access
// them is to first reinterpret_cast to some other pointer type.
//
// Coping is disallowed because you should always use memcpy(). Otherwise, you may run afoul of
// aliasing rules (particularly when copying words).
//
// A pointer of type word* should always be word-aligned even if won't actually be dereferenced as
// that type.
static_assert
(
sizeof
(
byte
)
==
1
,
"uint8_t is not one byte?"
);
static_assert
(
sizeof
(
word
)
==
8
,
"uint64_t is not 8 bytes?"
);
namespace
internal
{
class
bit
;
}
#ifdef __CDT_PARSER__
// Eclipse gets confused by decltypes, so we'll feed it these simplified-yet-compatible definitions.
//
// We could also consider using these definitions in opt builds. Trouble is, the mangled symbol
// names of any functions that take these types as inputs would be affected, so it would be
// important to compile the Cap'n Proto library and the client app with the same flags.
typedef
uint
BitCount
;
typedef
uint8_t
BitCount8
;
typedef
uint16_t
BitCount16
;
typedef
uint32_t
BitCount32
;
typedef
uint64_t
BitCount64
;
typedef
uint
ByteCount
;
typedef
uint8_t
ByteCount8
;
typedef
uint16_t
ByteCount16
;
typedef
uint32_t
ByteCount32
;
typedef
uint64_t
ByteCount64
;
typedef
uint
WordCount
;
typedef
uint8_t
WordCount8
;
typedef
uint16_t
WordCount16
;
typedef
uint32_t
WordCount32
;
typedef
uint64_t
WordCount64
;
constexpr
BitCount
BITS
=
1
;
constexpr
ByteCount
BYTES
=
1
;
constexpr
WordCount
WORDS
=
1
;
constexpr
uint
BITS_PER_BYTE
=
8
;
constexpr
uint
BITS_PER_WORD
=
64
;
constexpr
uint
BYTES_PER_WORD
=
8
;
#else
typedef
UnitMeasure
<
uint
,
internal
::
bit
>
BitCount
;
typedef
UnitMeasure
<
uint8_t
,
internal
::
bit
>
BitCount8
;
typedef
UnitMeasure
<
uint16_t
,
internal
::
bit
>
BitCount16
;
typedef
UnitMeasure
<
uint32_t
,
internal
::
bit
>
BitCount32
;
typedef
UnitMeasure
<
uint64_t
,
internal
::
bit
>
BitCount64
;
typedef
UnitMeasure
<
uint
,
byte
>
ByteCount
;
typedef
UnitMeasure
<
uint8_t
,
byte
>
ByteCount8
;
typedef
UnitMeasure
<
uint16_t
,
byte
>
ByteCount16
;
typedef
UnitMeasure
<
uint32_t
,
byte
>
ByteCount32
;
typedef
UnitMeasure
<
uint64_t
,
byte
>
ByteCount64
;
typedef
UnitMeasure
<
uint
,
word
>
WordCount
;
typedef
UnitMeasure
<
uint8_t
,
word
>
WordCount8
;
typedef
UnitMeasure
<
uint16_t
,
word
>
WordCount16
;
typedef
UnitMeasure
<
uint32_t
,
word
>
WordCount32
;
typedef
UnitMeasure
<
uint64_t
,
word
>
WordCount64
;
constexpr
BitCount
BITS
=
BitCount
::
ONE
;
constexpr
ByteCount
BYTES
=
ByteCount
::
ONE
;
constexpr
WordCount
WORDS
=
WordCount
::
ONE
;
constexpr
UnitRatio
<
uint
,
internal
::
bit
,
byte
>
BITS_PER_BYTE
(
8
);
constexpr
UnitRatio
<
uint
,
internal
::
bit
,
word
>
BITS_PER_WORD
(
64
);
constexpr
UnitRatio
<
uint
,
byte
,
word
>
BYTES_PER_WORD
(
8
);
template
<
typename
T
>
inline
constexpr
byte
*
operator
+
(
byte
*
ptr
,
UnitMeasure
<
T
,
byte
>
offset
)
{
return
ptr
+
offset
/
BYTES
;
}
template
<
typename
T
>
inline
constexpr
const
byte
*
operator
+
(
const
byte
*
ptr
,
UnitMeasure
<
T
,
byte
>
offset
)
{
return
ptr
+
offset
/
BYTES
;
}
template
<
typename
T
>
inline
constexpr
byte
*
operator
+=
(
byte
*&
ptr
,
UnitMeasure
<
T
,
byte
>
offset
)
{
return
ptr
=
ptr
+
offset
/
BYTES
;
}
template
<
typename
T
>
inline
constexpr
const
byte
*
operator
+=
(
const
byte
*
ptr
,
UnitMeasure
<
T
,
byte
>
offset
)
{
return
ptr
=
ptr
+
offset
/
BYTES
;
}
template
<
typename
T
>
inline
constexpr
word
*
operator
+
(
word
*
ptr
,
UnitMeasure
<
T
,
word
>
offset
)
{
return
ptr
+
offset
/
WORDS
;
}
template
<
typename
T
>
inline
constexpr
const
word
*
operator
+
(
const
word
*
ptr
,
UnitMeasure
<
T
,
word
>
offset
)
{
return
ptr
+
offset
/
WORDS
;
}
template
<
typename
T
>
inline
constexpr
word
*
operator
+=
(
word
*&
ptr
,
UnitMeasure
<
T
,
word
>
offset
)
{
return
ptr
=
ptr
+
offset
/
WORDS
;
}
template
<
typename
T
>
inline
constexpr
const
word
*
operator
+=
(
const
word
*&
ptr
,
UnitMeasure
<
T
,
word
>
offset
)
{
return
ptr
=
ptr
+
offset
/
WORDS
;
}
template
<
typename
T
>
inline
constexpr
byte
*
operator
-
(
byte
*
ptr
,
UnitMeasure
<
T
,
byte
>
offset
)
{
return
ptr
-
offset
/
BYTES
;
}
template
<
typename
T
>
inline
constexpr
const
byte
*
operator
-
(
const
byte
*
ptr
,
UnitMeasure
<
T
,
byte
>
offset
)
{
return
ptr
-
offset
/
BYTES
;
}
template
<
typename
T
>
inline
constexpr
byte
*
operator
-=
(
byte
*&
ptr
,
UnitMeasure
<
T
,
byte
>
offset
)
{
return
ptr
=
ptr
-
offset
/
BYTES
;
}
template
<
typename
T
>
inline
constexpr
const
byte
*
operator
-=
(
const
byte
*
ptr
,
UnitMeasure
<
T
,
byte
>
offset
)
{
return
ptr
=
ptr
-
offset
/
BYTES
;
}
template
<
typename
T
>
inline
constexpr
word
*
operator
-
(
word
*
ptr
,
UnitMeasure
<
T
,
word
>
offset
)
{
return
ptr
-
offset
/
WORDS
;
}
template
<
typename
T
>
inline
constexpr
const
word
*
operator
-
(
const
word
*
ptr
,
UnitMeasure
<
T
,
word
>
offset
)
{
return
ptr
-
offset
/
WORDS
;
}
template
<
typename
T
>
inline
constexpr
word
*
operator
-=
(
word
*&
ptr
,
UnitMeasure
<
T
,
word
>
offset
)
{
return
ptr
=
ptr
-
offset
/
WORDS
;
}
template
<
typename
T
>
inline
constexpr
const
word
*
operator
-=
(
const
word
*&
ptr
,
UnitMeasure
<
T
,
word
>
offset
)
{
return
ptr
=
ptr
-
offset
/
WORDS
;
}
#endif
inline
constexpr
ByteCount
intervalLength
(
const
byte
*
a
,
const
byte
*
b
)
{
return
uint
(
b
-
a
)
*
BYTES
;
}
inline
constexpr
WordCount
intervalLength
(
const
word
*
a
,
const
word
*
b
)
{
return
uint
(
b
-
a
)
*
WORDS
;
}
namespace
internal
{
#define CAPNPROTO_EXPECT_TRUE(condition) __builtin_expect(condition, true)
...
...
c++/src/capnproto/message.h
View file @
dd46a758
...
...
@@ -21,7 +21,6 @@
// (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 <inttypes.h>
#include <cstddef>
#include "macros.h"
...
...
@@ -36,6 +35,22 @@ class MessageReader;
class
MessageBuilder
;
class
ReadLimiter
;
struct
SegmentId
{
// TODO: Generalize this. class Id<Base, Type>.
uint32_t
number
;
inline
constexpr
SegmentId
()
:
number
(
0
)
{}
inline
constexpr
explicit
SegmentId
(
int
number
)
:
number
(
number
)
{}
inline
constexpr
bool
operator
==
(
const
SegmentId
&
other
)
{
return
number
==
other
.
number
;
}
inline
constexpr
bool
operator
!=
(
const
SegmentId
&
other
)
{
return
number
!=
other
.
number
;
}
inline
constexpr
bool
operator
<=
(
const
SegmentId
&
other
)
{
return
number
<=
other
.
number
;
}
inline
constexpr
bool
operator
>=
(
const
SegmentId
&
other
)
{
return
number
>=
other
.
number
;
}
inline
constexpr
bool
operator
<
(
const
SegmentId
&
other
)
{
return
number
<
other
.
number
;
}
inline
constexpr
bool
operator
>
(
const
SegmentId
&
other
)
{
return
number
>
other
.
number
;
}
};
class
MessageReader
{
// Abstract interface encapsulating a readable message. By implementing this interface, you can
// control how memory is allocated for the message. Or use MallocMessage to make things easy.
...
...
@@ -43,7 +58,7 @@ class MessageReader {
public
:
virtual
~
MessageReader
();
virtual
SegmentReader
*
tryGetSegment
(
uint32_t
index
)
=
0
;
virtual
SegmentReader
*
tryGetSegment
(
SegmentId
id
)
=
0
;
// Gets the segment with the given ID, or return nullptr if no such segment exists.
virtual
void
reportInvalidData
(
const
char
*
description
)
=
0
;
...
...
@@ -78,10 +93,10 @@ class MessageBuilder: public MessageReader {
public
:
virtual
~
MessageBuilder
();
virtual
SegmentBuilder
*
getSegment
(
uint32_t
id
)
=
0
;
virtual
SegmentBuilder
*
getSegment
(
SegmentId
id
)
=
0
;
// Get the segment with the given id. Crashes or throws an exception if no such segment exists.
virtual
SegmentBuilder
*
getSegmentWithAvailable
(
uint32_t
minimumSiz
e
)
=
0
;
virtual
SegmentBuilder
*
getSegmentWithAvailable
(
WordCount
minimumAvailabl
e
)
=
0
;
// Get a segment which has at least the given amount of space available, allocating it if
// necessary. Crashes or throws an exception if there is not enough memory.
...
...
@@ -95,7 +110,7 @@ class ReadLimiter {
// and overlapping are not permitted by the Cap'n Proto format because in many cases they could
// be used to craft a deceptively small message which could consume excessive server resources to
// process, perhaps even sending it into an infinite loop. Actually detecting overlaps would be
// time-consuming, so instead we just keep track of how many
byte
s worth of data structures the
// time-consuming, so instead we just keep track of how many
word
s worth of data structures the
// receiver has actually dereferenced and error out if this gets too high.
//
// This counting takes place as you call getters (for non-primitive values) on the message
...
...
@@ -105,66 +120,54 @@ class ReadLimiter {
public
:
inline
explicit
ReadLimiter
();
// No limit.
inline
explicit
ReadLimiter
(
int64_t
limit
);
// Limit to the given number of byte
s.
inline
explicit
ReadLimiter
(
WordCount64
limit
);
// Limit to the given number of word
s.
inline
bool
canRead
(
uint32_
t
amount
);
inline
bool
canRead
(
WordCoun
t
amount
);
private
:
int64_t
counter
;
WordCount64
limit
;
};
class
SegmentReader
{
public
:
inline
SegmentReader
(
MessageReader
*
message
,
uint32_t
id
,
const
void
*
ptr
,
uint32_
t
size
,
inline
SegmentReader
(
MessageReader
*
message
,
SegmentId
id
,
const
word
ptr
[],
WordCoun
t
size
,
ReadLimiter
*
readLimiter
);
CAPNPROTO_ALWAYS_INLINE
(
const
voi
d
*
getPtrChecked
(
uint32_t
offset
,
uint32_t
bytesBefore
,
uint32_t
bytesA
fter
));
CAPNPROTO_ALWAYS_INLINE
(
const
wor
d
*
getPtrChecked
(
WordCount
offset
,
WordCount
before
,
WordCount
a
fter
));
inline
MessageReader
*
getMessage
();
inline
uint32_t
getSegmentId
();
inline
SegmentId
getSegmentId
();
inline
const
void
*
getStartPtr
();
inline
uint32_t
getSize
();
inline
const
word
*
getStartPtr
();
inline
WordCount
getOffsetTo
(
const
word
*
ptr
);
inline
WordCount
getSize
();
private
:
MessageReader
*
message
;
uint32_t
id
;
uint32_
t
size
;
const
voi
d
*
start
;
SegmentId
id
;
WordCoun
t
size
;
const
wor
d
*
start
;
ReadLimiter
*
readLimiter
;
SegmentReader
(
const
SegmentReader
&
other
)
=
delete
;
SegmentReader
&
operator
=
(
const
SegmentReader
&
other
)
=
delete
;
void
readLimitReached
();
friend
class
SegmentBuilder
;
};
class
SegmentBuilder
:
public
SegmentReader
{
public
:
inline
SegmentBuilder
(
MessageBuilder
*
message
,
uint32_t
id
,
void
*
ptr
,
uint32_
t
available
);
inline
SegmentBuilder
(
MessageBuilder
*
message
,
SegmentId
id
,
word
ptr
[],
WordCoun
t
available
);
struct
Allocation
{
void
*
ptr
;
uint32_t
offset
;
inline
Allocation
()
:
ptr
(
nullptr
),
offset
(
0
)
{}
inline
Allocation
(
std
::
nullptr_t
)
:
ptr
(
nullptr
),
offset
(
0
)
{}
inline
Allocation
(
void
*
ptr
,
uint32_t
offset
)
:
ptr
(
ptr
),
offset
(
offset
)
{}
inline
bool
operator
==
(
std
::
nullptr_t
)
const
{
return
ptr
==
nullptr
;
}
};
CAPNPROTO_ALWAYS_INLINE
(
Allocation
allocate
(
uint32_t
amount
));
inline
void
*
getPtrUnchecked
(
uint32_t
offset
);
CAPNPROTO_ALWAYS_INLINE
(
word
*
allocate
(
WordCount
amount
));
inline
word
*
getPtrUnchecked
(
WordCount
offset
);
inline
MessageBuilder
*
getMessage
();
private
:
char
*
pos
;
char
*
end
;
word
*
pos
;
word
*
end
;
ReadLimiter
dummyLimiter
;
SegmentBuilder
(
const
SegmentBuilder
&
other
)
=
delete
;
...
...
@@ -177,64 +180,74 @@ private:
inline
ReadLimiter
::
ReadLimiter
()
// I didn't want to #include <limits> just for this one lousy constant.
:
counter
(
0x7fffffffffffffffll
)
{}
:
limit
(
uint64_t
(
0x7fffffffffffffffll
)
*
WORDS
)
{}
inline
ReadLimiter
::
ReadLimiter
(
int64_t
limit
)
:
counter
(
limit
)
{}
inline
ReadLimiter
::
ReadLimiter
(
WordCount64
limit
)
:
limit
(
limit
)
{}
inline
bool
ReadLimiter
::
canRead
(
uint32_t
amount
)
{
return
(
counter
-=
amount
)
>=
0
;
inline
bool
ReadLimiter
::
canRead
(
WordCount
amount
)
{
if
(
amount
>
limit
)
{
return
false
;
}
else
{
limit
-=
amount
;
return
true
;
}
}
// -------------------------------------------------------------------
inline
SegmentReader
::
SegmentReader
(
MessageReader
*
message
,
uint32_t
id
,
const
void
*
ptr
,
uint32_
t
size
,
ReadLimiter
*
readLimiter
)
inline
SegmentReader
::
SegmentReader
(
MessageReader
*
message
,
SegmentId
id
,
const
word
ptr
[],
WordCoun
t
size
,
ReadLimiter
*
readLimiter
)
:
message
(
message
),
id
(
id
),
size
(
size
),
start
(
ptr
),
readLimiter
(
readLimiter
)
{}
inline
const
void
*
SegmentReader
::
getPtrChecked
(
uint32_t
offset
,
uint32_t
bytesBefore
,
uint32_t
bytesA
fter
)
{
inline
const
word
*
SegmentReader
::
getPtrChecked
(
WordCount
offset
,
WordCount
before
,
WordCount
a
fter
)
{
// Check bounds. Watch out for overflow and underflow here.
if
(
offset
>
size
||
bytesBefore
>
offset
||
bytesAfter
>
size
-
offset
)
{
if
(
offset
>
size
||
before
>
offset
||
after
>
size
-
offset
)
{
return
nullptr
;
}
else
{
// Enforce the read limit. Synchronization is not necessary because readLimit is just a rough
// counter to prevent infinite loops leading to DoS attacks.
if
(
CAPNPROTO_EXPECT_FALSE
(
!
readLimiter
->
canRead
(
b
ytesBefore
+
bytesA
fter
)))
{
if
(
CAPNPROTO_EXPECT_FALSE
(
!
readLimiter
->
canRead
(
b
efore
+
a
fter
)))
{
message
->
reportReadLimitReached
();
}
return
reinterpret_cast
<
const
char
*>
(
start
)
+
offset
;
return
start
+
offset
;
}
}
inline
MessageReader
*
SegmentReader
::
getMessage
()
{
return
message
;
}
inline
uint32_t
SegmentReader
::
getSegmentId
()
{
return
id
;
}
inline
const
void
*
SegmentReader
::
getStartPtr
()
{
return
start
;
}
inline
uint32_t
SegmentReader
::
getSize
()
{
return
size
;
}
inline
SegmentId
SegmentReader
::
getSegmentId
()
{
return
id
;
}
inline
const
word
*
SegmentReader
::
getStartPtr
()
{
return
start
;
}
inline
WordCount
SegmentReader
::
getOffsetTo
(
const
word
*
ptr
)
{
return
intervalLength
(
start
,
ptr
);
}
inline
WordCount
SegmentReader
::
getSize
()
{
return
size
;
}
// -------------------------------------------------------------------
inline
SegmentBuilder
::
SegmentBuilder
(
MessageBuilder
*
message
,
uint32_t
id
,
void
*
ptr
,
uint32_
t
available
)
:
SegmentReader
(
message
,
id
,
ptr
,
0
,
&
dummyLimiter
),
pos
(
reinterpret_cast
<
char
*>
(
ptr
)
),
MessageBuilder
*
message
,
SegmentId
id
,
word
ptr
[],
WordCoun
t
available
)
:
SegmentReader
(
message
,
id
,
ptr
,
0
*
WORDS
,
&
dummyLimiter
),
pos
(
ptr
),
end
(
pos
+
available
)
{}
inline
SegmentBuilder
::
Allocation
SegmentBuilder
::
allocate
(
uint32_
t
amount
)
{
if
(
amount
>
end
-
pos
)
{
inline
word
*
SegmentBuilder
::
allocate
(
WordCoun
t
amount
)
{
if
(
amount
>
intervalLength
(
pos
,
end
)
)
{
return
nullptr
;
}
else
{
char
*
result
=
pos
;
word
*
result
=
pos
;
pos
+=
amount
;
size
+=
amount
;
return
Allocation
(
result
,
result
-
reinterpret_cast
<
const
char
*>
(
start
))
;
return
result
;
}
}
inline
void
*
SegmentBuilder
::
getPtrUnchecked
(
uint32_
t
offset
)
{
inline
word
*
SegmentBuilder
::
getPtrUnchecked
(
WordCoun
t
offset
)
{
// const_cast OK because SegmentBuilder's constructor always initializes its SegmentReader base
// class with a pointer that was originally non-const.
return
const_cast
<
char
*>
(
reinterpret_cast
<
const
char
*>
(
start
)
+
offset
);
return
const_cast
<
word
*>
(
start
+
offset
);
}
inline
MessageBuilder
*
SegmentBuilder
::
getMessage
()
{
...
...
c++/src/capnproto/unit-test.c++
0 → 100644
View file @
dd46a758
// 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 "unit.h"
#include <gtest/gtest.h>
#include <iostream>
namespace
capnproto
{
namespace
{
class
Bytes
;
class
KiB
;
class
MiB
;
typedef
UnitMeasure
<
int
,
Bytes
>
ByteCount
;
typedef
UnitMeasure
<
int
,
KiB
>
KiBCount
;
typedef
UnitMeasure
<
int
,
MiB
>
MiBCount
;
constexpr
ByteCount
BYTE
=
ByteCount
::
ONE
;
constexpr
KiBCount
KIB
=
KiBCount
::
ONE
;
constexpr
MiBCount
MIB
=
MiBCount
::
ONE
;
constexpr
UnitRatio
<
int
,
Bytes
,
KiB
>
BYTES_PER_KIB
(
1024
);
constexpr
UnitRatio
<
int
,
Bytes
,
MiB
>
BYTES_PER_MIB
(
1024
*
1024
);
constexpr
UnitRatio
<
int
,
KiB
,
MiB
>
KIB_PER_MIB
(
1024
);
template
<
typename
T
,
typename
U
>
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
UnitMeasure
<
T
,
U
>
value
)
{
return
os
<<
(
value
/
UnitMeasure
<
T
,
U
>::
ONE
);
}
TEST
(
UnitMeasure
,
Basics
)
{
KiBCount
k
=
15
*
KIB
;
EXPECT_EQ
(
15
,
k
/
KIB
);
EXPECT_EQ
(
16
*
KIB
,
k
+
KIB
);
k
+=
KIB
;
k
*=
2048
;
EXPECT_EQ
(
32
*
MIB
,
k
/
KIB_PER_MIB
);
EXPECT_TRUE
(
2
*
KIB
<
4
*
KIB
);
EXPECT_FALSE
(
8
*
KIB
<
4
*
KIB
);
}
}
// namespace
}
// namespace capnproto
c++/src/capnproto/unit.c++
0 → 100644
View file @
dd46a758
// 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 "unit.h"
namespace
capnproto
{
}
// namespace capnproto
c++/src/capnproto/unit.h
0 → 100644
View file @
dd46a758
// 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_UNIT_H_
#define CAPNPROTO_UNIT_H_
namespace
capnproto
{
template
<
typename
Number
,
typename
Unit1
,
typename
Unit2
>
class
UnitRatio
{
public
:
constexpr
UnitRatio
(
Number
unit1PerUnit2
)
:
unit1PerUnit2
(
unit1PerUnit2
)
{}
Number
unit1PerUnit2
;
};
template
<
typename
T
>
T
any
();
template
<
typename
Number
,
typename
Unit
>
class
UnitMeasure
{
public
:
inline
constexpr
UnitMeasure
()
{}
template
<
typename
OtherNumber
>
inline
constexpr
UnitMeasure
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
:
value
(
other
.
value
)
{}
static
constexpr
UnitMeasure
ONE
=
UnitMeasure
(
1
);
template
<
typename
OtherNumber
>
inline
constexpr
auto
operator
+
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
->
UnitMeasure
<
decltype
(
any
<
Number
>
()
+
any
<
OtherNumber
>
()),
Unit
>
{
return
UnitMeasure
<
decltype
(
any
<
Number
>
()
+
any
<
OtherNumber
>
()),
Unit
>
(
value
+
other
.
value
);
}
template
<
typename
OtherNumber
>
inline
constexpr
auto
operator
-
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
->
UnitMeasure
<
decltype
(
any
<
Number
>
()
-
any
<
OtherNumber
>
()),
Unit
>
{
return
UnitMeasure
<
decltype
(
any
<
Number
>
()
-
any
<
OtherNumber
>
()),
Unit
>
(
value
-
other
.
value
);
}
template
<
typename
OtherNumber
>
inline
constexpr
auto
operator
*
(
OtherNumber
other
)
const
->
UnitMeasure
<
decltype
(
any
<
Number
>
()
*
other
),
Unit
>
{
return
UnitMeasure
<
decltype
(
any
<
Number
>
()
*
other
),
Unit
>
(
value
*
other
);
}
template
<
typename
OtherNumber
>
inline
constexpr
auto
operator
/
(
OtherNumber
other
)
const
->
UnitMeasure
<
decltype
(
any
<
Number
>
()
/
other
),
Unit
>
{
return
UnitMeasure
<
decltype
(
any
<
Number
>
()
/
other
),
Unit
>
(
value
/
other
);
}
template
<
typename
OtherNumber
>
inline
constexpr
auto
operator
/
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
->
decltype
(
any
<
Number
>
()
/
any
<
OtherNumber
>
())
{
return
value
/
other
.
value
;
}
template
<
typename
OtherNumber
>
inline
constexpr
auto
operator
%
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
->
decltype
(
any
<
Number
>
()
%
any
<
OtherNumber
>
())
{
return
value
%
other
.
value
;
}
template
<
typename
OtherNumber
,
typename
OtherUnit
>
inline
constexpr
auto
operator
*
(
const
UnitRatio
<
OtherNumber
,
OtherUnit
,
Unit
>&
ratio
)
const
->
UnitMeasure
<
decltype
(
any
<
Number
>
()
*
any
<
OtherNumber
>
()),
OtherUnit
>
{
return
UnitMeasure
<
decltype
(
any
<
Number
>
()
*
any
<
OtherNumber
>
()),
OtherUnit
>
(
value
*
ratio
.
unit1PerUnit2
);
}
template
<
typename
OtherNumber
,
typename
OtherUnit
>
inline
constexpr
auto
operator
/
(
const
UnitRatio
<
OtherNumber
,
Unit
,
OtherUnit
>&
ratio
)
const
->
UnitMeasure
<
decltype
(
any
<
Number
>
()
/
any
<
OtherNumber
>
()),
OtherUnit
>
{
return
UnitMeasure
<
decltype
(
any
<
Number
>
()
/
any
<
OtherNumber
>
()),
OtherUnit
>
(
value
/
ratio
.
unit1PerUnit2
);
}
template
<
typename
OtherNumber
,
typename
OtherUnit
>
inline
constexpr
auto
operator
%
(
const
UnitRatio
<
OtherNumber
,
Unit
,
OtherUnit
>&
ratio
)
const
->
UnitMeasure
<
decltype
(
any
<
Number
>
()
%
any
<
OtherNumber
>
()),
Unit
>
{
return
UnitMeasure
<
decltype
(
any
<
Number
>
()
%
any
<
OtherNumber
>
()),
Unit
>
(
value
%
ratio
.
unit1PerUnit2
);
}
template
<
typename
OtherNumber
>
inline
constexpr
bool
operator
==
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
{
return
value
==
other
.
value
;
}
template
<
typename
OtherNumber
>
inline
constexpr
bool
operator
!=
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
{
return
value
!=
other
.
value
;
}
template
<
typename
OtherNumber
>
inline
constexpr
bool
operator
<=
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
{
return
value
<=
other
.
value
;
}
template
<
typename
OtherNumber
>
inline
constexpr
bool
operator
>=
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
{
return
value
>=
other
.
value
;
}
template
<
typename
OtherNumber
>
inline
constexpr
bool
operator
<
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
{
return
value
<
other
.
value
;
}
template
<
typename
OtherNumber
>
inline
constexpr
bool
operator
>
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
const
{
return
value
>
other
.
value
;
}
template
<
typename
OtherNumber
>
inline
UnitMeasure
&
operator
+=
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
{
value
+=
other
.
value
;
return
*
this
;
}
template
<
typename
OtherNumber
>
inline
UnitMeasure
&
operator
-=
(
const
UnitMeasure
<
OtherNumber
,
Unit
>&
other
)
{
value
-=
other
.
value
;
return
*
this
;
}
template
<
typename
OtherNumber
>
inline
UnitMeasure
&
operator
*=
(
OtherNumber
other
)
{
value
*=
other
;
return
*
this
;
}
template
<
typename
OtherNumber
>
inline
UnitMeasure
&
operator
/=
(
OtherNumber
other
)
{
value
/=
other
.
value
;
return
*
this
;
}
private
:
inline
explicit
constexpr
UnitMeasure
(
Number
value
)
:
value
(
value
)
{}
Number
value
;
template
<
typename
OtherNumber
,
typename
OtherUnit
>
friend
class
UnitMeasure
;
template
<
typename
Number1
,
typename
Number2
,
typename
Unit2
>
friend
inline
constexpr
auto
operator
*
(
Number1
a
,
UnitMeasure
<
Number2
,
Unit2
>
b
)
->
UnitMeasure
<
decltype
(
any
<
Number1
>
()
*
any
<
Number2
>
()),
Unit2
>
;
};
template
<
typename
Number
,
typename
Unit
>
constexpr
UnitMeasure
<
Number
,
Unit
>
UnitMeasure
<
Number
,
Unit
>::
ONE
;
template
<
typename
Number1
,
typename
Number2
,
typename
Unit
>
inline
constexpr
auto
operator
*
(
Number1
a
,
UnitMeasure
<
Number2
,
Unit
>
b
)
->
UnitMeasure
<
decltype
(
any
<
Number1
>
()
*
any
<
Number2
>
()),
Unit
>
{
return
UnitMeasure
<
decltype
(
any
<
Number1
>
()
*
any
<
Number2
>
()),
Unit
>
(
a
*
b
.
value
);
}
template
<
typename
Number1
,
typename
Number2
,
typename
Unit
,
typename
Unit2
>
inline
constexpr
auto
operator
*
(
UnitRatio
<
Number1
,
Unit2
,
Unit
>
ratio
,
UnitMeasure
<
Number2
,
Unit
>
measure
)
->
decltype
(
measure
*
ratio
)
{
return
measure
*
ratio
;
}
}
// namespace capnproto
#endif // CAPNPROTO_UNIT_H_
c++/src/capnproto/wire-format.c++
View file @
dd46a758
...
...
@@ -24,47 +24,49 @@
#include "wire-format.h"
#include "message.h"
#include "descriptor.h"
#include <limits>
namespace
capnproto
{
namespace
internal
{
namespace
debug
{
bool
fieldIsStruct
(
const
StructDescriptor
*
descriptor
,
int
fieldNumber
,
int
refIndex
)
{
bool
fieldIsStruct
(
const
StructDescriptor
*
descriptor
,
uint
fieldNumber
,
u
int
refIndex
)
{
return
descriptor
->
fieldCount
>
fieldNumber
&&
descriptor
->
fields
[
fieldNumber
].
size
==
FieldSize
::
REFERENCE
&&
descriptor
->
fields
[
fieldNumber
].
offset
==
refIndex
&&
descriptor
->
defaultReferences
[
refIndex
]
->
kind
==
Descriptor
::
Kind
::
STRUCT
;
}
bool
fieldIsList
(
const
StructDescriptor
*
descriptor
,
int
fieldNumber
,
int
refIndex
)
{
bool
fieldIsList
(
const
StructDescriptor
*
descriptor
,
uint
fieldNumber
,
u
int
refIndex
)
{
return
descriptor
->
fieldCount
>
fieldNumber
&&
descriptor
->
fields
[
fieldNumber
].
size
==
FieldSize
::
REFERENCE
&&
descriptor
->
fields
[
fieldNumber
].
offset
==
refIndex
&&
descriptor
->
defaultReferences
[
refIndex
]
->
kind
==
Descriptor
::
Kind
::
LIST
;
}
bool
fieldIsData
(
const
StructDescriptor
*
descriptor
,
int
fieldNumber
,
int
dataOffset
,
int
bitSize
)
{
bool
fieldIsData
(
const
StructDescriptor
*
descriptor
,
uint
fieldNumber
,
uint
dataOffset
,
BitCount
bitSize
)
{
return
descriptor
->
fieldCount
>
fieldNumber
&&
descriptor
->
fields
[
fieldNumber
].
size
!=
FieldSize
::
REFERENCE
&&
sizeInBits
(
descriptor
->
fields
[
fieldNumber
].
size
)
==
bitSize
&&
descriptor
->
fields
[
fieldNumber
].
offset
==
dataOffset
;
}
bool
dataFieldInRange
(
const
StructDescriptor
*
descriptor
,
uint
32_t
dataOffset
,
uint32_
t
size
)
{
return
descriptor
->
dataSize
*
sizeof
(
uint64_t
)
>=
(
dataOffset
*
size
)
;
bool
dataFieldInRange
(
const
StructDescriptor
*
descriptor
,
uint
dataOffset
,
ByteCoun
t
size
)
{
return
descriptor
->
dataSize
*
BYTES_PER_WORD
>=
dataOffset
*
size
;
}
bool
bitFieldInRange
(
const
StructDescriptor
*
descriptor
,
uint32_
t
offset
)
{
return
descriptor
->
dataSize
*
sizeof
(
uint64_t
)
>
offset
/
64
;
bool
bitFieldInRange
(
const
StructDescriptor
*
descriptor
,
BitCoun
t
offset
)
{
return
descriptor
->
dataSize
*
BITS_PER_WORD
>=
offset
;
}
bool
refFieldIsStruct
(
const
StructDescriptor
*
descriptor
,
int
refIndex
)
{
bool
refFieldIsStruct
(
const
StructDescriptor
*
descriptor
,
u
int
refIndex
)
{
return
descriptor
->
referenceCount
>
refIndex
&&
descriptor
->
defaultReferences
[
refIndex
]
->
kind
==
Descriptor
::
Kind
::
STRUCT
;
}
bool
refFieldIsList
(
const
StructDescriptor
*
descriptor
,
int
refIndex
)
{
bool
refFieldIsList
(
const
StructDescriptor
*
descriptor
,
u
int
refIndex
)
{
return
descriptor
->
referenceCount
>
refIndex
&&
descriptor
->
defaultReferences
[
refIndex
]
->
kind
==
Descriptor
::
Kind
::
LIST
;
}
...
...
@@ -72,21 +74,21 @@ bool refFieldIsList(const StructDescriptor* descriptor, int refIndex) {
bool
elementsAreStructs
(
const
ListDescriptor
*
descriptor
)
{
return
descriptor
->
elementSize
==
FieldSize
::
STRUCT
;
}
bool
elementsAreStructs
(
const
ListDescriptor
*
descriptor
,
uint32_
t
wordSize
)
{
bool
elementsAreStructs
(
const
ListDescriptor
*
descriptor
,
WordCoun
t
wordSize
)
{
return
descriptor
->
elementSize
==
FieldSize
::
STRUCT
&&
descriptor
->
elementDescriptor
->
asStruct
()
->
wordSize
()
==
wordSize
;
}
bool
elementsAreLists
(
const
ListDescriptor
*
descriptor
)
{
return
descriptor
->
elementSize
==
FieldSize
::
REFERENCE
;
}
bool
elementsAreData
(
const
ListDescriptor
*
descriptor
,
i
nt
bitSize
)
{
bool
elementsAreData
(
const
ListDescriptor
*
descriptor
,
BitCou
nt
bitSize
)
{
switch
(
descriptor
->
elementSize
)
{
case
FieldSize
:
:
REFERENCE
:
case
FieldSize
:
:
KEY_REFERENCE
:
case
FieldSize
:
:
STRUCT
:
return
false
;
default
:
return
tru
e
;
return
sizeInBits
(
descriptor
->
elementSize
)
==
bitSiz
e
;
}
}
...
...
@@ -94,6 +96,8 @@ bool elementsAreData(const ListDescriptor* descriptor, int bitSize) {
// =======================================================================================
static
const
WordCount
WORDS_PER_REFERENCE
=
1
*
WORDS
;
struct
WireReference
{
// A reference, in exactly the format in which it appears on the wire.
...
...
@@ -107,7 +111,11 @@ struct WireReference {
STRUCT
=
0
,
LIST
=
1
,
CAPABILITY
=
2
,
FAR
=
3
FAR
=
3
,
RESERVED_4
=
4
,
RESERVED_5
=
5
,
RESERVED_6
=
6
,
RESERVED_7
=
7
};
WireValue
<
uint32_t
>
offsetAndTag
;
...
...
@@ -115,9 +123,13 @@ struct WireReference {
union
{
struct
{
WireValue
<
uint8_t
>
fieldCount
;
WireValue
<
uint8_t
>
dataSize
;
WireValue
<
WordCount8
>
dataWordCount
;
WireValue
<
uint8_t
>
refCount
;
WireValue
<
uint8_t
>
reserved0
;
inline
WordCount
wordSize
()
const
{
return
dataWordCount
.
get
()
+
refCount
.
get
()
*
WORDS_PER_REFERENCE
;
}
}
structRef
;
// Also covers capabilities.
...
...
@@ -127,98 +139,101 @@ struct WireReference {
CAPNPROTO_ALWAYS_INLINE
(
FieldSize
elementSize
()
const
)
{
return
static_cast
<
FieldSize
>
(
elementSizeAndCount
.
get
()
>>
29
);
}
CAPNPROTO_ALWAYS_INLINE
(
uint
32_t
elementCount
()
const
)
{
CAPNPROTO_ALWAYS_INLINE
(
uint
elementCount
()
const
)
{
return
elementSizeAndCount
.
get
()
&
0x1fffffffu
;
}
}
listRef
;
struct
{
WireValue
<
uint32_t
>
segmentId
;
WireValue
<
SegmentId
>
segmentId
;
}
farRef
;
};
CAPNPROTO_ALWAYS_INLINE
(
bool
isNull
()
const
)
{
return
offsetAndTag
.
get
()
==
0
;
}
CAPNPROTO_ALWAYS_INLINE
(
uint32_t
offset
()
const
)
{
return
offsetAndTag
.
get
()
&
~
7
;
}
CAPNPROTO_ALWAYS_INLINE
(
int
tag
()
const
)
{
return
offsetAndTag
.
get
()
&
7
;
}
CAPNPROTO_ALWAYS_INLINE
(
WordCount
offset
()
const
)
{
return
(
offsetAndTag
.
get
()
>>
3
)
*
WORDS
;
}
CAPNPROTO_ALWAYS_INLINE
(
Tag
tag
()
const
)
{
return
static_cast
<
Tag
>
(
offsetAndTag
.
get
()
&
7
);
}
CAPNPROTO_ALWAYS_INLINE
(
void
setTagAndOffset
(
Tag
tag
,
uint32_t
offset
))
{
CAPNPROTO_DEBUG_ASSERT
((
offset
&
7
)
==
0
,
"Offsets must be word-aligned."
);
offsetAndTag
.
set
(
offset
|
tag
);
CAPNPROTO_ALWAYS_INLINE
(
void
setTagAndOffset
(
Tag
tag
,
WordCount
offset
))
{
offsetAndTag
.
set
(((
offset
/
WORDS
)
<<
3
)
|
tag
);
}
CAPNPROTO_ALWAYS_INLINE
(
void
setStruct
(
const
StructDescriptor
*
descriptor
,
uint32_
t
offset
))
{
CAPNPROTO_ALWAYS_INLINE
(
void
setStruct
(
const
StructDescriptor
*
descriptor
,
WordCoun
t
offset
))
{
setTagAndOffset
(
STRUCT
,
offset
);
structRef
.
fieldCount
.
set
(
descriptor
->
fieldCount
);
structRef
.
data
Size
.
set
(
descriptor
->
dataSize
);
structRef
.
data
WordCount
.
set
(
WordCount8
(
descriptor
->
dataSize
)
);
structRef
.
refCount
.
set
(
descriptor
->
referenceCount
);
structRef
.
reserved0
.
set
(
0
);
}
CAPNPROTO_ALWAYS_INLINE
(
void
setList
(
const
ListDescriptor
*
descriptor
,
uint32_t
elementCount
,
uint32_
t
offset
))
{
const
ListDescriptor
*
descriptor
,
int
elementCount
,
WordCoun
t
offset
))
{
setTagAndOffset
(
LIST
,
offset
);
CAPNPROTO_DEBUG_ASSERT
((
elementCount
>>
29
)
==
0
,
"Lists are limited to 2**29 elements."
);
listRef
.
elementSizeAndCount
.
set
(
(
static_cast
<
uint32_
t
>
(
descriptor
->
elementSize
)
<<
29
)
|
elementCount
);
(
static_cast
<
in
t
>
(
descriptor
->
elementSize
)
<<
29
)
|
elementCount
);
}
CAPNPROTO_ALWAYS_INLINE
(
void
setFar
(
uint32_t
segmentId
,
uint32_
t
offset
))
{
CAPNPROTO_ALWAYS_INLINE
(
void
setFar
(
SegmentId
segmentId
,
WordCoun
t
offset
))
{
setTagAndOffset
(
FAR
,
offset
);
farRef
.
segmentId
.
set
(
segmentId
);
}
};
static_assert
(
sizeof
(
WireReference
)
==
8
,
"Layout of capnproto::WireReference is wrong."
);
static_assert
(
sizeof
(
WireReference
)
==
sizeof
(
word
),
"Layout of capnproto::WireReference is wrong. It must be exactly one word or all hell will "
"break loose. (At the very least WORDS_PER_REFERENCE needs updating, but that's "
"probably not all.)"
);
// =======================================================================================
template
<
typename
T
>
static
CAPNPROTO_ALWAYS_INLINE
(
T
divRoundingUp
(
T
a
,
T
b
));
template
<
typename
T
>
static
inline
T
divRoundingUp
(
T
a
,
T
b
)
{
template
<
typename
T
,
typename
U
>
static
inline
decltype
(
T
()
/
U
())
divRoundingUp
(
T
a
,
U
b
)
{
return
(
a
+
b
-
1
)
/
b
;
}
template
<
typename
T
>
static
inline
const
void
*
offsetPtr
(
const
void
*
ptr
,
int
amount
)
{
return
reinterpret_cast
<
const
T
*>
(
ptr
)
+
amount
;
template
<
typename
T
,
typename
U
>
static
CAPNPROTO_ALWAYS_INLINE
(
T
divRoundingUp
(
UnitMeasure
<
T
,
U
>
a
,
UnitMeasure
<
T
,
U
>
b
));
template
<
typename
T
,
typename
U
>
static
inline
T
divRoundingUp
(
UnitMeasure
<
T
,
U
>
a
,
UnitMeasure
<
T
,
U
>
b
)
{
return
(
a
+
b
-
UnitMeasure
<
T
,
U
>::
ONE
)
/
b
;
}
template
<
typename
T
>
static
inline
void
*
offsetPtr
(
void
*
ptr
,
int
amount
)
{
return
reinterpret_cast
<
T
*>
(
ptr
)
+
amount
;
}
template
<
typename
T
>
static
inline
T
*
takeFromAllocation
(
SegmentBuilder
::
Allocation
&
allocation
,
int
count
=
1
)
{
T
*
result
=
reinterpret_cast
<
T
*>
(
allocation
.
ptr
);
allocation
.
ptr
=
result
+
count
;
allocation
.
offset
+=
sizeof
(
T
)
*
count
;
return
result
;
template
<
typename
T
,
typename
T2
,
typename
U
,
typename
U2
>
static
CAPNPROTO_ALWAYS_INLINE
(
decltype
(
UnitMeasure
<
T
,
U
>
()
/
UnitRatio
<
T2
,
U
,
U2
>
(
1
))
divRoundingUp
(
UnitMeasure
<
T
,
U
>
a
,
UnitRatio
<
T2
,
U
,
U2
>
b
));
template
<
typename
T
,
typename
T2
,
typename
U
,
typename
U2
>
static
inline
decltype
(
UnitMeasure
<
T
,
U
>
()
/
UnitRatio
<
T2
,
U
,
U2
>
(
1
))
divRoundingUp
(
UnitMeasure
<
T
,
U
>
a
,
UnitRatio
<
T2
,
U
,
U2
>
b
)
{
return
(
a
+
(
UnitMeasure
<
T2
,
U2
>::
ONE
*
b
-
UnitMeasure
<
T2
,
U
>::
ONE
))
/
b
;
}
struct
WireHelpers
{
static
CAPNPROTO_ALWAYS_INLINE
(
SegmentBuilder
::
Allocation
allocate
(
WireReference
*&
ref
,
SegmentBuilder
*&
segment
,
uint32_t
size
))
{
SegmentBuilder
::
Allocation
allocation
=
segment
->
allocate
(
size
);
static
CAPNPROTO_ALWAYS_INLINE
(
word
*
allocate
(
WireReference
*&
ref
,
SegmentBuilder
*&
segment
,
WordCount
amount
))
{
word
*
ptr
=
segment
->
allocate
(
amount
);
if
(
allocation
==
nullptr
)
{
if
(
ptr
==
nullptr
)
{
// Need to allocate in a new segment.
// Loop here just in case we ever make Segment::allocate() thread-safe -- in this case another
// thread could have grabbed the space between when we asked the message for the segment and
// when we asked the segment to allocate space.
do
{
segment
=
segment
->
getMessage
()
->
getSegmentWithAvailable
(
size
+
sizeof
(
WireReference
)
);
allocation
=
segment
->
allocate
(
size
+
sizeof
(
WireReference
)
);
}
while
(
CAPNPROTO_EXPECT_FALSE
(
allocation
==
nullptr
));
segment
=
segment
->
getMessage
()
->
getSegmentWithAvailable
(
amount
+
WORDS_PER_REFERENCE
);
ptr
=
segment
->
allocate
(
amount
+
WORDS_PER_REFERENCE
);
}
while
(
CAPNPROTO_EXPECT_FALSE
(
ptr
==
nullptr
));
ref
->
setFar
(
segment
->
getSegmentId
(),
allocation
.
offset
);
ref
=
takeFromAllocation
<
WireReference
>
(
allocation
);
ref
->
setFar
(
segment
->
getSegmentId
(),
segment
->
getOffsetTo
(
ptr
)
);
ref
=
reinterpret_cast
<
WireReference
*>
(
ptr
);
// Allocated space follows new reference.
return
allocation
;
return
ptr
+
WORDS_PER_REFERENCE
;
}
else
{
return
allocation
;
return
ptr
;
}
}
...
...
@@ -237,7 +252,7 @@ struct WireHelpers {
return
false
;
}
ref
=
reinterpret_cast
<
const
WireReference
*>
(
segment
->
getPtrChecked
(
ref
->
offset
(),
0
,
sizeof
(
WireReference
)
));
segment
->
getPtrChecked
(
ref
->
offset
(),
0
*
WORDS
,
WORDS_PER_REFERENCE
));
return
ref
!=
nullptr
;
}
else
{
return
true
;
...
...
@@ -248,13 +263,13 @@ struct WireHelpers {
const
StructDescriptor
*
descriptor
,
const
WireReference
*
ref
))
{
if
(
ref
->
structRef
.
fieldCount
.
get
()
>=
descriptor
->
fieldCount
)
{
// The incoming struct has all of the fields that we know about.
return
ref
->
structRef
.
data
Size
.
get
()
>=
descriptor
->
dataSize
&&
return
ref
->
structRef
.
data
WordCount
.
get
()
>=
descriptor
->
dataSize
&&
ref
->
structRef
.
refCount
.
get
()
>=
descriptor
->
referenceCount
;
}
else
if
(
ref
->
structRef
.
fieldCount
.
get
()
>
0
)
{
// We know about more fields than the struct has, and the struct is non-empty.
const
FieldDescriptor
*
field
=
&
descriptor
->
fields
[
ref
->
structRef
.
fieldCount
.
get
()
-
1
];
return
ref
->
structRef
.
data
Size
.
get
()
>=
field
->
requiredDataSize
&&
ref
->
structRef
.
refCount
.
get
()
>=
field
->
requiredReference
Size
;
return
ref
->
structRef
.
data
WordCount
.
get
()
>=
field
->
requiredDataSize
&&
ref
->
structRef
.
refCount
.
get
()
>=
field
->
requiredReference
Count
;
}
else
{
// The incoming struct has no fields, so is necessarily compatible.
return
true
;
...
...
@@ -264,20 +279,17 @@ struct WireHelpers {
static
CAPNPROTO_ALWAYS_INLINE
(
StructBuilder
initStructReference
(
const
StructDescriptor
*
descriptor
,
WireReference
*
ref
,
SegmentBuilder
*
segment
))
{
if
(
ref
->
isNull
())
{
// Calculate the size of the struct.
uint32_t
size
=
(
descriptor
->
dataSize
+
descriptor
->
referenceCount
)
*
sizeof
(
uint64_t
);
// Allocate space for the new struct.
SegmentBuilder
::
Allocation
allocation
=
allocate
(
ref
,
segment
,
size
);
word
*
ptr
=
allocate
(
ref
,
segment
,
descriptor
->
wordSize
()
);
// Advance the pointer to point between the data and reference segments.
takeFromAllocation
<
uint64_t
>
(
allocation
,
descriptor
->
dataSize
)
;
ptr
+=
descriptor
->
dataSize
;
// Initialize the reference.
ref
->
setStruct
(
descriptor
,
allocation
.
offset
);
ref
->
setStruct
(
descriptor
,
segment
->
getOffsetTo
(
ptr
)
);
// Build the StructBuilder.
return
StructBuilder
(
descriptor
,
segment
,
allocation
.
ptr
);
return
StructBuilder
(
descriptor
,
segment
,
ptr
);
}
else
{
followFars
(
ref
,
segment
);
...
...
@@ -296,41 +308,39 @@ struct WireHelpers {
static
CAPNPROTO_ALWAYS_INLINE
(
ListBuilder
initListReference
(
const
ListDescriptor
*
descriptor
,
WireReference
*
ref
,
SegmentBuilder
*
segment
,
uint
32_t
elementCount
))
{
SegmentBuilder
*
segment
,
uint
elementCount
))
{
if
(
descriptor
->
elementSize
==
FieldSize
::
STRUCT
)
{
const
StructDescriptor
*
elementDescriptor
=
descriptor
->
elementDescriptor
->
asStruct
();
// Allocate the list, prefixed by a single WireReference.
SegmentBuilder
::
Allocation
allocation
=
allocate
(
ref
,
segment
,
sizeof
(
WireReference
)
+
elementDescriptor
->
wordSize
()
*
elementCount
*
sizeof
(
uint64_t
));
word
*
ptr
=
allocate
(
ref
,
segment
,
WORDS_PER_REFERENCE
+
elementDescriptor
->
wordSize
()
*
elementCount
);
// Initialize the reference.
ref
->
setList
(
descriptor
,
elementCount
,
allocation
.
offset
);
WireReference
*
structRef
=
takeFromAllocation
<
WireReference
>
(
allocation
);
ref
->
setList
(
descriptor
,
elementCount
,
segment
->
getOffsetTo
(
ptr
));
// Skip past the data segment of the first struct.
takeFromAllocation
<
uint64_t
>
(
allocation
,
elementDescriptor
->
dataSize
);
// Initialize the struct reference.
structRef
->
setStruct
(
elementDescriptor
,
allocation
.
offset
);
// The list is prefixed by a struct reference.
WireReference
*
structRef
=
reinterpret_cast
<
WireReference
*>
(
ptr
);
word
*
structPtr
=
ptr
+
WORDS_PER_REFERENCE
+
elementDescriptor
->
dataSize
;
structRef
->
setStruct
(
elementDescriptor
,
segment
->
getOffsetTo
(
structPtr
));
// Build the ListBuilder.
return
ListBuilder
(
descriptor
,
segment
,
structRef
,
elementCount
);
return
ListBuilder
(
descriptor
,
segment
,
ptr
,
elementCount
);
}
else
{
// Calculate size of the list.
uint32_t
size
=
divRoundingUp
<
uint32_t
>
(
static_cast
<
uint32_t
>
(
sizeInBits
(
descriptor
->
elementSize
))
*
elementCount
,
8
);
// Calculate size of the list. Need to cast to uint here because a list can be up to
// 2**32-1 bits, so int would overflow. Plus uint division by a power of 2 is a bit shift.
WordCount
wordCount
=
divRoundingUp
(
sizeInBits
(
descriptor
->
elementSize
)
*
elementCount
,
BITS_PER_WORD
);
// Allocate the list.
SegmentBuilder
::
Allocation
allocation
=
allocate
(
ref
,
segment
,
size
);
word
*
ptr
=
allocate
(
ref
,
segment
,
wordCount
);
// Initialize the reference.
ref
->
setList
(
descriptor
,
elementCount
,
allocation
.
offset
);
ref
->
setList
(
descriptor
,
elementCount
,
segment
->
getOffsetTo
(
ptr
)
);
// Build the ListBuilder.
return
ListBuilder
(
descriptor
,
segment
,
allocation
.
ptr
,
elementCount
);
return
ListBuilder
(
descriptor
,
segment
,
ptr
,
elementCount
);
}
}
...
...
@@ -388,9 +398,9 @@ struct WireHelpers {
break
;
}
const
voi
d
*
ptr
=
segment
->
getPtrChecked
(
ref
->
offset
(),
ref
->
structRef
.
data
Size
.
get
()
*
sizeof
(
uint8_t
),
ref
->
structRef
.
refCount
.
get
()
*
sizeof
(
WireReference
)
);
const
wor
d
*
ptr
=
segment
->
getPtrChecked
(
ref
->
offset
(),
ref
->
structRef
.
data
WordCount
.
get
(
),
ref
->
structRef
.
refCount
.
get
()
*
WORDS_PER_REFERENCE
);
if
(
CAPNPROTO_EXPECT_FALSE
(
ptr
==
nullptr
))
{
segment
->
getMessage
()
->
reportInvalidData
(
...
...
@@ -399,10 +409,10 @@ struct WireHelpers {
}
return
StructReader
(
descriptor
,
segment
,
ptr
,
descriptor
->
defaultData
,
ref
->
structRef
.
fieldCount
.
get
(),
0
,
recursionLimit
-
1
);
ref
->
structRef
.
fieldCount
.
get
(),
0
*
BITS
,
recursionLimit
-
1
);
}
while
(
false
);
return
StructReader
(
descriptor
,
segment
,
nullptr
,
descriptor
->
defaultData
,
0
,
0
,
0
);
return
StructReader
(
descriptor
,
segment
,
nullptr
,
descriptor
->
defaultData
,
0
,
0
*
BITS
,
0
);
}
static
CAPNPROTO_ALWAYS_INLINE
(
ListReader
readListReference
(
...
...
@@ -434,15 +444,15 @@ struct WireHelpers {
if
(
ref
->
listRef
.
elementSize
()
==
FieldSize
::
STRUCT
)
{
// A struct list reference actually points to a struct reference which in turn points to the
// first struct in the list.
const
voi
d
*
ptrPtr
=
segment
->
getPtrChecked
(
ref
->
offset
(),
0
,
sizeof
(
WireReference
)
);
const
wor
d
*
ptrPtr
=
segment
->
getPtrChecked
(
ref
->
offset
(),
0
*
WORDS
,
WORDS_PER_REFERENCE
);
if
(
CAPNPROTO_EXPECT_FALSE
(
ptrPtr
==
nullptr
))
{
segment
->
getMessage
()
->
reportInvalidData
(
"Message contains out-of-bounds list reference."
);
break
;
}
uint32_
t
size
=
ref
->
listRef
.
elementCount
();
in
t
size
=
ref
->
listRef
.
elementCount
();
ref
=
reinterpret_cast
<
const
WireReference
*>
(
ptrPtr
);
if
(
CAPNPROTO_EXPECT_FALSE
(
ref
->
tag
()
!=
WireReference
::
STRUCT
))
{
...
...
@@ -451,12 +461,10 @@ struct WireHelpers {
break
;
}
int
step
=
(
ref
->
structRef
.
dataSize
.
get
()
+
ref
->
structRef
.
refCount
.
get
())
*
sizeof
(
uint8_t
);
const
void
*
ptr
=
segment
->
getPtrChecked
(
ref
->
offset
(),
ref
->
structRef
.
data
Size
.
get
()
*
sizeof
(
uint8_t
),
ref
->
structRef
.
refCount
.
get
()
*
sizeof
(
WireReference
)
+
step
*
(
size
-
1
));
ref
->
structRef
.
data
WordCount
.
get
(
),
ref
->
structRef
.
refCount
.
get
()
*
WORDS_PER_REFERENCE
+
ref
->
structRef
.
wordSize
()
*
(
size
-
1
));
if
(
CAPNPROTO_EXPECT_FALSE
(
ptr
==
nullptr
))
{
segment
->
getMessage
()
->
reportInvalidData
(
"Message contains out-of-bounds struct list reference."
);
...
...
@@ -467,7 +475,7 @@ struct WireHelpers {
// struct list. We need to manipulate the pointer to point at the first field of the
// struct. Together with the "stepBits", this will allow the struct list to be accessed as
// if it were a primitive list without branching.
ptr
=
offsetPtr
<
uint8_t
>
(
ptr
,
-
byteOffsetForFieldZero
(
descriptor
->
elementSize
)
);
ptr
=
reinterpret_cast
<
const
byte
*>
(
ptr
)
-
byteOffsetForFieldZero
(
descriptor
->
elementSize
);
// Check whether the size is compatible.
bool
compatible
=
true
;
...
...
@@ -477,7 +485,7 @@ struct WireHelpers {
case
FieldSize
:
:
TWO_BYTES
:
case
FieldSize
:
:
FOUR_BYTES
:
case
FieldSize
:
:
EIGHT_BYTES
:
compatible
=
ref
->
structRef
.
data
Size
.
get
()
>
0
;
compatible
=
ref
->
structRef
.
data
WordCount
.
get
()
>
0
*
WORDS
;
break
;
case
FieldSize
:
:
REFERENCE
:
...
...
@@ -485,7 +493,7 @@ struct WireHelpers {
break
;
case
FieldSize
:
:
KEY_REFERENCE
:
compatible
=
ref
->
structRef
.
data
Size
.
get
()
>
0
&&
compatible
=
ref
->
structRef
.
data
WordCount
.
get
()
>
0
*
WORDS
&&
ref
->
structRef
.
refCount
.
get
()
>
0
;
break
;
...
...
@@ -500,16 +508,15 @@ struct WireHelpers {
break
;
}
return
ListReader
(
descriptor
,
segment
,
ptr
,
size
,
step
*
8
,
return
ListReader
(
descriptor
,
segment
,
ptr
,
size
,
ref
->
structRef
.
wordSize
()
*
BITS_PER_WORD
,
ref
->
structRef
.
fieldCount
.
get
(),
recursionLimit
-
1
);
}
else
{
// The elements of the list are NOT structs.
i
nt
step
=
sizeInBits
(
ref
->
listRef
.
elementSize
());
BitCou
nt
step
=
sizeInBits
(
ref
->
listRef
.
elementSize
());
const
void
*
ptr
=
segment
->
getPtrChecked
(
ref
->
offset
(),
0
,
divRoundingUp
<
uint64_t
>
(
implicit_cast
<
uint64_t
>
(
ref
->
listRef
.
elementCount
())
*
step
,
8
));
const
void
*
ptr
=
segment
->
getPtrChecked
(
ref
->
offset
(),
0
*
WORDS
,
divRoundingUp
(
ref
->
listRef
.
elementCount
()
*
BitCount64
(
step
),
BITS_PER_WORD
));
if
(
CAPNPROTO_EXPECT_FALSE
(
ptr
==
nullptr
))
{
segment
->
getMessage
()
->
reportInvalidData
(
...
...
@@ -534,7 +541,8 @@ struct WireHelpers {
}
// Adjust the pointer to point where we expect it for a struct.
ptr
=
offsetPtr
<
uint8_t
>
(
ptr
,
byteOffsetForFieldZero
(
descriptor
->
elementSize
));
ptr
=
reinterpret_cast
<
const
byte
*>
(
ptr
)
+
byteOffsetForFieldZero
(
descriptor
->
elementSize
);
return
ListReader
(
descriptor
,
segment
,
ptr
,
ref
->
listRef
.
elementCount
(),
sizeInBits
(
ref
->
listRef
.
elementSize
()),
1
,
recursionLimit
);
...
...
@@ -549,7 +557,7 @@ struct WireHelpers {
case
FieldSize
:
:
REFERENCE
:
case
FieldSize
:
:
KEY_REFERENCE
:
case
FieldSize
:
:
STRUCT
:
return
ListReader
(
descriptor
,
segment
,
nullptr
,
descriptor
->
defaultCount
,
0
,
0
,
return
ListReader
(
descriptor
,
segment
,
nullptr
,
descriptor
->
defaultCount
,
0
*
BITS
,
0
,
recursionLimit
-
1
);
default
:
return
ListReader
(
descriptor
,
segment
,
descriptor
->
defaultData
,
descriptor
->
defaultCount
,
...
...
@@ -580,7 +588,7 @@ ListBuilder StructBuilder::getListFieldInternal(int refIndex) const {
StructReader
StructBuilder
::
asReader
()
const
{
return
StructReader
(
descriptor
,
segment
,
ptr
,
descriptor
->
defaultData
,
descriptor
->
fieldCount
,
0
,
1
<<
30
);
descriptor
->
fieldCount
,
0
*
BITS
,
std
::
numeric_limits
<
int
>::
max
()
);
}
StructReader
StructReader
::
getStructFieldInternal
(
int
fieldNumber
,
unsigned
int
refIndex
)
const
{
...
...
@@ -602,10 +610,10 @@ ListReader StructReader::getListFieldInternal(int fieldNumber, unsigned int refI
}
StructBuilder
ListBuilder
::
getStructElementInternal
(
unsigned
int
index
,
uint32_t
elementWord
Size
)
const
{
unsigned
int
index
,
WordCount
element
Size
)
const
{
return
StructBuilder
(
descriptor
->
elementDescriptor
->
asStruct
(),
segment
,
offsetPtr
<
uint64_t
>
(
ptr
,
elementWordSize
*
index
)
);
ptr
+
elementSize
*
index
);
}
ListBuilder
ListBuilder
::
initListElementInternal
(
unsigned
int
index
,
uint32_t
size
)
const
{
...
...
@@ -641,14 +649,16 @@ StructReader ListReader::getStructElementInternal(unsigned int index) const {
segment
->
getMessage
()
->
reportInvalidData
(
"Message is too deeply-nested or contains cycles."
);
}
else
{
uint64_t
indexBit
=
static_cast
<
uint64_t
>
(
index
)
*
stepBits
;
BitCount64
indexBit
=
static_cast
<
uint64_t
>
(
index
)
*
stepBits
;
return
StructReader
(
elementDescriptor
,
segment
,
offsetPtr
<
uint8_t
>
(
ptr
,
indexBit
/
8
),
descriptor
->
defaultData
,
structFieldCount
,
indexBit
%
8
,
recursionLimit
-
1
);
elementDescriptor
,
segment
,
reinterpret_cast
<
const
byte
*>
(
ptr
)
+
indexBit
/
BITS_PER_BYTE
,
descriptor
->
defaultData
,
structFieldCount
,
indexBit
%
BITS_PER_BYTE
,
recursionLimit
-
1
);
}
}
return
StructReader
(
elementDescriptor
,
segment
,
nullptr
,
descriptor
->
defaultData
,
0
,
0
,
0
);
return
StructReader
(
elementDescriptor
,
segment
,
nullptr
,
descriptor
->
defaultData
,
0
,
0
*
BITS
,
0
);
}
ListReader
ListReader
::
getListElementInternal
(
unsigned
int
index
,
uint32_t
size
)
const
{
...
...
@@ -659,7 +669,8 @@ ListReader ListReader::getListElementInternal(unsigned int index, uint32_t size)
}
else
{
return
WireHelpers
::
readListReference
(
descriptor
->
elementDescriptor
->
asList
(),
reinterpret_cast
<
const
WireReference
*>
(
offsetPtr
<
uint64_t
>
(
ptr
,
index
*
(
stepBits
/
64
))),
reinterpret_cast
<
const
WireReference
*>
(
ptr
)
+
index
*
(
stepBits
/
BITS_PER_WORD
/
WORDS_PER_REFERENCE
),
segment
,
recursionLimit
);
}
}
...
...
c++/src/capnproto/wire-format.h
View file @
dd46a758
...
...
@@ -30,7 +30,6 @@
#ifndef CAPNPROTO_WIRE_FORMAT_H_
#define CAPNPROTO_WIRE_FORMAT_H_
#include <inttypes.h>
#include "macros.h"
namespace
capnproto
{
...
...
@@ -51,18 +50,18 @@ namespace debug {
// header is #included from generated headers, whereas descriptor.h is only #included in generated
// source files.
bool
fieldIsStruct
(
const
StructDescriptor
*
descriptor
,
int
fieldNumber
,
int
refIndex
);
bool
fieldIsList
(
const
StructDescriptor
*
descriptor
,
int
fieldNumber
,
int
refIndex
);
bool
fieldIsData
(
const
StructDescriptor
*
descriptor
,
int
fieldNumber
,
int
dataOffset
,
i
nt
bitSize
);
bool
dataFieldInRange
(
const
StructDescriptor
*
descriptor
,
uint
32_t
dataOffset
,
uint32_
t
size
);
bool
bitFieldInRange
(
const
StructDescriptor
*
descriptor
,
uint32_
t
offset
);
bool
refFieldIsStruct
(
const
StructDescriptor
*
descriptor
,
int
refIndex
);
bool
refFieldIsList
(
const
StructDescriptor
*
descriptor
,
int
refIndex
);
bool
fieldIsStruct
(
const
StructDescriptor
*
descriptor
,
uint
fieldNumber
,
u
int
refIndex
);
bool
fieldIsList
(
const
StructDescriptor
*
descriptor
,
uint
fieldNumber
,
u
int
refIndex
);
bool
fieldIsData
(
const
StructDescriptor
*
descriptor
,
uint
fieldNumber
,
u
int
dataOffset
,
BitCou
nt
bitSize
);
bool
dataFieldInRange
(
const
StructDescriptor
*
descriptor
,
uint
dataOffset
,
ByteCoun
t
size
);
bool
bitFieldInRange
(
const
StructDescriptor
*
descriptor
,
BitCoun
t
offset
);
bool
refFieldIsStruct
(
const
StructDescriptor
*
descriptor
,
u
int
refIndex
);
bool
refFieldIsList
(
const
StructDescriptor
*
descriptor
,
u
int
refIndex
);
bool
elementsAreStructs
(
const
ListDescriptor
*
descriptor
);
bool
elementsAreStructs
(
const
ListDescriptor
*
descriptor
,
uint32_
t
wordSize
);
bool
elementsAreStructs
(
const
ListDescriptor
*
descriptor
,
WordCoun
t
wordSize
);
bool
elementsAreLists
(
const
ListDescriptor
*
descriptor
);
bool
elementsAreData
(
const
ListDescriptor
*
descriptor
,
i
nt
bitSize
);
bool
elementsAreData
(
const
ListDescriptor
*
descriptor
,
BitCou
nt
bitSize
);
}
// namespace debug
class
StructBuilder
;
...
...
@@ -74,6 +73,14 @@ struct WireHelpers;
// -------------------------------------------------------------------
template
<
typename
T
>
struct
NoInfer
{
// Use NoInfer<T>::Type in place of T for a function parameter to prevent inference of the
// parameter. There's something in the standard library for this but I didn't want to #include
// type_traits or whatever.
typedef
T
Type
;
};
template
<
typename
T
>
class
WireValue
{
// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the
...
...
@@ -101,14 +108,19 @@ private:
class
StructBuilder
{
public
:
inline
StructBuilder
()
:
descriptor
(
nullptr
),
segment
(
nullptr
),
ptr
(
nullptr
)
{}
static
StructBuilder
initRoot
(
const
StructDescriptor
*
descriptor
,
SegmentBuilder
*
segment
,
word
*
location
);
template
<
typename
T
>
inline
T
getDataField
(
u
nsigned
int
offset
)
const
;
inline
T
getDataField
(
uint
offset
)
const
;
// Get the data field value of the given type at the given offset. The offset is measured in
// multiples of the field size, determined by the type.
template
<
typename
T
>
inline
void
setDataField
(
u
nsigned
int
offset
,
T
value
)
const
;
// Set the data field value at the given offset.
Be careful to use the correct type.
inline
void
setDataField
(
u
int
offset
,
typename
NoInfer
<
T
>::
Type
value
)
const
;
// Set the data field value at the given offset.
CAPNPROTO_ALWAYS_INLINE
(
StructBuilder
getStructField
(
int
refIndex
)
const
);
// Get the struct field at the given index in the reference segment. Allocates space for the
...
...
@@ -128,9 +140,9 @@ public:
private
:
const
StructDescriptor
*
descriptor
;
// Descriptor for the struct.
SegmentBuilder
*
segment
;
// Memory segment in which the struct resides.
voi
d
*
ptr
;
// Pointer to the location between the struct's data and reference segments.
wor
d
*
ptr
;
// Pointer to the location between the struct's data and reference segments.
inline
StructBuilder
(
const
StructDescriptor
*
descriptor
,
SegmentBuilder
*
segment
,
voi
d
*
ptr
)
inline
StructBuilder
(
const
StructDescriptor
*
descriptor
,
SegmentBuilder
*
segment
,
wor
d
*
ptr
)
:
descriptor
(
descriptor
),
segment
(
segment
),
ptr
(
ptr
)
{}
StructBuilder
getStructFieldInternal
(
int
refIndex
)
const
;
...
...
@@ -146,17 +158,21 @@ private:
class
StructReader
{
public
:
inline
StructReader
()
:
descriptor
(
nullptr
),
segment
(
nullptr
),
ptr
{
nullptr
,
nullptr
},
fieldCount
(
0
),
bit0Offset
(
0
*
BITS
),
recursionLimit
(
0
)
{}
template
<
typename
T
>
inline
T
getDataField
(
int
fieldNumber
,
u
nsigned
int
offset
)
const
;
inline
T
getDataField
(
int
fieldNumber
,
uint
offset
)
const
;
// Get the data field value of the given type at the given offset. The offset is measured in
// multiples of the field size, determined by the type.
CAPNPROTO_ALWAYS_INLINE
(
StructReader
getStructField
(
int
fieldNumber
,
u
nsigned
int
refIndex
)
const
);
StructReader
getStructField
(
int
fieldNumber
,
uint
refIndex
)
const
);
// Get the struct field at the given index in the reference segment, or the default value if not
// initialized.
CAPNPROTO_ALWAYS_INLINE
(
ListReader
getListField
(
int
fieldNumber
,
u
nsigned
int
refIndex
)
const
);
CAPNPROTO_ALWAYS_INLINE
(
ListReader
getListField
(
int
fieldNumber
,
uint
refIndex
)
const
);
// Get the list field at the given index in the reference segment, or the default value if not
// initialized.
...
...
@@ -168,10 +184,17 @@ private:
// ptr[0] points to the location between the struct's data and reference segments.
// ptr[1] points to the end of the *default* data segment.
// We put these in an array so we can choose between them without a branch.
// These pointers are not necessarily word-aligned -- they are aligned as well as necessary for
// the data they might point at. So if the struct has only one field that we know of, and it is
// of type Int16, then the pointers only need to be 16-bit aligned. Or if the struct has fields
// of type Int16 and Int64 (in that order), but the struct reference on the wire self-reported
// as having only one field (therefore, only the Int16), then ptr[0] need only be 16-bit aligned
// while ptr[1] must be 64-bit aligned. This relaxation of alignment is needed to handle the
// case where a list of primitives is upgraded to a list of structs.
int
fieldCount
;
// Number of fields the struct is reported to have.
i
nt
bit0Offset
;
BitCou
nt
bit0Offset
;
// A special hack: When accessing a boolean with field number zero, pretend its offset is this
// instead of the usual zero. This is needed to allow a boolean list to be upgraded to a list
// of structs.
...
...
@@ -181,13 +204,13 @@ private:
// Once this reaches zero, further pointers will be pruned.
inline
StructReader
(
const
StructDescriptor
*
descriptor
,
SegmentReader
*
segment
,
const
void
*
ptr
,
const
void
*
defaultData
,
int
fieldCount
,
i
nt
bit0Offset
,
const
void
*
ptr
,
const
void
*
defaultData
,
int
fieldCount
,
BitCou
nt
bit0Offset
,
int
recursionLimit
)
:
descriptor
(
descriptor
),
segment
(
segment
),
ptr
{
ptr
,
defaultData
},
fieldCount
(
fieldCount
),
bit0Offset
(
bit0Offset
),
recursionLimit
(
recursionLimit
)
{}
StructReader
getStructFieldInternal
(
int
fieldNumber
,
u
nsigned
int
refIndex
)
const
;
ListReader
getListFieldInternal
(
int
fieldNumber
,
u
nsigned
int
refIndex
)
const
;
StructReader
getStructFieldInternal
(
int
fieldNumber
,
uint
refIndex
)
const
;
ListReader
getListFieldInternal
(
int
fieldNumber
,
uint
refIndex
)
const
;
// The public methods are inlined and simply wrap these "Internal" methods after doing debug
// asserts. This way, debugging is enabled by the caller's compiler flags rather than
// libcapnproto's debug flags.
...
...
@@ -201,26 +224,28 @@ private:
class
ListBuilder
{
public
:
inline
ListBuilder
()
:
descriptor
(
nullptr
),
segment
(
nullptr
),
ptr
(
nullptr
),
elementCount
(
0
)
{}
inline
uint32_t
size
();
// The number of elements in the list.
template
<
typename
T
>
CAPNPROTO_ALWAYS_INLINE
(
T
getDataElement
(
u
nsigned
int
index
)
const
);
CAPNPROTO_ALWAYS_INLINE
(
T
getDataElement
(
uint
index
)
const
);
// Get the element of the given type at the given index.
template
<
typename
T
>
CAPNPROTO_ALWAYS_INLINE
(
void
setDataElement
(
u
nsigned
int
index
,
T
value
)
const
);
// Set the element at the given index.
Be careful to use the correct type.
CAPNPROTO_ALWAYS_INLINE
(
void
setDataElement
(
u
int
index
,
typename
NoInfer
<
T
>::
Type
value
)
const
);
// Set the element at the given index.
CAPNPROTO_ALWAYS_INLINE
(
StructBuilder
getStructElement
(
u
nsigned
int
index
,
uint32_t
elementWord
Size
)
const
);
StructBuilder
getStructElement
(
u
int
index
,
WordCount
element
Size
)
const
);
// Get the struct element at the given index. elementWordSize is the size, in 64-bit words, of
// each element.
CAPNPROTO_ALWAYS_INLINE
(
ListBuilder
initListElement
(
u
nsigned
int
index
,
uint32_t
size
)
const
);
CAPNPROTO_ALWAYS_INLINE
(
ListBuilder
initListElement
(
uint
index
,
uint32_t
size
)
const
);
// Create a new list element of the given size at the given index.
CAPNPROTO_ALWAYS_INLINE
(
ListBuilder
getListElement
(
u
nsigned
int
index
)
const
);
CAPNPROTO_ALWAYS_INLINE
(
ListBuilder
getListElement
(
uint
index
)
const
);
// Get the existing list element at the given index.
ListReader
asReader
()
const
;
...
...
@@ -229,16 +254,16 @@ public:
private
:
const
ListDescriptor
*
descriptor
;
// Descriptor for the list.
SegmentBuilder
*
segment
;
// Memory segment in which the list resides.
voi
d
*
ptr
;
// Pointer to the beginning of the list.
wor
d
*
ptr
;
// Pointer to the beginning of the list.
uint32_t
elementCount
;
// Number of elements in the list.
inline
ListBuilder
(
const
ListDescriptor
*
descriptor
,
SegmentBuilder
*
segment
,
voi
d
*
ptr
,
uint32_t
size
)
wor
d
*
ptr
,
uint32_t
size
)
:
descriptor
(
descriptor
),
segment
(
segment
),
ptr
(
ptr
),
elementCount
(
size
)
{}
StructBuilder
getStructElementInternal
(
u
nsigned
int
index
,
uint32_t
elementWord
Size
)
const
;
ListBuilder
initListElementInternal
(
u
nsigned
int
index
,
uint32_t
size
)
const
;
ListBuilder
getListElementInternal
(
u
nsigned
int
index
)
const
;
StructBuilder
getStructElementInternal
(
u
int
index
,
WordCount
element
Size
)
const
;
ListBuilder
initListElementInternal
(
uint
index
,
uint32_t
size
)
const
;
ListBuilder
getListElementInternal
(
uint
index
)
const
;
// The public methods are inlined and simply wrap these "Internal" methods after doing debug
// asserts. This way, debugging is enabled by the caller's compiler flags rather than
// libcapnproto's debug flags.
...
...
@@ -249,17 +274,21 @@ private:
class
ListReader
{
public
:
inline
ListReader
()
:
descriptor
(
nullptr
),
segment
(
nullptr
),
ptr
(
nullptr
),
elementCount
(
0
),
stepBits
(
0
*
BITS
),
structFieldCount
(
0
),
recursionLimit
(
0
)
{}
inline
uint32_t
size
();
// The number of elements in the list.
template
<
typename
T
>
CAPNPROTO_ALWAYS_INLINE
(
T
getDataElement
(
u
nsigned
int
index
)
const
);
CAPNPROTO_ALWAYS_INLINE
(
T
getDataElement
(
uint
index
)
const
);
// Get the element of the given type at the given index.
CAPNPROTO_ALWAYS_INLINE
(
StructReader
getStructElement
(
u
nsigned
int
index
)
const
);
CAPNPROTO_ALWAYS_INLINE
(
StructReader
getStructElement
(
uint
index
)
const
);
// Get the struct element at the given index.
CAPNPROTO_ALWAYS_INLINE
(
ListReader
getListElement
(
u
nsigned
int
index
,
uint32_t
size
)
const
);
CAPNPROTO_ALWAYS_INLINE
(
ListReader
getListElement
(
uint
index
,
uint32_t
size
)
const
);
// Get the list element at the given index.
private
:
...
...
@@ -267,11 +296,12 @@ private:
SegmentReader
*
segment
;
// Memory segment in which the list resides.
const
void
*
ptr
;
// Pointer to the data. If NULL, use defaultReferences. (Never NULL for data lists.)
// Pointer to the data. If null, use defaultReferences. (Never null for data lists.)
// Must be aligned appropriately for the elements.
uint32_t
elementCount
;
// Number of elements in the list.
unsigned
i
nt
stepBits
;
BitCou
nt
stepBits
;
// The distance between elements, in bits. This is usually the element size, but can be larger
// if the sender upgraded a data list to a struct list. It will always be aligned properly for
// the type. Unsigned so that division by a constant power of 2 is efficient.
...
...
@@ -284,13 +314,13 @@ private:
// Once this reaches zero, further pointers will be pruned.
inline
ListReader
(
const
ListDescriptor
*
descriptor
,
SegmentReader
*
segment
,
const
void
*
ptr
,
uint32_t
size
,
i
nt
stepBits
,
int
structFieldCount
,
const
void
*
ptr
,
uint32_t
size
,
BitCou
nt
stepBits
,
int
structFieldCount
,
int
recursionLimit
)
:
descriptor
(
descriptor
),
segment
(
segment
),
ptr
(
ptr
),
elementCount
(
size
),
stepBits
(
stepBits
),
structFieldCount
(
structFieldCount
),
recursionLimit
(
recursionLimit
)
{}
StructReader
getStructElementInternal
(
u
nsigned
int
index
)
const
;
ListReader
getListElementInternal
(
u
nsigned
int
index
,
uint32_t
size
)
const
;
StructReader
getStructElementInternal
(
uint
index
)
const
;
ListReader
getListElementInternal
(
uint
index
,
uint32_t
size
)
const
;
// The public methods are inlined and simply wrap these "Internal" methods after doing debug
// asserts. This way, debugging is enabled by the caller's compiler flags rather than
// libcapnproto's debug flags.
...
...
@@ -304,31 +334,31 @@ private:
// Internal implementation details...
template
<
typename
T
>
inline
T
StructBuilder
::
getDataField
(
u
nsigned
int
offset
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
dataFieldInRange
(
descriptor
,
offset
,
sizeof
(
T
)),
inline
T
StructBuilder
::
getDataField
(
uint
offset
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
dataFieldInRange
(
descriptor
,
offset
,
sizeof
(
T
)
*
BYTES
),
"StructBuilder::getDataField() type mismatch."
);
return
reinterpret_cast
<
WireValue
<
T
>*>
(
ptr
)[
-
offset
].
get
();
}
template
<>
inline
bool
StructBuilder
::
getDataField
<
bool
>
(
u
nsigned
int
offset
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
bitFieldInRange
(
descriptor
,
offset
),
inline
bool
StructBuilder
::
getDataField
<
bool
>
(
uint
offset
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
bitFieldInRange
(
descriptor
,
offset
*
BITS
),
"StructBuilder::getDataField<bool>() type mismatch."
);
uint8_t
byte
=
*
(
reinterpret_cast
<
uint8_t
*>
(
ptr
)
-
(
offset
/
8
)
-
1
);
return
(
byte
&
(
1
<<
(
offset
%
8
)))
!=
0
;
}
template
<
typename
T
>
inline
void
StructBuilder
::
setDataField
(
u
nsigned
int
offset
,
T
value
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
dataFieldInRange
(
descriptor
,
offset
,
sizeof
(
T
)),
inline
void
StructBuilder
::
setDataField
(
u
int
offset
,
typename
NoInfer
<
T
>::
Type
value
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
dataFieldInRange
(
descriptor
,
offset
,
sizeof
(
T
)
*
BYTES
),
"StructBuilder::setDataField() type mismatch."
);
reinterpret_cast
<
WireValue
<
T
>*>
(
ptr
)[
-
offset
].
set
(
value
);
}
template
<>
inline
void
StructBuilder
::
setDataField
<
bool
>
(
u
nsigned
int
offset
,
bool
value
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
bitFieldInRange
(
descriptor
,
offset
),
inline
void
StructBuilder
::
setDataField
<
bool
>
(
uint
offset
,
bool
value
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
bitFieldInRange
(
descriptor
,
offset
*
BITS
),
"StructBuilder::setDataField<bool>() type mismatch."
);
uint8_t
*
byte
=
reinterpret_cast
<
uint8_t
*>
(
ptr
)
-
(
offset
/
8
)
-
1
;
*
byte
=
(
*
byte
&
~
(
1
<<
(
offset
%
8
)))
...
...
@@ -356,33 +386,34 @@ inline ListBuilder StructBuilder::getListField(int refIndex) const {
// -------------------------------------------------------------------
template
<
typename
T
>
T
StructReader
::
getDataField
(
int
fieldNumber
,
unsigned
int
offset
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
fieldIsData
(
descriptor
,
fieldNumber
,
offset
,
sizeof
(
T
)
*
8
),
T
StructReader
::
getDataField
(
int
fieldNumber
,
uint
offset
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
fieldIsData
(
descriptor
,
fieldNumber
,
offset
,
sizeof
(
T
)
*
BYTES
*
BITS_PER_BYTE
),
"StructReader::getDataField() type mismatch."
);
const
void
*
dataPtr
=
ptr
[
fieldNumber
>=
fieldCount
];
return
reinterpret_cast
<
WireValue
<
T
>*>
(
dataPtr
)[
-
offset
].
get
();
}
template
<>
inline
bool
StructReader
::
getDataField
<
bool
>
(
int
fieldNumber
,
u
nsigned
int
offset
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
fieldIsData
(
descriptor
,
fieldNumber
,
offset
,
1
),
inline
bool
StructReader
::
getDataField
<
bool
>
(
int
fieldNumber
,
uint
offset
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
fieldIsData
(
descriptor
,
fieldNumber
,
offset
,
1
*
BITS
),
"StructReader::getDataField<bool>() type mismatch."
);
// This branch should always be optimized away when inlining.
if
(
offset
==
0
)
offset
=
bit0Offset
;
if
(
offset
==
0
)
offset
=
bit0Offset
/
BITS
;
const
void
*
dataPtr
=
ptr
[
fieldNumber
>=
fieldCount
];
uint8_t
byte
=
*
(
reinterpret_cast
<
const
uint8_t
*>
(
dataPtr
)
-
(
offset
/
8
)
-
1
);
return
(
byte
&
(
1
<<
(
offset
%
8
)))
!=
0
;
}
inline
StructReader
StructReader
::
getStructField
(
int
fieldNumber
,
u
nsigned
int
refIndex
)
const
{
inline
StructReader
StructReader
::
getStructField
(
int
fieldNumber
,
uint
refIndex
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
fieldIsStruct
(
descriptor
,
fieldNumber
,
refIndex
),
"StructReader::getStructField() type mismatch."
);
return
getStructFieldInternal
(
fieldNumber
,
refIndex
);
}
inline
ListReader
StructReader
::
getListField
(
int
fieldNumber
,
u
nsigned
int
refIndex
)
const
{
inline
ListReader
StructReader
::
getListField
(
int
fieldNumber
,
uint
refIndex
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
fieldIsList
(
descriptor
,
fieldNumber
,
refIndex
),
"StructReader::getListField() type mismatch."
);
return
getListFieldInternal
(
fieldNumber
,
refIndex
);
...
...
@@ -393,30 +424,30 @@ inline ListReader StructReader::getListField(int fieldNumber, unsigned int refIn
inline
uint32_t
ListBuilder
::
size
()
{
return
elementCount
;
}
template
<
typename
T
>
inline
T
ListBuilder
::
getDataElement
(
u
nsigned
int
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
sizeof
(
T
)
*
8
),
inline
T
ListBuilder
::
getDataElement
(
uint
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
sizeof
(
T
)
*
BYTES
*
BITS_PER_BYTE
),
"ListBuilder::getDataElement() type mismatch."
);
return
reinterpret_cast
<
WireValue
<
T
>*>
(
ptr
)[
index
].
get
();
}
template
<>
inline
bool
ListBuilder
::
getDataElement
<
bool
>
(
u
nsigned
int
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
1
),
inline
bool
ListBuilder
::
getDataElement
<
bool
>
(
uint
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
1
*
BITS
),
"ListBuilder::getDataElement<bool>() type mismatch."
);
uint8_t
byte
=
*
(
reinterpret_cast
<
uint8_t
*>
(
ptr
)
+
(
index
/
8
));
return
(
byte
&
(
1
<<
(
index
%
8
)))
!=
0
;
}
template
<
typename
T
>
inline
void
ListBuilder
::
setDataElement
(
u
nsigned
int
index
,
T
value
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
sizeof
(
T
)
*
8
),
inline
void
ListBuilder
::
setDataElement
(
u
int
index
,
typename
NoInfer
<
T
>::
Type
value
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
sizeof
(
T
)
*
BYTES
*
BITS_PER_BYTE
),
"ListBuilder::setDataElement() type mismatch."
);
reinterpret_cast
<
WireValue
<
T
>*>
(
ptr
)[
index
].
set
(
value
);
}
template
<>
inline
void
ListBuilder
::
setDataElement
<
bool
>
(
u
nsigned
int
index
,
bool
value
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
1
),
inline
void
ListBuilder
::
setDataElement
<
bool
>
(
uint
index
,
bool
value
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
1
*
BITS
),
"ListBuilder::setDataElement<bool>() type mismatch."
);
uint8_t
*
byte
=
reinterpret_cast
<
uint8_t
*>
(
ptr
)
+
(
index
/
8
);
*
byte
=
(
*
byte
&
~
(
1
<<
(
index
%
8
)))
...
...
@@ -424,21 +455,21 @@ inline void ListBuilder::setDataElement<bool>(unsigned int index, bool value) co
}
inline
StructBuilder
ListBuilder
::
getStructElement
(
u
nsigned
int
index
,
uint32_t
elementWord
Size
)
const
{
u
int
index
,
WordCount
element
Size
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
index
<
elementCount
,
"List index out of range."
);
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreStructs
(
descriptor
,
element
Word
Size
),
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreStructs
(
descriptor
,
elementSize
),
"ListBuilder::getStructElement() type mismatch."
);
return
getStructElementInternal
(
index
,
element
Word
Size
);
return
getStructElementInternal
(
index
,
elementSize
);
}
inline
ListBuilder
ListBuilder
::
initListElement
(
u
nsigned
int
index
,
uint32_t
size
)
const
{
inline
ListBuilder
ListBuilder
::
initListElement
(
uint
index
,
uint32_t
size
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
index
<
elementCount
,
"List index out of range."
);
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreLists
(
descriptor
),
"ListBuilder::initListElement() type mismatch."
);
return
initListElementInternal
(
index
,
size
);
}
inline
ListBuilder
ListBuilder
::
getListElement
(
u
nsigned
int
index
)
const
{
inline
ListBuilder
ListBuilder
::
getListElement
(
uint
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
index
<
elementCount
,
"List index out of range."
);
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreLists
(
descriptor
),
"ListBuilder::getListElement() type mismatch."
);
...
...
@@ -450,30 +481,30 @@ inline ListBuilder ListBuilder::getListElement(unsigned int index) const {
inline
uint32_t
ListReader
::
size
()
{
return
elementCount
;
}
template
<
typename
T
>
inline
T
ListReader
::
getDataElement
(
u
nsigned
int
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
sizeof
(
T
)
*
8
),
inline
T
ListReader
::
getDataElement
(
uint
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
sizeof
(
T
)
*
BYTES
*
BITS_PER_BYTE
),
"ListReader::getDataElement() type mismatch."
);
return
*
reinterpret_cast
<
const
T
*>
(
reinterpret_cast
<
const
uint8_t
*>
(
ptr
)
+
index
*
(
stepBits
/
8
));
reinterpret_cast
<
const
byte
*>
(
ptr
)
+
index
*
(
stepBits
/
BITS_PER_BYTE
));
}
template
<>
inline
bool
ListReader
::
getDataElement
<
bool
>
(
u
nsigned
int
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
1
),
inline
bool
ListReader
::
getDataElement
<
bool
>
(
uint
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreData
(
descriptor
,
1
*
BITS
),
"ListReader::getDataElement<bool>() type mismatch."
);
u
nsigned
int
bitIndex
=
index
*
stepBits
;
u
int
bitIndex
=
index
*
stepBits
/
BITS
;
uint8_t
byte
=
*
(
reinterpret_cast
<
const
uint8_t
*>
(
ptr
)
+
(
bitIndex
/
8
));
return
(
byte
&
(
1
<<
(
bitIndex
%
8
)))
!=
0
;
}
inline
StructReader
ListReader
::
getStructElement
(
u
nsigned
int
index
)
const
{
inline
StructReader
ListReader
::
getStructElement
(
uint
index
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
index
<
elementCount
,
"List index out of range."
);
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreStructs
(
descriptor
),
"ListReader::getStructElement() type mismatch."
);
return
getStructElementInternal
(
index
);
}
inline
ListReader
ListReader
::
getListElement
(
u
nsigned
int
index
,
uint32_t
size
)
const
{
inline
ListReader
ListReader
::
getListElement
(
uint
index
,
uint32_t
size
)
const
{
CAPNPROTO_DEBUG_ASSERT
(
index
<
elementCount
,
"List index out of range."
);
CAPNPROTO_DEBUG_ASSERT
(
debug
::
elementsAreLists
(
descriptor
),
"ListReader::getListElement() type mismatch."
);
...
...
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