Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
bda7b361
Commit
bda7b361
authored
Dec 19, 2019
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Extend number parser with support for ranges
parent
2381afd4
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
235 additions
and
27 deletions
+235
-27
libcaf_core/caf/detail/parser/chars.hpp
libcaf_core/caf/detail/parser/chars.hpp
+5
-1
libcaf_core/caf/detail/parser/fsm.hpp
libcaf_core/caf/detail/parser/fsm.hpp
+28
-2
libcaf_core/caf/detail/parser/read_floating_point.hpp
libcaf_core/caf/detail/parser/read_floating_point.hpp
+2
-1
libcaf_core/caf/detail/parser/read_number.hpp
libcaf_core/caf/detail/parser/read_number.hpp
+121
-18
libcaf_core/caf/pec.hpp
libcaf_core/caf/pec.hpp
+3
-1
libcaf_core/test/detail/parser/read_number.cpp
libcaf_core/test/detail/parser/read_number.cpp
+76
-4
No files found.
libcaf_core/caf/detail/parser/chars.hpp
View file @
bda7b361
...
@@ -38,7 +38,11 @@ constexpr bool in_whitelist(char whitelist, char ch) {
...
@@ -38,7 +38,11 @@ constexpr bool in_whitelist(char whitelist, char ch) {
}
}
inline
bool
in_whitelist
(
const
char
*
whitelist
,
char
ch
)
{
inline
bool
in_whitelist
(
const
char
*
whitelist
,
char
ch
)
{
return
strchr
(
whitelist
,
ch
)
!=
nullptr
;
// Note: using strchr breaks if `ch == '\0'`.
for
(
char
c
=
*
whitelist
++
;
c
!=
'\0'
;
c
=
*
whitelist
++
)
if
(
c
==
ch
)
return
true
;
return
false
;
}
}
inline
bool
in_whitelist
(
bool
(
*
filter
)(
char
),
char
ch
)
{
inline
bool
in_whitelist
(
bool
(
*
filter
)(
char
),
char
ch
)
{
...
...
libcaf_core/caf/detail/parser/fsm.hpp
View file @
bda7b361
...
@@ -273,18 +273,30 @@
...
@@ -273,18 +273,30 @@
#endif // CAF_MSVC
#endif // CAF_MSVC
///
Mak
es a transition into another state if the `statement` is true.
///
Enabl
es a transition into another state if the `statement` is true.
#define transition_if(statement, ...) \
#define transition_if(statement, ...) \
if (statement) { \
if (statement) { \
transition(__VA_ARGS__) \
transition(__VA_ARGS__) \
}
}
/// Makes an epsiolon transition into another state if the `statement` is true.
/// Enables a transition if the constexpr `statement` is true.
#define transition_static_if(statement, ...) \
if constexpr (statement) { \
transition(__VA_ARGS__) \
}
/// Enables an epsiolon transition if the `statement` is true.
#define epsilon_if(statement, ...) \
#define epsilon_if(statement, ...) \
if (statement) { \
if (statement) { \
epsilon(__VA_ARGS__) \
epsilon(__VA_ARGS__) \
}
}
/// Enables an epsiolon transition if the constexpr `statement` is true.
#define epsilon_static_if(statement, ...) \
if constexpr (statement) { \
epsilon(__VA_ARGS__) \
}
/// Makes an transition transition into another FSM if `statement` is true,
/// Makes an transition transition into another FSM if `statement` is true,
/// resuming at state `target`.
/// resuming at state `target`.
#define fsm_transition_if(statement, ...) \
#define fsm_transition_if(statement, ...) \
...
@@ -292,9 +304,23 @@
...
@@ -292,9 +304,23 @@
fsm_transition(__VA_ARGS__) \
fsm_transition(__VA_ARGS__) \
}
}
/// Makes an transition transition into another FSM if `statement` is true,
/// resuming at state `target`.
#define fsm_transition_static_if(statement, ...) \
if constexpr (statement) { \
fsm_transition(__VA_ARGS__) \
}
/// Makes an epsilon transition into another FSM if `statement` is true,
/// Makes an epsilon transition into another FSM if `statement` is true,
/// resuming at state `target`.
/// resuming at state `target`.
#define fsm_epsilon_if(statement, ...) \
#define fsm_epsilon_if(statement, ...) \
if (statement) { \
if (statement) { \
fsm_epsilon(__VA_ARGS__) \
fsm_epsilon(__VA_ARGS__) \
}
}
/// Makes an epsilon transition into another FSM if `statement` is true,
/// resuming at state `target`.
#define fsm_epsilon_static_if(statement, ...) \
if constexpr (statement) { \
fsm_epsilon(__VA_ARGS__) \
}
libcaf_core/caf/detail/parser/read_floating_point.hpp
View file @
bda7b361
...
@@ -112,7 +112,8 @@ void read_floating_point(State& ps, Consumer&& consumer,
...
@@ -112,7 +112,8 @@ void read_floating_point(State& ps, Consumer&& consumer,
start
();
start
();
unstable_state
(
init
)
{
unstable_state
(
init
)
{
epsilon_if
(
start_value
==
none
,
regular_init
)
epsilon_if
(
start_value
==
none
,
regular_init
)
epsilon
(
after_dec
)
epsilon
(
after_dec
,
"eE."
)
epsilon
(
after_dot
,
any_char
)
}
}
state
(
regular_init
)
{
state
(
regular_init
)
{
transition
(
regular_init
,
"
\t
"
)
transition
(
regular_init
,
"
\t
"
)
...
...
libcaf_core/caf/detail/parser/read_number.hpp
View file @
bda7b361
...
@@ -19,8 +19,10 @@
...
@@ -19,8 +19,10 @@
#pragma once
#pragma once
#include <cstdint>
#include <cstdint>
#include <type_traits>
#include "caf/config.hpp"
#include "caf/config.hpp"
#include "caf/detail/consumer.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_char.hpp"
...
@@ -36,10 +38,25 @@ CAF_PUSH_UNUSED_LABEL_WARNING
...
@@ -36,10 +38,25 @@ CAF_PUSH_UNUSED_LABEL_WARNING
namespace
caf
::
detail
::
parser
{
namespace
caf
::
detail
::
parser
{
/// Reads the second half of 'n..m' range statement.
///
/// Expect the current position to point at the number *after* the dots:
///
/// ~~~
/// foo = [1..2]
/// ~~~^
/// ~~~
template
<
class
State
,
class
Consumer
>
void
read_number_range
(
State
&
ps
,
Consumer
&
consumer
,
int64_t
begin
);
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
/// `double`.
template
<
class
State
,
class
Consumer
>
template
<
class
State
,
class
Consumer
,
class
EnableFloat
=
std
::
true_type
,
void
read_number
(
State
&
ps
,
Consumer
&
consumer
)
{
class
EnableRange
=
std
::
false_type
>
void
read_number
(
State
&
ps
,
Consumer
&
consumer
,
EnableFloat
=
{},
EnableRange
=
{})
{
static
constexpr
bool
enable_float
=
EnableFloat
::
value
;
static
constexpr
bool
enable_range
=
EnableRange
::
value
;
// Our result when reading an integer number.
// Our result when reading an integer number.
int64_t
result
=
0
;
int64_t
result
=
0
;
// Computes the result on success.
// Computes the result on success.
...
@@ -47,6 +64,7 @@ void read_number(State& ps, Consumer& consumer) {
...
@@ -47,6 +64,7 @@ void read_number(State& ps, Consumer& consumer) {
if
(
ps
.
code
<=
pec
::
trailing_character
)
if
(
ps
.
code
<=
pec
::
trailing_character
)
consumer
.
value
(
result
);
consumer
.
value
(
result
);
});
});
using
odbl
=
optional
<
double
>
;
// clang-format off
// clang-format off
// Definition of our parser FSM.
// Definition of our parser FSM.
start
();
start
();
...
@@ -54,17 +72,22 @@ void read_number(State& ps, Consumer& consumer) {
...
@@ -54,17 +72,22 @@ void read_number(State& ps, Consumer& consumer) {
transition
(
init
,
"
\t
"
)
transition
(
init
,
"
\t
"
)
transition
(
has_plus
,
'+'
)
transition
(
has_plus
,
'+'
)
transition
(
has_minus
,
'-'
)
transition
(
has_minus
,
'-'
)
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
0.
}),
done
,
'.'
,
g
.
disable
())
epsilon
(
has_plus
)
epsilon
(
has_plus
)
}
}
// "+" or "-" alone aren't numbers.
// "+" or "-" alone aren't numbers.
state
(
has_plus
)
{
state
(
has_plus
)
{
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
0.
}),
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
0.
}),
done
,
'.'
,
g
.
disable
())
done
,
'.'
,
g
.
disable
())
transition
(
pos_zero
,
'0'
)
transition
(
pos_zero
,
'0'
)
epsilon
(
pos_dec
)
epsilon
(
pos_dec
)
}
}
state
(
has_minus
)
{
state
(
has_minus
)
{
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
0.
},
true
),
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
0.
},
true
),
done
,
'.'
,
g
.
disable
())
done
,
'.'
,
g
.
disable
())
transition
(
neg_zero
,
'0'
)
transition
(
neg_zero
,
'0'
)
epsilon
(
neg_dec
)
epsilon
(
neg_dec
)
...
@@ -73,15 +96,13 @@ void read_number(State& ps, Consumer& consumer) {
...
@@ -73,15 +96,13 @@ void read_number(State& ps, Consumer& consumer) {
term_state
(
pos_zero
)
{
term_state
(
pos_zero
)
{
transition
(
start_pos_bin
,
"bB"
)
transition
(
start_pos_bin
,
"bB"
)
transition
(
start_pos_hex
,
"xX"
)
transition
(
start_pos_hex
,
"xX"
)
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
0.
}),
transition_static_if
(
enable_float
||
enable_range
,
pos_dot
,
'.'
)
done
,
'.'
,
g
.
disable
())
epsilon
(
pos_oct
)
epsilon
(
pos_oct
)
}
}
term_state
(
neg_zero
)
{
term_state
(
neg_zero
)
{
transition
(
start_neg_bin
,
"bB"
)
transition
(
start_neg_bin
,
"bB"
)
transition
(
start_neg_hex
,
"xX"
)
transition
(
start_neg_hex
,
"xX"
)
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
0.
},
true
),
transition_static_if
(
enable_float
||
enable_range
,
neg_dot
,
'.'
)
done
,
'.'
,
g
.
disable
())
epsilon
(
neg_oct
)
epsilon
(
neg_oct
)
}
}
// Binary integers.
// Binary integers.
...
@@ -131,19 +152,101 @@ void read_number(State& ps, Consumer& consumer) {
...
@@ -131,19 +152,101 @@ void read_number(State& ps, Consumer& consumer) {
term_state
(
pos_dec
)
{
term_state
(
pos_dec
)
{
transition
(
pos_dec
,
decimal_chars
,
add_ascii
<
10
>
(
result
,
ch
),
transition
(
pos_dec
,
decimal_chars
,
add_ascii
<
10
>
(
result
,
ch
),
pec
::
integer_overflow
)
pec
::
integer_overflow
)
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
result
}),
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
result
}),
done
,
"eE"
,
g
.
disable
())
done
,
"eE"
,
g
.
disable
())
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
result
}),
transition_static_if
(
enable_float
||
enable_range
,
pos_dot
,
'.'
)
done
,
'.'
,
g
.
disable
())
}
}
// Reads the integer part of the mantissa or a negative decimal integer.
// Reads the integer part of the mantissa or a negative decimal integer.
term_state
(
neg_dec
)
{
term_state
(
neg_dec
)
{
transition
(
neg_dec
,
decimal_chars
,
sub_ascii
<
10
>
(
result
,
ch
),
transition
(
neg_dec
,
decimal_chars
,
sub_ascii
<
10
>
(
result
,
ch
),
pec
::
integer_underflow
)
pec
::
integer_underflow
)
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
result
},
true
),
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
result
},
true
),
done
,
"eE"
,
g
.
disable
())
done
,
"eE"
,
g
.
disable
())
fsm_epsilon
(
read_floating_point
(
ps
,
consumer
,
optional
<
double
>
{
result
},
true
),
transition_static_if
(
enable_float
||
enable_range
,
neg_dot
,
'.'
)
}
unstable_state
(
pos_dot
)
{
fsm_transition_static_if
(
enable_range
,
read_number_range
(
ps
,
consumer
,
result
),
done
,
'.'
,
g
.
disable
())
done
,
'.'
,
g
.
disable
())
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
result
}),
done
,
any_char
,
g
.
disable
())
epsilon
(
done
)
}
unstable_state
(
neg_dot
)
{
fsm_transition_static_if
(
enable_range
,
read_number_range
(
ps
,
consumer
,
result
),
done
,
'.'
,
g
.
disable
())
fsm_epsilon_static_if
(
enable_float
,
read_floating_point
(
ps
,
consumer
,
odbl
{
result
},
true
),
done
,
any_char
,
g
.
disable
())
epsilon
(
done
)
}
term_state
(
done
)
{
// nop
}
fin
();
// clang-format on
}
template
<
class
State
,
class
Consumer
>
void
read_number_range
(
State
&
ps
,
Consumer
&
consumer
,
int64_t
begin
)
{
optional
<
int64_t
>
end
;
optional
<
int64_t
>
step
;
auto
end_consumer
=
make_consumer
(
end
);
auto
step_consumer
=
make_consumer
(
step
);
auto
generate_2
=
[
&
](
int64_t
n
,
int64_t
m
)
{
if
(
n
<=
m
)
while
(
n
<=
m
)
consumer
.
value
(
n
++
);
else
while
(
n
>=
m
)
consumer
.
value
(
n
--
);
};
auto
generate_3
=
[
&
](
int64_t
n
,
int64_t
m
,
int64_t
s
)
{
if
(
n
==
m
)
{
consumer
.
value
(
n
);
return
;
}
if
(
s
==
0
||
(
n
>
m
&&
s
>
0
)
||
(
n
<
m
&&
s
<
0
))
{
ps
.
code
=
pec
::
invalid_range_expression
;
return
;
}
if
(
n
<=
m
)
for
(
auto
i
=
n
;
i
<=
m
;
i
+=
s
)
consumer
.
value
(
i
);
else
for
(
auto
i
=
n
;
i
>=
m
;
i
+=
s
)
consumer
.
value
(
i
);
};
auto
g
=
caf
::
detail
::
make_scope_guard
([
&
]
{
if
(
ps
.
code
<=
pec
::
trailing_character
)
{
if
(
!
end
)
{
ps
.
code
=
pec
::
invalid_range_expression
;
}
else
if
(
!
step
)
{
generate_2
(
begin
,
*
end
);
}
else
{
generate_3
(
begin
,
*
end
,
*
step
);
}
}
});
static
constexpr
std
::
false_type
no_float
=
std
::
false_type
{};
// clang-format off
// Definition of our parser FSM.
start
();
state
(
init
)
{
fsm_epsilon
(
read_number
(
ps
,
end_consumer
,
no_float
),
after_end_num
)
}
term_state
(
after_end_num
)
{
transition
(
first_dot
,
'.'
)
}
state
(
first_dot
)
{
transition
(
second_dot
,
'.'
)
}
state
(
second_dot
)
{
fsm_epsilon
(
read_number
(
ps
,
step_consumer
,
no_float
),
done
)
}
}
term_state
(
done
)
{
term_state
(
done
)
{
// nop
// nop
...
...
libcaf_core/caf/pec.hpp
View file @
bda7b361
...
@@ -72,7 +72,9 @@ enum class pec : uint8_t {
...
@@ -72,7 +72,9 @@ enum class pec : uint8_t {
repeated_field_name
,
repeated_field_name
,
/// Stopped while reading a user-defined type with one or more missing
/// Stopped while reading a user-defined type with one or more missing
/// mandatory fields.
/// mandatory fields.
missing_field
,
missing_field
=
20
,
/// Parsing a range statement ('n..m' or 'n..m..step') failed.
invalid_range_expression
,
};
};
/// @relates pec
/// @relates pec
...
...
libcaf_core/test/detail/parser/read_number.cpp
View file @
bda7b361
...
@@ -36,16 +36,26 @@ using namespace caf;
...
@@ -36,16 +36,26 @@ using namespace caf;
namespace
{
namespace
{
struct
number
s_parser
_consumer
{
struct
number_consumer
{
variant
<
int64_t
,
double
>
x
;
variant
<
int64_t
,
double
>
x
;
inline
void
value
(
double
y
)
{
void
value
(
double
y
)
{
x
=
y
;
x
=
y
;
}
}
inline
void
value
(
int64_t
y
)
{
void
value
(
int64_t
y
)
{
x
=
y
;
x
=
y
;
}
}
};
};
struct
range_consumer
{
std
::
vector
<
int64_t
>
xs
;
void
value
(
double
)
{
CAF_FAIL
(
"range consumer called with a double"
);
}
void
value
(
int64_t
y
)
{
xs
.
emplace_back
(
y
);
}
};
struct
res_t
{
struct
res_t
{
variant
<
pec
,
double
,
int64_t
>
val
;
variant
<
pec
,
double
,
int64_t
>
val
;
template
<
class
T
>
template
<
class
T
>
...
@@ -54,6 +64,10 @@ struct res_t {
...
@@ -54,6 +64,10 @@ struct res_t {
}
}
};
};
std
::
string
to_string
(
const
res_t
&
x
)
{
return
caf
::
visit
([](
auto
&
y
)
{
return
deep_to_string
(
y
);
},
x
.
val
);
}
bool
operator
==
(
const
res_t
&
x
,
const
res_t
&
y
)
{
bool
operator
==
(
const
res_t
&
x
,
const
res_t
&
y
)
{
if
(
x
.
val
.
index
()
!=
y
.
val
.
index
())
if
(
x
.
val
.
index
()
!=
y
.
val
.
index
())
return
false
;
return
false
;
...
@@ -70,7 +84,7 @@ bool operator==(const res_t& x, const res_t& y) {
...
@@ -70,7 +84,7 @@ bool operator==(const res_t& x, const res_t& y) {
struct
numbers_parser
{
struct
numbers_parser
{
res_t
operator
()(
string_view
str
)
{
res_t
operator
()(
string_view
str
)
{
number
s_parser
_consumer
f
;
number_consumer
f
;
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_number
(
res
,
f
);
detail
::
parser
::
read_number
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
if
(
res
.
code
==
pec
::
success
)
...
@@ -79,6 +93,17 @@ struct numbers_parser {
...
@@ -79,6 +93,17 @@ struct numbers_parser {
}
}
};
};
struct
range_parser
{
expected
<
std
::
vector
<
int64_t
>>
operator
()(
string_view
str
)
{
range_consumer
f
;
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_number
(
res
,
f
,
std
::
true_type
{},
std
::
true_type
{});
if
(
res
.
code
==
pec
::
success
)
return
std
::
move
(
f
.
xs
);
return
make_error
(
res
);
}
};
template
<
class
T
>
template
<
class
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
res_t
>::
type
res
(
T
x
)
{
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
res_t
>::
type
res
(
T
x
)
{
return
{
static_cast
<
int64_t
>
(
x
)};
return
{
static_cast
<
int64_t
>
(
x
)};
...
@@ -92,6 +117,7 @@ res(T x) {
...
@@ -92,6 +117,7 @@ res(T x) {
struct
fixture
{
struct
fixture
{
numbers_parser
p
;
numbers_parser
p
;
range_parser
r
;
};
};
}
// namespace
}
// namespace
...
@@ -205,12 +231,18 @@ CAF_TEST(floating point numbers) {
...
@@ -205,12 +231,18 @@ CAF_TEST(floating point numbers) {
CHECK_NUMBER
(
0.0
);
CHECK_NUMBER
(
0.0
);
CHECK_NUMBER
(
.0
);
CHECK_NUMBER
(
.0
);
CHECK_NUMBER
(
0.
);
CHECK_NUMBER
(
0.
);
CHECK_NUMBER
(
1.1
);
CHECK_NUMBER
(
.1
);
CHECK_NUMBER
(
1.
);
CHECK_NUMBER
(
0.123
);
CHECK_NUMBER
(
0.123
);
CHECK_NUMBER
(
.123
);
CHECK_NUMBER
(
.123
);
CHECK_NUMBER
(
123.456
);
CHECK_NUMBER
(
123.456
);
CHECK_NUMBER
(
-
0.0
);
CHECK_NUMBER
(
-
0.0
);
CHECK_NUMBER
(
-
.0
);
CHECK_NUMBER
(
-
.0
);
CHECK_NUMBER
(
-
0.
);
CHECK_NUMBER
(
-
0.
);
CHECK_NUMBER
(
-
1.1
);
CHECK_NUMBER
(
-
.1
);
CHECK_NUMBER
(
-
1.
);
CHECK_NUMBER
(
-
0.123
);
CHECK_NUMBER
(
-
0.123
);
CHECK_NUMBER
(
-
.123
);
CHECK_NUMBER
(
-
.123
);
CHECK_NUMBER
(
-
123.456
);
CHECK_NUMBER
(
-
123.456
);
...
@@ -269,4 +301,44 @@ CAF_TEST(fractional mantissa with negative exponent) {
...
@@ -269,4 +301,44 @@ CAF_TEST(fractional mantissa with negative exponent) {
CHECK_NUMBER
(
-
42.0001e-5
);
CHECK_NUMBER
(
-
42.0001e-5
);
}
}
#define CHECK_RANGE(expr, ...) \
CAF_CHECK_EQUAL(r(expr), std::vector<int64_t>({__VA_ARGS__}))
CAF_TEST
(
a
range
from
n
to
n
is
just
n
)
{
CHECK_RANGE
(
"0..0"
,
0
);
CHECK_RANGE
(
"1..1"
,
1
);
CHECK_RANGE
(
"2..2"
,
2
);
CHECK_RANGE
(
"101..101"
,
101
);
CHECK_RANGE
(
"101..101..1"
,
101
);
CHECK_RANGE
(
"101..101..2"
,
101
);
CHECK_RANGE
(
"101..101..-1"
,
101
);
CHECK_RANGE
(
"101..101..-2"
,
101
);
}
CAF_TEST
(
ranges
are
either
ascending
or
descending
)
{
CHECK_RANGE
(
"0..1"
,
0
,
1
);
CHECK_RANGE
(
"0..2"
,
0
,
1
,
2
);
CHECK_RANGE
(
"0..3"
,
0
,
1
,
2
,
3
);
CHECK_RANGE
(
"3..0"
,
3
,
2
,
1
,
0
);
CHECK_RANGE
(
"3..1"
,
3
,
2
,
1
);
CHECK_RANGE
(
"3..2"
,
3
,
2
);
}
CAF_TEST
(
ranges
can
use
positive
step
values
)
{
CHECK_RANGE
(
"2..6..2"
,
2
,
4
,
6
);
CHECK_RANGE
(
"3..8..3"
,
3
,
6
);
}
CAF_TEST
(
ranges
can
use
negative
step
values
)
{
CHECK_RANGE
(
"6..2..-2"
,
6
,
4
,
2
);
CHECK_RANGE
(
"8..3..-3"
,
8
,
5
);
}
CAF_TEST
(
ranges
can
use
signed
integers
)
{
CHECK_RANGE
(
"+2..+6..+2"
,
2
,
4
,
6
);
CHECK_RANGE
(
"+6..+2..-2"
,
6
,
4
,
2
);
CHECK_RANGE
(
"+2..-2..-2"
,
2
,
0
,
-
2
);
CHECK_RANGE
(
"-2..+2..+2"
,
-
2
,
0
,
2
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
CAF_TEST_FIXTURE_SCOPE_END
()
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