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
0a54c46d
Commit
0a54c46d
authored
Mar 30, 2017
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve bounded types implementation.
parent
0c3ec192
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
200 additions
and
11 deletions
+200
-11
units-test.c++
c++/src/kj/units-test.c++
+42
-5
units.h
c++/src/kj/units.h
+158
-6
No files found.
c++/src/kj/units-test.c++
View file @
0a54c46d
...
...
@@ -144,9 +144,9 @@ TEST(UnitMeasure, GuardedConst) {
// COMPILE ERROR: guardedLShift<0x10, 60>();
}
template
<
uint
value
>
constexpr
Guarded
<
value
,
uint
>
guardedValue
(
)
{
return
Guarded
<
value
,
uint
>
(
v
alue
,
unsafe
);
template
<
uint
value
,
typename
T
=
uint
>
constexpr
Guarded
<
value
,
T
>
guardedValue
(
NoInfer
<
T
>
runtimeValue
=
value
)
{
return
Guarded
<
value
,
T
>
(
runtimeV
alue
,
unsafe
);
}
TEST
(
UnitMeasure
,
Guarded
)
{
...
...
@@ -205,8 +205,8 @@ TEST(UnitMeasure, Guarded) {
bar
=
guardedValue
<
3
>
()
*
guardedValue
<
4
>
();
// COMPILE ERROR: bar = guardedValue<2>() * guardedValue<7>();
foo
.
subtractChecked
(
guardedValue
<
122
>
(),
[]()
{
KJ_FAIL_EXPECT
();
});
foo
.
subtractChecked
(
guardedValue
<
123
>
(),
[]()
{
KJ_FAIL_EXPECT
();
});
foo
.
subtractChecked
(
guardedValue
<
122
>
(),
[]()
{
KJ_FAIL_EXPECT
(
""
);
});
foo
.
subtractChecked
(
guardedValue
<
123
>
(),
[]()
{
KJ_FAIL_EXPECT
(
""
);
});
caught
=
false
;
foo
.
subtractChecked
(
guardedValue
<
124
>
(),
[
&
]()
{
caught
=
true
;
});
KJ_EXPECT
(
caught
);
...
...
@@ -312,5 +312,42 @@ TEST(UnitMeasure, GuardedQuantity) {
KJ_EXPECT
(
expected
==
10
);
}
template
<
typename
T
>
void
assertTypeAndValue
(
T
a
,
T
b
)
{
KJ_EXPECT
(
a
==
b
);
}
TEST
(
UnitMeasure
,
GuardedMinMax
)
{
assertTypeAndValue
(
guarded
<
5
>
(),
kj
::
max
(
guarded
<
4
>
(),
guarded
<
5
>
()));
assertTypeAndValue
(
guarded
<
5
>
(),
kj
::
max
(
guarded
<
5
>
(),
guarded
<
4
>
()));
assertTypeAndValue
(
guarded
<
4
>
(),
kj
::
max
(
guarded
<
4
>
(),
guarded
<
4
>
()));
assertTypeAndValue
(
guarded
<
4
>
(),
kj
::
min
(
guarded
<
4
>
(),
guarded
<
5
>
()));
assertTypeAndValue
(
guarded
<
4
>
(),
kj
::
min
(
guarded
<
5
>
(),
guarded
<
4
>
()));
assertTypeAndValue
(
guarded
<
4
>
(),
kj
::
min
(
guarded
<
4
>
(),
guarded
<
4
>
()));
typedef
uint8_t
t1
;
typedef
uint16_t
t2
;
assertTypeAndValue
(
guardedValue
<
5
,
t2
>
(
3
),
kj
::
max
(
guardedValue
<
4
,
t2
>
(
3
),
guardedValue
<
5
,
t1
>
(
2
)));
assertTypeAndValue
(
guardedValue
<
5
,
t2
>
(
3
),
kj
::
max
(
guardedValue
<
5
,
t1
>
(
2
),
guardedValue
<
4
,
t2
>
(
3
)));
assertTypeAndValue
(
guardedValue
<
4
,
t2
>
(
3
),
kj
::
max
(
guardedValue
<
4
,
t2
>
(
3
),
guardedValue
<
4
,
t2
>
(
3
)));
assertTypeAndValue
(
guardedValue
<
4
,
t2
>
(
2
),
kj
::
min
(
guardedValue
<
4
,
t2
>
(
3
),
guardedValue
<
5
,
t1
>
(
2
)));
assertTypeAndValue
(
guardedValue
<
4
,
t2
>
(
2
),
kj
::
min
(
guardedValue
<
5
,
t1
>
(
2
),
guardedValue
<
4
,
t2
>
(
3
)));
assertTypeAndValue
(
guardedValue
<
4
,
t2
>
(
3
),
kj
::
min
(
guardedValue
<
4
,
t2
>
(
3
),
guardedValue
<
4
,
t2
>
(
3
)));
assertTypeAndValue
(
guardedValue
<
5
,
t1
>
(
4
),
kj
::
max
(
guarded
<
4
>
(),
guardedValue
<
5
,
t1
>
(
2
)));
assertTypeAndValue
(
guardedValue
<
5
,
t1
>
(
4
),
kj
::
max
(
guardedValue
<
5
,
t1
>
(
2
),
guarded
<
4
>
()));
assertTypeAndValue
(
guardedValue
<
4
,
t1
>
(
2
),
kj
::
min
(
guarded
<
4
>
(),
guardedValue
<
5
,
t1
>
(
2
)));
assertTypeAndValue
(
guardedValue
<
4
,
t1
>
(
2
),
kj
::
min
(
guardedValue
<
5
,
t1
>
(
2
),
guarded
<
4
>
()));
// These two are degenerate cases. Currently they fail to compile but meybe they shouldn't?
// assertTypeAndValue(guarded<5>(), kj::max(guardedValue<4,t2>(3), guarded<5>()));
// assertTypeAndValue(guarded<5>(), kj::max(guarded<5>(), guardedValue<4,t2>(3)));
assertTypeAndValue
(
guardedValue
<
4
,
t2
>
(
3
),
kj
::
min
(
guardedValue
<
4
,
t2
>
(
3
),
guarded
<
5
>
()));
assertTypeAndValue
(
guardedValue
<
4
,
t2
>
(
3
),
kj
::
min
(
guarded
<
5
>
(),
guardedValue
<
4
,
t2
>
(
3
)));
}
}
// namespace
}
// namespace kj
c++/src/kj/units.h
View file @
0a54c46d
...
...
@@ -182,12 +182,13 @@ private:
template
<
typename
OtherNumber
,
typename
OtherUnit1
,
typename
OtherUnit2
>
friend
class
UnitRatio
;
template
<
typename
N1
,
typename
N2
,
typename
U1
,
typename
U2
>
template
<
typename
N1
,
typename
N2
,
typename
U1
,
typename
U2
,
typename
>
friend
inline
constexpr
UnitRatio
<
decltype
(
N1
()
*
N2
()),
U1
,
U2
>
operator
*
(
N1
,
UnitRatio
<
N2
,
U1
,
U2
>
);
};
template
<
typename
N1
,
typename
N2
,
typename
U1
,
typename
U2
>
template
<
typename
N1
,
typename
N2
,
typename
U1
,
typename
U2
,
typename
=
EnableIf
<
isIntegralOrGuarded
<
N1
>
()
&&
isIntegralOrGuarded
<
N2
>
()
>>
inline
constexpr
UnitRatio
<
decltype
(
N1
()
*
N2
()),
U1
,
U2
>
operator
*
(
N1
n
,
UnitRatio
<
N2
,
U1
,
U2
>
r
)
{
return
UnitRatio
<
decltype
(
N1
()
*
N2
()),
U1
,
U2
>
(
n
*
r
.
unit1PerUnit2
,
unsafe
);
...
...
@@ -297,25 +298,25 @@ public:
template
<
typename
OtherNumber
,
typename
OtherUnit
>
inline
constexpr
Quantity
<
decltype
(
Number
()
*
OtherNumber
()),
OtherUnit
>
operator
*
(
const
UnitRatio
<
OtherNumber
,
OtherUnit
,
Unit
>&
ratio
)
const
{
operator
*
(
UnitRatio
<
OtherNumber
,
OtherUnit
,
Unit
>
ratio
)
const
{
return
Quantity
<
decltype
(
Number
()
*
OtherNumber
()),
OtherUnit
>
(
value
*
ratio
.
unit1PerUnit2
,
unsafe
);
}
template
<
typename
OtherNumber
,
typename
OtherUnit
>
inline
constexpr
Quantity
<
decltype
(
Number
()
/
OtherNumber
()),
OtherUnit
>
operator
/
(
const
UnitRatio
<
OtherNumber
,
Unit
,
OtherUnit
>&
ratio
)
const
{
operator
/
(
UnitRatio
<
OtherNumber
,
Unit
,
OtherUnit
>
ratio
)
const
{
return
Quantity
<
decltype
(
Number
()
/
OtherNumber
()),
OtherUnit
>
(
value
/
ratio
.
unit1PerUnit2
,
unsafe
);
}
template
<
typename
OtherNumber
,
typename
OtherUnit
>
inline
constexpr
Quantity
<
decltype
(
Number
()
%
OtherNumber
()),
Unit
>
operator
%
(
const
UnitRatio
<
OtherNumber
,
Unit
,
OtherUnit
>&
ratio
)
const
{
operator
%
(
UnitRatio
<
OtherNumber
,
Unit
,
OtherUnit
>
ratio
)
const
{
return
Quantity
<
decltype
(
Number
()
%
OtherNumber
()),
Unit
>
(
value
%
ratio
.
unit1PerUnit2
,
unsafe
);
}
template
<
typename
OtherNumber
,
typename
OtherUnit
>
inline
constexpr
UnitRatio
<
decltype
(
Number
()
/
OtherNumber
()),
Unit
,
OtherUnit
>
operator
/
(
const
Quantity
<
OtherNumber
,
OtherUnit
>&
other
)
const
{
operator
/
(
Quantity
<
OtherNumber
,
OtherUnit
>
other
)
const
{
return
UnitRatio
<
decltype
(
Number
()
/
OtherNumber
()),
Unit
,
OtherUnit
>
(
value
/
other
.
value
,
unsafe
);
}
...
...
@@ -511,6 +512,12 @@ class GuardedConst {
// A constant integer value on which we can do bit size analysis.
public
:
GuardedConst
()
=
default
;
inline
constexpr
GuardedConst
(
decltype
(
kj
::
maxValue
))
{}
inline
constexpr
GuardedConst
(
decltype
(
kj
::
minValue
))
{}
// These aren't directly useful but cause kj::max()/kj::min() to choose types correctly.
inline
constexpr
uint
unwrap
()
const
{
return
value
;
}
#define OP(op, check) \
...
...
@@ -582,6 +589,17 @@ static constexpr uint64_t guardedLShift() {
return
a
<<
b
;
}
template
<
uint
a
,
uint
b
>
inline
constexpr
GuardedConst
<
kj
::
min
(
a
,
b
)
>
min
(
GuardedConst
<
a
>
,
GuardedConst
<
b
>
)
{
return
guarded
<
kj
::
min
(
a
,
b
)
>
();
}
template
<
uint
a
,
uint
b
>
inline
constexpr
GuardedConst
<
kj
::
max
(
a
,
b
)
>
max
(
GuardedConst
<
a
>
,
GuardedConst
<
b
>
)
{
return
guarded
<
kj
::
max
(
a
,
b
)
>
();
}
// We need to override min() and max() between constants because the ternary operator in the
// default implementation would complain.
// -------------------------------------------------------------------
template
<
uint64_t
maxN
,
typename
T
>
...
...
@@ -686,6 +704,27 @@ public:
return
Guarded
<
maxN
-
otherValue
,
T
>
(
value
-
otherValue
,
unsafe
);
}
template
<
uint64_t
otherMax
,
typename
OtherT
>
inline
Maybe
<
Guarded
<
maxN
,
decltype
(
T
()
-
OtherT
())
>>
trySubtract
(
const
Guarded
<
otherMax
,
OtherT
>&
other
)
const
{
// Subtract a number, calling func() if the result would underflow.
if
(
value
<
other
.
value
)
{
return
nullptr
;
}
else
{
return
Guarded
<
maxN
,
decltype
(
T
()
-
OtherT
())
>
(
value
-
other
.
value
,
unsafe
);
}
}
template
<
uint
otherValue
>
inline
Maybe
<
Guarded
<
maxN
-
otherValue
,
T
>>
trySubtract
(
GuardedConst
<
otherValue
>
)
const
{
// Subtract a number, calling func() if the result would underflow.
if
(
value
<
otherValue
)
{
return
nullptr
;
}
else
{
return
Guarded
<
maxN
-
otherValue
,
T
>
(
value
-
otherValue
,
unsafe
);
}
}
inline
constexpr
Guarded
(
T
value
,
decltype
(
unsafe
))
:
value
(
value
)
{}
template
<
uint64_t
otherMax
,
typename
OtherT
>
inline
constexpr
Guarded
(
Guarded
<
otherMax
,
OtherT
>
value
,
decltype
(
unsafe
))
...
...
@@ -699,6 +738,21 @@ private:
template
<
uint64_t
,
typename
>
friend
class
Guarded
;
template
<
uint64_t
aN
,
uint64_t
bN
,
typename
A
,
typename
B
>
friend
constexpr
Guarded
<
kj
::
min
(
aN
,
bN
),
WiderType
<
A
,
B
>>
min
(
Guarded
<
aN
,
A
>
a
,
Guarded
<
bN
,
B
>
b
);
template
<
uint64_t
aN
,
uint
b
,
typename
A
>
friend
constexpr
Guarded
<
kj
::
min
(
aN
,
b
),
A
>
min
(
Guarded
<
aN
,
A
>
a
,
GuardedConst
<
b
>
);
template
<
uint64_t
aN
,
uint
b
,
typename
A
>
friend
constexpr
Guarded
<
kj
::
min
(
aN
,
b
),
A
>
min
(
GuardedConst
<
b
>
,
Guarded
<
aN
,
A
>
a
);
template
<
uint64_t
aN
,
uint64_t
bN
,
typename
A
,
typename
B
>
friend
constexpr
Guarded
<
kj
::
max
(
aN
,
bN
),
WiderType
<
A
,
B
>>
max
(
Guarded
<
aN
,
A
>
a
,
Guarded
<
bN
,
B
>
b
);
template
<
uint64_t
aN
,
uint
b
,
typename
A
>
friend
constexpr
Guarded
<
kj
::
max
(
aN
,
b
),
A
>
max
(
Guarded
<
aN
,
A
>
a
,
GuardedConst
<
b
>
);
template
<
uint64_t
aN
,
uint
b
,
typename
A
>
friend
constexpr
Guarded
<
kj
::
max
(
aN
,
b
),
A
>
max
(
GuardedConst
<
b
>
,
Guarded
<
aN
,
A
>
a
);
};
template
<
typename
Number
>
...
...
@@ -727,6 +781,39 @@ inline constexpr auto assumeBits(Quantity<Number, Unit> value)
assumeBits
<
bits
>
(
value
/
unit
<
Quantity
<
Number
,
Unit
>>
()),
unsafe
);
}
template
<
uint64_t
maxN
,
typename
Number
>
inline
constexpr
Guarded
<
maxN
,
Number
>
assumeMax
(
Number
value
)
{
return
Guarded
<
maxN
,
Number
>
(
value
,
unsafe
);
}
template
<
uint64_t
newMaxN
,
uint64_t
maxN
,
typename
T
>
inline
constexpr
Guarded
<
newMaxN
,
T
>
assumeMax
(
Guarded
<
maxN
,
T
>
value
)
{
return
Guarded
<
newMaxN
,
T
>
(
value
,
unsafe
);
}
template
<
uint64_t
maxN
,
typename
Number
,
typename
Unit
>
inline
constexpr
auto
assumeMax
(
Quantity
<
Number
,
Unit
>
value
)
->
Quantity
<
decltype
(
assumeMax
<
maxN
>
(
value
/
unit
<
Quantity
<
Number
,
Unit
>>
())),
Unit
>
{
return
Quantity
<
decltype
(
assumeMax
<
maxN
>
(
value
/
unit
<
Quantity
<
Number
,
Unit
>>
())),
Unit
>
(
assumeMax
<
maxN
>
(
value
/
unit
<
Quantity
<
Number
,
Unit
>>
()),
unsafe
);
}
template
<
uint
maxN
,
typename
Number
>
inline
constexpr
Guarded
<
maxN
,
Number
>
assumeMax
(
GuardedConst
<
maxN
>
,
Number
value
)
{
return
assumeMax
<
maxN
>
(
value
);
}
template
<
uint
newMaxN
,
uint64_t
maxN
,
typename
T
>
inline
constexpr
Guarded
<
newMaxN
,
T
>
assumeMax
(
GuardedConst
<
maxN
>
,
Guarded
<
maxN
,
T
>
value
)
{
return
assumeMax
<
maxN
>
(
value
);
}
template
<
uint
maxN
,
typename
Number
,
typename
Unit
>
inline
constexpr
auto
assumeMax
(
Quantity
<
GuardedConst
<
maxN
>
,
Unit
>
,
Quantity
<
Number
,
Unit
>
value
)
->
decltype
(
assumeMax
<
maxN
>
(
value
))
{
return
assumeMax
<
maxN
>
(
value
);
}
struct
ThrowOverflow
{
void
operator
()()
const
;
};
...
...
@@ -749,6 +836,19 @@ inline constexpr Quantity<Guarded<newMax, T>, Unit> assertMax(
kj
::
fwd
<
ErrorFunc
>
(
errorFunc
))
*
unit
<
decltype
(
value
)
>
();
}
template
<
uint
newMax
,
uint64_t
maxN
,
typename
T
,
typename
ErrorFunc
>
inline
constexpr
Guarded
<
newMax
,
T
>
assertMax
(
GuardedConst
<
newMax
>
,
Guarded
<
maxN
,
T
>
value
,
ErrorFunc
&&
errorFunc
)
{
return
assertMax
<
newMax
>
(
value
,
kj
::
mv
(
errorFunc
));
}
template
<
uint
newMax
,
uint64_t
maxN
,
typename
T
,
typename
Unit
,
typename
ErrorFunc
>
inline
constexpr
Quantity
<
Guarded
<
newMax
,
T
>
,
Unit
>
assertMax
(
Quantity
<
GuardedConst
<
newMax
>
,
Unit
>
,
Quantity
<
Guarded
<
maxN
,
T
>
,
Unit
>
value
,
ErrorFunc
&&
errorFunc
)
{
return
assertMax
<
newMax
>
(
value
,
kj
::
mv
(
errorFunc
));
}
template
<
uint64_t
newBits
,
uint64_t
maxN
,
typename
T
,
typename
ErrorFunc
=
ThrowOverflow
>
inline
constexpr
Guarded
<
maxValueForBits
<
newBits
>
(),
T
>
assertMaxBits
(
Guarded
<
maxN
,
T
>
value
,
ErrorFunc
&&
errorFunc
=
ErrorFunc
())
{
...
...
@@ -792,6 +892,37 @@ inline auto subtractChecked(Quantity<T, Unit> value, Quantity<U, Unit> other, Er
*
unit
<
Quantity
<
T
,
Unit
>>
();
}
template
<
uint64_t
maxN
,
typename
T
,
typename
Other
>
inline
auto
trySubtract
(
Guarded
<
maxN
,
T
>
value
,
Other
other
)
->
decltype
(
value
.
trySubtract
(
other
))
{
return
value
.
trySubtract
(
other
);
}
template
<
typename
T
,
typename
U
,
typename
Unit
>
inline
auto
trySubtract
(
Quantity
<
T
,
Unit
>
value
,
Quantity
<
U
,
Unit
>
other
)
->
Maybe
<
Quantity
<
decltype
(
subtractChecked
(
T
(),
U
(),
int
())),
Unit
>>
{
return
trySubtract
(
value
/
unit
<
Quantity
<
T
,
Unit
>>
(),
other
/
unit
<
Quantity
<
U
,
Unit
>>
())
.
map
([](
decltype
(
subtractChecked
(
T
(),
U
(),
int
()))
x
)
{
return
x
*
unit
<
Quantity
<
T
,
Unit
>>
();
});
}
template
<
uint64_t
aN
,
uint64_t
bN
,
typename
A
,
typename
B
>
inline
constexpr
Guarded
<
kj
::
min
(
aN
,
bN
),
WiderType
<
A
,
B
>>
min
(
Guarded
<
aN
,
A
>
a
,
Guarded
<
bN
,
B
>
b
)
{
return
Guarded
<
kj
::
min
(
aN
,
bN
),
WiderType
<
A
,
B
>>
(
kj
::
min
(
a
.
value
,
b
.
value
),
unsafe
);
}
template
<
uint64_t
aN
,
uint64_t
bN
,
typename
A
,
typename
B
>
inline
constexpr
Guarded
<
kj
::
max
(
aN
,
bN
),
WiderType
<
A
,
B
>>
max
(
Guarded
<
aN
,
A
>
a
,
Guarded
<
bN
,
B
>
b
)
{
return
Guarded
<
kj
::
max
(
aN
,
bN
),
WiderType
<
A
,
B
>>
(
kj
::
max
(
a
.
value
,
b
.
value
),
unsafe
);
}
// We need to override min() and max() because:
// 1) WiderType<> might not choose the correct bounds.
// 2) One of the two sides of the ternary operator in the default implementation would fail to
// typecheck even though it is OK in practice.
// -------------------------------------------------------------------
// Operators between Guarded and GuardedConst
...
...
@@ -867,6 +998,27 @@ inline constexpr Guarded<cvalue, decltype(uint() - T())>
return
Guarded
<
cvalue
,
decltype
(
uint
()
-
T
())
>
(
cvalue
-
value
.
unwrap
(),
unsafe
);
}
template
<
uint64_t
aN
,
uint
b
,
typename
A
>
inline
constexpr
Guarded
<
kj
::
min
(
aN
,
b
),
A
>
min
(
Guarded
<
aN
,
A
>
a
,
GuardedConst
<
b
>
)
{
return
Guarded
<
kj
::
min
(
aN
,
b
),
A
>
(
kj
::
min
(
b
,
a
.
value
),
unsafe
);
}
template
<
uint64_t
aN
,
uint
b
,
typename
A
>
inline
constexpr
Guarded
<
kj
::
min
(
aN
,
b
),
A
>
min
(
GuardedConst
<
b
>
,
Guarded
<
aN
,
A
>
a
)
{
return
Guarded
<
kj
::
min
(
aN
,
b
),
A
>
(
kj
::
min
(
a
.
value
,
b
),
unsafe
);
}
template
<
uint64_t
aN
,
uint
b
,
typename
A
>
inline
constexpr
Guarded
<
kj
::
max
(
aN
,
b
),
A
>
max
(
Guarded
<
aN
,
A
>
a
,
GuardedConst
<
b
>
)
{
return
Guarded
<
kj
::
max
(
aN
,
b
),
A
>
(
kj
::
max
(
b
,
a
.
value
),
unsafe
);
}
template
<
uint64_t
aN
,
uint
b
,
typename
A
>
inline
constexpr
Guarded
<
kj
::
max
(
aN
,
b
),
A
>
max
(
GuardedConst
<
b
>
,
Guarded
<
aN
,
A
>
a
)
{
return
Guarded
<
kj
::
max
(
aN
,
b
),
A
>
(
kj
::
max
(
a
.
value
,
b
),
unsafe
);
}
// We need to override min() between a Guarded and a constant since:
// 1) WiderType<> might choose GuardedConst over a 1-byte Guarded, which is wrong.
// 2) To clamp the bounds of the output type.
// 3) Same ternary operator typechecking issues.
// -------------------------------------------------------------------
template
<
uint64_t
maxN
,
typename
T
>
...
...
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