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
648839c3
Commit
648839c3
authored
Jun 06, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enforce transitive constness for Maybe<T&> and Array<T>.
parent
b7e1266b
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
137 additions
and
45 deletions
+137
-45
blob.h
c++/src/capnproto/blob.h
+33
-12
layout.h
c++/src/capnproto/layout.h
+2
-12
test-util.h
c++/src/capnproto/test-util.h
+1
-1
common-test.c++
c++/src/kj/common-test.c++
+17
-0
common.h
c++/src/kj/common.h
+84
-20
No files found.
c++/src/capnproto/blob.h
View file @
648839c3
...
...
@@ -86,12 +86,12 @@ public:
inline
Builder
(
decltype
(
nullptr
))
:
ArrayPtr
<
byte
>
(
nullptr
)
{}
inline
Builder
(
byte
*
value
,
size_t
size
)
:
ArrayPtr
<
byte
>
(
value
,
size
)
{}
inline
Builder
(
kj
::
Array
<
byte
>&
value
)
:
ArrayPtr
<
byte
>
(
value
)
{}
inline
Builder
(
const
ArrayPtr
<
byte
>&
value
)
:
ArrayPtr
<
byte
>
(
value
)
{}
inline
Builder
(
ArrayPtr
<
byte
>&
value
)
:
ArrayPtr
<
byte
>
(
value
)
{}
inline
Data
::
Reader
asReader
()
const
{
return
Data
::
Reader
(
*
this
);
}
};
class
Text
::
Builder
{
class
Text
::
Builder
:
public
kj
::
DisallowConstCopy
{
// Basically identical to kj::StringPtr, except that the contents are non-const.
public
:
...
...
@@ -104,8 +104,10 @@ public:
inline
Reader
asReader
()
const
{
return
Reader
(
content
.
begin
(),
content
.
size
());
}
inline
operator
kj
::
ArrayPtr
<
char
>
()
const
;
inline
kj
::
ArrayPtr
<
char
>
asArray
()
const
;
inline
operator
kj
::
ArrayPtr
<
char
>
();
inline
kj
::
ArrayPtr
<
char
>
asArray
();
inline
operator
kj
::
ArrayPtr
<
const
char
>
()
const
;
inline
kj
::
ArrayPtr
<
const
char
>
asArray
()
const
;
// Result does not include NUL terminator.
inline
operator
kj
::
StringPtr
()
const
;
...
...
@@ -119,8 +121,10 @@ public:
inline
char
operator
[](
size_t
index
)
const
{
return
content
[
index
];
}
inline
char
*
begin
()
const
{
return
content
.
begin
();
}
inline
char
*
end
()
const
{
return
content
.
end
()
-
1
;
}
inline
char
*
begin
()
{
return
content
.
begin
();
}
inline
char
*
end
()
{
return
content
.
end
()
-
1
;
}
inline
const
char
*
begin
()
const
{
return
content
.
begin
();
}
inline
const
char
*
end
()
const
{
return
content
.
end
()
-
1
;
}
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
content
.
size
()
<=
1
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
content
.
size
()
>
1
;
}
...
...
@@ -132,8 +136,10 @@ public:
inline
bool
operator
<=
(
Builder
other
)
const
{
return
asString
()
<=
other
.
asString
();
}
inline
bool
operator
>=
(
Builder
other
)
const
{
return
asString
()
>=
other
.
asString
();
}
inline
Builder
slice
(
size_t
start
)
const
;
inline
kj
::
ArrayPtr
<
char
>
slice
(
size_t
start
,
size_t
end
)
const
;
inline
kj
::
StringPtr
slice
(
size_t
start
)
const
;
inline
kj
::
ArrayPtr
<
const
char
>
slice
(
size_t
start
,
size_t
end
)
const
;
inline
Builder
slice
(
size_t
start
);
inline
kj
::
ArrayPtr
<
char
>
slice
(
size_t
start
,
size_t
end
);
// A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter
// version that assumes end = size().
...
...
@@ -160,18 +166,33 @@ inline kj::StringPtr Text::Builder::asString() const {
return
kj
::
StringPtr
(
content
.
begin
(),
content
.
size
()
-
1
);
}
inline
Text
::
Builder
::
operator
kj
::
ArrayPtr
<
char
>
()
const
{
inline
Text
::
Builder
::
operator
kj
::
ArrayPtr
<
char
>
()
{
return
content
.
slice
(
0
,
content
.
size
()
-
1
);
}
inline
kj
::
ArrayPtr
<
char
>
Text
::
Builder
::
asArray
()
const
{
inline
kj
::
ArrayPtr
<
char
>
Text
::
Builder
::
asArray
()
{
return
content
.
slice
(
0
,
content
.
size
()
-
1
);
}
inline
Text
::
Builder
Text
::
Builder
::
slice
(
size_t
start
)
const
{
inline
Text
::
Builder
::
operator
kj
::
ArrayPtr
<
const
char
>
()
const
{
return
content
.
slice
(
0
,
content
.
size
()
-
1
);
}
inline
kj
::
ArrayPtr
<
const
char
>
Text
::
Builder
::
asArray
()
const
{
return
content
.
slice
(
0
,
content
.
size
()
-
1
);
}
inline
kj
::
StringPtr
Text
::
Builder
::
slice
(
size_t
start
)
const
{
return
asReader
().
slice
(
start
);
}
inline
kj
::
ArrayPtr
<
const
char
>
Text
::
Builder
::
slice
(
size_t
start
,
size_t
end
)
const
{
return
content
.
slice
(
start
,
end
);
}
inline
Text
::
Builder
Text
::
Builder
::
slice
(
size_t
start
)
{
return
Text
::
Builder
(
content
.
slice
(
start
,
content
.
size
()));
}
inline
kj
::
ArrayPtr
<
char
>
Text
::
Builder
::
slice
(
size_t
start
,
size_t
end
)
const
{
inline
kj
::
ArrayPtr
<
char
>
Text
::
Builder
::
slice
(
size_t
start
,
size_t
end
)
{
return
content
.
slice
(
start
,
end
);
}
...
...
c++/src/capnproto/layout.h
View file @
648839c3
...
...
@@ -51,16 +51,6 @@ class SegmentBuilder;
// =============================================================================
struct
DisallowConstCopy
{
DisallowConstCopy
()
=
default
;
DisallowConstCopy
(
DisallowConstCopy
&
);
DisallowConstCopy
(
DisallowConstCopy
&&
)
=
default
;
DisallowConstCopy
&
operator
=
(
DisallowConstCopy
&
);
DisallowConstCopy
&
operator
=
(
DisallowConstCopy
&&
)
=
default
;
};
inline
DisallowConstCopy
::
DisallowConstCopy
(
DisallowConstCopy
&
)
=
default
;
inline
DisallowConstCopy
&
DisallowConstCopy
::
operator
=
(
DisallowConstCopy
&
)
=
default
;
enum
class
FieldSize
:
uint8_t
{
// TODO(cleanup): Rename to FieldLayout or maybe ValueLayout.
...
...
@@ -300,7 +290,7 @@ private:
T
value
;
};
class
StructBuilder
:
public
DisallowConstCopy
{
class
StructBuilder
:
public
kj
::
DisallowConstCopy
{
public
:
inline
StructBuilder
()
:
segment
(
nullptr
),
data
(
nullptr
),
pointers
(
nullptr
),
bit0Offset
(
0
)
{}
...
...
@@ -520,7 +510,7 @@ private:
// -------------------------------------------------------------------
class
ListBuilder
:
public
DisallowConstCopy
{
class
ListBuilder
:
public
kj
::
DisallowConstCopy
{
public
:
inline
ListBuilder
()
:
segment
(
nullptr
),
ptr
(
nullptr
),
elementCount
(
0
*
ELEMENTS
),
...
...
c++/src/capnproto/test-util.h
View file @
648839c3
...
...
@@ -35,7 +35,7 @@ inline std::ostream& operator<<(std::ostream& os, const Data::Reader& value) {
return
os
.
write
(
reinterpret_cast
<
const
char
*>
(
value
.
begin
()),
value
.
size
());
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Data
::
Builder
&
value
)
{
return
os
.
write
(
reinterpret_cast
<
char
*>
(
value
.
begin
()),
value
.
size
());
return
os
.
write
(
reinterpret_cast
<
c
onst
c
har
*>
(
value
.
begin
()),
value
.
size
());
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Text
::
Reader
&
value
)
{
return
os
.
write
(
value
.
begin
(),
value
.
size
());
...
...
c++/src/kj/common-test.c++
View file @
648839c3
...
...
@@ -152,6 +152,23 @@ TEST(Common, Maybe) {
}
}
TEST
(
Common
,
MaybeConstness
)
{
int
i
;
Maybe
<
int
&>
mi
=
i
;
const
Maybe
<
int
&>
cmi
=
mi
;
// const Maybe<int&> cmi2 = cmi; // shouldn't compile! Transitive const violation.
Maybe
<
const
int
&>
mci
=
mi
;
const
Maybe
<
const
int
&>
cmci
=
mci
;
const
Maybe
<
const
int
&>
cmci2
=
cmci
;
KJ_IF_MAYBE
(
i2
,
cmci2
)
{
EXPECT_EQ
(
&
i
,
i2
);
}
else
{
ADD_FAILURE
();
}
}
class
Foo
{
public
:
virtual
~
Foo
()
{}
...
...
c++/src/kj/common.h
View file @
648839c3
...
...
@@ -202,6 +202,56 @@ T instance() noexcept;
// Like std::declval, but doesn't transform T into an rvalue reference. If you want that, specify
// instance<T&&>().
struct
DisallowConstCopy
{
// Inherit from this, or declare a member variable of this type, to prevent the class from being
// copyable from a const reference -- instead, it will only be copyable from non-const references.
// This is useful for enforcing transitive constness of contained pointers.
//
// For example, say you have a type T which contains a pointer. T has non-const methods which
// modify the value at that pointer, but T's const methods are designed to allow reading only.
// Unfortunately, if T has a regular copy constructor, someone can simply make a copy of T and
// then use it to modify the pointed-to value. However, if T inherits DisallowConstCopy, then
// callers will only be able to copy non-const instances of T. Ideally, there is some
// parallel type ImmutableT which is like a version of T that only has const methods, and can
// be copied from a const T.
//
// Note that due to C++ rules about implicit copy constructors and assignment operators, any
// type that contains or inherits from a type that disallows const copies will also automatically
// disallow const copies. Hey, cool, that's exactly what we want.
DisallowConstCopy
()
=
default
;
DisallowConstCopy
(
DisallowConstCopy
&
);
DisallowConstCopy
(
DisallowConstCopy
&&
)
=
default
;
DisallowConstCopy
&
operator
=
(
DisallowConstCopy
&
);
DisallowConstCopy
&
operator
=
(
DisallowConstCopy
&&
)
=
default
;
};
// Apparently these cannot be defaulted inside the class due to some obscure C++ rule.
inline
DisallowConstCopy
::
DisallowConstCopy
(
DisallowConstCopy
&
)
=
default
;
inline
DisallowConstCopy
&
DisallowConstCopy
::
operator
=
(
DisallowConstCopy
&
)
=
default
;
template
<
typename
T
>
struct
DisallowConstCopyIfNotConst
:
public
DisallowConstCopy
{
// Inherit from this when implementing a template that contains a pointer to T and which should
// enforce transitive constness. If T is a const type, this has no effect. Otherwise, it is
// an alias for DisallowConstCopy.
};
template
<
typename
T
>
struct
DisallowConstCopyIfNotConst
<
const
T
>
{};
template
<
typename
T
>
struct
EnableIfNotConst_
{
typedef
T
Type
;
};
template
<
typename
T
>
struct
EnableIfNotConst_
<
const
T
>
;
template
<
typename
T
>
using
EnableIfNotConst
=
typename
EnableIfNotConst_
<
T
>::
Type
;
template
<
typename
T
>
struct
EnableIfConst_
;
template
<
typename
T
>
struct
EnableIfConst_
<
const
T
>
{
typedef
T
Type
;
};
template
<
typename
T
>
using
EnableIfConst
=
typename
EnableIfConst_
<
T
>::
Type
;
template
<
typename
T
,
typename
U
>
struct
EnableIfDifferent_
{
typedef
int
Type
;
};
template
<
typename
T
>
struct
EnableIfDifferent_
<
T
,
T
>
{};
template
<
typename
T
,
typename
U
>
using
EnableIfDifferent
=
typename
EnableIfDifferent_
<
T
,
U
>::
Type
;
// =======================================================================================
// Equivalents to std::move() and std::forward(), since these are very commonly needed and the
// std header <utility> pulls in lots of other stuff.
...
...
@@ -428,8 +478,6 @@ public:
Maybe
(
decltype
(
nullptr
))
noexcept
:
ptr
(
nullptr
)
{}
~
Maybe
()
noexcept
{}
inline
Maybe
&
operator
=
(
Maybe
&&
other
)
{
ptr
=
kj
::
mv
(
other
.
ptr
);
return
*
this
;
}
inline
Maybe
&
operator
=
(
const
Maybe
&
other
)
{
ptr
=
other
.
ptr
;
return
*
this
;
}
...
...
@@ -471,19 +519,24 @@ private:
};
template
<
typename
T
>
class
Maybe
<
T
&>
{
class
Maybe
<
T
&>
:
public
DisallowConstCopyIfNotConst
<
T
>
{
public
:
Maybe
()
:
ptr
(
nullptr
)
{}
Maybe
()
noexcept
:
ptr
(
nullptr
)
{}
Maybe
(
T
&
t
)
noexcept
:
ptr
(
&
t
)
{}
Maybe
(
T
*
t
)
noexcept
:
ptr
(
t
)
{}
Maybe
(
const
Maybe
&
other
)
noexcept
:
ptr
(
other
.
ptr
)
{}
template
<
typename
U
>
Maybe
(
const
Maybe
<
U
&>&
other
)
:
ptr
(
other
.
ptr
)
{}
Maybe
(
decltype
(
nullptr
))
noexcept
:
ptr
(
nullptr
)
{}
~
Maybe
()
noexcept
{}
template
<
typename
U
>
inline
Maybe
(
Maybe
<
U
&>&
other
)
noexcept
:
ptr
(
other
.
ptr
)
{}
template
<
typename
U
>
inline
Maybe
(
const
Maybe
<
const
U
&>&
other
)
noexcept
:
ptr
(
other
.
ptr
)
{}
inline
Maybe
(
decltype
(
nullptr
))
noexcept
:
ptr
(
nullptr
)
{}
inline
Maybe
&
operator
=
(
const
Maybe
&
other
)
{
ptr
=
other
.
ptr
;
return
*
this
;
}
inline
Maybe
&
operator
=
(
T
&
other
)
noexcept
{
ptr
=
&
other
;
}
inline
Maybe
&
operator
=
(
T
*
other
)
noexcept
{
ptr
=
other
;
}
template
<
typename
U
>
inline
Maybe
&
operator
=
(
Maybe
<
U
&>&
other
)
noexcept
{
ptr
=
other
.
ptr
;
return
*
this
;
}
template
<
typename
U
>
inline
Maybe
&
operator
=
(
const
Maybe
<
const
U
&>&
other
)
noexcept
{
ptr
=
other
.
ptr
;
return
*
this
;
}
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
ptr
==
nullptr
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
ptr
!=
nullptr
;
}
...
...
@@ -508,14 +561,13 @@ private:
friend
U
*
internal
::
readMaybe
(
const
Maybe
<
U
&>&
maybe
);
};
// =======================================================================================
// ArrayPtr
//
// So common that we put it in common.h rather than array.h.
template
<
typename
T
>
class
ArrayPtr
{
class
ArrayPtr
:
public
DisallowConstCopyIfNotConst
<
T
>
{
// A pointer to an array. Includes a size. Like any pointer, it doesn't own the target data,
// and passing by value only copies the pointer, not the target.
...
...
@@ -533,23 +585,35 @@ public:
}
inline
size_t
size
()
const
{
return
size_
;
}
inline
T
&
operator
[](
size_t
index
)
const
{
inline
const
T
&
operator
[](
size_t
index
)
const
{
KJ_IREQUIRE
(
index
<
size_
,
"Out-of-bounds ArrayPtr access."
);
return
ptr
[
index
];
}
inline
T
&
operator
[](
size_t
index
)
{
KJ_IREQUIRE
(
index
<
size_
,
"Out-of-bounds ArrayPtr access."
);
return
ptr
[
index
];
}
inline
T
*
begin
()
const
{
return
ptr
;
}
inline
T
*
end
()
const
{
return
ptr
+
size_
;
}
inline
T
&
front
()
const
{
return
*
ptr
;
}
inline
T
&
back
()
const
{
return
*
(
ptr
+
size_
-
1
);
}
inline
T
*
begin
()
{
return
ptr
;
}
inline
T
*
end
()
{
return
ptr
+
size_
;
}
inline
T
&
front
()
{
return
*
ptr
;
}
inline
T
&
back
()
{
return
*
(
ptr
+
size_
-
1
);
}
inline
const
T
*
begin
()
const
{
return
ptr
;
}
inline
const
T
*
end
()
const
{
return
ptr
+
size_
;
}
inline
const
T
&
front
()
const
{
return
*
ptr
;
}
inline
const
T
&
back
()
const
{
return
*
(
ptr
+
size_
-
1
);
}
inline
ArrayPtr
slice
(
size_t
start
,
size_t
end
)
const
{
inline
ArrayPtr
<
const
T
>
slice
(
size_t
start
,
size_t
end
)
const
{
KJ_IREQUIRE
(
start
<=
end
&&
end
<=
size_
,
"Out-of-bounds ArrayPtr::slice()."
);
return
ArrayPtr
<
const
T
>
(
ptr
+
start
,
end
-
start
);
}
inline
ArrayPtr
slice
(
size_t
start
,
size_t
end
)
{
KJ_IREQUIRE
(
start
<=
end
&&
end
<=
size_
,
"Out-of-bounds ArrayPtr::slice()."
);
return
ArrayPtr
(
ptr
+
start
,
end
-
start
);
}
inline
bool
operator
==
(
decltype
(
nullptr
))
{
return
size_
==
0
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
{
return
size_
!=
0
;
}
inline
bool
operator
==
(
decltype
(
nullptr
))
const
{
return
size_
==
0
;
}
inline
bool
operator
!=
(
decltype
(
nullptr
))
const
{
return
size_
!=
0
;
}
inline
bool
operator
==
(
const
ArrayPtr
&
other
)
const
{
if
(
size_
!=
other
.
size_
)
return
false
;
...
...
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