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
31be7eb2
Commit
31be7eb2
authored
Dec 23, 2020
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-implement config_option using get_as
parent
f6ae028a
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
157 additions
and
448 deletions
+157
-448
libcaf_core/caf/config_option.hpp
libcaf_core/caf/config_option.hpp
+19
-15
libcaf_core/caf/config_option_adder.hpp
libcaf_core/caf/config_option_adder.hpp
+2
-6
libcaf_core/caf/config_value.hpp
libcaf_core/caf/config_value.hpp
+10
-170
libcaf_core/caf/detail/dispatch_parse_cli.hpp
libcaf_core/caf/detail/dispatch_parse_cli.hpp
+0
-61
libcaf_core/caf/detail/type_traits.hpp
libcaf_core/caf/detail/type_traits.hpp
+38
-0
libcaf_core/caf/make_config_option.hpp
libcaf_core/caf/make_config_option.hpp
+17
-37
libcaf_core/src/actor_system_config.cpp
libcaf_core/src/actor_system_config.cpp
+8
-7
libcaf_core/src/config_option.cpp
libcaf_core/src/config_option.cpp
+11
-3
libcaf_core/src/config_option_adder.cpp
libcaf_core/src/config_option_adder.cpp
+5
-0
libcaf_core/src/config_option_set.cpp
libcaf_core/src/config_option_set.cpp
+26
-16
libcaf_core/src/detail/config_consumer.cpp
libcaf_core/src/detail/config_consumer.cpp
+1
-1
libcaf_core/src/make_config_option.cpp
libcaf_core/src/make_config_option.cpp
+13
-48
libcaf_core/test/config_option.cpp
libcaf_core/test/config_option.cpp
+7
-7
libcaf_core/test/config_value.cpp
libcaf_core/test/config_value.cpp
+0
-77
No files found.
libcaf_core/caf/config_option.hpp
View file @
31be7eb2
...
...
@@ -36,19 +36,17 @@ public:
/// Custom vtable-like struct for delegating to type-specific functions and
/// storing type-specific information shared by several config options.
struct
meta_state
{
/// Performs a type check on the config value and then stores the converted
/// value in the given storage location unless the storage pointer was set
/// to `nullptr`.
error
(
*
store
)(
void
*
,
const
config_value
&
);
/// Tries to perform this sequence of steps:
/// - Convert the config value to the type of the config option.
/// - Assign the converted value back to the config value to synchronize
/// conversions back to the caller.
/// - Store the converted value in the pointer unless it is `nullptr`.
error
(
*
sync
)(
void
*
,
config_value
&
);
/// Tries to extract a value from the given location. Exists for backward
/// compatibility only and will get removed with CAF 0.17.
config_value
(
*
get
)(
const
void
*
);
/// Tries to parse an input string. Stores and returns the parsed value on
/// success, returns an error otherwise.
expected
<
config_value
>
(
*
parse
)(
void
*
,
string_view
);
/// Human-readable name of the option's type.
std
::
string
type_name
;
};
...
...
@@ -88,9 +86,19 @@ public:
/// Returns the full name for this config option as "<category>.<long name>".
string_view
full_name
()
const
noexcept
;
/// Performs a type check for `x` and then stores `x` in this option unless it
/// is stateless.
error
store
(
const
config_value
&
x
)
const
;
/// Synchronizes the value of this config option with `x` and vice versa.
///
/// Tries to perform this sequence of steps:
/// - Convert the config value to the type of the config option.
/// - Assign the converted value back to the config value to synchronize
/// conversions back to the caller.
/// - Store the converted value unless this option is stateless.
error
sync
(
config_value
&
x
)
const
;
[[
deprecated
(
"use sync instead"
)]]
error
store
(
const
config_value
&
x
)
const
;
[[
deprecated
(
"use sync instead"
)]]
expected
<
config_value
>
parse
(
string_view
input
)
const
;
/// Returns a human-readable representation of this option's expected type.
string_view
type_name
()
const
noexcept
;
...
...
@@ -101,10 +109,6 @@ public:
/// Returns whether the category is optional for CLI options.
bool
has_flat_cli_name
()
const
noexcept
;
/// Tries to parse an input string. Stores and returns the parsed value on
/// success, returns an error otherwise.
expected
<
config_value
>
parse
(
string_view
input
)
const
;
/// @private
// TODO: remove with CAF 0.17
optional
<
config_value
>
get
()
const
;
...
...
libcaf_core/caf/config_option_adder.hpp
View file @
31be7eb2
...
...
@@ -52,14 +52,10 @@ public:
config_option_adder
&
add_neg
(
bool
&
ref
,
string_view
name
,
string_view
description
);
/// For backward compatibility only. Do not use for new code!
/// @private
config_option_adder
&
[[
deprecated
(
"use timespan options instead"
)]]
config_option_adder
&
add_us
(
size_t
&
ref
,
string_view
name
,
string_view
description
);
/// For backward compatibility only. Do not use for new code!
/// @private
config_option_adder
&
[[
deprecated
(
"use timespan options instead"
)]]
config_option_adder
&
add_ms
(
size_t
&
ref
,
string_view
name
,
string_view
description
);
private:
...
...
libcaf_core/caf/config_value.hpp
View file @
31be7eb2
...
...
@@ -225,7 +225,7 @@ public:
template
<
class
T
>
error
assign
(
const
T
&
x
)
{
config_value_writer
writer
{
this
};
if
(
detail
::
save
(
writer
,
x
))
if
(
writer
.
apply
(
x
))
return
{};
else
return
{
writer
.
move_error
()};
...
...
@@ -306,22 +306,6 @@ private:
/// @relates config_value
CAF_CORE_EXPORT
std
::
string
to_string
(
const
config_value
&
x
);
// -- convenience constants ----------------------------------------------------
/// Type of the `top_level_cli_parsing` constant.
using
top_level_cli_parsing_t
=
std
::
false_type
;
/// Signals parsing of top-level config values when used as third argument to
/// `parse_cli`.
constexpr
auto
top_level_cli_parsing
=
top_level_cli_parsing_t
{};
/// Type of the `top_level_cli_parsing` constant.
using
nested_cli_parsing_t
=
std
::
true_type
;
/// Signals parsing of nested config values when used as third argument to
/// `parse_cli`.
constexpr
auto
nested_cli_parsing
=
nested_cli_parsing_t
{};
// -- conversion via get_as ----------------------------------------------------
template
<
class
T
>
...
...
@@ -464,12 +448,17 @@ expected<T> get_as(const config_value& x, inspector_access_type::list) {
if
(
auto
wrapped_values
=
x
.
to_list
())
{
using
value_type
=
typename
T
::
value_type
;
T
result
;
if
constexpr
(
detail
::
has_reserve_t
<
T
>
)
result
.
reserve
(
wrapped_values
->
size
());
for
(
const
auto
&
wrapped_value
:
*
wrapped_values
)
if
(
auto
maybe_value
=
get_as
<
value_type
>
(
wrapped_value
))
if
(
auto
maybe_value
=
get_as
<
value_type
>
(
wrapped_value
))
{
if
constexpr
(
detail
::
has_emplace_back_t
<
T
>
)
result
.
emplace_back
(
std
::
move
(
*
maybe_value
));
else
result
.
insert
(
result
.
end
(),
std
::
move
(
*
maybe_value
));
}
else
{
return
{
std
::
move
(
maybe_value
.
error
())};
}
return
{
std
::
move
(
result
)};
}
else
{
return
{
std
::
move
(
wrapped_values
.
error
())};
...
...
@@ -566,11 +555,6 @@ struct default_config_value_access {
static
T
convert
(
T
x
)
{
return
x
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
x
,
Nested
)
{
detail
::
parse
(
ps
,
x
);
}
};
/// @relates config_value
...
...
@@ -626,11 +610,6 @@ struct CAF_CORE_EXPORT config_value_access<timespan> {
static
timespan
convert
(
timespan
x
)
{
return
x
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
timespan
&
x
,
Nested
)
{
detail
::
parse
(
ps
,
x
);
}
};
template
<
>
...
...
@@ -656,11 +635,6 @@ struct CAF_CORE_EXPORT config_value_access<float> {
static
double
convert
(
float
x
)
{
return
x
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
float
&
x
,
Nested
)
{
detail
::
parse
(
ps
,
x
);
}
};
template
<
>
...
...
@@ -686,15 +660,6 @@ struct CAF_CORE_EXPORT config_value_access<std::string> {
static
std
::
string
convert
(
std
::
string
x
)
{
return
x
;
}
template
<
bool
IsNested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
std
::
string
&
x
,
std
::
integral_constant
<
bool
,
IsNested
>
)
{
if
constexpr
(
IsNested
)
detail
::
parse_element
(
ps
,
x
,
",={}[]"
);
else
detail
::
parse
(
ps
,
x
);
}
};
// -- implementation details for get/get_if/holds_alternative ------------------
...
...
@@ -818,11 +783,6 @@ struct integral_config_value_access {
static
T
convert
(
T
x
)
{
return
x
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
x
,
Nested
)
{
detail
::
parse
(
ps
,
x
);
}
};
template
<
class
T
>
...
...
@@ -875,74 +835,6 @@ struct list_config_value_access {
result
.
emplace_back
(
value_access
::
convert
(
x
));
return
result
;
}
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
xs
,
top_level_cli_parsing_t
)
{
bool
has_open_token
;
auto
val_token
=
config_value_access_token
<
value_type
>
();
if
constexpr
(
std
::
is_same
<
decltype
(
val_token
),
config_value_access_type
::
list
>::
value
)
{
// The outer square brackets are optional in nested lists. This means we
// need to check for "[[" at the beginning and otherwise we assume the
// leading '[' was omitted.
string_parser_state
tmp
{
ps
.
i
,
ps
.
e
};
has_open_token
=
tmp
.
consume
(
'['
)
&&
tmp
.
consume
(
'['
);
if
(
has_open_token
)
ps
.
consume
(
'['
);
}
else
{
has_open_token
=
ps
.
consume
(
'['
);
}
do
{
ps
.
skip_whitespaces
();
if
(
has_open_token
)
{
if
(
ps
.
consume
(
']'
))
{
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
return
;
}
}
else
if
(
ps
.
at_end
())
{
// Allow trailing commas and empty strings.
ps
.
code
=
pec
::
success
;
return
;
}
value_type
tmp
;
value_access
::
parse_cli
(
ps
,
tmp
,
nested_cli_parsing
);
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
;
return
;
}
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
}
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
xs
,
nested_cli_parsing_t
)
{
if
(
!
ps
.
consume
(
'['
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
}
do
{
if
(
ps
.
consume
(
']'
))
{
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
return
;
}
value_type
tmp
;
value_access
::
parse_cli
(
ps
,
tmp
,
nested_cli_parsing
);
if
(
ps
.
code
>
pec
::
trailing_character
)
return
;
xs
.
insert
(
xs
.
end
(),
std
::
move
(
tmp
));
}
while
(
ps
.
consume
(
','
));
if
(
!
ps
.
consume
(
']'
))
{
ps
.
code
=
ps
.
at_end
()
?
pec
::
unexpected_eof
:
pec
::
unexpected_character
;
return
;
}
ps
.
skip_whitespaces
();
ps
.
code
=
ps
.
at_end
()
?
pec
::
success
:
pec
::
trailing_character
;
}
};
template
<
class
T
>
...
...
@@ -993,11 +885,6 @@ struct map_config_value_access {
return
std
::
move
(
*
result
);
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
map_type
&
xs
,
Nested
)
{
detail
::
parse
(
ps
,
xs
);
}
static
config_value
::
dictionary
convert
(
const
map_type
&
xs
)
{
config_value
::
dictionary
result
;
for
(
const
auto
&
x
:
xs
)
...
...
@@ -1050,11 +937,6 @@ struct tuple_config_value_access<std::tuple<Ts...>> {
return
result
;
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
tuple_type
&
xs
,
Nested
)
{
rec_parse
(
ps
,
xs
,
detail
::
int_token
<
0
>
(),
detail
::
type_list
<
Ts
...
>
());
}
private:
template
<
int
Pos
>
static
void
...
...
@@ -1119,24 +1001,6 @@ private:
return
rec_convert
(
result
,
xs
,
detail
::
int_token
<
Pos
+
1
>
(),
detail
::
type_list
<
Us
...
>
());
}
template
<
int
Pos
>
static
void
rec_parse
(
string_parser_state
&
,
tuple_type
&
,
detail
::
int_token
<
Pos
>
,
detail
::
type_list
<>
)
{
// nop
}
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
=
config_value_access_t
<
U
>
;
trait
::
parse_cli
(
std
::
get
<
Pos
>
(
xs
),
nested_cli_parsing
);
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
...
>
());
}
};
}
// namespace detail
...
...
@@ -1289,30 +1153,6 @@ struct inspect_config_value_access {
return
std
::
move
(
*
result
);
}
template
<
class
Nested
>
static
void
parse_cli
(
string_parser_state
&
ps
,
T
&
x
,
Nested
token
)
{
auto
first
=
ps
.
i
;
config_value
tmp
;
detail
::
parse
(
ps
,
tmp
);
// If the first attempt fails, rewind the parser state and try parsing the
// input as a string. This allows unescaped inputs.
if
(
ps
.
code
!=
pec
::
success
)
{
ps
.
code
=
pec
::
success
;
ps
.
i
=
first
;
std
::
string
str
;
config_value_access_t
<
std
::
string
>::
parse_cli
(
ps
,
str
,
token
);
if
(
ps
.
code
==
pec
::
success
)
tmp
=
config_value
{
std
::
move
(
str
)};
}
if
(
ps
.
code
==
pec
::
success
)
{
if
(
auto
res
=
caf
::
get_if
<
T
>
(
&
tmp
))
{
x
=
detail
::
move_if_not_ptr
(
res
);
}
else
{
ps
.
code
=
pec
::
invalid_argument
;
}
}
}
static
config_value
convert
(
const
T
&
x
)
{
config_value
result
;
config_value_writer
writer
{
&
result
};
...
...
libcaf_core/caf/detail/dispatch_parse_cli.hpp
deleted
100644 → 0
View file @
f6ae028a
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 <type_traits>
#include "caf/config_value.hpp"
#include "caf/detail/type_traits.hpp"
namespace
caf
::
detail
{
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
)...);
}
};
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
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
>
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 caf::detail
libcaf_core/caf/detail/type_traits.hpp
View file @
31be7eb2
...
...
@@ -685,6 +685,44 @@ public:
static
constexpr
bool
value
=
sfinae_type
::
value
;
};
template
<
class
T
>
struct
has_reserve
{
private:
template
<
class
List
>
static
auto
sfinae
(
List
*
l
)
->
decltype
(
l
->
reserve
(
10
),
std
::
true_type
());
template
<
class
U
>
static
auto
sfinae
(...)
->
std
::
false_type
;
using
sfinae_type
=
decltype
(
sfinae
<
T
>
(
nullptr
));
public:
static
constexpr
bool
value
=
sfinae_type
::
value
;
};
template
<
class
T
>
constexpr
bool
has_reserve_t
=
has_reserve
<
T
>::
value
;
template
<
class
T
>
struct
has_emplace_back
{
private:
template
<
class
List
>
static
auto
sfinae
(
List
*
l
)
->
decltype
(
l
->
emplace_back
(
std
::
declval
<
typename
List
::
value_type
>
()),
std
::
true_type
());
template
<
class
U
>
static
auto
sfinae
(...)
->
std
::
false_type
;
using
sfinae_type
=
decltype
(
sfinae
<
T
>
(
nullptr
));
public:
static
constexpr
bool
value
=
sfinae_type
::
value
;
};
template
<
class
T
>
constexpr
bool
has_emplace_back_t
=
has_emplace_back
<
T
>::
value
;
template
<
class
T
>
class
has_call_error_handler
{
private:
...
...
libcaf_core/caf/make_config_option.hpp
View file @
31be7eb2
...
...
@@ -22,7 +22,6 @@
#include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/parse.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/error.hpp"
#include "caf/expected.hpp"
...
...
@@ -33,51 +32,32 @@
namespace
caf
::
detail
{
template
<
class
T
>
error
store_impl
(
void
*
ptr
,
const
config_value
&
x
)
{
if
(
holds_alternative
<
T
>
(
x
))
{
error
sync_impl
(
void
*
ptr
,
config_value
&
x
)
{
if
(
auto
val
=
get_as
<
T
>
(
x
))
{
if
(
auto
err
=
x
.
assign
(
*
val
);
!
err
)
{
if
(
ptr
)
*
static_cast
<
T
*>
(
ptr
)
=
get
<
T
>
(
x
);
*
static_cast
<
T
*>
(
ptr
)
=
std
::
move
(
*
val
);
return
none
;
}
else
{
return
make_error
(
pec
::
type_mismatch
)
;
return
err
;
}
}
template
<
class
T
>
config_value
get_impl
(
const
void
*
ptr
)
{
using
trait
=
detail
::
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
)
{
T
tmp
;
return
parse_impl
(
&
tmp
,
str
);
}
else
{
return
std
::
move
(
val
.
error
());
}
if
constexpr
(
detail
::
has_clear_member
<
T
>::
value
)
ptr
->
clear
();
using
trait
=
detail
::
config_value_access_t
<
T
>
;
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
trait
::
parse_cli
(
ps
,
*
ptr
,
top_level_cli_parsing
);
if
(
ps
.
code
!=
pec
::
success
)
return
make_error
(
ps
);
return
config_value
{
trait
::
convert
(
*
ptr
)};
}
CAF_CORE_EXPORT
expected
<
config_value
>
parse_impl
(
std
::
string
*
ptr
,
string_view
str
);
template
<
class
T
>
expected
<
config_value
>
parse_impl_delegate
(
void
*
ptr
,
string_view
str
)
{
return
parse_impl
(
reinterpret_cast
<
T
*>
(
ptr
),
str
);
config_value
get_impl
(
const
void
*
ptr
)
{
config_value
result
;
auto
err
=
result
.
assign
(
*
static_cast
<
const
T
*>
(
ptr
));
static_cast
<
void
>
(
err
);
// Safe to discard because sync() fails otherwise.
return
result
;
}
template
<
class
T
>
config_option
::
meta_state
*
option_meta_state_instance
()
{
using
trait
=
detail
::
config_value_access_t
<
T
>
;
static
config_option
::
meta_state
obj
{
store_impl
<
T
>
,
get_impl
<
T
>
,
parse_impl_delegate
<
T
>
,
static
config_option
::
meta_state
obj
{
sync_impl
<
T
>
,
get_impl
<
T
>
,
trait
::
type_name
()};
return
&
obj
;
}
...
...
@@ -109,12 +89,12 @@ make_negated_config_option(bool& storage, string_view category,
string_view
name
,
string_view
description
);
// Reads timespans, but stores an integer representing microsecond resolution.
CAF_CORE_EXPORT
config_option
[[
deprecated
(
"use timespan options instead"
)]]
CAF_CORE_EXPORT
config_option
make_us_resolution_config_option
(
size_t
&
storage
,
string_view
category
,
string_view
name
,
string_view
description
);
// Reads timespans, but stores an integer representing millisecond resolution.
CAF_CORE_EXPORT
config_option
[[
deprecated
(
"use timespan options instead"
)]]
CAF_CORE_EXPORT
config_option
make_ms_resolution_config_option
(
size_t
&
storage
,
string_view
category
,
string_view
name
,
string_view
description
);
...
...
libcaf_core/src/actor_system_config.cpp
View file @
31be7eb2
...
...
@@ -340,7 +340,7 @@ actor_system_config& actor_system_config::set_impl(string_view name,
if
(
opt
==
nullptr
)
{
std
::
cerr
<<
"*** failed to set config parameter "
<<
name
<<
": invalid name"
<<
std
::
endl
;
}
else
if
(
auto
err
=
opt
->
s
tore
(
value
))
{
}
else
if
(
auto
err
=
opt
->
s
ync
(
value
))
{
std
::
cerr
<<
"*** failed to set config parameter "
<<
name
<<
": "
<<
to_string
(
err
)
<<
std
::
endl
;
}
else
{
...
...
@@ -412,12 +412,13 @@ error actor_system_config::extract_config_file_path(string_list& args) {
args
.
erase
(
i
);
return
make_error
(
pec
::
missing_argument
,
std
::
move
(
str
));
}
auto
evalue
=
ptr
->
parse
(
path
);
if
(
!
evalue
)
return
std
::
move
(
evalue
.
error
());
put
(
content
,
"config-file"
,
*
evalue
);
ptr
->
store
(
*
evalue
);
config_value
val
{
path
};
if
(
auto
err
=
ptr
->
sync
(
val
);
!
err
)
{
put
(
content
,
"config-file"
,
std
::
move
(
val
));
return
none
;
}
else
{
return
err
;
}
}
const
settings
&
content
(
const
actor_system_config
&
cfg
)
{
...
...
libcaf_core/src/config_option.cpp
View file @
31be7eb2
...
...
@@ -128,9 +128,13 @@ string_view config_option::full_name() const noexcept {
return
buf_slice
(
buf_
[
0
]
==
'?'
?
1
:
0
,
long_name_separator_
);
}
error
config_option
::
sync
(
config_value
&
x
)
const
{
return
meta_
->
sync
(
value_
,
x
);
}
error
config_option
::
store
(
const
config_value
&
x
)
const
{
CAF_ASSERT
(
meta_
->
store
!=
nullptr
)
;
return
meta_
->
store
(
value_
,
x
);
auto
cpy
=
x
;
return
sync
(
cpy
);
}
string_view
config_option
::
type_name
()
const
noexcept
{
...
...
@@ -146,7 +150,11 @@ bool config_option::has_flat_cli_name() const noexcept {
}
expected
<
config_value
>
config_option
::
parse
(
string_view
input
)
const
{
return
meta_
->
parse
(
value_
,
input
);
config_value
val
{
input
};
if
(
auto
err
=
sync
(
val
))
return
{
std
::
move
(
err
)};
else
return
{
std
::
move
(
val
)};
}
optional
<
config_value
>
config_option
::
get
()
const
{
...
...
libcaf_core/src/config_option_adder.cpp
View file @
31be7eb2
...
...
@@ -18,8 +18,11 @@
#include "caf/config_option_adder.hpp"
#include "caf/config.hpp"
#include "caf/config_option_set.hpp"
CAF_PUSH_DEPRECATED_WARNING
namespace
caf
{
config_option_adder
::
config_option_adder
(
config_option_set
&
target
,
...
...
@@ -53,3 +56,5 @@ config_option_adder& config_option_adder::add_impl(config_option&& opt) {
}
}
// namespace caf
CAF_POP_WARNINGS
libcaf_core/src/config_option_set.cpp
View file @
31be7eb2
...
...
@@ -137,6 +137,12 @@ auto config_option_set::parse(settings& config, argument_iterator first,
// Parses an argument.
using
iter
=
string
::
const_iterator
;
auto
consume
=
[
&
](
const
config_option
&
opt
,
iter
arg_begin
,
iter
arg_end
)
{
auto
to_pec_code
=
[](
const
error
&
err
)
{
if
(
err
.
category
()
==
type_id_v
<
pec
>
)
return
static_cast
<
pec
>
(
err
.
code
());
else
return
pec
::
invalid_argument
;
};
// Extract option name and category.
auto
opt_name
=
opt
.
long_name
();
auto
opt_ctg
=
opt
.
category
();
...
...
@@ -144,27 +150,31 @@ auto config_option_set::parse(settings& config, argument_iterator first,
auto
&
entry
=
opt_ctg
==
"global"
?
config
:
select_entry
(
config
,
opt_ctg
);
// Flags only consume the current element.
if
(
opt
.
is_flag
())
{
if
(
arg_begin
!=
arg_end
)
return
pec
::
invalid_argument
;
if
(
arg_begin
==
arg_end
)
{
config_value
cfg_true
{
true
};
opt
.
store
(
cfg_true
);
if
(
auto
err
=
opt
.
sync
(
cfg_true
);
!
err
)
{
entry
[
opt_name
]
=
cfg_true
;
return
pec
::
success
;
}
else
{
if
(
arg_begin
==
arg_end
)
return
pec
::
missing_argument
;
auto
slice_size
=
static_cast
<
size_t
>
(
std
::
distance
(
arg_begin
,
arg_end
));
string_view
slice
{
&*
arg_begin
,
slice_size
};
auto
val
=
opt
.
parse
(
slice
);
if
(
!
val
)
{
auto
&
err
=
val
.
error
();
if
(
err
.
category
()
==
type_id_v
<
pec
>
)
return
static_cast
<
pec
>
(
err
.
code
());
return
pec
::
invalid_argument
;
return
to_pec_code
(
err
);
}
opt
.
store
(
*
val
);
entry
[
opt_name
]
=
std
::
move
(
*
val
)
;
}
else
{
return
pec
::
invalid_argument
;
}
}
else
{
if
(
arg_begin
!=
arg_end
)
{
auto
arg_size
=
static_cast
<
size_t
>
(
std
::
distance
(
arg_begin
,
arg_end
));
config_value
val
{
string_view
{
std
::
addressof
(
*
arg_begin
),
arg_size
}};
if
(
auto
err
=
opt
.
sync
(
val
);
!
err
)
{
entry
[
opt_name
]
=
std
::
move
(
val
);
return
pec
::
success
;
}
else
{
return
to_pec_code
(
err
);
}
}
else
{
return
pec
::
missing_argument
;
}
}
};
// We loop over the first N-1 values, because we always consider two
// arguments at once.
...
...
libcaf_core/src/detail/config_consumer.cpp
View file @
31be7eb2
...
...
@@ -159,7 +159,7 @@ pec config_consumer::value_impl(config_value&& x) {
// Sync with config option object if available.
if
(
options_
!=
nullptr
)
if
(
auto
opt
=
options_
->
qualified_name_lookup
(
category_
,
current_key_
))
if
(
auto
err
=
opt
->
s
tore
(
x
))
if
(
auto
err
=
opt
->
s
ync
(
x
))
return
pec
::
type_mismatch
;
// Insert / replace value in the map.
if
(
auto
dict
=
get_if
<
settings
>
(
&
x
))
{
...
...
libcaf_core/src/make_config_option.cpp
View file @
31be7eb2
...
...
@@ -23,57 +23,20 @@
#include "caf/config_value.hpp"
#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::config_value_access_t<type>::type_name()};
using
std
::
string
;
namespace
caf
{
namespace
detail
{
expected
<
config_value
>
parse_impl
(
std
::
string
*
ptr
,
string_view
str
)
{
// Parse quoted strings, otherwise consume the entire string.
auto
e
=
str
.
end
();
auto
i
=
std
::
find_if
(
str
.
begin
(),
e
,
[](
char
c
)
{
return
!
isspace
(
c
);
});
if
(
i
==
e
)
{
if
(
ptr
!=
nullptr
)
ptr
->
assign
(
i
,
e
);
return
config_value
{
std
::
string
{
i
,
e
}};
}
if
(
*
i
==
'"'
)
{
if
(
ptr
==
nullptr
)
{
std
::
string
tmp
;
if
(
auto
err
=
parse
(
str
,
tmp
))
return
err
;
return
config_value
{
std
::
move
(
tmp
)};
}
else
{
if
(
auto
err
=
parse
(
str
,
*
ptr
))
return
err
;
return
config_value
{
*
ptr
};
}
}
if
(
ptr
!=
nullptr
)
ptr
->
assign
(
str
.
begin
(),
str
.
end
());
return
config_value
{
std
::
string
{
str
.
begin
(),
str
.
end
()}};
}
}
// namespace detail
namespace
{
using
meta_state
=
config_option
::
meta_state
;
error
bool_store_neg
(
void
*
ptr
,
const
config_value
&
x
)
{
if
(
holds_alternative
<
bool
>
(
x
))
{
error
bool_sync_neg
(
void
*
ptr
,
config_value
&
x
)
{
if
(
auto
val
=
get_as
<
bool
>
(
x
))
{
x
=
config_value
{
*
val
};
if
(
ptr
)
*
static_cast
<
bool
*>
(
ptr
)
=
!
get
<
bool
>
(
x
)
;
*
static_cast
<
bool
*>
(
ptr
)
=
!
*
val
;
return
none
;
}
else
{
return
make_error
(
pec
::
type_mismatch
);
return
std
::
move
(
val
.
error
()
);
}
}
...
...
@@ -81,20 +44,22 @@ config_value bool_get_neg(const void* ptr) {
return
config_value
{
!*
static_cast
<
const
bool
*>
(
ptr
)};
}
meta_state
bool_neg_meta
{
bool_s
tore_neg
,
bool_get_neg
,
nullptr
,
meta_state
bool_neg_meta
{
bool_s
ync_neg
,
bool_get_neg
,
detail
::
config_value_access_t
<
bool
>::
type_name
()};
template
<
uint64_t
Denominator
>
error
store_timespan
(
void
*
ptr
,
const
config_value
&
x
)
{
if
(
holds_alternative
<
timespan
>
(
x
))
{
error
sync_timespan
(
void
*
ptr
,
config_value
&
x
)
{
if
(
auto
val
=
get_as
<
timespan
>
(
x
))
{
x
=
config_value
{
*
val
};
if
(
ptr
)
*
static_cast
<
size_t
*>
(
ptr
)
=
static_cast
<
size_t
>
(
get
<
timespan
>
(
x
).
count
())
/
Denominator
;
return
none
;
}
else
{
return
make_error
(
pec
::
type_mismatch
);
return
std
::
move
(
val
.
error
()
);
}
}
template
<
uint64_t
Denominator
>
config_value
get_timespan
(
const
void
*
ptr
)
{
auto
ival
=
static_cast
<
int64_t
>
(
*
static_cast
<
const
size_t
*>
(
ptr
));
...
...
@@ -102,10 +67,10 @@ config_value get_timespan(const void* ptr) {
return
config_value
{
val
};
}
meta_state
us_res_meta
{
s
tore_timespan
<
1000
>
,
get_timespan
<
1000
>
,
nullptr
,
meta_state
us_res_meta
{
s
ync_timespan
<
1000
>
,
get_timespan
<
1000
>
,
detail
::
config_value_access_t
<
timespan
>::
type_name
()};
meta_state
ms_res_meta
{
s
tore_timespan
<
1000000
>
,
get_timespan
<
1000000
>
,
nullptr
,
meta_state
ms_res_meta
{
s
ync_timespan
<
1000000
>
,
get_timespan
<
1000000
>
,
detail
::
config_value_access_t
<
timespan
>::
type_name
()};
}
// namespace
...
...
libcaf_core/test/config_option.cpp
View file @
31be7eb2
...
...
@@ -48,12 +48,12 @@ constexpr int64_t underflow() {
template
<
class
T
>
optional
<
T
>
read
(
string_view
arg
)
{
auto
co
=
make_config_option
<
T
>
(
category
,
name
,
explanation
)
;
auto
res
=
co
.
parse
(
arg
);
if
(
res
&&
holds_alternative
<
T
>
(
*
res
))
{
if
(
auto
err
=
co
.
store
(
*
res
);
!
err
)
return
get
<
T
>
(
*
res
)
;
}
auto
result
=
T
{}
;
auto
co
=
make_config_option
<
T
>
(
result
,
category
,
name
,
explanation
);
config_value
val
{
arg
};
if
(
auto
err
=
co
.
sync
(
val
);
!
err
)
return
{
std
::
move
(
result
)}
;
else
return
none
;
}
...
...
libcaf_core/test/config_value.cpp
View file @
31be7eb2
...
...
@@ -999,83 +999,6 @@ CAF_TEST(successful parsing) {
CAF_CHECK_EQUAL
(
get
<
di
>
(
parse
(
"{a=1,b=2}"
)),
di
({{
"a"
,
1
},
{
"b"
,
2
}}));
}
#define CHECK_CLI_PARSE(type, str, ...) \
do { \
/* Note: parse_impl from make_config_option.hpp internally dispatches */
\
/* to parse_cli. No need to replicate that wrapping code here. */
\
if (auto res = caf::detail::parse_impl<type>(nullptr, str)) { \
type expected_res{__VA_ARGS__}; \
if (auto unboxed = ::caf::get_if<type>(std::addressof(*res))) { \
if (*unboxed == expected_res) \
CAF_CHECK_PASSED("parse(" << str << ") == " << expected_res); \
else \
CAF_CHECK_FAILED(*unboxed << " != " << expected_res); \
} else { \
CAF_CHECK_FAILED(*res << " != " << expected_res); \
} \
} else { \
CAF_CHECK_FAILED("parse(" << str << ") -> " << res.error()); \
} \
} while (false)
#define CHECK_CLI_PARSE_FAILS(type, str) \
do { \
if (auto res = caf::detail::parse_impl<type>(nullptr, str)) { \
CAF_CHECK_FAILED("unexpected parser result: " << *res); \
} else { \
CAF_CHECK_PASSED("parse(" << str << ") == " << res.error()); \
} \
} while (false)
CAF_TEST
(
parsing
via
parse_cli
enables
shortcut
syntax
for
some
types
)
{
using
ls
=
std
::
vector
<
string
>
;
// List-of-strings.
using
li
=
std
::
vector
<
int
>
;
// List-of-integers.
using
lli
=
std
::
vector
<
li
>
;
// List-of-list-of-integers.
CAF_MESSAGE
(
"lists can omit square brackets"
);
CHECK_CLI_PARSE
(
int
,
"123"
,
123
);
CHECK_CLI_PARSE
(
li
,
"[ 1,2 , 3 ,]"
,
1
,
2
,
3
);
CHECK_CLI_PARSE
(
li
,
"[ 1,2 , 3 ]"
,
1
,
2
,
3
);
CHECK_CLI_PARSE
(
li
,
" 1,2 , 3 ,"
,
1
,
2
,
3
);
CHECK_CLI_PARSE
(
li
,
" 1,2 , 3 "
,
1
,
2
,
3
);
CHECK_CLI_PARSE
(
li
,
" [ ] "
,
li
{});
CHECK_CLI_PARSE
(
li
,
" "
,
li
{});
CHECK_CLI_PARSE
(
li
,
""
,
li
{});
CHECK_CLI_PARSE
(
li
,
"[123]"
,
123
);
CHECK_CLI_PARSE
(
li
,
"123"
,
123
);
CAF_MESSAGE
(
"brackets must have matching opening/closing brackets"
);
CHECK_CLI_PARSE_FAILS
(
li
,
" 1,2 , 3 ,]"
);
CHECK_CLI_PARSE_FAILS
(
li
,
" 1,2 , 3 ]"
);
CHECK_CLI_PARSE_FAILS
(
li
,
"123]"
);
CHECK_CLI_PARSE_FAILS
(
li
,
"[ 1,2 , 3 ,"
);
CHECK_CLI_PARSE_FAILS
(
li
,
"[ 1,2 , 3 "
);
CHECK_CLI_PARSE_FAILS
(
li
,
"[123"
);
CAF_MESSAGE
(
"string lists can omit quotation marks"
);
CHECK_CLI_PARSE
(
string
,
R"_("123")_"
,
"123"
);
CHECK_CLI_PARSE
(
string
,
R"_(123)_"
,
"123"
);
CHECK_CLI_PARSE
(
ls
,
R"_([ "1 ","2" , "3" ,])_"
,
"1 "
,
"2"
,
"3"
);
CHECK_CLI_PARSE
(
ls
,
R"_([ 1,2 , 3 ,])_"
,
"1"
,
"2"
,
"3"
);
CHECK_CLI_PARSE
(
ls
,
R"_([ 1,2 , 3 ])_"
,
"1"
,
"2"
,
"3"
);
CHECK_CLI_PARSE
(
ls
,
R"_( 1,2 , 3 ,)_"
,
"1"
,
"2"
,
"3"
);
CHECK_CLI_PARSE
(
ls
,
R"_( 1,2 , 3 )_"
,
"1"
,
"2"
,
"3"
);
CHECK_CLI_PARSE
(
ls
,
R"_( [ ] )_"
,
ls
{});
CHECK_CLI_PARSE
(
ls
,
R"_( )_"
,
ls
{});
CHECK_CLI_PARSE
(
ls
,
R"_(["abc"])_"
,
"abc"
);
CHECK_CLI_PARSE
(
ls
,
R"_([abc])_"
,
"abc"
);
CHECK_CLI_PARSE
(
ls
,
R"_("abc")_"
,
"abc"
);
CHECK_CLI_PARSE
(
ls
,
R"_(abc)_"
,
"abc"
);
CAF_MESSAGE
(
"nested lists can omit the outer square brackets"
);
CHECK_CLI_PARSE
(
lli
,
"[[1, 2, 3, ], ]"
,
li
({
1
,
2
,
3
}));
CHECK_CLI_PARSE
(
lli
,
"[[1, 2, 3]]"
,
li
({
1
,
2
,
3
}));
CHECK_CLI_PARSE
(
lli
,
"[1, 2, 3, ]"
,
li
({
1
,
2
,
3
}));
CHECK_CLI_PARSE
(
lli
,
"[1, 2, 3]"
,
li
({
1
,
2
,
3
}));
CHECK_CLI_PARSE
(
lli
,
"[[1], [2]]"
,
li
({
1
}),
li
({
2
}));
CHECK_CLI_PARSE
(
lli
,
"[1], [2]"
,
li
({
1
}),
li
({
2
}));
CHECK_CLI_PARSE_FAILS
(
lli
,
"1"
);
CHECK_CLI_PARSE_FAILS
(
lli
,
"1, 2"
);
CHECK_CLI_PARSE_FAILS
(
lli
,
"[1, 2]]"
);
CHECK_CLI_PARSE_FAILS
(
lli
,
"[[1, 2]"
);
}
CAF_TEST
(
unsuccessful
parsing
)
{
auto
parse
=
[](
const
string
&
str
)
{
auto
x
=
config_value
::
parse
(
str
);
...
...
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