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
11c4eaca
Unverified
Commit
11c4eaca
authored
Oct 12, 2019
by
Dominik Charousset
Committed by
GitHub
Oct 12, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #929
Allow users to extend config_value API
parents
41df839f
25a601e1
Changes
50
Hide whitespace changes
Inline
Side-by-side
Showing
50 changed files
with
1336 additions
and
326 deletions
+1336
-326
libcaf_core/caf/all.hpp
libcaf_core/caf/all.hpp
+3
-0
libcaf_core/caf/config_value.hpp
libcaf_core/caf/config_value.hpp
+220
-85
libcaf_core/caf/config_value_field.hpp
libcaf_core/caf/config_value_field.hpp
+66
-0
libcaf_core/caf/config_value_object_access.hpp
libcaf_core/caf/config_value_object_access.hpp
+173
-0
libcaf_core/caf/detail/config_value_field_impl.hpp
libcaf_core/caf/detail/config_value_field_impl.hpp
+195
-0
libcaf_core/caf/detail/dispatch_parse_cli.hpp
libcaf_core/caf/detail/dispatch_parse_cli.hpp
+62
-0
libcaf_core/caf/detail/parse.hpp
libcaf_core/caf/detail/parse.hpp
+30
-30
libcaf_core/caf/detail/parser/read_atom.hpp
libcaf_core/caf/detail/parser/read_atom.hpp
+2
-4
libcaf_core/caf/detail/parser/read_bool.hpp
libcaf_core/caf/detail/parser/read_bool.hpp
+2
-3
libcaf_core/caf/detail/parser/read_floating_point.hpp
libcaf_core/caf/detail/parser/read_floating_point.hpp
+4
-5
libcaf_core/caf/detail/parser/read_ini.hpp
libcaf_core/caf/detail/parser/read_ini.hpp
+18
-18
libcaf_core/caf/detail/parser/read_ipv4_address.hpp
libcaf_core/caf/detail/parser/read_ipv4_address.hpp
+4
-5
libcaf_core/caf/detail/parser/read_ipv6_address.hpp
libcaf_core/caf/detail/parser/read_ipv6_address.hpp
+6
-7
libcaf_core/caf/detail/parser/read_number.hpp
libcaf_core/caf/detail/parser/read_number.hpp
+2
-3
libcaf_core/caf/detail/parser/read_number_or_timespan.hpp
libcaf_core/caf/detail/parser/read_number_or_timespan.hpp
+2
-4
libcaf_core/caf/detail/parser/read_signed_integer.hpp
libcaf_core/caf/detail/parser/read_signed_integer.hpp
+2
-3
libcaf_core/caf/detail/parser/read_string.hpp
libcaf_core/caf/detail/parser/read_string.hpp
+2
-3
libcaf_core/caf/detail/parser/read_timespan.hpp
libcaf_core/caf/detail/parser/read_timespan.hpp
+2
-3
libcaf_core/caf/detail/parser/read_unsigned_integer.hpp
libcaf_core/caf/detail/parser/read_unsigned_integer.hpp
+2
-3
libcaf_core/caf/detail/parser/read_uri.hpp
libcaf_core/caf/detail/parser/read_uri.hpp
+6
-7
libcaf_core/caf/detail/type_traits.hpp
libcaf_core/caf/detail/type_traits.hpp
+4
-0
libcaf_core/caf/fwd.hpp
libcaf_core/caf/fwd.hpp
+2
-0
libcaf_core/caf/make_config_option.hpp
libcaf_core/caf/make_config_option.hpp
+14
-11
libcaf_core/caf/make_config_value_field.hpp
libcaf_core/caf/make_config_value_field.hpp
+92
-0
libcaf_core/caf/parser_state.hpp
libcaf_core/caf/parser_state.hpp
+29
-10
libcaf_core/caf/pec.hpp
libcaf_core/caf/pec.hpp
+8
-1
libcaf_core/caf/span.hpp
libcaf_core/caf/span.hpp
+7
-0
libcaf_core/caf/uri.hpp
libcaf_core/caf/uri.hpp
+0
-1
libcaf_core/src/actor_system_config.cpp
libcaf_core/src/actor_system_config.cpp
+1
-2
libcaf_core/src/config_value.cpp
libcaf_core/src/config_value.cpp
+3
-3
libcaf_core/src/detail/parse.cpp
libcaf_core/src/detail/parse.cpp
+13
-13
libcaf_core/src/ipv4_address.cpp
libcaf_core/src/ipv4_address.cpp
+2
-1
libcaf_core/src/ipv6_address.cpp
libcaf_core/src/ipv6_address.cpp
+2
-1
libcaf_core/src/make_config_option.cpp
libcaf_core/src/make_config_option.cpp
+33
-40
libcaf_core/src/pec.cpp
libcaf_core/src/pec.cpp
+1
-1
libcaf_core/src/uri.cpp
libcaf_core/src/uri.cpp
+2
-3
libcaf_core/test/config_option.cpp
libcaf_core/test/config_option.cpp
+0
-1
libcaf_core/test/detail/ini_consumer.cpp
libcaf_core/test/detail/ini_consumer.cpp
+9
-14
libcaf_core/test/detail/parse.cpp
libcaf_core/test/detail/parse.cpp
+2
-2
libcaf_core/test/detail/parser/read_atom.cpp
libcaf_core/test/detail/parser/read_atom.cpp
+4
-4
libcaf_core/test/detail/parser/read_bool.cpp
libcaf_core/test/detail/parser/read_bool.cpp
+4
-4
libcaf_core/test/detail/parser/read_floating_point.cpp
libcaf_core/test/detail/parser/read_floating_point.cpp
+4
-3
libcaf_core/test/detail/parser/read_ini.cpp
libcaf_core/test/detail/parser/read_ini.cpp
+11
-8
libcaf_core/test/detail/parser/read_number.cpp
libcaf_core/test/detail/parser/read_number.cpp
+4
-4
libcaf_core/test/detail/parser/read_number_or_timespan.cpp
libcaf_core/test/detail/parser/read_number_or_timespan.cpp
+4
-4
libcaf_core/test/detail/parser/read_signed_integer.cpp
libcaf_core/test/detail/parser/read_signed_integer.cpp
+5
-4
libcaf_core/test/detail/parser/read_string.cpp
libcaf_core/test/detail/parser/read_string.cpp
+4
-4
libcaf_core/test/detail/parser/read_timespan.cpp
libcaf_core/test/detail/parser/read_timespan.cpp
+5
-1
libcaf_core/test/detail/parser/read_unsigned_integer.cpp
libcaf_core/test/detail/parser/read_unsigned_integer.cpp
+4
-3
libcaf_core/test/make_config_value_field.cpp
libcaf_core/test/make_config_value_field.cpp
+260
-0
No files found.
libcaf_core/caf/all.hpp
View file @
11c4eaca
...
...
@@ -50,6 +50,8 @@
#include "caf/config_option.hpp"
#include "caf/config_option_adder.hpp"
#include "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/config_value_object_access.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/defaults.hpp"
#include "caf/deserializer.hpp"
...
...
@@ -69,6 +71,7 @@
#include "caf/local_actor.hpp"
#include "caf/logger.hpp"
#include "caf/make_config_option.hpp"
#include "caf/make_config_value_field.hpp"
#include "caf/may_have_timeout.hpp"
#include "caf/memory_managed.hpp"
#include "caf/message.hpp"
...
...
libcaf_core/caf/config_value.hpp
View file @
11c4eaca
...
...
@@ -31,6 +31,7 @@
#include "caf/atom.hpp"
#include "caf/detail/bounds_checker.hpp"
#include "caf/detail/move_if_not_ptr.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp"
...
...
@@ -230,6 +231,14 @@ struct default_config_value_access {
static
T
get
(
const
config_value
&
x
)
{
return
caf
::
get
<
T
>
(
x
.
get_data
());
}
static
T
convert
(
T
x
)
{
return
x
;
}
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
x
)
{
detail
::
parse
(
ps
,
x
);
}
};
struct
config_value_access_unspecialized
{};
...
...
@@ -238,39 +247,59 @@ struct config_value_access_unspecialized {};
template
<
class
T
>
struct
config_value_access
:
config_value_access_unspecialized
{};
#define CAF_DEFAULT_CONFIG_VALUE_ACCESS(type
)
\
#define CAF_DEFAULT_CONFIG_VALUE_ACCESS(type
, name)
\
template <> \
struct config_value_access<type> : default_config_value_access<type> {}
struct config_value_access<type> : default_config_value_access<type> { \
static std::string type_name() { \
return name; \
} \
}
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
bool
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
double
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
atom_value
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
timespan
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
std
::
string
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
config_value
::
list
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
config_value
::
dictionary
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
bool
,
"boolean"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
double
,
"real64"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
atom_value
,
"atom"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
timespan
,
"timespan"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
config_value
::
list
,
"list"
);
CAF_DEFAULT_CONFIG_VALUE_ACCESS
(
config_value
::
dictionary
,
"dictionary"
);
#undef CAF_DEFAULT_CONFIG_VALUE_ACCESS
template
<
>
struct
config_value_access
<
std
::
string
>
:
default_config_value_access
<
std
::
string
>
{
using
super
=
default_config_value_access
<
std
::
string
>
;
static
std
::
string
type_name
()
{
return
"string"
;
}
using
super
::
parse_cli
;
static
void
parse_cli
(
string_parser_state
&
ps
,
std
::
string
&
x
,
const
char
*
char_blacklist
)
{
detail
::
parse_element
(
ps
,
x
,
char_blacklist
);
}
};
enum
class
select_config_value_hint
{
is_custom
,
is_integral
,
is_list
,
is_map
,
is_list
,
is_custom
,
is_missing
,
};
template
<
class
T
>
constexpr
select_config_value_hint
select_config_value_oracle
()
{
return
!
std
::
is_base_of
<
config_value_access_unspecialized
,
config_value_access
<
T
>>::
value
?
select_config_value_hint
::
is_custom
:
(
std
::
is_integral
<
T
>::
value
?
select_config_value_hint
::
is_integral
:
(
detail
::
is_map_like
<
T
>::
value
?
select_config_value_hint
::
is_map
:
(
detail
::
is_list_like
<
T
>::
value
?
select_config_value_hint
::
is_
list
return
std
::
is_integral
<
T
>::
value
&&
!
std
::
is_same
<
T
,
bool
>::
value
?
select_config_value_hint
::
is_integral
:
(
detail
::
is_map_like
<
T
>::
value
?
select_config_value_hint
::
is_map
:
(
detail
::
is_list_like
<
T
>::
value
?
select_config_value_hint
::
is_list
:
(
!
std
::
is_base_of
<
config_value_access_unspecialized
,
config_value_access
<
T
>
>::
value
?
select_config_value_hint
::
is_
custom
:
select_config_value_hint
::
is_missing
)));
}
...
...
@@ -284,8 +313,8 @@ struct select_config_value_access {
};
template
<
class
T
>
using
select_config_value_access_t
=
typename
select_config_value_access
<
T
>::
type
;
using
select_config_value_access_t
=
typename
select_config_value_access
<
T
>::
type
;
template
<
>
struct
sum_type_access
<
config_value
>
{
...
...
@@ -362,13 +391,25 @@ struct sum_type_access<config_value> {
template
<
class
T
>
struct
select_config_value_access
<
T
,
select_config_value_hint
::
is_integral
>
{
struct
type
{
using
integer_type
=
config_value
::
integer
;
static
std
::
string
type_name
()
{
std
::
string
result
;
if
(
std
::
is_signed
<
T
>::
value
)
result
=
"int"
;
else
result
=
"uint"
;
result
+=
std
::
to_string
(
sizeof
(
T
)
*
8
);
return
result
;
}
static
bool
is
(
const
config_value
&
x
)
{
auto
ptr
=
caf
::
get_if
<
typename
config_value
::
integer
>
(
x
.
get_data_ptr
());
auto
ptr
=
caf
::
get_if
<
integer_type
>
(
x
.
get_data_ptr
());
return
ptr
!=
nullptr
&&
detail
::
bounds_checker
<
T
>::
check
(
*
ptr
);
}
static
optional
<
T
>
get_if
(
const
config_value
*
x
)
{
auto
ptr
=
caf
::
get_if
<
typename
config_value
::
integer
>
(
x
->
get_data_ptr
());
auto
ptr
=
caf
::
get_if
<
integer_type
>
(
x
->
get_data_ptr
());
if
(
ptr
!=
nullptr
&&
detail
::
bounds_checker
<
T
>::
check
(
*
ptr
))
return
static_cast
<
T
>
(
*
ptr
);
return
none
;
...
...
@@ -379,6 +420,14 @@ struct select_config_value_access<T, select_config_value_hint::is_integral> {
CAF_ASSERT
(
res
!=
none
);
return
*
res
;
}
static
T
convert
(
T
x
)
{
return
x
;
}
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
x
)
{
detail
::
parse
(
ps
,
x
);
}
};
};
...
...
@@ -390,13 +439,19 @@ struct select_config_value_access<T, select_config_value_hint::is_list> {
using
value_type
=
typename
list_type
::
value_type
;
using
value_trait
=
select_config_value_access_t
<
value_type
>
;
static
std
::
string
type_name
()
{
return
"list of "
+
value_trait
::
type_name
();
}
static
bool
is
(
const
config_value
&
x
)
{
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
&
x
);
if
(
lst
!=
nullptr
)
{
return
std
::
all_of
(
lst
->
begin
(),
lst
->
end
(),
[](
const
config_value
&
y
)
{
return
caf
::
holds_alternative
<
value_type
>
(
y
);
}
);
}
return
lst
!=
nullptr
&&
std
::
all_of
(
lst
->
begin
(),
lst
->
end
(),
[](
const
config_value
&
y
)
{
return
caf
::
holds_alternative
<
value_type
>
(
y
);
});
return
false
;
}
...
...
@@ -404,8 +459,7 @@ struct select_config_value_access<T, select_config_value_hint::is_list> {
list_type
result
;
auto
out
=
std
::
inserter
(
result
,
result
.
end
());
auto
extract
=
[
&
](
const
config_value
&
y
)
{
auto
opt
=
caf
::
get_if
<
value_type
>
(
&
y
);
if
(
opt
)
{
if
(
auto
opt
=
caf
::
get_if
<
value_type
>
(
&
y
))
{
*
out
++
=
move_if_optional
(
opt
);
return
true
;
}
...
...
@@ -423,10 +477,38 @@ struct select_config_value_access<T, select_config_value_hint::is_list> {
CAF_RAISE_ERROR
(
"invalid type found"
);
return
std
::
move
(
*
result
);
}
static
config_value
::
list
convert
(
const
list_type
&
xs
)
{
config_value
::
list
result
;
for
(
const
auto
&
x
:
xs
)
result
.
emplace_back
(
value_trait
::
convert
(
x
));
return
result
;
}
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
xs
)
{
config_value
::
dictionary
result
;
bool
has_open_token
=
ps
.
consume
(
'['
);
do
{
if
(
has_open_token
&&
ps
.
consume
(
']'
))
{
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
return
;
}
value_type
tmp
;
value_trait
::
parse_cli
(
ps
,
tmp
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
xs
.
insert
(
xs
.
end
(),
std
::
move
(
tmp
));
}
while
(
ps
.
consume
(
','
));
if
(
has_open_token
&&
!
ps
.
consume
(
']'
))
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
}
};
};
/// Catches all non-specialized
list
types.
/// Catches all non-specialized
map
types.
template
<
class
T
>
struct
select_config_value_access
<
T
,
select_config_value_hint
::
is_map
>
{
struct
type
{
...
...
@@ -434,14 +516,22 @@ struct select_config_value_access<T, select_config_value_hint::is_map> {
using
mapped_type
=
typename
map_type
::
mapped_type
;
using
mapped_trait
=
select_config_value_access_t
<
mapped_type
>
;
static
std
::
string
type_name
()
{
std
::
string
result
=
"dictionary of "
;
auto
nested_name
=
mapped_trait
::
type_name
();
result
.
insert
(
result
.
end
(),
nested_name
.
begin
(),
nested_name
.
end
());
return
result
;
}
static
bool
is
(
const
config_value
&
x
)
{
using
value_type
=
config_value
::
dictionary
::
value_type
;
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
&
x
);
if
(
dict
!=
nullptr
)
{
return
std
::
all_of
(
dict
->
begin
(),
dict
->
end
(),
[](
const
value_type
&
y
)
{
return
caf
::
holds_alternative
<
mapped_type
>
(
y
.
second
);
});
}
auto
is_mapped_type
=
[](
const
value_type
&
y
)
{
return
caf
::
holds_alternative
<
mapped_type
>
(
y
.
second
);
};
if
(
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
&
x
))
return
std
::
all_of
(
dict
->
begin
(),
dict
->
end
(),
is_mapped_type
);
return
false
;
}
...
...
@@ -450,14 +540,14 @@ struct select_config_value_access<T, select_config_value_hint::is_map> {
map_type
result
;
auto
extract
=
[
&
](
const
value_type
&
y
)
{
if
(
auto
opt
=
caf
::
get_if
<
mapped_type
>
(
&
y
.
second
))
{
result
.
emplace
(
y
.
first
,
*
opt
);
result
.
emplace
(
y
.
first
,
move_if_optional
(
opt
)
);
return
true
;
}
return
false
;
};
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
x
);
if
(
dict
!=
nullptr
&&
std
::
all_of
(
dict
->
begin
(),
dict
->
end
(),
extract
))
return
result
;
if
(
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
x
))
if
(
std
::
all_of
(
dict
->
begin
(),
dict
->
end
(),
extract
))
return
result
;
return
none
;
}
...
...
@@ -467,25 +557,47 @@ struct select_config_value_access<T, select_config_value_hint::is_map> {
CAF_RAISE_ERROR
(
"invalid type found"
);
return
std
::
move
(
*
result
);
}
static
void
parse_cli
(
string_parser_state
&
ps
,
map_type
&
xs
)
{
detail
::
parse
(
ps
,
xs
);
}
static
config_value
::
dictionary
convert
(
const
map_type
&
xs
)
{
config_value
::
dictionary
result
;
for
(
const
auto
&
x
:
xs
)
result
.
emplace
(
x
.
first
,
mapped_trait
::
convert
(
x
.
second
));
return
result
;
}
};
};
template
<
>
struct
config_value_access
<
float
>
{
static
bool
is
(
const
config_value
&
x
)
{
static
inline
std
::
string
type_name
()
{
return
"real32"
;
}
static
inline
bool
is
(
const
config_value
&
x
)
{
return
holds_alternative
<
double
>
(
x
.
get_data
());
}
static
optional
<
float
>
get_if
(
const
config_value
*
x
)
{
auto
res
=
caf
::
get_if
<
double
>
(
&
(
x
->
get_data
()));
if
(
res
)
static
inline
optional
<
float
>
get_if
(
const
config_value
*
x
)
{
if
(
auto
res
=
caf
::
get_if
<
double
>
(
&
(
x
->
get_data
())))
return
static_cast
<
float
>
(
*
res
);
return
none
;
}
static
float
get
(
const
config_value
&
x
)
{
static
inline
float
get
(
const
config_value
&
x
)
{
return
static_cast
<
float
>
(
caf
::
get
<
double
>
(
x
.
get_data
()));
}
static
inline
double
convert
(
float
x
)
{
return
x
;
}
static
inline
void
parse_cli
(
string_parser_state
&
ps
,
float
&
x
)
{
detail
::
parse
(
ps
,
x
);
}
};
/// Implements automagic unboxing of `std::tuple<Ts...>` from a heterogeneous
...
...
@@ -495,6 +607,13 @@ template <class... Ts>
struct
config_value_access
<
std
::
tuple
<
Ts
...
>>
{
using
tuple_type
=
std
::
tuple
<
Ts
...
>
;
static
std
::
string
type_name
()
{
auto
result
=
"tuple["
;
rec_name
(
result
,
true
,
detail
::
int_token
<
0
>
(),
detail
::
type_list
<
Ts
...
>
());
result
+=
']'
;
return
result
;
}
static
bool
is
(
const
config_value
&
x
)
{
if
(
auto
lst
=
caf
::
get_if
<
config_value
::
list
>
(
&
x
))
{
if
(
lst
->
size
()
!=
sizeof
...(
Ts
))
...
...
@@ -522,11 +641,38 @@ struct config_value_access<std::tuple<Ts...>> {
CAF_RAISE_ERROR
(
"invalid type found"
);
}
static
config_value
::
list
convert
(
const
tuple_type
&
xs
)
{
config_value
::
list
result
;
rec_convert
(
result
,
xs
,
detail
::
int_token
<
0
>
(),
detail
::
type_list
<
Ts
...
>
());
return
result
;
}
static
void
parse_cli
(
string_parser_state
&
ps
,
tuple_type
&
xs
)
{
rec_parse
(
ps
,
xs
,
detail
::
int_token
<
0
>
(),
detail
::
type_list
<
Ts
...
>
());
}
private:
template
<
int
Pos
>
static
void
rec_name
(
std
::
string
&
,
bool
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<>
)
{
// nop
}
template
<
int
Pos
,
class
U
,
class
...
Us
>
static
void
rec_name
(
std
::
string
&
result
,
bool
is_first
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<
U
,
Us
...
>
)
{
if
(
!
is_first
)
result
+=
", "
;
using
nested
=
config_value_access
<
U
>
;
auto
nested_name
=
nested
::
type_name
();
result
.
insert
(
result
.
end
(),
nested_name
.
begin
(),
nested_name
.
end
());
return
rec_name
(
result
,
false
,
detail
::
int_token
<
Pos
+
1
>
(),
detail
::
type_list
<
Us
...
>
());
}
template
<
int
Pos
>
static
bool
rec_is
(
const
config_value
::
list
&
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<>
)
{
// End of recursion.
return
true
;
}
...
...
@@ -541,7 +687,6 @@ private:
template
<
int
Pos
>
static
bool
rec_get
(
const
config_value
::
list
&
,
tuple_type
&
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<>
)
{
// End of recursion.
return
true
;
}
...
...
@@ -555,48 +700,38 @@ private:
}
return
false
;
}
};
/// Implements automagic unboxing of `dictionary<V>` from a homogeneous
/// `config_value::dictionary`.
/// @relates config_value
template
<
class
V
>
struct
config_value_access
<
dictionary
<
V
>>
{
using
map_type
=
dictionary
<
V
>
;
using
kvp
=
std
::
pair
<
const
std
::
string
,
config_value
>
;
template
<
int
Pos
>
static
void
rec_convert
(
config_value
::
list
&
,
const
tuple_type
&
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<>
)
{
// nop
}
static
bool
is
(
const
config_value
&
x
)
{
auto
lst
=
caf
::
get_if
<
config_value
::
dictionary
>
(
&
x
);
if
(
lst
!=
nullptr
)
{
return
std
::
all_of
(
lst
->
begin
(),
lst
->
end
(),
[](
const
kvp
&
y
)
{
return
holds_alternative
<
V
>
(
y
.
second
);
});
}
return
false
;
template
<
int
Pos
,
class
U
,
class
...
Us
>
static
void
rec_convert
(
config_value
::
list
&
result
,
const
tuple_type
&
xs
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<
U
,
Us
...
>
)
{
using
trait
=
select_config_value_access_t
<
U
>
;
result
.
emplace_back
(
trait
::
convert
(
std
::
get
<
Pos
>
(
xs
)));
return
rec_convert
(
result
,
xs
,
detail
::
int_token
<
Pos
+
1
>
(),
detail
::
type_list
<
Us
...
>
());
}
static
optional
<
map_type
>
get_if
(
const
config_value
*
x
)
{
map_type
result
;
auto
extract
=
[
&
](
const
kvp
&
y
)
{
auto
opt
=
caf
::
get_if
<
V
>
(
&
(
y
.
second
));
if
(
opt
)
{
result
.
emplace
(
y
.
first
,
std
::
move
(
*
opt
));
return
true
;
}
return
false
;
};
auto
lst
=
caf
::
get_if
<
config_value
::
dictionary
>
(
x
);
if
(
lst
!=
nullptr
&&
std
::
all_of
(
lst
->
begin
(),
lst
->
end
(),
extract
))
return
result
;
return
none
;
template
<
int
Pos
>
static
void
rec_parse
(
string_parser_state
&
,
tuple_type
&
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<>
)
{
// nop
}
static
map_type
get
(
const
config_value
&
x
)
{
auto
result
=
get_if
(
&
x
);
if
(
!
result
)
CAF_RAISE_ERROR
(
"invalid type found"
);
return
std
::
move
(
*
result
);
template
<
int
Pos
,
class
U
,
class
...
Us
>
static
void
rec_parse
(
string_parser_state
&
ps
,
tuple_type
&
xs
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<
U
,
Us
...
>
)
{
using
trait
=
select_config_value_access_t
<
U
>
;
trait
::
parse_cli
(
std
::
get
<
Pos
>
(
xs
));
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
if
(
sizeof
...(
Us
)
>
0
&&
!
ps
.
consume
(
','
))
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
rec_parse
(
ps
,
xs
,
detail
::
int_token
<
Pos
+
1
>
(),
detail
::
type_list
<
Us
...
>
());
}
};
...
...
libcaf_core/caf/config_value_field.hpp
0 → 100644
View file @
11c4eaca
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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/fwd.hpp"
#include "caf/parser_state.hpp"
namespace
caf
{
/// Describes a field of `Object`.
template
<
class
Object
>
class
config_value_field
{
public:
using
object_type
=
Object
;
virtual
~
config_value_field
()
=
default
;
// -- observers --------------------------------------------------------------
/// Checks whether `x` matches the type of this field.
virtual
bool
type_check
(
const
config_value
&
x
)
const
noexcept
=
0
;
/// Returns whether this field in `object` contains valid data.
virtual
bool
valid
(
const
Object
&
object
)
const
noexcept
=
0
;
/// Returns whether this field has a default value.
virtual
bool
has_default
()
const
noexcept
=
0
;
/// Returns the name of this field.
virtual
string_view
name
()
const
noexcept
=
0
;
/// Returns the value of this field in `object` as config value.
virtual
config_value
get
(
const
Object
&
object
)
const
=
0
;
// -- modifiers --------------------------------------------------------------
/// Sets this field in `object` to `x`.
/// @pre `can_set(x)`
virtual
void
set
(
Object
&
object
,
const
config_value
&
x
)
const
=
0
;
/// Restores the default value for this field in `object`.
/// @pre `has_default()`
virtual
void
set_default
(
Object
&
object
)
const
=
0
;
/// Parses the content for this field in `object` from `ps`.
virtual
void
parse_cli
(
string_parser_state
&
ps
,
Object
&
object
,
const
char
*
char_blacklist
=
""
)
const
=
0
;
};
}
// namespace caf
libcaf_core/caf/config_value_object_access.hpp
0 → 100644
View file @
11c4eaca
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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/config_value.hpp"
#include "caf/config_value_field.hpp"
namespace
caf
{
/// Enables user-defined types in config files and on the CLI by converting
/// them to and from `config_value::dictionary`.
///
/// ~~
/// struct trait {
/// using object_type = ...;
///
/// static string_value type_name();
///
/// static span<config_value_field<object_type>*> fields();
/// };
/// ~~
template
<
class
Trait
>
struct
config_value_object_access
{
using
object_type
=
typename
Trait
::
object_type
;
static
std
::
string
type_name
()
{
return
Trait
::
type_name
();
}
static
bool
extract
(
const
config_value
*
src
,
object_type
*
dst
)
{
auto
dict
=
caf
::
get_if
<
config_value
::
dictionary
>
(
src
);
if
(
!
dict
)
return
false
;
for
(
auto
field
:
Trait
::
fields
())
{
auto
value
=
caf
::
get_if
(
dict
,
field
->
name
());
if
(
!
value
)
{
if
(
!
field
->
has_default
())
return
false
;
if
(
dst
)
field
->
set_default
(
*
dst
);
}
else
if
(
field
->
type_check
(
*
value
))
{
if
(
dst
)
field
->
set
(
*
dst
,
*
value
);
}
else
{
return
false
;
}
}
return
true
;
}
static
bool
is
(
const
config_value
&
x
)
{
return
extract
(
&
x
,
nullptr
);
}
static
optional
<
object_type
>
get_if
(
const
config_value
*
x
)
{
object_type
result
;
if
(
extract
(
x
,
&
result
))
return
result
;
return
none
;
}
static
object_type
get
(
const
config_value
&
x
)
{
auto
result
=
get_if
(
&
x
);
if
(
!
result
)
CAF_RAISE_ERROR
(
"config_value does not contain requested object"
);
return
std
::
move
(
*
result
);
}
static
config_value
::
dictionary
convert
(
const
object_type
&
x
)
{
config_value
::
dictionary
result
;
for
(
auto
field
:
Trait
::
fields
())
result
.
emplace
(
field
->
name
(),
field
->
get
(
x
));
return
result
;
}
static
void
parse_cli
(
string_parser_state
&
ps
,
object_type
&
x
)
{
using
field_type
=
config_value_field
<
object_type
>
;
std
::
vector
<
field_type
*>
parsed_fields
;
auto
got
=
[
&
](
field_type
*
f
)
{
auto
e
=
parsed_fields
.
end
();
return
std
::
find
(
parsed_fields
.
begin
(),
e
,
f
)
!=
e
;
};
auto
push
=
[
&
](
field_type
*
f
)
{
if
(
got
(
f
))
return
false
;
parsed_fields
.
emplace_back
(
f
);
return
true
;
};
auto
finalize
=
[
&
]
{
for
(
auto
field
:
Trait
::
fields
())
{
if
(
!
got
(
field
))
{
if
(
field
->
has_default
())
{
field
->
set_default
(
x
);
}
else
{
ps
.
code
=
pec
::
missing_field
;
return
;
}
}
}
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
};
auto
fs
=
Trait
::
fields
();
if
(
!
ps
.
consume
(
'{'
))
{
ps
.
code
=
pec
::
unexpected_character
;
return
;
}
using
string_access
=
select_config_value_access_t
<
std
::
string
>
;
config_value
::
dictionary
result
;
do
{
if
(
ps
.
consume
(
'}'
))
{
finalize
();
return
;
}
std
::
string
field_name
;
string_access
::
parse_cli
(
ps
,
field_name
,
"=}"
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
if
(
!
ps
.
consume
(
'='
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
}
auto
predicate
=
[
&
](
config_value_field
<
object_type
>*
x
)
{
return
x
->
name
()
==
field_name
;
};
auto
f
=
std
::
find_if
(
fs
.
begin
(),
fs
.
end
(),
predicate
);
if
(
f
==
fs
.
end
())
{
ps
.
code
=
pec
::
invalid_field_name
;
return
;
}
auto
fptr
=
*
f
;
if
(
!
push
(
fptr
))
{
ps
.
code
=
pec
::
repeated_field_name
;
return
;
}
fptr
->
parse_cli
(
ps
,
x
,
",}"
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
if
(
ps
.
at_end
())
{
ps
.
code
=
pec
::
unexpected_eof
;
return
;
}
if
(
!
fptr
->
valid
(
x
))
{
ps
.
code
=
pec
::
illegal_argument
;
return
;
}
result
[
fptr
->
name
()]
=
fptr
->
get
(
x
);
}
while
(
ps
.
consume
(
','
));
if
(
!
ps
.
consume
(
'}'
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
}
finalize
();
}
};
}
// namespace caf
libcaf_core/caf/detail/config_value_field_impl.hpp
0 → 100644
View file @
11c4eaca
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 <string>
#include <utility>
#include "caf/config_value.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/dispatch_parse_cli.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/optional.hpp"
#include "caf/string_view.hpp"
namespace
caf
{
namespace
detail
{
template
<
class
MemberObjectPointer
>
class
config_value_field_impl
;
// A config value with direct access to a field via member object pointer.
template
<
class
Value
,
class
Object
>
class
config_value_field_impl
<
Value
Object
::*>
:
public
config_value_field
<
Object
>
{
public:
using
member_pointer
=
Value
Object
::*
;
using
object_type
=
Object
;
using
value_type
=
Value
;
using
predicate_pointer
=
bool
(
*
)(
const
value_type
&
);
constexpr
config_value_field_impl
(
string_view
name
,
member_pointer
ptr
,
optional
<
value_type
>
default_value
=
none
,
predicate_pointer
predicate
=
nullptr
)
:
name_
(
name
),
ptr_
(
ptr
),
default_value_
(
std
::
move
(
default_value
)),
predicate_
(
predicate
)
{
// nop
}
constexpr
config_value_field_impl
(
config_value_field_impl
&&
)
=
default
;
bool
type_check
(
const
config_value
&
x
)
const
noexcept
override
{
return
holds_alternative
<
value_type
>
(
x
);
}
bool
valid
(
const
object_type
&
x
)
const
noexcept
override
{
return
predicate_
?
predicate_
(
x
.
*
ptr_
)
:
true
;
}
void
set
(
object_type
&
x
,
const
config_value
&
y
)
const
override
{
x
.
*
ptr_
=
caf
::
get
<
value_type
>
(
y
);
}
config_value
get
(
const
object_type
&
x
)
const
override
{
using
access
=
select_config_value_access_t
<
value_type
>
;
return
config_value
{
access
::
convert
(
x
.
*
ptr_
)};
}
void
parse_cli
(
string_parser_state
&
ps
,
object_type
&
x
,
const
char
*
char_blacklist
)
const
override
{
detail
::
dispatch_parse_cli
(
ps
,
x
.
*
ptr_
,
char_blacklist
);
}
string_view
name
()
const
noexcept
override
{
return
name_
;
}
bool
has_default
()
const
noexcept
override
{
return
static_cast
<
bool
>
(
default_value_
);
}
void
set_default
(
object_type
&
x
)
const
override
{
x
.
*
ptr_
=
*
default_value_
;
}
private:
string_view
name_
;
member_pointer
ptr_
;
optional
<
value_type
>
default_value_
;
predicate_pointer
predicate_
;
};
template
<
class
Get
>
struct
config_value_field_base
{
using
trait
=
get_callable_trait_t
<
Get
>
;
static_assert
(
trait
::
num_args
==
1
,
"Get must take exactly one argument (the object)"
);
using
arg_type
=
tl_head_t
<
typename
trait
::
arg_types
>
;
using
value_type
=
decay_t
<
typename
trait
::
result_type
>
;
using
type
=
config_value_field
<
decay_t
<
arg_type
>>
;
};
template
<
class
Get
>
using
config_value_field_base_t
=
typename
config_value_field_base
<
Get
>::
type
;
// A config value with access to a field via getter and setter.
template
<
class
Get
,
class
Set
>
class
config_value_field_impl
<
std
::
pair
<
Get
,
Set
>>
:
public
config_value_field_base_t
<
Get
>
{
public:
using
super
=
config_value_field_base_t
<
Get
>
;
using
object_type
=
typename
super
::
object_type
;
using
get_trait
=
get_callable_trait_t
<
Get
>
;
using
value_type
=
decay_t
<
typename
get_trait
::
result_type
>
;
using
predicate_pointer
=
bool
(
*
)(
const
value_type
&
);
constexpr
config_value_field_impl
(
string_view
name
,
Get
getter
,
Set
setter
,
optional
<
value_type
>
default_value
=
none
,
predicate_pointer
predicate
=
nullptr
)
:
name_
(
name
),
get_
(
std
::
move
(
getter
)),
set_
(
std
::
move
(
setter
)),
default_value_
(
std
::
move
(
default_value
)),
predicate_
(
predicate
)
{
// nop
}
constexpr
config_value_field_impl
(
config_value_field_impl
&&
)
=
default
;
bool
type_check
(
const
config_value
&
x
)
const
noexcept
override
{
return
holds_alternative
<
value_type
>
(
x
);
}
void
set
(
object_type
&
x
,
const
config_value
&
y
)
const
override
{
set_
(
x
,
caf
::
get
<
value_type
>
(
y
));
}
config_value
get
(
const
object_type
&
x
)
const
override
{
using
access
=
select_config_value_access_t
<
value_type
>
;
return
config_value
{
access
::
convert
(
get_
(
x
))};
}
bool
valid
(
const
object_type
&
x
)
const
noexcept
override
{
return
predicate_
?
predicate_
(
get_
(
x
))
:
true
;
}
void
parse_cli
(
string_parser_state
&
ps
,
object_type
&
x
,
const
char
*
char_blacklist
)
const
override
{
value_type
tmp
;
detail
::
dispatch_parse_cli
(
ps
,
tmp
,
char_blacklist
);
if
(
ps
.
code
<=
pec
::
trailing_character
)
set_
(
x
,
std
::
move
(
tmp
));
}
string_view
name
()
const
noexcept
override
{
return
name_
;
}
bool
has_default
()
const
noexcept
override
{
return
static_cast
<
bool
>
(
default_value_
);
}
void
set_default
(
object_type
&
x
)
const
override
{
set_
(
x
,
*
default_value_
);
}
private:
string_view
name_
;
Get
get_
;
Set
set_
;
optional
<
value_type
>
default_value_
;
predicate_pointer
predicate_
;
};
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/
type_name
.hpp
→
libcaf_core/caf/detail/
dispatch_parse_cli
.hpp
View file @
11c4eaca
...
...
@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-201
8
Dominik Charousset *
* Copyright 2011-201
9
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 *
...
...
@@ -18,116 +18,44 @@
#pragma once
#include <string>
#include <type_traits>
#include <vector>
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp"
#include "caf/timestamp.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/type_traits.hpp"
namespace
caf
{
namespace
detail
{
template
<
size_t
Bytes
>
struct
type_name_builder_int_size
;
template
<
>
struct
type_name_builder_int_size
<
1
>
{
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"8"
;
}
};
template
<
>
struct
type_name_builder_int_size
<
2
>
{
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"16"
;
}
};
template
<
>
struct
type_name_builder_int_size
<
4
>
{
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"32"
;
}
};
template
<
>
struct
type_name_builder_int_size
<
8
>
{
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"64"
;
}
};
template
<
class
T
,
bool
IsInteger
=
std
::
is_integral
<
T
>
::
value
>
struct
type_name_builder
;
template
<
>
struct
type_name_builder
<
bool
,
true
>
{
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"boolean"
;
template
<
class
Trait
>
struct
dispatch_parse_cli_helper
{
template
<
class
...
Ts
>
auto
operator
()(
Ts
&&
...
xs
)
->
decltype
(
Trait
::
parse_cli
(
std
::
forward
<
Ts
>
(
xs
)...))
{
return
Trait
::
parse_cli
(
std
::
forward
<
Ts
>
(
xs
)...);
}
};
#define CAF_TYPE_NAME_BUILDER_NOINT(class_name, pretty_name) \
template <> \
struct type_name_builder<class_name, false> { \
void operator()(std::string& result) const { \
result += pretty_name; \
} \
}
CAF_TYPE_NAME_BUILDER_NOINT
(
float
,
"32-bit real"
);
CAF_TYPE_NAME_BUILDER_NOINT
(
double
,
"64-bit real"
);
CAF_TYPE_NAME_BUILDER_NOINT
(
timespan
,
"timespan"
);
CAF_TYPE_NAME_BUILDER_NOINT
(
std
::
string
,
"string"
);
CAF_TYPE_NAME_BUILDER_NOINT
(
atom_value
,
"atom"
);
CAF_TYPE_NAME_BUILDER_NOINT
(
uri
,
"uri"
);
#undef CAF_TYPE_NAME_BUILDER
template
<
class
T
>
struct
type_name_builder
<
T
,
true
>
{
void
operator
()(
std
::
string
&
result
)
const
{
// TODO: replace with if constexpr when switching to C++17
if
(
!
std
::
is_signed
<
T
>::
value
)
result
+=
'u'
;
result
+=
"int"
;
type_name_builder_int_size
<
sizeof
(
T
)
>
g
;
g
(
result
);
}
};
template
<
class
T
>
struct
type_name_builder
<
std
::
vector
<
T
>
,
false
>
{
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"list of "
;
type_name_builder
<
T
>
g
;
g
(
result
);
}
};
template
<
class
Access
,
class
T
>
void
dispatch_parse_cli
(
std
::
true_type
,
string_parser_state
&
ps
,
T
&
x
,
const
char
*
char_blacklist
)
{
Access
::
parse_cli
(
ps
,
x
,
char_blacklist
);
}
template
<
class
T
>
struct
type_name_builder
<
dictionary
<
T
>
,
false
>
{
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"dictionary of "
;
type_name_builder
<
T
>
g
;
g
(
result
);
}
};
template
<
class
Access
,
class
T
>
void
dispatch_parse_cli
(
std
::
false_type
,
string_parser_state
&
ps
,
T
&
x
,
const
char
*
)
{
Access
::
parse_cli
(
ps
,
x
);
}
template
<
class
T
>
std
::
string
type_name
()
{
std
::
string
result
;
type_name_builder
<
T
>
f
;
f
(
result
);
return
result
;
void
dispatch_parse_cli
(
string_parser_state
&
ps
,
T
&
x
,
const
char
*
char_blacklist
)
{
using
access
=
caf
::
select_config_value_access_t
<
T
>
;
using
helper_fun
=
dispatch_parse_cli_helper
<
access
>
;
using
token_type
=
bool_token
<
detail
::
is_callable_with
<
helper_fun
,
string_parser_state
&
,
T
&
,
const
char
*>::
value
>
;
token_type
token
;
dispatch_parse_cli
<
access
>
(
token
,
ps
,
x
,
char_blacklist
);
}
}
// namespace detail
...
...
libcaf_core/caf/detail/parse.hpp
View file @
11c4eaca
...
...
@@ -25,94 +25,94 @@
#include <utility>
#include <vector>
#include "caf/detail/parser/state.hpp"
#include "caf/detail/squashed_int.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp"
#include "caf/none.hpp"
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/unit.hpp"
namespace
caf
{
namespace
detail
{
using
parse_state
=
parser
::
state
<
string_view
::
iterator
>
;
// -- boolean type -------------------------------------------------------------
void
parse
(
parse
_state
&
ps
,
bool
&
x
);
void
parse
(
string_parser
_state
&
ps
,
bool
&
x
);
// -- signed integer types -----------------------------------------------------
void
parse
(
parse
_state
&
ps
,
int8_t
&
x
);
void
parse
(
string_parser
_state
&
ps
,
int8_t
&
x
);
void
parse
(
parse
_state
&
ps
,
int16_t
&
x
);
void
parse
(
string_parser
_state
&
ps
,
int16_t
&
x
);
void
parse
(
parse
_state
&
ps
,
int32_t
&
x
);
void
parse
(
string_parser
_state
&
ps
,
int32_t
&
x
);
void
parse
(
parse
_state
&
ps
,
int64_t
&
x
);
void
parse
(
string_parser
_state
&
ps
,
int64_t
&
x
);
// -- unsigned integer types ---------------------------------------------------
void
parse
(
parse
_state
&
ps
,
uint8_t
&
x
);
void
parse
(
string_parser
_state
&
ps
,
uint8_t
&
x
);
void
parse
(
parse
_state
&
ps
,
uint16_t
&
x
);
void
parse
(
string_parser
_state
&
ps
,
uint16_t
&
x
);
void
parse
(
parse
_state
&
ps
,
uint32_t
&
x
);
void
parse
(
string_parser
_state
&
ps
,
uint32_t
&
x
);
void
parse
(
parse
_state
&
ps
,
uint64_t
&
x
);
void
parse
(
string_parser
_state
&
ps
,
uint64_t
&
x
);
// -- non-fixed size integer types ---------------------------------------------
template
<
class
T
>
detail
::
enable_if_t
<
std
::
is_integral
<
T
>::
value
>
parse
(
parse_state
&
ps
,
T
&
x
)
{
detail
::
enable_if_t
<
std
::
is_integral
<
T
>::
value
>
parse
(
string_parser_state
&
ps
,
T
&
x
)
{
using
squashed_type
=
squashed_int_t
<
T
>
;
return
parse
(
ps
,
reinterpret_cast
<
squashed_type
&>
(
x
));
}
// -- floating point types -----------------------------------------------------
void
parse
(
parse
_state
&
ps
,
float
&
x
);
void
parse
(
string_parser
_state
&
ps
,
float
&
x
);
void
parse
(
parse
_state
&
ps
,
double
&
x
);
void
parse
(
string_parser
_state
&
ps
,
double
&
x
);
// -- CAF types ----------------------------------------------------------------
void
parse
(
parse
_state
&
ps
,
timespan
&
x
);
void
parse
(
string_parser
_state
&
ps
,
timespan
&
x
);
void
parse
(
parse
_state
&
ps
,
atom_value
&
x
);
void
parse
(
string_parser
_state
&
ps
,
atom_value
&
x
);
void
parse
(
parse
_state
&
ps
,
ipv4_address
&
x
);
void
parse
(
string_parser
_state
&
ps
,
ipv4_address
&
x
);
void
parse
(
parse
_state
&
ps
,
ipv4_subnet
&
x
);
void
parse
(
string_parser
_state
&
ps
,
ipv4_subnet
&
x
);
void
parse
(
parse
_state
&
ps
,
ipv4_endpoint
&
x
);
void
parse
(
string_parser
_state
&
ps
,
ipv4_endpoint
&
x
);
void
parse
(
parse
_state
&
ps
,
ipv6_address
&
x
);
void
parse
(
string_parser
_state
&
ps
,
ipv6_address
&
x
);
void
parse
(
parse
_state
&
ps
,
ipv6_subnet
&
x
);
void
parse
(
string_parser
_state
&
ps
,
ipv6_subnet
&
x
);
void
parse
(
parse
_state
&
ps
,
ipv6_endpoint
&
x
);
void
parse
(
string_parser
_state
&
ps
,
ipv6_endpoint
&
x
);
void
parse
(
parse
_state
&
ps
,
uri
&
x
);
void
parse
(
string_parser
_state
&
ps
,
uri
&
x
);
// -- STL types ----------------------------------------------------------------
void
parse
(
parse
_state
&
ps
,
std
::
string
&
x
);
void
parse
(
string_parser
_state
&
ps
,
std
::
string
&
x
);
// -- container types ----------------------------------------------------------
void
parse_element
(
parse_state
&
ps
,
std
::
string
&
x
,
const
char
*
char_blacklist
);
void
parse_element
(
string_parser_state
&
ps
,
std
::
string
&
x
,
const
char
*
char_blacklist
);
template
<
class
T
>
enable_if_t
<!
is_pair
<
T
>::
value
>
parse_element
(
parse
_state
&
ps
,
T
&
x
,
enable_if_t
<!
is_pair
<
T
>::
value
>
parse_element
(
string_parser
_state
&
ps
,
T
&
x
,
const
char
*
)
{
parse
(
ps
,
x
);
}
template
<
class
First
,
class
Second
,
size_t
N
>
void
parse_element
(
parse
_state
&
ps
,
std
::
pair
<
First
,
Second
>&
kvp
,
void
parse_element
(
string_parser
_state
&
ps
,
std
::
pair
<
First
,
Second
>&
kvp
,
const
char
(
&
char_blacklist
)[
N
])
{
static_assert
(
N
>
0
,
"empty array"
);
// TODO: consider to guard the blacklist computation with
...
...
@@ -133,7 +133,7 @@ void parse_element(parse_state& ps, std::pair<First, Second>& kvp,
}
template
<
class
T
>
enable_if_tt
<
is_iterable
<
T
>>
parse
(
parse
_state
&
ps
,
T
&
xs
)
{
enable_if_tt
<
is_iterable
<
T
>>
parse
(
string_parser
_state
&
ps
,
T
&
xs
)
{
using
value_type
=
deconst_kvp_t
<
typename
T
::
value_type
>
;
static
constexpr
auto
is_map_type
=
is_pair
<
value_type
>::
value
;
static
constexpr
auto
opening_char
=
is_map_type
?
'{'
:
'['
;
...
...
@@ -181,7 +181,7 @@ enable_if_tt<is_iterable<T>> parse(parse_state& ps, T& xs) {
template
<
class
T
>
error
parse
(
string_view
str
,
T
&
x
)
{
parse
_state
ps
{
str
.
begin
(),
str
.
end
()};
string_parser
_state
ps
{
str
.
begin
(),
str
.
end
()};
parse
(
ps
,
x
);
if
(
ps
.
code
==
pec
::
success
)
return
none
;
...
...
libcaf_core/caf/detail/parser/read_atom.hpp
View file @
11c4eaca
...
...
@@ -26,7 +26,6 @@
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
...
...
@@ -40,9 +39,8 @@ 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_atom
(
state
<
Iterator
,
Sentinel
>&
ps
,
Consumer
&&
consumer
,
bool
accept_unquoted
=
false
)
{
template
<
class
State
,
class
Consumer
>
void
read_atom
(
State
&
ps
,
Consumer
&&
consumer
,
bool
accept_unquoted
=
false
)
{
size_t
pos
=
0
;
char
buf
[
11
];
memset
(
buf
,
0
,
sizeof
(
buf
));
...
...
libcaf_core/caf/detail/parser/read_bool.hpp
View file @
11c4eaca
...
...
@@ -24,7 +24,6 @@
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
...
...
@@ -37,8 +36,8 @@ namespace detail {
namespace
parser
{
/// Reads a boolean.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_bool
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_bool
(
State
&
ps
,
Consumer
&&
consumer
)
{
bool
res
=
false
;
auto
g
=
make_scope_guard
([
&
]
{
if
(
ps
.
code
<=
pec
::
trailing_character
)
...
...
libcaf_core/caf/detail/parser/read_floating_point.hpp
View file @
11c4eaca
...
...
@@ -26,7 +26,6 @@
#include "caf/detail/parser/chars.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"
#include "caf/detail/scope_guard.hpp"
#include "caf/optional.hpp"
...
...
@@ -45,8 +44,8 @@ namespace parser {
/// @param consumer Sink for generated values.
/// @param start_value Allows another parser to pre-initialize this parser with
/// the pre-decimal value.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
,
class
ValueType
>
void
read_floating_point
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
,
template
<
class
State
,
class
Consumer
,
class
ValueType
>
void
read_floating_point
(
State
&
ps
,
Consumer
&&
consumer
,
optional
<
ValueType
>
start_value
,
bool
negative
=
false
)
{
// Any exponent larger than 511 always overflows.
...
...
@@ -185,8 +184,8 @@ void read_floating_point(state<Iterator, Sentinel>& ps, Consumer&& consumer,
// clang-format on
}
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_floating_point
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_floating_point
(
State
&
ps
,
Consumer
&&
consumer
)
{
using
consumer_type
=
typename
std
::
decay
<
Consumer
>::
type
;
using
value_type
=
typename
consumer_type
::
value_type
;
return
read_floating_point
(
ps
,
consumer
,
optional
<
value_type
>
{});
...
...
libcaf_core/caf/detail/parser/read_ini.hpp
View file @
11c4eaca
...
...
@@ -58,8 +58,8 @@ namespace parser {
// }]
//
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ini_comment
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
)
{
template
<
class
State
,
class
Consumer
>
void
read_ini_comment
(
State
&
ps
,
Consumer
&&
)
{
start
();
term_state
(
init
)
{
transition
(
done
,
'\n'
)
...
...
@@ -71,11 +71,11 @@ void read_ini_comment(state<Iterator, Sentinel>& ps, Consumer&&) {
fin
();
}
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ini_value
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
);
template
<
class
State
,
class
Consumer
>
void
read_ini_value
(
State
&
ps
,
Consumer
&&
consumer
);
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ini_list
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ini_list
(
State
&
ps
,
Consumer
&&
consumer
)
{
start
();
state
(
init
)
{
epsilon
(
before_value
)
...
...
@@ -98,8 +98,8 @@ void read_ini_list(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
fin
();
}
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ini_map
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ini_map
(
State
&
ps
,
Consumer
&&
consumer
)
{
std
::
string
key
;
auto
alnum_or_dash
=
[](
char
x
)
{
return
isalnum
(
x
)
||
x
==
'-'
||
x
==
'_'
;
...
...
@@ -154,8 +154,8 @@ void read_ini_map(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
// clang-format on
}
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ini_uri
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ini_uri
(
State
&
ps
,
Consumer
&&
consumer
)
{
uri_builder
builder
;
auto
g
=
make_scope_guard
([
&
]
{
if
(
ps
.
code
<=
pec
::
trailing_character
)
...
...
@@ -180,8 +180,8 @@ void read_ini_uri(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
fin
();
}
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ini_value
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ini_value
(
State
&
ps
,
Consumer
&&
consumer
)
{
start
();
state
(
init
)
{
fsm_epsilon
(
read_string
(
ps
,
consumer
),
done
,
'"'
)
...
...
@@ -200,8 +200,8 @@ void read_ini_value(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
}
/// Reads an INI formatted input.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ini_section
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ini_section
(
State
&
ps
,
Consumer
&&
consumer
)
{
using
std
::
swap
;
std
::
string
tmp
;
auto
alnum
=
[](
char
x
)
{
return
isalnum
(
x
)
||
x
==
'_'
;
};
...
...
@@ -254,8 +254,8 @@ void read_ini_section(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
/// Reads a nested group, e.g., "[foo.bar]" would consume "[foo.]" in read_ini
/// and then delegate to this function for parsing "bar]".
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_nested_group
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_nested_group
(
State
&
ps
,
Consumer
&&
consumer
)
{
using
std
::
swap
;
std
::
string
key
;
auto
alnum
=
[](
char
x
)
{
return
isalnum
(
x
)
||
x
==
'_'
;
};
...
...
@@ -290,8 +290,8 @@ void read_nested_group(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
}
/// Reads an INI formatted input.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ini
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ini
(
State
&
ps
,
Consumer
&&
consumer
)
{
using
std
::
swap
;
std
::
string
tmp
{
"global"
};
auto
alnum
=
[](
char
x
)
{
return
isalnum
(
x
)
||
x
==
'_'
;
};
...
...
libcaf_core/caf/detail/parser/read_ipv4_address.hpp
View file @
11c4eaca
...
...
@@ -25,7 +25,6 @@
#include "caf/detail/parser/chars.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"
#include "caf/detail/scope_guard.hpp"
#include "caf/ipv4_address.hpp"
...
...
@@ -48,8 +47,8 @@ struct read_ipv4_octet_consumer {
}
};
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ipv4_octet
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ipv4_octet
(
State
&
ps
,
Consumer
&
consumer
)
{
uint8_t
res
=
0
;
// Reads the a decimal place.
auto
rd_decimal
=
[
&
](
char
c
)
{
...
...
@@ -72,8 +71,8 @@ void read_ipv4_octet(state<Iterator, Sentinel>& ps, Consumer& consumer) {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ipv4_address
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ipv4_address
(
State
&
ps
,
Consumer
&&
consumer
)
{
read_ipv4_octet_consumer
f
;
auto
g
=
make_scope_guard
([
&
]
{
if
(
ps
.
code
<=
pec
::
trailing_character
)
{
...
...
libcaf_core/caf/detail/parser/read_ipv6_address.hpp
View file @
11c4eaca
...
...
@@ -27,7 +27,6 @@
#include "caf/detail/parser/chars.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"
#include "caf/detail/scope_guard.hpp"
#include "caf/ipv4_address.hpp"
...
...
@@ -57,8 +56,8 @@ namespace parser {
// h16 = 1*4HEXDIG
/// Reads 16 (hex) bits of an IPv6 address.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ipv6_h16
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ipv6_h16
(
State
&
ps
,
Consumer
&
consumer
)
{
uint16_t
res
=
0
;
size_t
digits
=
0
;
// Reads the a hexadecimal place.
...
...
@@ -83,8 +82,8 @@ void read_ipv6_h16(state<Iterator, Sentinel>& ps, Consumer& consumer) {
}
/// Reads 16 (hex) or 32 (IPv4 notation) bits of an IPv6 address.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ipv6_h16_or_l32
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ipv6_h16_or_l32
(
State
&
ps
,
Consumer
&
consumer
)
{
enum
mode_t
{
indeterminate
,
v6_bits
,
v4_octets
};
mode_t
mode
=
indeterminate
;
uint16_t
hex_res
=
0
;
...
...
@@ -173,8 +172,8 @@ read_ipv6_address_piece_consumer<F> make_read_ipv6_address_piece_consumer(F f) {
/// Reads a number, i.e., on success produces either an `int64_t` or a
/// `double`.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_ipv6_address
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_ipv6_address
(
State
&
ps
,
Consumer
&&
consumer
)
{
// IPv6 allows omitting blocks of zeros, splitting the string into a part
// before the zeros (prefix) and a part after the zeros (suffix). For example,
// ff::1 is 00FF0000000000000000000000000001
...
...
libcaf_core/caf/detail/parser/read_number.hpp
View file @
11c4eaca
...
...
@@ -26,7 +26,6 @@
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/is_digit.hpp"
#include "caf/detail/parser/read_floating_point.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
...
...
@@ -41,8 +40,8 @@ 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
)
{
template
<
class
State
,
class
Consumer
>
void
read_number
(
State
&
ps
,
Consumer
&
consumer
)
{
// Our result when reading an integer number.
int64_t
result
=
0
;
// Computes the result on success.
...
...
libcaf_core/caf/detail/parser/read_number_or_timespan.hpp
View file @
11c4eaca
...
...
@@ -27,7 +27,6 @@
#include "caf/detail/parser/is_char.hpp"
#include "caf/detail/parser/read_number.hpp"
#include "caf/detail/parser/read_timespan.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/none.hpp"
#include "caf/optional.hpp"
...
...
@@ -45,9 +44,8 @@ namespace parser {
/// Reads a number or a duration, i.e., on success produces an `int64_t`, a
/// `double`, or a `timespan`.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_number_or_timespan
(
state
<
Iterator
,
Sentinel
>&
ps
,
Consumer
&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_number_or_timespan
(
State
&
ps
,
Consumer
&
consumer
)
{
using
namespace
std
::
chrono
;
struct
interim_consumer
{
variant
<
none_t
,
int64_t
,
double
>
interim
;
...
...
libcaf_core/caf/detail/parser/read_signed_integer.hpp
View file @
11c4eaca
...
...
@@ -26,7 +26,6 @@
#include "caf/detail/parser/chars.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"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
...
...
@@ -41,8 +40,8 @@ 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_signed_integer
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_signed_integer
(
State
&
ps
,
Consumer
&&
consumer
)
{
using
consumer_type
=
typename
std
::
decay
<
Consumer
>::
type
;
using
value_type
=
typename
consumer_type
::
value_type
;
static_assert
(
std
::
is_integral
<
value_type
>::
value
...
...
libcaf_core/caf/detail/parser/read_string.hpp
View file @
11c4eaca
...
...
@@ -23,7 +23,6 @@
#include "caf/config.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
...
...
@@ -37,8 +36,8 @@ namespace parser {
/// Reads a quoted or unquoted string. Quoted strings allow escaping, while
/// unquoted strings may only include alphanumeric characters.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_string
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_string
(
State
&
ps
,
Consumer
&&
consumer
)
{
std
::
string
res
;
auto
g
=
caf
::
detail
::
make_scope_guard
([
&
]
{
if
(
ps
.
code
<=
pec
::
trailing_character
)
...
...
libcaf_core/caf/detail/parser/read_timespan.hpp
View file @
11c4eaca
...
...
@@ -24,7 +24,6 @@
#include "caf/config.hpp"
#include "caf/detail/parser/read_signed_integer.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/optional.hpp"
#include "caf/pec.hpp"
...
...
@@ -39,8 +38,8 @@ namespace detail {
namespace
parser
{
/// Reads a timespan.
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_timespan
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
,
template
<
class
State
,
class
Consumer
>
void
read_timespan
(
State
&
ps
,
Consumer
&&
consumer
,
optional
<
int64_t
>
num
=
none
)
{
using
namespace
std
::
chrono
;
struct
interim_consumer
{
...
...
libcaf_core/caf/detail/parser/read_unsigned_integer.hpp
View file @
11c4eaca
...
...
@@ -26,7 +26,6 @@
#include "caf/detail/parser/chars.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"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
...
...
@@ -41,8 +40,8 @@ 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_unsigned_integer
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_unsigned_integer
(
State
&
ps
,
Consumer
&&
consumer
)
{
using
consumer_type
=
typename
std
::
decay
<
Consumer
>::
type
;
using
value_type
=
typename
consumer_type
::
value_type
;
static_assert
(
std
::
is_integral
<
value_type
>::
value
...
...
libcaf_core/caf/detail/parser/read_uri.hpp
View file @
11c4eaca
...
...
@@ -22,7 +22,6 @@
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/chars.hpp"
#include "caf/detail/parser/read_ipv6_address.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/pec.hpp"
#include "caf/uri.hpp"
...
...
@@ -47,8 +46,8 @@ namespace parser {
// generate ranges for the subcomponents. URIs can't have linebreaks, so we can
// safely keep track of the position by looking at the column.
template
<
class
Iterator
,
class
Sentinel
>
void
read_uri_percent_encoded
(
state
<
Iterator
,
Sentinel
>
&
ps
,
std
::
string
&
str
)
{
template
<
class
State
>
void
read_uri_percent_encoded
(
State
&
ps
,
std
::
string
&
str
)
{
uint8_t
char_code
=
0
;
auto
g
=
make_scope_guard
([
&
]
{
if
(
ps
.
code
<=
pec
::
trailing_character
)
...
...
@@ -75,8 +74,8 @@ inline bool uri_unprotected_char(char c) {
transition(next_state, uri_unprotected_char, dest += ch) \
fsm_transition(read_uri_percent_encoded(ps, dest), next_state, '%')
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_uri_query
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_uri_query
(
State
&
ps
,
Consumer
&&
consumer
)
{
// Local variables.
uri
::
query_map
result
;
std
::
string
key
;
...
...
@@ -113,8 +112,8 @@ void read_uri_query(state<Iterator, Sentinel>& ps, Consumer&& consumer) {
fin
();
}
template
<
class
Iterator
,
class
Sentinel
,
class
Consumer
>
void
read_uri
(
state
<
Iterator
,
Sentinel
>
&
ps
,
Consumer
&&
consumer
)
{
template
<
class
State
,
class
Consumer
>
void
read_uri
(
State
&
ps
,
Consumer
&&
consumer
)
{
// Local variables.
std
::
string
str
;
uint16_t
port
=
0
;
...
...
libcaf_core/caf/detail/type_traits.hpp
View file @
11c4eaca
...
...
@@ -445,6 +445,7 @@ struct callable_trait<R (Ts...)> {
using
arg_types
=
type_list
<
Ts
...
>
;
using
fun_sig
=
R
(
Ts
...);
using
fun_type
=
std
::
function
<
R
(
Ts
...)
>
;
static
constexpr
size_t
num_args
=
sizeof
...(
Ts
);
};
// member const function pointer
...
...
@@ -508,6 +509,9 @@ struct get_callable_trait_helper<T, false, false> {};
template
<
class
T
>
struct
get_callable_trait
:
get_callable_trait_helper
<
decay_t
<
T
>>
{};
template
<
class
T
>
using
get_callable_trait_t
=
typename
get_callable_trait
<
T
>::
type
;
/// Checks wheter `T` is a function or member function.
template
<
class
T
>
struct
is_callable
{
...
...
libcaf_core/caf/fwd.hpp
View file @
11c4eaca
...
...
@@ -56,6 +56,8 @@ template <class> struct timeout_definition;
template
<
class
,
class
>
class
stream_stage
;
template
<
class
Iterator
,
class
Sentinel
=
Iterator
>
struct
parser_state
;
// -- 3 param templates --------------------------------------------------------
template
<
class
,
class
,
int
>
class
actor_cast_access
;
...
...
libcaf_core/caf/make_config_option.hpp
View file @
11c4eaca
...
...
@@ -23,7 +23,7 @@
#include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/type_
name
.hpp"
#include "caf/detail/type_
traits
.hpp"
#include "caf/error.hpp"
#include "caf/expected.hpp"
#include "caf/fwd.hpp"
...
...
@@ -48,20 +48,22 @@ void store_impl(void* ptr, const config_value& x) {
template
<
class
T
>
config_value
get_impl
(
const
void
*
ptr
)
{
return
config_value
{
*
reinterpret_cast
<
const
T
*>
(
ptr
)};
using
trait
=
select_config_value_access_t
<
T
>
;
return
config_value
{
trait
::
convert
(
*
reinterpret_cast
<
const
T
*>
(
ptr
))};
}
template
<
class
T
>
expected
<
config_value
>
parse_impl
(
T
*
ptr
,
string_view
str
)
{
if
(
ptr
!=
nullptr
)
{
if
(
auto
err
=
parse
(
str
,
*
ptr
))
return
err
;
return
config_value
{
*
ptr
};
if
(
!
ptr
)
{
T
tmp
;
return
parse_impl
(
&
tmp
,
str
);
}
T
tmp
;
if
(
auto
err
=
parse
(
str
,
tmp
))
return
err
;
return
config_value
{
std
::
move
(
tmp
)};
using
trait
=
select_config_value_access_t
<
T
>
;
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
trait
::
parse_cli
(
ps
,
*
ptr
);
if
(
ps
.
code
!=
pec
::
success
)
return
make_error
(
ps
);
return
config_value
{
trait
::
convert
(
*
ptr
)};
}
expected
<
config_value
>
parse_impl
(
std
::
string
*
ptr
,
string_view
str
);
...
...
@@ -73,9 +75,10 @@ expected<config_value> parse_impl_delegate(void* ptr, string_view str) {
template
<
class
T
>
config_option
::
meta_state
*
option_meta_state_instance
()
{
using
trait
=
select_config_value_access_t
<
T
>
;
static
config_option
::
meta_state
obj
{
check_impl
<
T
>
,
store_impl
<
T
>
,
get_impl
<
T
>
,
parse_impl_delegate
<
T
>
,
detail
::
type_name
<
T
>
()};
trait
::
type_name
()};
return
&
obj
;
}
...
...
libcaf_core/caf/make_config_value_field.hpp
0 → 100644
View file @
11c4eaca
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 <array>
#include <tuple>
#include <type_traits>
#include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_impl.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/type_traits.hpp"
namespace
caf
{
/// Creates a field with direct access to a member in `T` via member-to-object
/// pointer.
template
<
class
T
,
class
U
,
class
...
Args
>
detail
::
config_value_field_impl
<
U
T
::*>
make_config_value_field
(
string_view
name
,
U
T
::*
ptr
,
Args
&&
...
xs
)
{
return
{
name
,
ptr
,
std
::
forward
<
Args
>
(
xs
)...};
}
/// Creates a field with access to a member in `T` via `getter` and `setter`.
template
<
class
Getter
,
class
Setter
,
class
E
=
detail
::
enable_if_t
<!
std
::
is_member_pointer
<
Getter
>
::
value
>
,
class
...
Args
>
detail
::
config_value_field_impl
<
std
::
pair
<
Getter
,
Setter
>>
make_config_value_field
(
string_view
name
,
Getter
getter
,
Setter
setter
,
Args
&&
...
xs
)
{
return
{
name
,
std
::
move
(
getter
),
std
::
move
(
setter
),
std
::
forward
<
Args
>
(
xs
)...};
}
template
<
class
T
,
class
...
Ts
>
class
config_value_field_storage
{
public:
using
tuple_type
=
std
::
tuple
<
T
,
Ts
...
>
;
using
object_type
=
typename
T
::
object_type
;
using
indices
=
typename
detail
::
il_indices
<
tuple_type
>::
type
;
using
array_type
=
std
::
array
<
config_value_field
<
object_type
>*
,
sizeof
...(
Ts
)
+
1
>
;
template
<
class
...
Us
>
config_value_field_storage
(
T
x
,
Us
&&
...
xs
)
:
fields_
(
std
::
move
(
x
),
std
::
forward
<
Us
>
(
xs
)...)
{
init
(
detail
::
get_indices
(
fields_
));
}
config_value_field_storage
(
config_value_field_storage
&&
)
=
default
;
span
<
config_value_field
<
object_type
>*>
fields
()
{
return
make_span
(
ptr_fields_
);
}
private:
template
<
long
...
Pos
>
void
init
(
detail
::
int_list
<
Pos
...
>
)
{
ptr_fields_
=
array_type
{{
&
std
::
get
<
Pos
>
(
fields_
)...}};
}
std
::
tuple
<
T
,
Ts
...
>
fields_
;
array_type
ptr_fields_
;
};
template
<
class
...
Ts
>
config_value_field_storage
<
Ts
...
>
make_config_value_field_storage
(
Ts
...
fields
)
{
return
{
std
::
move
(
fields
)...};
}
}
// namespace caf
libcaf_core/caf/
detail/parser/
state.hpp
→
libcaf_core/caf/
parser_
state.hpp
View file @
11c4eaca
...
...
@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-201
8
Dominik Charousset *
* Copyright 2011-201
9
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 *
...
...
@@ -21,29 +21,39 @@
#include <cctype>
#include <cstdint>
#include "caf/fwd.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace
caf
{
namespace
detail
{
namespace
parser
{
template
<
class
Iterator
,
class
Sentinel
=
Iterator
>
struct
state
{
/// Stores all informations necessary for implementing an FSM-based parser.
template
<
class
Iterator
,
class
Sentinel
>
struct
parser_state
{
/// Current position of the parser.
Iterator
i
;
/// End-of-input marker.
Sentinel
e
;
/// Current state of the parser.
pec
code
;
/// Current line in the input.
int32_t
line
;
/// Position in the current line.
int32_t
column
;
state
()
noexcept
:
i
(),
e
(),
code
(
pec
::
success
),
line
(
1
),
column
(
1
)
{
parser_
state
()
noexcept
:
i
(),
e
(),
code
(
pec
::
success
),
line
(
1
),
column
(
1
)
{
// nop
}
explicit
state
(
Iterator
first
)
noexcept
:
state
()
{
explicit
parser_state
(
Iterator
first
)
noexcept
:
parser_
state
()
{
i
=
first
;
}
state
(
Iterator
first
,
Sentinel
last
)
noexcept
:
state
()
{
parser_state
(
Iterator
first
,
Sentinel
last
)
noexcept
:
parser_
state
()
{
i
=
first
;
e
=
last
;
}
...
...
@@ -92,6 +102,15 @@ struct state {
}
};
}
// namespace parser
}
// namespace detail
/// Returns an error object from the current code in `ps` as well as its
/// current position.
template
<
class
Iterator
,
class
Sentinel
>
auto
make_error
(
const
parser_state
<
Iterator
,
Sentinel
>&
ps
)
->
decltype
(
make_error
(
ps
.
code
,
ps
.
line
,
ps
.
column
))
{
return
make_error
(
ps
.
code
,
ps
.
line
,
ps
.
column
);
}
/// Specialization for parsers operating on string views.
using
string_parser_state
=
parser_state
<
string_view
::
iterator
>
;
}
// namespace caf
libcaf_core/caf/pec.hpp
View file @
11c4eaca
...
...
@@ -65,6 +65,13 @@ enum class pec : uint8_t {
missing_argument
,
/// Stopped because the key of a category was taken.
illegal_category
,
/// Stopped at an unexpected field name while reading a user-defined type.
invalid_field_name
,
/// Stopped at a repeated field name while reading a user-defined type.
repeated_field_name
,
/// Stopped while reading a user-defined type with one or more missing
/// mandatory fields.
missing_field
,
};
/// Returns an error object from given error code.
...
...
@@ -72,7 +79,7 @@ error make_error(pec code);
/// Returns an error object from given error code with additional context
/// information for where the parser stopped in the input.
error
make_error
(
pec
code
,
size_t
line
,
size
_t
column
);
error
make_error
(
pec
code
,
int32_t
line
,
int32
_t
column
);
/// Returns an error object from given error code with additional context
/// information for where the parser stopped in the argument.
...
...
libcaf_core/caf/span.hpp
View file @
11c4eaca
...
...
@@ -221,6 +221,13 @@ auto make_span(T& xs) -> span<detail::remove_reference_t<decltype(xs[0])>> {
return
{
xs
.
data
(),
xs
.
size
()};
}
/// Convenience function to make using `caf::span` more convenient without the
/// deduction guides.
template
<
class
T
,
size_t
N
>
span
<
T
>
make_span
(
T
(
&
xs
)[
N
])
{
return
{
xs
,
N
};
}
/// Convenience function to make using `caf::span` more convenient without the
/// deduction guides.
template
<
class
T
>
...
...
libcaf_core/caf/uri.hpp
View file @
11c4eaca
...
...
@@ -22,7 +22,6 @@
#include <vector>
#include "caf/detail/comparable.hpp"
#include "caf/detail/parser/state.hpp"
#include "caf/detail/unordered_flat_map.hpp"
#include "caf/fwd.hpp"
#include "caf/intrusive_ptr.hpp"
...
...
libcaf_core/src/actor_system_config.cpp
View file @
11c4eaca
...
...
@@ -494,8 +494,7 @@ error actor_system_config::parse_config(std::istream& source,
if
(
!
source
)
return
make_error
(
sec
::
runtime_error
,
"source stream invalid"
);
detail
::
ini_consumer
consumer
{
opts
,
result
};
detail
::
parser
::
state
<
ini_iter
,
ini_sentinel
>
res
;
res
.
i
=
ini_iter
{
&
source
};
parser_state
<
ini_iter
,
ini_sentinel
>
res
{
ini_iter
{
&
source
}};
detail
::
parser
::
read_ini
(
res
,
consumer
);
if
(
res
.
i
!=
res
.
e
)
return
make_error
(
res
.
code
,
res
.
line
,
res
.
column
);
...
...
libcaf_core/src/config_value.cpp
View file @
11c4eaca
...
...
@@ -26,7 +26,9 @@
#include "caf/detail/parser/read_ini.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/expected.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace
caf
{
...
...
@@ -66,10 +68,8 @@ expected<config_value> config_value::parse(string_view::iterator first,
if
(
++
i
==
last
)
return
make_error
(
pec
::
unexpected_eof
);
// Dispatch to parser.
parser
::
state
<
string_view
::
iterator
>
res
;
detail
::
ini_value_consumer
f
;
res
.
i
=
i
;
res
.
e
=
last
;
string_parser_state
res
{
i
,
last
};
parser
::
read_ini_value
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
return
std
::
move
(
f
.
result
);
...
...
libcaf_core/src/detail/parse.cpp
View file @
11c4eaca
...
...
@@ -39,7 +39,7 @@
#include "caf/uri_builder.hpp"
#define PARSE_IMPL(type, parser_name) \
void parse(
parse_state& ps, type& x) {
\
void parse(
string_parser_state& ps, type& x) {
\
parser::read_##parser_name(ps, make_consumer(x)); \
}
...
...
@@ -55,7 +55,7 @@ struct literal {
}
};
void
parse
(
parse
_state
&
ps
,
literal
&
x
)
{
void
parse
(
string_parser
_state
&
ps
,
literal
&
x
)
{
CAF_ASSERT
(
x
.
str
.
size
()
>
0
);
if
(
ps
.
current
()
!=
x
.
str
[
0
])
{
ps
.
code
=
pec
::
unexpected_character
;
...
...
@@ -72,12 +72,12 @@ void parse(parse_state& ps, literal& x) {
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
}
void
parse_sequence
(
parse
_state
&
)
{
void
parse_sequence
(
string_parser
_state
&
)
{
// End of recursion.
}
template
<
class
T
,
class
...
Ts
>
void
parse_sequence
(
parse
_state
&
ps
,
T
&&
x
,
Ts
&&
...
xs
)
{
void
parse_sequence
(
string_parser
_state
&
ps
,
T
&&
x
,
Ts
&&
...
xs
)
{
parse
(
ps
,
x
);
// TODO: use `if constexpr` when switching to C++17
if
(
sizeof
...(
Ts
)
>
0
)
{
...
...
@@ -111,11 +111,11 @@ PARSE_IMPL(double, floating_point)
PARSE_IMPL
(
timespan
,
timespan
)
void
parse
(
parse
_state
&
ps
,
atom_value
&
x
)
{
void
parse
(
string_parser
_state
&
ps
,
atom_value
&
x
)
{
parser
::
read_atom
(
ps
,
make_consumer
(
x
),
true
);
}
void
parse
(
parse
_state
&
ps
,
uri
&
x
)
{
void
parse
(
string_parser
_state
&
ps
,
uri
&
x
)
{
uri_builder
builder
;
if
(
ps
.
consume
(
'<'
))
{
parser
::
read_uri
(
ps
,
builder
);
...
...
@@ -126,7 +126,7 @@ void parse(parse_state& ps, uri& x) {
return
;
}
}
else
{
read_uri
(
ps
,
builder
);
parser
::
read_uri
(
ps
,
builder
);
}
if
(
ps
.
code
<=
pec
::
trailing_character
)
x
=
builder
.
make
();
...
...
@@ -134,7 +134,7 @@ void parse(parse_state& ps, uri& x) {
PARSE_IMPL
(
ipv4_address
,
ipv4_address
)
void
parse
(
parse
_state
&
ps
,
ipv4_subnet
&
x
)
{
void
parse
(
string_parser
_state
&
ps
,
ipv4_subnet
&
x
)
{
ipv4_address
addr
;
uint8_t
prefix_length
;
parse_sequence
(
ps
,
addr
,
literal
{
"/"
},
prefix_length
);
...
...
@@ -147,7 +147,7 @@ void parse(parse_state& ps, ipv4_subnet& x) {
}
}
void
parse
(
parse
_state
&
ps
,
ipv4_endpoint
&
x
)
{
void
parse
(
string_parser
_state
&
ps
,
ipv4_endpoint
&
x
)
{
ipv4_address
addr
;
uint16_t
port
;
parse_sequence
(
ps
,
addr
,
literal
{
":"
},
port
);
...
...
@@ -157,7 +157,7 @@ void parse(parse_state& ps, ipv4_endpoint& x) {
PARSE_IMPL
(
ipv6_address
,
ipv6_address
)
void
parse
(
parse
_state
&
ps
,
ipv6_subnet
&
x
)
{
void
parse
(
string_parser
_state
&
ps
,
ipv6_subnet
&
x
)
{
// TODO: this algorithm is currently not one-pass. The reason we need to
// check whether the input is a valid ipv4_subnet first is that "1.2.3.0" is
// a valid IPv6 address, but "1.2.3.0/16" results in the wrong subnet when
...
...
@@ -185,7 +185,7 @@ void parse(parse_state& ps, ipv6_subnet& x) {
}
}
void
parse
(
parse
_state
&
ps
,
ipv6_endpoint
&
x
)
{
void
parse
(
string_parser
_state
&
ps
,
ipv6_endpoint
&
x
)
{
ipv6_address
addr
;
uint16_t
port
;
if
(
ps
.
consume
(
'['
))
{
...
...
@@ -200,7 +200,7 @@ void parse(parse_state& ps, ipv6_endpoint& x) {
x
=
ipv6_endpoint
{
addr
,
port
};
}
void
parse
(
parse
_state
&
ps
,
std
::
string
&
x
)
{
void
parse
(
string_parser
_state
&
ps
,
std
::
string
&
x
)
{
ps
.
skip_whitespaces
();
if
(
ps
.
current
()
==
'"'
)
{
parser
::
read_string
(
ps
,
make_consumer
(
x
));
...
...
@@ -213,7 +213,7 @@ void parse(parse_state& ps, std::string& x) {
ps
.
code
=
pec
::
success
;
}
void
parse_element
(
parse
_state
&
ps
,
std
::
string
&
x
,
void
parse_element
(
string_parser
_state
&
ps
,
std
::
string
&
x
,
const
char
*
char_blacklist
)
{
ps
.
skip_whitespaces
();
if
(
ps
.
current
()
==
'"'
)
{
...
...
libcaf_core/src/ipv4_address.cpp
View file @
11c4eaca
...
...
@@ -21,6 +21,7 @@
#include "caf/detail/network_order.hpp"
#include "caf/detail/parser/read_ipv4_address.hpp"
#include "caf/error.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
...
...
@@ -89,8 +90,8 @@ std::string to_string(const ipv4_address& x) {
error
parse
(
string_view
str
,
ipv4_address
&
dest
)
{
using
namespace
detail
;
parser
::
state
<
string_view
::
iterator
>
res
{
str
.
begin
(),
str
.
end
()};
ipv4_address_consumer
f
{
dest
};
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
parser
::
read_ipv4_address
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
return
none
;
...
...
libcaf_core/src/ipv6_address.cpp
View file @
11c4eaca
...
...
@@ -23,6 +23,7 @@
#include "caf/detail/parser/read_ipv6_address.hpp"
#include "caf/error.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
...
...
@@ -212,8 +213,8 @@ std::string to_string(ipv6_address x) {
error
parse
(
string_view
str
,
ipv6_address
&
dest
)
{
using
namespace
detail
;
parser
::
state
<
string_view
::
iterator
>
res
{
str
.
begin
(),
str
.
end
()};
ipv6_address_consumer
f
{
dest
};
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
parser
::
read_ipv6_address
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
return
none
;
...
...
libcaf_core/src/make_config_option.cpp
View file @
11c4eaca
...
...
@@ -24,9 +24,11 @@
#include "caf/optional.hpp"
#define DEFAULT_META(type, parse_fun) \
config_option::meta_state type##_meta_state{ \
default_config_option_check<type>, default_config_option_store<type>, \
get_impl<type>, parse_fun, detail::type_name<type>()};
config_option::meta_state \
type##_meta_state{default_config_option_check<type>, \
default_config_option_store<type>, get_impl<type>, \
parse_fun, \
select_config_value_access_t<type>::type_name()};
using
std
::
string
;
...
...
@@ -75,43 +77,34 @@ config_value bool_get_neg(const void* ptr) {
}
meta_state
bool_neg_meta
{
detail
::
check_impl
<
bool
>
,
bool_store_neg
,
bool_get_neg
,
nullptr
,
detail
::
type_name
<
bool
>
()};
meta_state
us_res_meta
{
[](
const
config_value
&
x
)
->
error
{
if
(
holds_alternative
<
timespan
>
(
x
))
return
none
;
return
make_error
(
pec
::
type_mismatch
);
},
[](
void
*
ptr
,
const
config_value
&
x
)
{
*
static_cast
<
size_t
*>
(
ptr
)
=
static_cast
<
size_t
>
(
get
<
timespan
>
(
x
).
count
())
/
1000
;
},
[](
const
void
*
ptr
)
->
config_value
{
auto
ival
=
static_cast
<
int64_t
>
(
*
static_cast
<
const
size_t
*>
(
ptr
));
timespan
val
{
ival
*
1000
};
return
config_value
{
val
};
},
nullptr
,
detail
::
type_name
<
timespan
>
()
};
meta_state
ms_res_meta
{[](
const
config_value
&
x
)
->
error
{
if
(
holds_alternative
<
timespan
>
(
x
))
return
none
;
return
make_error
(
pec
::
type_mismatch
);
},
[](
void
*
ptr
,
const
config_value
&
x
)
{
*
static_cast
<
size_t
*>
(
ptr
)
=
static_cast
<
size_t
>
(
get
<
timespan
>
(
x
).
count
()
/
1000000
);
},
[](
const
void
*
ptr
)
->
config_value
{
auto
ival
=
static_cast
<
int64_t
>
(
*
static_cast
<
const
size_t
*>
(
ptr
));
timespan
val
{
ival
*
1000000
};
return
config_value
{
val
};
},
nullptr
,
detail
::
type_name
<
timespan
>
()};
nullptr
,
select_config_value_access_t
<
bool
>::
type_name
()};
error
check_timespan
(
const
config_value
&
x
)
{
if
(
holds_alternative
<
timespan
>
(
x
))
return
none
;
return
make_error
(
pec
::
type_mismatch
);
}
template
<
uint64_t
Denominator
>
void
store_timespan
(
void
*
ptr
,
const
config_value
&
x
)
{
*
static_cast
<
size_t
*>
(
ptr
)
=
static_cast
<
size_t
>
(
get
<
timespan
>
(
x
).
count
())
/
Denominator
;
}
template
<
uint64_t
Denominator
>
config_value
get_timespan
(
const
void
*
ptr
)
{
auto
ival
=
static_cast
<
int64_t
>
(
*
static_cast
<
const
size_t
*>
(
ptr
));
timespan
val
{
ival
*
Denominator
};
return
config_value
{
val
};
}
meta_state
us_res_meta
{
check_timespan
,
store_timespan
<
1000
>
,
get_timespan
<
1000
>
,
nullptr
,
select_config_value_access_t
<
timespan
>::
type_name
()};
meta_state
ms_res_meta
{
check_timespan
,
store_timespan
<
1000000
>
,
get_timespan
<
1000000
>
,
nullptr
,
select_config_value_access_t
<
timespan
>::
type_name
()};
}
// namespace
...
...
libcaf_core/src/pec.cpp
View file @
11c4eaca
...
...
@@ -29,7 +29,7 @@ error make_error(pec code) {
return
{
static_cast
<
uint8_t
>
(
code
),
atom
(
"parser"
)};
}
error
make_error
(
pec
code
,
size_t
line
,
size
_t
column
)
{
error
make_error
(
pec
code
,
int32_t
line
,
int32
_t
column
)
{
config_value
::
dictionary
context
;
context
[
"line"
]
=
line
;
context
[
"column"
]
=
column
;
...
...
libcaf_core/src/uri.cpp
View file @
11c4eaca
...
...
@@ -146,12 +146,11 @@ std::string to_string(const uri::authority_type& x) {
}
error
parse
(
string_view
str
,
uri
&
dest
)
{
detail
::
parse
_state
ps
{
str
.
begin
(),
str
.
end
()};
string_parser
_state
ps
{
str
.
begin
(),
str
.
end
()};
parse
(
ps
,
dest
);
if
(
ps
.
code
==
pec
::
success
)
return
none
;
return
make_error
(
ps
.
code
,
static_cast
<
size_t
>
(
ps
.
line
),
static_cast
<
size_t
>
(
ps
.
column
));
return
make_error
(
ps
);
}
expected
<
uri
>
make_uri
(
string_view
str
)
{
...
...
libcaf_core/test/config_option.cpp
View file @
11c4eaca
...
...
@@ -185,7 +185,6 @@ CAF_TEST(type timespan) {
CAF_TEST
(
lists
)
{
using
int_list
=
std
::
vector
<
int
>
;
CAF_CHECK_EQUAL
(
read
<
int_list
>
(
""
),
int_list
({}));
CAF_CHECK_EQUAL
(
read
<
int_list
>
(
"[]"
),
int_list
({}));
CAF_CHECK_EQUAL
(
read
<
int_list
>
(
"1, 2, 3"
),
int_list
({
1
,
2
,
3
}));
CAF_CHECK_EQUAL
(
read
<
int_list
>
(
"[1, 2, 3]"
),
int_list
({
1
,
2
,
3
}));
...
...
libcaf_core/test/detail/ini_consumer.cpp
View file @
11c4eaca
...
...
@@ -33,7 +33,7 @@ using ls = std::vector<std::string>;
namespace
{
const
char
test_ini
[]
=
R"(
const
expr
const
string_view
test_ini
=
R"(
is_server=true
port=4242
nodes=["sun", "venus", ]
...
...
@@ -44,7 +44,7 @@ file-name = "foobar.ini" ; our file name
impl = 'foo';some atom
)"
;
const
char
test_ini2
[]
=
R"(
const
expr
const
string_view
test_ini2
=
R"(
is_server = true
logger = {
file-name = "foobar.ini"
...
...
@@ -58,7 +58,6 @@ nodes = ["sun", "venus"]
)"
;
struct
fixture
{
detail
::
parser
::
state
<
std
::
string
::
const_iterator
>
res
;
config_option_set
options
;
settings
config
;
...
...
@@ -78,20 +77,18 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE
(
ini_consumer_tests
,
fixture
)
CAF_TEST
(
ini_value_consumer
)
{
st
d
::
string
str
=
R"("hello world")"
;
st
ring_view
str
=
R"("hello world")"
;
detail
::
ini_value_consumer
consumer
;
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_ini_value
(
res
,
consumer
);
CAF_CHECK_EQUAL
(
res
.
code
,
pec
::
success
);
CAF_CHECK_EQUAL
(
get
<
string
>
(
consumer
.
result
),
"hello world"
);
}
CAF_TEST
(
ini_consumer
)
{
st
d
::
string
str
=
test_ini
;
st
ring_view
str
=
test_ini
;
detail
::
ini_consumer
consumer
{
options
,
config
};
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_ini
(
res
,
consumer
);
CAF_CHECK_EQUAL
(
res
.
code
,
pec
::
success
);
CAF_CHECK_EQUAL
(
get
<
bool
>
(
config
,
"is_server"
),
true
);
...
...
@@ -103,12 +100,11 @@ CAF_TEST(ini_consumer) {
}
CAF_TEST
(
simplified
syntax
)
{
st
d
::
string
str
=
test_ini
;
st
ring_view
str
=
test_ini
;
CAF_MESSAGE
(
"read test_ini"
);
{
detail
::
ini_consumer
consumer
{
options
,
config
};
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_ini
(
res
,
consumer
);
CAF_CHECK_EQUAL
(
res
.
code
,
pec
::
success
);
}
...
...
@@ -117,8 +113,7 @@ CAF_TEST(simplified syntax) {
CAF_MESSAGE
(
"read test_ini2"
);
{
detail
::
ini_consumer
consumer
{
options
,
config2
};
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_ini
(
res
,
consumer
);
CAF_CHECK_EQUAL
(
res
.
code
,
pec
::
success
);
}
...
...
libcaf_core/test/detail/parse.cpp
View file @
11c4eaca
...
...
@@ -61,11 +61,11 @@ timespan operator"" _h(unsigned long long x) {
template
<
class
T
>
expected
<
T
>
read
(
string_view
str
)
{
T
result
;
detail
::
parse
_state
ps
{
str
.
begin
(),
str
.
end
()};
string_parser
_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parse
(
ps
,
result
);
if
(
ps
.
code
==
pec
::
success
)
return
result
;
return
make_error
(
ps
.
code
,
ps
.
line
,
ps
.
column
);
return
make_error
(
ps
);
}
}
// namespace
...
...
libcaf_core/test/detail/parser/read_atom.cpp
View file @
11c4eaca
...
...
@@ -24,6 +24,8 @@
#include <string>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
...
...
@@ -40,11 +42,9 @@ struct atom_parser_consumer {
using
res_t
=
variant
<
pec
,
atom_value
>
;
struct
atom_parser
{
res_t
operator
()(
std
::
string
str
)
{
detail
::
parser
::
state
<
std
::
string
::
iterator
>
res
;
res_t
operator
()(
string_view
str
)
{
atom_parser_consumer
f
;
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_atom
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
return
f
.
x
;
...
...
libcaf_core/test/detail/parser/read_bool.cpp
View file @
11c4eaca
...
...
@@ -24,6 +24,8 @@
#include <string>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
...
...
@@ -40,11 +42,9 @@ struct bool_parser_consumer {
using
res_t
=
variant
<
pec
,
bool
>
;
struct
bool_parser
{
res_t
operator
()(
std
::
string
str
)
{
detail
::
parser
::
state
<
std
::
string
::
iterator
>
res
;
res_t
operator
()(
string_view
str
)
{
bool_parser_consumer
f
;
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_bool
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
return
f
.
x
;
...
...
libcaf_core/test/detail/parser/read_floating_point.cpp
View file @
11c4eaca
...
...
@@ -24,8 +24,9 @@
#include <string>
#include "caf/detail/parser/state.hpp"
#include "caf/pec.hpp"
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
...
...
@@ -43,7 +44,7 @@ struct double_consumer {
optional
<
double
>
read
(
string_view
str
)
{
double_consumer
consumer
;
detail
::
parser
::
state
<
string_view
::
iterator
>
ps
{
str
.
begin
(),
str
.
end
()};
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_floating_point
(
ps
,
consumer
);
if
(
ps
.
code
!=
pec
::
success
)
return
none
;
...
...
libcaf_core/test/detail/parser/read_ini.cpp
View file @
11c4eaca
...
...
@@ -25,6 +25,11 @@
#include <string>
#include <vector>
#include "caf/config_value.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
using
namespace
caf
;
namespace
{
...
...
@@ -85,11 +90,9 @@ struct ini_consumer {
};
struct
fixture
{
expected
<
log_type
>
parse
(
std
::
string
str
,
bool
expect_success
=
true
)
{
detail
::
parser
::
state
<
std
::
string
::
iterator
>
res
;
expected
<
log_type
>
parse
(
string_view
str
,
bool
expect_success
=
true
)
{
test_consumer
f
;
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_ini
(
res
,
f
);
if
((
res
.
code
==
pec
::
success
)
!=
expect_success
)
{
CAF_MESSAGE
(
"unexpected parser result state: "
<<
res
.
code
);
...
...
@@ -105,7 +108,7 @@ log_type make_log(Ts&&... xs) {
}
// Tests basic functionality.
const
auto
ini0
=
R"(
const
expr
const
string_view
ini0
=
R"(
[1group]
1value=321
[_foo]
...
...
@@ -204,7 +207,7 @@ const auto ini0_log = make_log(
// clang-format on
// Tests nested parameters.
const
auto
ini1
=
R"(
const
expr
const
string_view
ini1
=
R"(
foo {
bar = {
value1 = 1
...
...
@@ -241,11 +244,11 @@ const auto ini1_log = make_log(
);
// clang-format on
const
auto
ini2
=
"#"
;
const
expr
const
string_view
ini2
=
"#"
;
const
auto
ini2_log
=
make_log
();
const
auto
ini3
=
"; foobar
\n
!"
;
const
expr
const
string_view
ini3
=
"; foobar
\n
!"
;
const
auto
ini3_log
=
make_log
();
...
...
libcaf_core/test/detail/parser/read_number.cpp
View file @
11c4eaca
...
...
@@ -27,7 +27,9 @@
#include "caf/detail/parser/add_ascii.hpp"
#include "caf/detail/parser/sub_ascii.hpp"
#include "caf/expected.hpp"
#include "caf/parser_state.hpp"
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
...
...
@@ -67,11 +69,9 @@ bool operator==(const res_t& x, const res_t& y) {
}
struct
numbers_parser
{
res_t
operator
()(
std
::
string
str
)
{
detail
::
parser
::
state
<
std
::
string
::
iterator
>
res
;
res_t
operator
()(
string_view
str
)
{
numbers_parser_consumer
f
;
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_number
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
return
f
.
x
;
...
...
libcaf_core/test/detail/parser/read_number_or_timespan.cpp
View file @
11c4eaca
...
...
@@ -24,6 +24,8 @@
#include <string>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
...
...
@@ -68,11 +70,9 @@ bool operator==(const res_t& x, const res_t& y) {
}
struct
number_or_timespan_parser
{
res_t
operator
()(
std
::
string
str
)
{
detail
::
parser
::
state
<
std
::
string
::
iterator
>
res
;
res_t
operator
()(
string_view
str
)
{
number_or_timespan_parser_consumer
f
;
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_number_or_timespan
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
return
f
.
x
;
...
...
libcaf_core/test/detail/parser/read_signed_integer.cpp
View file @
11c4eaca
...
...
@@ -22,8 +22,9 @@
#include "caf/test/dsl.hpp"
#include "caf/
detail/parser/
state.hpp"
#include "caf/
parser_
state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
...
...
@@ -43,7 +44,7 @@ struct signed_integer_consumer {
template
<
class
T
>
optional
<
T
>
read
(
string_view
str
)
{
signed_integer_consumer
<
T
>
consumer
;
detail
::
parser
::
state
<
string_view
::
iterator
>
ps
{
str
.
begin
(),
str
.
end
()};
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_signed_integer
(
ps
,
consumer
);
if
(
ps
.
code
!=
pec
::
success
)
return
none
;
...
...
@@ -53,7 +54,7 @@ optional<T> read(string_view str) {
template
<
class
T
>
bool
underflow
(
string_view
str
)
{
signed_integer_consumer
<
T
>
consumer
;
detail
::
parser
::
state
<
string_view
::
iterator
>
ps
{
str
.
begin
(),
str
.
end
()};
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_signed_integer
(
ps
,
consumer
);
return
ps
.
code
==
pec
::
integer_underflow
;
}
...
...
@@ -61,7 +62,7 @@ bool underflow(string_view str) {
template
<
class
T
>
bool
overflow
(
string_view
str
)
{
signed_integer_consumer
<
T
>
consumer
;
detail
::
parser
::
state
<
string_view
::
iterator
>
ps
{
str
.
begin
(),
str
.
end
()};
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_signed_integer
(
ps
,
consumer
);
return
ps
.
code
==
pec
::
integer_overflow
;
}
...
...
libcaf_core/test/detail/parser/read_string.cpp
View file @
11c4eaca
...
...
@@ -24,6 +24,8 @@
#include <string>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
...
...
@@ -40,11 +42,9 @@ struct string_parser_consumer {
using
res_t
=
variant
<
pec
,
std
::
string
>
;
struct
string_parser
{
res_t
operator
()(
std
::
string
str
)
{
detail
::
parser
::
state
<
std
::
string
::
iterator
>
res
;
res_t
operator
()(
string_view
str
)
{
string_parser_consumer
f
;
res
.
i
=
str
.
begin
();
res
.
e
=
str
.
end
();
string_parser_state
res
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_string
(
res
,
f
);
if
(
res
.
code
==
pec
::
success
)
return
f
.
x
;
...
...
libcaf_core/test/detail/parser/read_timespan.cpp
View file @
11c4eaca
...
...
@@ -24,6 +24,10 @@
#include <chrono>
#include "caf/parser_state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
namespace
{
...
...
@@ -62,7 +66,7 @@ struct timespan_consumer {
optional
<
timespan
>
read
(
string_view
str
)
{
timespan_consumer
consumer
;
detail
::
parser
::
state
<
string_view
::
iterator
>
ps
{
str
.
begin
(),
str
.
end
()};
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_timespan
(
ps
,
consumer
);
if
(
ps
.
code
!=
pec
::
success
)
return
none
;
...
...
libcaf_core/test/detail/parser/read_unsigned_integer.cpp
View file @
11c4eaca
...
...
@@ -22,8 +22,9 @@
#include "caf/test/dsl.hpp"
#include "caf/
detail/parser/
state.hpp"
#include "caf/
parser_
state.hpp"
#include "caf/string_view.hpp"
#include "caf/variant.hpp"
using
namespace
caf
;
...
...
@@ -43,7 +44,7 @@ struct unsigned_integer_consumer {
template
<
class
T
>
optional
<
T
>
read
(
string_view
str
)
{
unsigned_integer_consumer
<
T
>
consumer
;
detail
::
parser
::
state
<
string_view
::
iterator
>
ps
{
str
.
begin
(),
str
.
end
()};
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_unsigned_integer
(
ps
,
consumer
);
if
(
ps
.
code
!=
pec
::
success
)
return
none
;
...
...
@@ -53,7 +54,7 @@ optional<T> read(string_view str) {
template
<
class
T
>
bool
overflow
(
string_view
str
)
{
unsigned_integer_consumer
<
T
>
consumer
;
detail
::
parser
::
state
<
string_view
::
iterator
>
ps
{
str
.
begin
(),
str
.
end
()};
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_unsigned_integer
(
ps
,
consumer
);
return
ps
.
code
==
pec
::
integer_overflow
;
}
...
...
libcaf_core/test/make_config_value_field.cpp
0 → 100644
View file @
11c4eaca
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 make_config_value_field
#include "caf/make_config_value_field.hpp"
#include "caf/test/dsl.hpp"
#include "caf/config_option_set.hpp"
#include "caf/config_value_object_access.hpp"
using
namespace
caf
;
namespace
{
struct
foobar
{
int
foo
=
0
;
std
::
string
bar
;
foobar
()
=
default
;
foobar
(
int
foo
,
std
::
string
bar
)
:
foo
(
foo
),
bar
(
std
::
move
(
bar
))
{
// nop
}
};
std
::
string
to_string
(
const
foobar
&
x
)
{
return
deep_to_string
(
std
::
forward_as_tuple
(
x
.
foo
,
x
.
bar
));
}
bool
operator
==
(
const
foobar
&
x
,
const
foobar
&
y
)
{
return
x
.
foo
==
y
.
foo
&&
x
.
bar
==
y
.
bar
;
}
bool
foo_valid
(
const
int
&
x
)
{
return
x
>=
0
;
}
int
get_foo_fun
(
foobar
x
)
{
return
x
.
foo
;
}
void
set_foo_fun
(
foobar
&
x
,
const
int
&
value
)
{
x
.
foo
=
value
;
}
struct
get_foo_t
{
int
operator
()(
const
foobar
&
x
)
const
noexcept
{
return
x
.
foo
;
}
};
struct
set_foo_t
{
int
&
operator
()(
foobar
&
x
,
int
value
)
const
noexcept
{
x
.
foo
=
value
;
return
x
.
foo
;
}
};
struct
foobar_trait
{
using
object_type
=
foobar
;
static
std
::
string
type_name
()
{
return
"foobar"
;
}
static
span
<
config_value_field
<
object_type
>*>
fields
()
{
static
auto
singleton
=
make_config_value_field_storage
(
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
123
),
make_config_value_field
(
"bar"
,
&
foobar
::
bar
));
return
singleton
.
fields
();
}
};
struct
foobar_foobar
{
foobar
x
;
foobar
y
;
foobar_foobar
()
=
default
;
foobar_foobar
(
foobar
x
,
foobar
y
)
:
x
(
x
),
y
(
y
)
{
// nop
}
};
std
::
string
to_string
(
const
foobar_foobar
&
x
)
{
return
deep_to_string
(
std
::
forward_as_tuple
(
x
.
x
,
x
.
y
));
}
bool
operator
==
(
const
foobar_foobar
&
x
,
const
foobar_foobar
&
y
)
{
return
x
.
x
==
y
.
x
&&
x
.
y
==
y
.
y
;
}
struct
foobar_foobar_trait
{
using
object_type
=
foobar_foobar
;
static
std
::
string
type_name
()
{
return
"foobar-foobar"
;
}
static
span
<
config_value_field
<
object_type
>*>
fields
()
{
static
auto
singleton
=
make_config_value_field_storage
(
make_config_value_field
(
"x"
,
&
foobar_foobar
::
x
),
make_config_value_field
(
"y"
,
&
foobar_foobar
::
y
));
return
singleton
.
fields
();
}
};
struct
fixture
{
get_foo_t
get_foo
;
set_foo_t
set_foo
;
config_option_set
opts
;
void
test_foo_field
(
config_value_field
<
foobar
>&
foo_field
)
{
foobar
x
;
CAF_CHECK_EQUAL
(
foo_field
.
name
(),
"foo"
);
CAF_REQUIRE
(
foo_field
.
has_default
());
CAF_CHECK
(
foo_field
.
valid
(
x
));
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
0
));
foo_field
.
set_default
(
x
);
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
42
));
CAF_CHECK
(
!
foo_field
.
type_check
(
config_value
(
1.
)));
CAF_CHECK
(
foo_field
.
type_check
(
config_value
(
-
1
)));
foo_field
.
set
(
x
,
config_value
(
-
1
));
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
-
1
));
CAF_CHECK
(
!
foo_field
.
valid
(
x
));
string_view
input
=
"123"
;
string_parser_state
ps
{
input
.
begin
(),
input
.
end
()};
foo_field
.
parse_cli
(
ps
,
x
);
CAF_CHECK_EQUAL
(
ps
.
code
,
pec
::
success
);
CAF_CHECK_EQUAL
(
foo_field
.
get
(
x
),
config_value
(
123
));
}
template
<
class
T
>
expected
<
T
>
read
(
std
::
vector
<
std
::
string
>
args
)
{
settings
cfg
;
auto
res
=
opts
.
parse
(
cfg
,
args
);
if
(
res
.
first
!=
pec
::
success
)
return
make_error
(
res
.
first
,
*
res
.
second
);
auto
x
=
get_if
<
T
>
(
&
cfg
,
"value"
);
if
(
x
==
none
)
return
sec
::
invalid_argument
;
return
*
x
;
};
};
}
// namespace
namespace
caf
{
template
<
>
struct
config_value_access
<
foobar
>
:
config_value_object_access
<
foobar_trait
>
{
};
template
<
>
struct
config_value_access
<
foobar_foobar
>
:
config_value_object_access
<
foobar_foobar_trait
>
{};
}
// namespace caf
CAF_TEST_FIXTURE_SCOPE
(
make_config_value_field_tests
,
fixture
)
CAF_TEST
(
construction
from
pointer
to
member
)
{
make_config_value_field
(
"foo"
,
&
foobar
::
foo
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
none
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
none
,
nullptr
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
,
nullptr
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
,
foo_valid
);
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
,
[](
const
int
&
x
)
{
return
x
!=
0
;
});
}
CAF_TEST
(
pointer
to
member
access
)
{
auto
foo_field
=
make_config_value_field
(
"foo"
,
&
foobar
::
foo
,
42
,
foo_valid
);
test_foo_field
(
foo_field
);
}
CAF_TEST
(
construction
from
getter
and
setter
)
{
auto
get_foo_lambda
=
[](
const
foobar
&
x
)
{
return
x
.
foo
;
};
auto
set_foo_lambda
=
[](
foobar
&
x
,
int
value
)
{
x
.
foo
=
value
;
};
make_config_value_field
(
"foo"
,
get_foo
,
set_foo
);
make_config_value_field
(
"foo"
,
get_foo_fun
,
set_foo
);
make_config_value_field
(
"foo"
,
get_foo_fun
,
set_foo_fun
);
make_config_value_field
(
"foo"
,
get_foo_lambda
,
set_foo_lambda
);
}
CAF_TEST
(
getter
and
setter
access
)
{
auto
foo_field
=
make_config_value_field
(
"foo"
,
get_foo
,
set_foo
,
42
,
foo_valid
);
test_foo_field
(
foo_field
);
}
CAF_TEST
(
oject
access
from
dictionary
-
foobar
)
{
settings
x
;
put
(
x
,
"my-value.bar"
,
"hello"
);
CAF_MESSAGE
(
"without foo member"
);
{
CAF_REQUIRE
(
holds_alternative
<
foobar
>
(
x
,
"my-value"
));
CAF_REQUIRE
(
get_if
<
foobar
>
(
&
x
,
"my-value"
)
!=
caf
::
none
);
auto
fb
=
get
<
foobar
>
(
x
,
"my-value"
);
CAF_CHECK_EQUAL
(
fb
.
foo
,
123
);
CAF_CHECK_EQUAL
(
fb
.
bar
,
"hello"
);
}
CAF_MESSAGE
(
"with foo member"
);
put
(
x
,
"my-value.foo"
,
42
);
{
CAF_REQUIRE
(
holds_alternative
<
foobar
>
(
x
,
"my-value"
));
CAF_REQUIRE
(
get_if
<
foobar
>
(
&
x
,
"my-value"
)
!=
caf
::
none
);
auto
fb
=
get
<
foobar
>
(
x
,
"my-value"
);
CAF_CHECK_EQUAL
(
fb
.
foo
,
42
);
CAF_CHECK_EQUAL
(
fb
.
bar
,
"hello"
);
}
}
CAF_TEST
(
oject
access
from
dictionary
-
foobar_foobar
)
{
settings
x
;
put
(
x
,
"my-value.x.foo"
,
1
);
put
(
x
,
"my-value.x.bar"
,
"hello"
);
put
(
x
,
"my-value.y.bar"
,
"world"
);
CAF_REQUIRE
(
holds_alternative
<
foobar_foobar
>
(
x
,
"my-value"
));
CAF_REQUIRE
(
get_if
<
foobar_foobar
>
(
&
x
,
"my-value"
)
!=
caf
::
none
);
auto
fbfb
=
get
<
foobar_foobar
>
(
x
,
"my-value"
);
CAF_CHECK_EQUAL
(
fbfb
.
x
.
foo
,
1
);
CAF_CHECK_EQUAL
(
fbfb
.
x
.
bar
,
"hello"
);
CAF_CHECK_EQUAL
(
fbfb
.
y
.
foo
,
123
);
CAF_CHECK_EQUAL
(
fbfb
.
y
.
bar
,
"world"
);
}
CAF_TEST
(
object
access
from
CLI
arguments
-
foobar
)
{
opts
.
add
<
foobar
>
(
"value,v"
,
"some value"
);
CAF_CHECK_EQUAL
(
read
<
foobar
>
({
"--value={foo = 1, bar = hello}"
}),
foobar
(
1
,
"hello"
));
CAF_CHECK_EQUAL
(
read
<
foobar
>
({
"-v{bar =
\"
hello
\"
}"
}),
foobar
(
123
,
"hello"
));
CAF_CHECK_EQUAL
(
read
<
foobar
>
({
"-v"
,
"{foo = 1, bar =hello ,}"
}),
foobar
(
1
,
"hello"
));
}
CAF_TEST
(
object
access
from
CLI
arguments
-
foobar_foobar
)
{
using
fbfb
=
foobar_foobar
;
opts
.
add
<
fbfb
>
(
"value,v"
,
"some value"
);
CAF_CHECK_EQUAL
(
read
<
fbfb
>
({
"-v{x={bar = hello},y={foo=1,bar=world!},}"
}),
fbfb
({
123
,
"hello"
},
{
1
,
"world!"
}));
}
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