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
350b1941
Commit
350b1941
authored
May 13, 2018
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement an FSM-based one-pass number parser
parent
ea4fb677
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
959 additions
and
0 deletions
+959
-0
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+1
-0
libcaf_core/caf/detail/parser/add_ascii.hpp
libcaf_core/caf/detail/parser/add_ascii.hpp
+42
-0
libcaf_core/caf/detail/parser/ascii_to_int.hpp
libcaf_core/caf/detail/parser/ascii_to_int.hpp
+47
-0
libcaf_core/caf/detail/parser/ec.hpp
libcaf_core/caf/detail/parser/ec.hpp
+60
-0
libcaf_core/caf/detail/parser/fsm.hpp
libcaf_core/caf/detail/parser/fsm.hpp
+85
-0
libcaf_core/caf/detail/parser/is_char.hpp
libcaf_core/caf/detail/parser/is_char.hpp
+42
-0
libcaf_core/caf/detail/parser/is_digit.hpp
libcaf_core/caf/detail/parser/is_digit.hpp
+54
-0
libcaf_core/caf/detail/parser/read_number.hpp
libcaf_core/caf/detail/parser/read_number.hpp
+247
-0
libcaf_core/caf/detail/parser/state.hpp
libcaf_core/caf/detail/parser/state.hpp
+62
-0
libcaf_core/caf/detail/parser/sub_ascii.hpp
libcaf_core/caf/detail/parser/sub_ascii.hpp
+43
-0
libcaf_core/src/ec.cpp
libcaf_core/src/ec.cpp
+51
-0
libcaf_core/test/read_number.cpp
libcaf_core/test/read_number.cpp
+225
-0
No files found.
libcaf_core/CMakeLists.txt
View file @
350b1941
...
...
@@ -46,6 +46,7 @@ set(LIBCAF_CORE_SRCS
src/downstream_messages.cpp
src/duration.cpp
src/dynamic_message_data.cpp
src/ec.cpp
src/error.cpp
src/event_based_actor.cpp
src/execution_unit.cpp
...
...
libcaf_core/caf/detail/parser/add_ascii.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/detail/parser/ascii_to_int.hpp"
namespace
caf
{
namespace
detail
{
namespace
parser
{
// Sum up integers when parsing positive integers.
// @returns `false` on an overflow, otherwise `true`.
// @pre `isdigit(c) || (Base == 16 && isxdigit(c))`
template
<
int
Base
,
class
T
>
bool
add_ascii
(
T
&
x
,
char
c
)
{
ascii_to_int
<
Base
,
T
>
f
;
auto
before
=
x
;
x
=
(
x
*
Base
)
+
f
(
c
);
return
before
<=
x
;
}
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/parser/ascii_to_int.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
namespace
caf
{
namespace
detail
{
namespace
parser
{
template
<
int
Base
,
class
T
>
struct
ascii_to_int
{
// @pre `c` is a valid ASCII digit, i.e., matches [0-9].
constexpr
T
operator
()(
char
c
)
const
{
return
c
-
'0'
;
}
};
template
<
class
T
>
struct
ascii_to_int
<
16
,
T
>
{
// @pre `c` is a valid ASCII hex digit, i.e., matches [0-9A-Fa-f].
constexpr
T
operator
()(
char
c
)
const
{
// Numbers start at position 48 in the ASCII table.
// Uppercase characters start at position 65 in the ASCII table.
// Lowercase characters start at position 97 in the ASCII table.
return
c
<=
'9'
?
c
-
'0'
:
(
c
<=
'F'
?
10
+
(
c
-
'A'
)
:
10
+
(
c
-
'a'
));
}
};
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/parser/ec.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
namespace
caf
{
namespace
detail
{
namespace
parser
{
enum
class
ec
:
uint8_t
{
/// Not-an-error.
success
,
/// Parser succeeded but found trailing character(s).
trailing_character
,
/// Parser stopped after reaching the end while still expecting input.
unexpected_eof
,
/// Parser stopped after reading an unexpected character.
unexpected_character
,
/// Cannot construct a negative caf::duration.
negative_duration
,
/// Cannot construct a caf::duration with a value exceeding uint32_t.
duration_overflow
,
/// Too many characters for an atom.
too_many_characters
,
/// Unrecognized character after escaping `\`.
illegal_escape_sequence
,
/// Misplaced newline, e.g., inside a string.
unexpected_newline
,
/// Parsed positive integer exceeds the number of available bits.
integer_overflow
,
/// Parsed negative integer exceeds the number of available bits.
integer_underflow
,
/// Exponent of parsed double is less than the minimum supported exponent.
exponent_underflow
,
/// Exponent of parsed double is greater than the maximum supported exponent.
exponent_overflow
,
};
const
char
*
to_string
(
ec
x
);
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/parser/fsm.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#define start() \
char ch = ps.current(); \
goto s_init; \
s_unexpected_eof: \
ps.code = ec::unexpected_eof; \
return; \
{ \
static constexpr ec mismatch_ec = ec::unexpected_character
#define state(name) \
ps.code = mismatch_ec; \
return; \
} \
{ \
static constexpr ec mismatch_ec = ec::unexpected_character; \
s_##name : __attribute__((unused)); \
if (ch == '\0') \
goto s_unexpected_eof; \
e_##name : __attribute__((unused));
#define term_state(name) \
ps.code = mismatch_ec; \
return; \
} \
{ \
static constexpr ec mismatch_ec = ec::trailing_character; \
s_##name : __attribute__((unused)); \
if (ch == '\0') \
goto s_fin; \
e_##name : __attribute__((unused));
#define fin() \
ps.code = mismatch_ec; \
return; \
} \
s_fin: \
ps.code = ec::success; \
return;
#define input(predicate, target) \
if (predicate(ch)) { \
ch = ps.next(); \
goto s_##target; \
}
#define action(predicate, target, statement) \
if (predicate(ch)) { \
statement; \
ch = ps.next(); \
goto s_##target; \
}
#define checked_action(predicate, target, statement, error_code) \
if (predicate(ch)) { \
if (statement) { \
ch = ps.next(); \
goto s_##target; \
} else { \
ps.code = error_code; \
return; \
} \
}
#define epsilon(target) goto e_##target;
libcaf_core/caf/detail/parser/is_char.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
namespace
caf
{
namespace
detail
{
namespace
parser
{
/// Returns whether `c` equals `C`.
template
<
char
C
>
bool
is_char
(
char
c
)
{
return
c
==
C
;
}
/// Returns whether `c` equals `C` (case insensitive).
template
<
char
C
>
bool
is_ichar
(
char
c
)
{
static_assert
(
C
>=
'a'
&&
C
<=
'z'
,
"Expected a-z (lowercase)."
);
return
c
==
C
||
c
==
(
C
-
32
);
}
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/parser/is_digit.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
namespace
caf
{
namespace
detail
{
namespace
parser
{
/// Returns whether `c` is a valid digit for a given base.
template
<
int
Base
>
bool
is_digit
(
char
c
);
template
<
>
bool
is_digit
<
2
>
(
char
c
)
{
return
c
==
'0'
||
c
==
'1'
;
}
template
<
>
bool
is_digit
<
8
>
(
char
c
)
{
return
c
>=
'0'
&&
c
<=
'7'
;
}
template
<
>
bool
is_digit
<
10
>
(
char
c
)
{
return
c
>=
'0'
&&
c
<=
'9'
;
}
template
<
>
bool
is_digit
<
16
>
(
char
c
)
{
return
(
c
>=
'0'
&&
c
<=
'9'
)
||
(
c
>=
'A'
&&
c
<=
'F'
)
||
(
c
>=
'a'
&&
c
<=
'f'
);
}
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/parser/read_number.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include "caf/detail/scope_guard.hpp"
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/ec.hpp"
#include "caf/detail/parser/fsm.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
namespace
caf
{
namespace
detail
{
namespace
parser
{
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_number
(
state
<
Iterator
,
Sentinel
>&
ps
,
Consumer
&
consumer
)
{
// Any exponent larger than 511 always overflows.
static
constexpr
int
max_double_exponent
=
511
;
// We assume a simple integer until proven wrong.
enum
result_type_t
{
integer
,
positive_double
,
negative_double
};
auto
result_type
=
integer
;
// Adjusts our mantissa, e.g., 1.23 becomes 123 with a dec_exp of -2.
auto
dec_exp
=
0
;
// Exponent part of a floating point literal.
auto
exp
=
0
;
// Our result when reading a floating point number.
auto
dbl_res
=
0.
;
// Our result when reading an integer number.
int64_t
int_res
=
0
;
// Computes the result on success.
auto
g
=
caf
::
detail
::
make_scope_guard
([
&
]
{
if
(
ps
.
code
<=
ec
::
trailing_character
)
{
if
(
result_type
==
integer
)
{
consumer
.
value
(
int_res
);
return
;
}
// Compute final floating point number.
// 1) Fix the exponent.
exp
+=
dec_exp
;
// 2) Check whether exponent is in valid range.
if
(
exp
<
-
max_double_exponent
)
{
ps
.
code
=
ec
::
exponent_underflow
;
return
;
}
if
(
exp
>
max_double_exponent
)
{
ps
.
code
=
ec
::
exponent_overflow
;
return
;
}
// 3) Scale result.
// Pre-computed powers of 10 for the scaling loop.
static
double
powerTable
[]
=
{
1e1
,
1e2
,
1e4
,
1e8
,
1e16
,
1e32
,
1e64
,
1e128
,
1e256
};
auto
i
=
0
;
if
(
exp
<
0
)
{
for
(
auto
n
=
-
exp
;
n
!=
0
;
n
>>=
1
,
++
i
)
if
(
n
&
0x01
)
dbl_res
/=
powerTable
[
i
];
}
else
{
for
(
auto
n
=
exp
;
n
!=
0
;
n
>>=
1
,
++
i
)
if
(
n
&
0x01
)
dbl_res
*=
powerTable
[
i
];
}
// 4) Fix sign and call consumer.
consumer
.
value
(
result_type
==
positive_double
?
dbl_res
:
-
dbl_res
);
}
});
// Switches from parsing an integer to parsing a double.
auto
ch_res
=
[
&
](
result_type_t
x
)
{
CAF_ASSERT
(
result_type
=
integer
);
result_type
=
x
;
// We parse doubles as positive number and restore the sign in `g`.
dbl_res
=
result_type
==
negative_double
?
-
static_cast
<
double
>
(
int_res
)
:
static_cast
<
double
>
(
int_res
);
};
// Reads the a decimal place.
auto
rd_decimal
=
[
&
](
char
c
)
{
--
dec_exp
;
return
add_ascii
<
10
>
(
dbl_res
,
c
);
};
// Definition of our parser FSM.
start
();
state
(
init
)
{
input
(
is_char
<
' '
>
,
init
)
input
(
is_char
<
'\t'
>
,
init
)
input
(
is_char
<
'+'
>
,
has_plus
)
input
(
is_char
<
'-'
>
,
has_minus
)
input
(
is_char
<
'0'
>
,
pos_zero
)
epsilon
(
has_plus
)
}
// "+" or "-" alone aren't numbers.
state
(
has_plus
)
{
action
(
is_char
<
'.'
>
,
leading_dot
,
ch_res
(
positive_double
))
input
(
is_char
<
'0'
>
,
pos_zero
)
epsilon
(
pos_dec
)
}
state
(
has_minus
)
{
action
(
is_char
<
'.'
>
,
leading_dot
,
ch_res
(
negative_double
))
input
(
is_char
<
'0'
>
,
neg_zero
)
epsilon
(
neg_dec
)
}
// Disambiguate base.
term_state
(
pos_zero
)
{
input
(
is_ichar
<
'b'
>
,
start_pos_bin
)
input
(
is_ichar
<
'x'
>
,
start_pos_hex
)
action
(
is_char
<
'.'
>
,
trailing_dot
,
ch_res
(
positive_double
))
epsilon
(
pos_oct
)
}
term_state
(
neg_zero
)
{
input
(
is_ichar
<
'b'
>
,
start_neg_bin
)
input
(
is_ichar
<
'x'
>
,
start_neg_hex
)
action
(
is_char
<
'.'
>
,
trailing_dot
,
ch_res
(
negative_double
))
epsilon
(
neg_oct
)
}
// Binary integers.
state
(
start_pos_bin
)
{
epsilon
(
pos_bin
)
}
term_state
(
pos_bin
)
{
checked_action
(
is_digit
<
2
>
,
pos_bin
,
add_ascii
<
2
>
(
int_res
,
ch
),
ec
::
integer_overflow
)
}
state
(
start_neg_bin
)
{
epsilon
(
neg_bin
)
}
term_state
(
neg_bin
)
{
checked_action
(
is_digit
<
2
>
,
neg_bin
,
sub_ascii
<
2
>
(
int_res
,
ch
),
ec
::
integer_underflow
)
}
// Octal integers.
state
(
start_pos_oct
)
{
epsilon
(
pos_oct
)
}
term_state
(
pos_oct
)
{
checked_action
(
is_digit
<
8
>
,
pos_oct
,
add_ascii
<
8
>
(
int_res
,
ch
),
ec
::
integer_overflow
)
}
state
(
start_neg_oct
)
{
epsilon
(
neg_oct
)
}
term_state
(
neg_oct
)
{
checked_action
(
is_digit
<
8
>
,
neg_oct
,
sub_ascii
<
8
>
(
int_res
,
ch
),
ec
::
integer_underflow
)
}
// Hexal integers.
state
(
start_pos_hex
)
{
epsilon
(
pos_hex
)
}
term_state
(
pos_hex
)
{
checked_action
(
is_digit
<
16
>
,
pos_hex
,
add_ascii
<
16
>
(
int_res
,
ch
),
ec
::
integer_overflow
)
}
state
(
start_neg_hex
)
{
epsilon
(
neg_hex
)
}
term_state
(
neg_hex
)
{
checked_action
(
is_digit
<
16
>
,
neg_hex
,
sub_ascii
<
16
>
(
int_res
,
ch
),
ec
::
integer_underflow
)
}
// Reads the integer part of the mantissa or a positive decimal integer.
term_state
(
pos_dec
)
{
checked_action
(
is_digit
<
10
>
,
pos_dec
,
add_ascii
<
10
>
(
int_res
,
ch
),
ec
::
integer_overflow
)
action
(
is_ichar
<
'e'
>
,
has_e
,
ch_res
(
positive_double
))
action
(
is_char
<
'.'
>
,
trailing_dot
,
ch_res
(
positive_double
))
}
// Reads the integer part of the mantissa or a negative decimal integer.
term_state
(
neg_dec
)
{
checked_action
(
is_digit
<
10
>
,
neg_dec
,
sub_ascii
<
10
>
(
int_res
,
ch
),
ec
::
integer_underflow
)
action
(
is_ichar
<
'e'
>
,
has_e
,
ch_res
(
negative_double
))
action
(
is_char
<
'.'
>
,
trailing_dot
,
ch_res
(
negative_double
))
}
// ".", "+.", etc. aren't valid numbers, so this state isn't terminal.
state
(
leading_dot
)
{
checked_action
(
is_digit
<
10
>
,
after_dot
,
rd_decimal
(
ch
),
ec
::
exponent_underflow
)
}
// "1." is a valid number, so a trailing dot is a terminal state.
term_state
(
trailing_dot
)
{
checked_action
(
is_digit
<
10
>
,
after_dot
,
rd_decimal
(
ch
),
ec
::
exponent_underflow
)
input
(
is_ichar
<
'e'
>
,
has_e
)
}
// Read the decimal part of a mantissa.
term_state
(
after_dot
)
{
checked_action
(
is_digit
<
10
>
,
after_dot
,
rd_decimal
(
ch
),
ec
::
exponent_underflow
)
input
(
is_ichar
<
'e'
>
,
has_e
)
}
// "...e", "...e+", and "...e-" aren't valid numbers, so these states are not
// terminal.
state
(
has_e
)
{
input
(
is_char
<
'+'
>
,
has_plus_after_e
)
input
(
is_char
<
'-'
>
,
has_minus_after_e
)
checked_action
(
is_digit
<
10
>
,
pos_exp
,
add_ascii
<
10
>
(
exp
,
ch
),
ec
::
exponent_overflow
)
}
state
(
has_plus_after_e
)
{
checked_action
(
is_digit
<
10
>
,
pos_exp
,
add_ascii
<
10
>
(
exp
,
ch
),
ec
::
exponent_overflow
)
}
state
(
has_minus_after_e
)
{
checked_action
(
is_digit
<
10
>
,
neg_exp
,
sub_ascii
<
10
>
(
exp
,
ch
),
ec
::
exponent_underflow
)
}
// Read a positive exponent.
term_state
(
pos_exp
)
{
checked_action
(
is_digit
<
10
>
,
pos_exp
,
add_ascii
<
10
>
(
exp
,
ch
),
ec
::
exponent_overflow
)
}
// Read a negative exponent.
term_state
(
neg_exp
)
{
checked_action
(
is_digit
<
10
>
,
neg_exp
,
sub_ascii
<
10
>
(
exp
,
ch
),
ec
::
exponent_underflow
)
}
fin
();
}
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/parser/state.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include "caf/detail/parser/ec.hpp"
namespace
caf
{
namespace
detail
{
namespace
parser
{
template
<
class
Iterator
,
class
Sentinel
=
Iterator
>
struct
state
{
Iterator
i
;
Sentinel
e
;
ec
code
;
int32_t
line
=
1
;
int32_t
column
=
1
;
/// Returns the null terminator when reaching the end of the string,
/// otherwise the next character.
char
next
()
noexcept
{
++
i
;
if
(
i
!=
e
)
{
auto
c
=
*
i
;
if
(
c
==
'\n'
)
{
++
line
;
column
=
1
;
}
else
{
++
column
;
}
return
c
;
}
return
'\0'
;
}
/// Returns the null terminator if `i == e`, otherwise the current character.
char
current
()
const
noexcept
{
return
i
!=
e
?
*
i
:
'\0'
;
}
};
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/parser/sub_ascii.hpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/detail/parser/ascii_to_int.hpp"
namespace
caf
{
namespace
detail
{
namespace
parser
{
// Subtracs integers when parsing negative integers.
// @returns `false` on an underflow, otherwise `true`.
// @pre `isdigit(c) || (Base == 16 && isxdigit(c))`
template
<
int
Base
,
class
T
>
bool
sub_ascii
(
T
&
x
,
char
c
)
{
ascii_to_int
<
Base
,
T
>
f
;
auto
before
=
x
;
x
=
(
x
*
Base
)
-
f
(
c
);
return
before
>=
x
;
}
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/src/ec.cpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/parser/ec.hpp"
namespace
{
constexpr
const
char
*
tbl
[]
=
{
"success"
,
"trailing_character"
,
"unexpected_eof"
,
"unexpected_character"
,
"negative_duration"
,
"duration_overflow"
,
"too_many_characters"
,
"illegal_escape_sequence"
,
"unexpected_newline"
,
"integer_overflow"
,
"integer_underflow"
,
"exponent_underflow"
,
"exponent_overflow"
,
};
}
// namespace <anonymous>
namespace
caf
{
namespace
detail
{
namespace
parser
{
const
char
*
to_string
(
ec
x
)
{
return
tbl
[
static_cast
<
uint8_t
>
(
x
)];
}
}
// namespace parser
}
// namespace detail
}
// namespace caf
libcaf_core/test/read_number.cpp
0 → 100644
View file @
350b1941
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE read_number
#include <string>
#include "caf/test/unit_test.hpp"
#include "caf/variant.hpp"
#include "caf/detail/parser/read_number.hpp"
using
namespace
caf
;
using
detail
::
parser
::
ec
;
namespace
{
struct
numbers_parser_consumer
{
variant
<
int64_t
,
double
>
x
;
inline
void
value
(
double
y
)
{
x
=
y
;
}
inline
void
value
(
int64_t
y
)
{
x
=
y
;
}
};
struct
res_t
{
variant
<
ec
,
double
,
int64_t
>
val
;
template
<
class
T
>
res_t
(
T
&&
x
)
:
val
(
std
::
forward
<
T
>
(
x
))
{
// nop
}
};
bool
operator
==
(
const
res_t
&
x
,
const
res_t
&
y
)
{
if
(
x
.
val
.
index
()
!=
y
.
val
.
index
())
return
false
;
// Implements a safe equal comparison for double.
caf
::
test
::
equal_to
f
;
using
caf
::
get
;
using
caf
::
holds_alternative
;
if
(
holds_alternative
<
ec
>
(
x
.
val
))
return
f
(
get
<
ec
>
(
x
.
val
),
get
<
ec
>
(
y
.
val
));
if
(
holds_alternative
<
double
>
(
x
.
val
))
return
f
(
get
<
double
>
(
x
.
val
),
get
<
double
>
(
y
.
val
));
return
f
(
get
<
int64_t
>
(
x
.
val
),
get
<
int64_t
>
(
y
.
val
));
}
struct
numbers_parser
{
res_t
operator
()(
std
::
string
str
)
{
detail
::
parser
::
state
<
std
::
string
::
iterator
>
res
;
numbers_parser_consumer
f
;
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
detail
::
parser
::
read_number
(
res
,
f
);
if
(
res
.
code
==
ec
::
success
)
return
f
.
x
;
return
res
.
code
;
}
};
template
<
class
T
>
typename
std
::
enable_if
<
std
::
is_integral
<
T
>::
value
,
res_t
>::
type
res
(
T
x
)
{
return
{
static_cast
<
int64_t
>
(
x
)};
}
template
<
class
T
>
typename
std
::
enable_if
<
std
::
is_floating_point
<
T
>::
value
,
res_t
>::
type
res
(
T
x
)
{
return
{
static_cast
<
double
>
(
x
)};
}
struct
fixture
{
numbers_parser
p
;
};
}
// namespace <anonymous>
#define CHECK_NUMBER(x) CAF_CHECK_EQUAL(p(#x), res(x))
CAF_TEST_FIXTURE_SCOPE
(
read_number_tests
,
fixture
)
CAF_TEST
(
binary
numbers
)
{
/* TODO: use this implementation when switching to C++14
CHECK_NUMBER(0b0);
CHECK_NUMBER(0b10);
CHECK_NUMBER(0b101);
CHECK_NUMBER(0B1001);
CHECK_NUMBER(-0b0);
CHECK_NUMBER(-0b101);
CHECK_NUMBER(-0B1001);
*/
CAF_CHECK_EQUAL
(
p
(
"0b0"
),
res
(
0
));
CAF_CHECK_EQUAL
(
p
(
"0b10"
),
res
(
2
));
CAF_CHECK_EQUAL
(
p
(
"0b101"
),
res
(
5
));
CAF_CHECK_EQUAL
(
p
(
"0B1001"
),
res
(
9
));
CAF_CHECK_EQUAL
(
p
(
"-0b0"
),
res
(
0
));
CAF_CHECK_EQUAL
(
p
(
"-0b101"
),
res
(
-
5
));
CAF_CHECK_EQUAL
(
p
(
"-0B1001"
),
res
(
-
9
));
}
CAF_TEST
(
octal
numbers
)
{
// valid numbers
CHECK_NUMBER
(
00
);
CHECK_NUMBER
(
010
);
CHECK_NUMBER
(
0123
);
CHECK_NUMBER
(
0777
);
CHECK_NUMBER
(
-
00
);
CHECK_NUMBER
(
-
0123
);
// invalid numbers
CAF_CHECK_EQUAL
(
p
(
"018"
),
ec
::
trailing_character
);
}
CAF_TEST
(
decimal
numbers
)
{
CHECK_NUMBER
(
0
);
CHECK_NUMBER
(
10
);
CHECK_NUMBER
(
123
);
CHECK_NUMBER
(
-
0
);
CHECK_NUMBER
(
-
123
);
}
CAF_TEST
(
hexadecimal
numbers
)
{
// valid numbers
CHECK_NUMBER
(
0x0
);
CHECK_NUMBER
(
0x10
);
CHECK_NUMBER
(
0X123
);
CHECK_NUMBER
(
0xAF01
);
CHECK_NUMBER
(
-
0x0
);
CHECK_NUMBER
(
-
0x123
);
CHECK_NUMBER
(
-
0xaf01
);
// invalid numbers
CAF_CHECK_EQUAL
(
p
(
"0xFG"
),
ec
::
trailing_character
);
CAF_CHECK_EQUAL
(
p
(
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
),
ec
::
integer_overflow
);
CAF_CHECK_EQUAL
(
p
(
"-0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
),
ec
::
integer_underflow
);
}
CAF_TEST
(
floating
point
numbers
)
{
CHECK_NUMBER
(
0.0
);
CHECK_NUMBER
(
.0
);
CHECK_NUMBER
(
0.
);
CHECK_NUMBER
(
0.123
);
CHECK_NUMBER
(
.123
);
CHECK_NUMBER
(
123.456
);
CHECK_NUMBER
(
-
0.0
);
CHECK_NUMBER
(
-
.0
);
CHECK_NUMBER
(
-
0.
);
CHECK_NUMBER
(
-
0.123
);
CHECK_NUMBER
(
-
.123
);
CHECK_NUMBER
(
-
123.456
);
}
CAF_TEST
(
integer
mantissa
with
positive
exponent
)
{
CHECK_NUMBER
(
321E1
);
CHECK_NUMBER
(
321e1
);
CHECK_NUMBER
(
321e+1
);
CHECK_NUMBER
(
123e2
);
CHECK_NUMBER
(
-
4e2
);
CHECK_NUMBER
(
1e1
);
CHECK_NUMBER
(
1e2
);
CHECK_NUMBER
(
1e3
);
CHECK_NUMBER
(
1e4
);
CHECK_NUMBER
(
1e5
);
CHECK_NUMBER
(
1e6
);
}
CAF_TEST
(
integer
mantissa
with
negative
exponent
)
{
// valid numbers
CHECK_NUMBER
(
321E-1
);
CHECK_NUMBER
(
321e-1
);
CHECK_NUMBER
(
123e-2
);
CHECK_NUMBER
(
-
4e-2
);
CHECK_NUMBER
(
1e-1
);
CHECK_NUMBER
(
1e-2
);
CHECK_NUMBER
(
1e-3
);
CHECK_NUMBER
(
1e-4
);
CHECK_NUMBER
(
1e-5
);
CHECK_NUMBER
(
1e-6
);
// invalid numbers
CAF_CHECK_EQUAL
(
p
(
"-9.9999e-e511"
),
ec
::
unexpected_character
);
CAF_CHECK_EQUAL
(
p
(
"-9.9999e-511"
),
ec
::
exponent_underflow
);
}
CAF_TEST
(
fractional
mantissa
with
positive
exponent
)
{
CHECK_NUMBER
(
3.21E1
);
CHECK_NUMBER
(
3.21e+1
);
CHECK_NUMBER
(
3.21e+1
);
CHECK_NUMBER
(
12.3e2
);
CHECK_NUMBER
(
-
0.001e3
);
CHECK_NUMBER
(
0.0001e5
);
CHECK_NUMBER
(
-
42.001e3
);
CHECK_NUMBER
(
42.0001e5
);
}
CAF_TEST
(
fractional
mantissa
with
negative
exponent
)
{
CHECK_NUMBER
(
3.21E-1
);
CHECK_NUMBER
(
3.21e-1
);
CHECK_NUMBER
(
12.3e-2
);
CHECK_NUMBER
(
-
0.001e-3
);
CHECK_NUMBER
(
-
0.0001e-5
);
CHECK_NUMBER
(
-
42.001e-3
);
CHECK_NUMBER
(
-
42001e-6
);
CHECK_NUMBER
(
-
42.0001e-5
);
}
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