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
b1a512e2
Commit
b1a512e2
authored
Jun 15, 2018
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-implement help texts
parent
64324ccf
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
385 additions
and
44 deletions
+385
-44
libcaf_core/caf/actor_system_config.hpp
libcaf_core/caf/actor_system_config.hpp
+4
-3
libcaf_core/caf/config.hpp
libcaf_core/caf/config.hpp
+8
-0
libcaf_core/caf/config_option.hpp
libcaf_core/caf/config_option.hpp
+4
-0
libcaf_core/caf/config_option_set.hpp
libcaf_core/caf/config_option_set.hpp
+3
-0
libcaf_core/caf/detail/type_name.hpp
libcaf_core/caf/detail/type_name.hpp
+148
-0
libcaf_core/caf/make_config_option.hpp
libcaf_core/caf/make_config_option.hpp
+8
-1
libcaf_core/src/actor_system_config.cpp
libcaf_core/src/actor_system_config.cpp
+98
-20
libcaf_core/src/config_option.cpp
libcaf_core/src/config_option.cpp
+5
-17
libcaf_core/src/config_option_set.cpp
libcaf_core/src/config_option_set.cpp
+93
-3
libcaf_core/test/config_option_set.cpp
libcaf_core/test/config_option_set.cpp
+14
-0
No files found.
libcaf_core/caf/actor_system_config.hpp
View file @
b1a512e2
...
...
@@ -268,7 +268,10 @@ public:
bool
cli_helptext_printed
;
/// Stores CLI arguments that were not consumed by CAF.
message
args_remainder
;
message
args_remainder
CAF_DEPRECATED
;
/// Stores CLI arguments that were not consumed by CAF.
string_list
remainder
;
// -- caf-run parameters -----------------------------------------------------
...
...
@@ -430,8 +433,6 @@ private:
static
std
::
string
render_exit_reason
(
uint8_t
,
atom_value
,
const
message
&
);
void
extract_config_file_path
(
string_list
&
args
);
config_option_set
options_
;
};
}
// namespace caf
...
...
libcaf_core/caf/config.hpp
View file @
b1a512e2
...
...
@@ -96,6 +96,9 @@
# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wnon-virtual-dtor\"")
# define CAF_PUSH_DEPRECATED_WARNING \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
# define CAF_POP_WARNINGS \
_Pragma("clang diagnostic pop")
# define CAF_ANNOTATE_FALLTHROUGH [[clang::fallthrough]]
...
...
@@ -122,6 +125,9 @@
# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"")
# define CAF_PUSH_DEPRECATED_WARNING \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
# define CAF_POP_WARNINGS \
_Pragma("GCC diagnostic pop")
# define CAF_ANNOTATE_FALLTHROUGH static_cast<void>(0)
...
...
@@ -154,6 +160,8 @@
# define CAF_UNLIKELY(x) x
# define CAF_DEPRECATED
# define CAF_PUSH_WARNINGS
# define CAF_PUSH_NON_VIRTUAL_DTOR_WARNING
# define CAF_PUSH_DEPRECATED_WARNING
# define CAF_POP_WARNINGS
# define CAF_ANNOTATE_FALLTHROUGH static_cast<void>(0)
#endif
...
...
libcaf_core/caf/config_option.hpp
View file @
b1a512e2
...
...
@@ -33,6 +33,7 @@ public:
struct
vtbl_type
{
error
(
*
check
)(
const
config_value
&
);
void
(
*
store
)(
void
*
,
const
config_value
&
);
std
::
string
(
*
type_name
)();
};
// -- constructors, destructors, and assignment operators --------------------
...
...
@@ -78,6 +79,9 @@ public:
/// @pre `check(x) == none`.
void
store
(
const
config_value
&
x
)
const
;
/// Returns a human-readable representation of this option's expected type.
std
::
string
type_name
()
const
;
private:
std
::
string
category_
;
std
::
string
long_name_
;
...
...
libcaf_core/caf/config_option_set.hpp
View file @
b1a512e2
...
...
@@ -113,6 +113,9 @@ public:
return
*
this
;
}
/// Generates human-readable help text for all options.
std
::
string
help_text
(
bool
global_only
=
true
)
const
;
// -- parsing ----------------------------------------------------------------
/// Parses a given range as CLI arguments into `config`.
...
...
libcaf_core/caf/detail/type_name.hpp
0 → 100644
View file @
b1a512e2
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <map>
#include <string>
#include <type_traits>
#include <vector>
#include "caf/fwd.hpp"
#include "caf/timestamp.hpp"
namespace
caf
{
namespace
detail
{
template
<
size_t
Bytes
>
struct
type_name_builder_int_size
;
template
<
>
struct
type_name_builder_int_size
<
1
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"8"
;
}
};
template
<
>
struct
type_name_builder_int_size
<
2
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"16"
;
}
};
template
<
>
struct
type_name_builder_int_size
<
4
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"32"
;
}
};
template
<
>
struct
type_name_builder_int_size
<
8
>
{
inline
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
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"boolean"
;
}
};
template
<
>
struct
type_name_builder
<
float
,
false
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"32-bit real"
;
}
};
template
<
>
struct
type_name_builder
<
double
,
false
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"64-bit real"
;
}
};
template
<
>
struct
type_name_builder
<
timespan
,
false
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"timespan"
;
}
};
template
<
>
struct
type_name_builder
<
std
::
string
,
false
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"string"
;
}
};
template
<
>
struct
type_name_builder
<
atom_value
,
false
>
{
inline
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"atom"
;
}
};
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
T
>
struct
type_name_builder
<
std
::
map
<
std
::
string
,
T
>
,
false
>
{
void
operator
()(
std
::
string
&
result
)
const
{
result
+=
"dictionary of "
;
type_name_builder
<
T
>
g
;
g
(
result
);
}
};
template
<
class
T
>
std
::
string
type_name
()
{
std
::
string
result
;
type_name_builder
<
T
>
f
;
f
(
result
);
return
result
;
}
}
// namespace detail
}
// namespace caf
libcaf_core/caf/make_config_option.hpp
View file @
b1a512e2
...
...
@@ -20,6 +20,7 @@
#include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/type_name.hpp"
#include "caf/pec.hpp"
namespace
caf
{
...
...
@@ -34,7 +35,10 @@ config_option make_config_option(const char* category, const char* name,
return
none
;
return
make_error
(
pec
::
type_mismatch
);
},
nullptr
nullptr
,
[]
{
return
detail
::
type_name
<
T
>
();
}
};
return
{
category
,
name
,
description
,
std
::
is_same
<
T
,
bool
>::
value
,
vtbl
};
}
...
...
@@ -51,6 +55,9 @@ config_option make_config_option(T& storage, const char* category,
},
[](
void
*
ptr
,
const
config_value
&
x
)
{
*
static_cast
<
T
*>
(
ptr
)
=
get
<
T
>
(
x
);
},
[]
{
return
detail
::
type_name
<
T
>
();
}
};
return
{
category
,
name
,
description
,
std
::
is_same
<
T
,
bool
>::
value
,
...
...
libcaf_core/src/actor_system_config.cpp
View file @
b1a512e2
...
...
@@ -29,6 +29,8 @@
#include "caf/detail/parser/read_string.hpp"
#include "caf/message_builder.hpp"
CAF_PUSH_DEPRECATED_WARNING
namespace
caf
{
actor_system_config
::
opt_group
::
opt_group
(
config_option_set
&
xs
,
...
...
@@ -92,14 +94,19 @@ actor_system_config::actor_system_config()
middleman_cached_udp_buffers
=
10
;
middleman_max_pending_msgs
=
10
;
// fill our options vector for creating INI and CLI parsers
opt_group
{
options_
,
"streaming"
}
opt_group
{
custom_options_
,
"global"
}
.
add
<
bool
>
(
cli_helptext_printed
,
"help,h?"
,
"print help and exit"
)
.
add
<
bool
>
(
cli_helptext_printed
,
"long-help"
,
"print all help options and exit"
)
.
add
<
bool
>
(
"dump-config"
,
"print configuration in INI format and exit"
);
opt_group
{
custom_options_
,
"streaming"
}
.
add
(
streaming_desired_batch_complexity_us
,
"desired-batch-complexity-us"
,
"sets the desired timespan for a single batch"
)
.
add
(
streaming_max_batch_delay_us
,
"max-batch-delay-us"
,
"sets the maximum delay for sending underfull batches in microseconds"
)
.
add
(
streaming_credit_round_interval_us
,
"credit-round-interval-us"
,
"sets the length of credit intervals in microseconds"
);
opt_group
{
options_
,
"scheduler"
}
opt_group
{
custom_
options_
,
"scheduler"
}
.
add
(
scheduler_policy
,
"policy"
,
"sets the scheduling policy to either 'stealing' (default) or 'sharing'"
)
.
add
(
scheduler_max_threads
,
"max-threads"
,
...
...
@@ -112,7 +119,7 @@ actor_system_config::actor_system_config()
"sets the rate in ms in which the profiler collects data"
)
.
add
(
scheduler_profiling_output_file
,
"profiling-output-file"
,
"sets the output file for the profiler"
);
opt_group
(
options_
,
"work-stealing"
)
opt_group
(
custom_
options_
,
"work-stealing"
)
.
add
(
work_stealing_aggressive_poll_attempts
,
"aggressive-poll-attempts"
,
"sets the number of zero-sleep-interval polling attempts"
)
.
add
(
work_stealing_aggressive_steal_interval
,
"aggressive-steal-interval"
,
...
...
@@ -127,7 +134,7 @@ actor_system_config::actor_system_config()
"sets the frequency of steal attempts during relaxed polling"
)
.
add
(
work_stealing_relaxed_sleep_duration_us
,
"relaxed-sleep-duration"
,
"sets the sleep interval between poll attempts during relaxed polling"
);
opt_group
{
options_
,
"logger"
}
opt_group
{
custom_
options_
,
"logger"
}
.
add
(
logger_file_name
,
"file-name"
,
"sets the filesystem path of the log file"
)
.
add
(
logger_file_format
,
"file-format"
,
...
...
@@ -146,7 +153,7 @@ actor_system_config::actor_system_config()
"deprecated (use file-name instead)"
)
.
add
(
logger_component_filter
,
"filter"
,
"deprecated (use console-component-filter instead)"
);
opt_group
{
options_
,
"middleman"
}
opt_group
{
custom_
options_
,
"middleman"
}
.
add
(
middleman_network_backend
,
"network-backend"
,
"sets the network backend to either 'default' or 'asio' (if available)"
)
.
add
(
middleman_app_identifier
,
"app-identifier"
,
...
...
@@ -171,10 +178,10 @@ actor_system_config::actor_system_config()
.
add
(
middleman_max_pending_msgs
,
"max-pending-messages"
,
"sets the max number of UDP pending messages due to ordering "
"(default: 10)"
);
opt_group
(
options_
,
"opencl"
)
opt_group
(
custom_
options_
,
"opencl"
)
.
add
(
opencl_device_ids
,
"device-ids"
,
"restricts which OpenCL devices are accessed by CAF"
);
opt_group
(
options_
,
"openssl"
)
opt_group
(
custom_
options_
,
"openssl"
)
.
add
(
openssl_certificate
,
"certificate"
,
"sets the path to the file containining the certificate for this node PEM format"
)
.
add
(
openssl_key
,
"key"
,
...
...
@@ -227,31 +234,100 @@ actor_system_config::make_help_text(const std::vector<message::cli_arg>& xs) {
actor_system_config
&
actor_system_config
::
parse
(
int
argc
,
char
**
argv
,
const
char
*
ini_file_cstr
)
{
if
(
argc
<
2
)
return
*
this
;
string_list
args
{
argv
+
1
,
argv
+
argc
}
;
string_list
args
;
if
(
argc
>
1
)
args
.
assign
(
argv
+
1
,
argv
+
argc
)
;
return
parse
(
std
::
move
(
args
),
ini_file_cstr
);
}
actor_system_config
&
actor_system_config
::
parse
(
int
argc
,
char
**
argv
,
std
::
istream
&
ini
)
{
if
(
argc
<
2
)
return
*
this
;
string_list
args
{
argv
+
1
,
argv
+
argc
}
;
string_list
args
;
if
(
argc
>
1
)
args
.
assign
(
argv
+
1
,
argv
+
argc
)
;
return
parse
(
std
::
move
(
args
),
ini
);
}
namespace
{
struct
ini_iter
{
std
::
istream
*
ini
;
char
ch
;
explicit
ini_iter
(
std
::
istream
*
istr
)
:
ini
(
istr
)
{
ini
->
get
(
ch
);
}
ini_iter
()
:
ini
(
nullptr
)
{
// nop
}
ini_iter
(
const
ini_iter
&
)
=
default
;
ini_iter
&
operator
=
(
const
ini_iter
&
)
=
default
;
inline
char
operator
*
()
const
{
return
ch
;
}
inline
ini_iter
&
operator
++
()
{
ini
->
get
(
ch
);
return
*
this
;
}
};
struct
ini_sentinel
{
};
bool
operator
!=
(
ini_iter
iter
,
ini_sentinel
)
{
return
!
iter
.
ini
->
fail
();
}
}
// namespace <anonymous>
actor_system_config
&
actor_system_config
::
parse
(
string_list
args
,
std
::
istream
&
ini
)
{
//
(2) content of the INI file overrides hard-coded defaults
//
Content of the INI file overrides hard-coded defaults.
if
(
ini
.
good
())
{
detail
::
ini_consumer
consumer
{
options_
,
content
};
detail
::
parser
::
state
<
std
::
istream_iterator
<
char
>
>
res
;
res
.
i
=
std
::
istream_iterator
<
char
>
{
ini
};
detail
::
ini_consumer
consumer
{
custom_
options_
,
content
};
detail
::
parser
::
state
<
ini_iter
,
ini_sentinel
>
res
;
res
.
i
=
ini_iter
{
&
ini
};
detail
::
parser
::
read_ini
(
res
,
consumer
);
if
(
res
.
i
!=
res
.
e
)
std
::
cerr
<<
"*** error in config file [line "
<<
res
.
line
<<
" col "
<<
res
.
column
<<
"]: "
<<
to_string
(
res
.
code
)
<<
std
::
endl
;
}
// CLI options override the content of the INI file.
using
std
::
make_move_iterator
;
auto
res
=
custom_options_
.
parse
(
content
,
args
);
if
(
res
.
second
!=
args
.
end
())
{
if
(
res
.
first
!=
pec
::
success
)
{
std
::
cerr
<<
"error: at argument
\"
"
<<
*
res
.
second
<<
"
\"
: "
<<
to_string
(
res
.
first
)
<<
std
::
endl
;
cli_helptext_printed
=
true
;
}
auto
first
=
args
.
begin
();
first
+=
std
::
distance
(
args
.
cbegin
(),
res
.
second
);
remainder
.
insert
(
remainder
.
end
(),
make_move_iterator
(
first
),
make_move_iterator
(
args
.
end
()));
args_remainder
=
message_builder
{
remainder
.
begin
(),
remainder
.
end
()}
.
move_to_message
();
}
// Generate help text if needed.
if
(
cli_helptext_printed
)
{
bool
long_help
=
get_or
(
content
,
"global.long-help"
,
false
);
std
::
cout
<<
custom_options_
.
help_text
(
!
long_help
)
<<
std
::
endl
;
}
// Generate INI dump if needed.
if
(
!
cli_helptext_printed
&&
get_or
(
content
,
"global.dump-config"
,
false
))
{
for
(
auto
&
category
:
content
)
{
std
::
cout
<<
'['
<<
category
.
first
<<
"]
\n
"
;
for
(
auto
&
kvp
:
category
.
second
)
if
(
kvp
.
first
!=
"dump-config"
)
std
::
cout
<<
kvp
.
first
<<
'='
<<
to_string
(
kvp
.
second
)
<<
'\n'
;
}
std
::
cout
<<
std
::
flush
;
cli_helptext_printed
=
true
;
}
// (3) CLI options override the content of the INI file
options_
.
parse
(
content
,
args
);
return
*
this
;
}
...
...
@@ -298,7 +374,7 @@ actor_system_config::add_error_category(atom_value x, error_renderer y) {
actor_system_config
&
actor_system_config
::
set_impl
(
const
char
*
name
,
config_value
value
)
{
auto
opt
=
options_
.
qualified_name_lookup
(
name
);
auto
opt
=
custom_
options_
.
qualified_name_lookup
(
name
);
if
(
opt
!=
nullptr
&&
opt
->
check
(
value
)
==
none
)
{
opt
->
store
(
value
);
content
[
opt
->
category
()][
name
]
=
std
::
move
(
value
);
...
...
@@ -368,3 +444,5 @@ content(const actor_system_config& cfg) {
}
}
// namespace caf
CAF_POP_WARNINGS
libcaf_core/src/config_option.cpp
View file @
b1a512e2
...
...
@@ -44,23 +44,6 @@ string get_short_names(const char* name) {
namespace
caf
{
const
char
*
type_name_visitor_tbl
[]
{
"a boolean"
,
"a float"
,
"a double"
,
"a string"
,
"an atom_value"
,
"an 8-bit integer"
,
"an 8-bit unsigned integer"
,
"a 16-bit integer"
,
"a 16-bit unsigned integer"
,
"a 32-bit integer"
,
"a 32-bit unsigned integer"
,
"a 64-bit integer"
,
"a 64-bit unsigned integer"
,
"a duration"
};
config_option
::
config_option
(
string
category
,
const
char
*
name
,
string
description
,
bool
is_flag
,
const
vtbl_type
&
vtbl
,
void
*
value
)
...
...
@@ -93,4 +76,9 @@ void config_option::store(const config_value& x) const {
}
}
std
::
string
config_option
::
type_name
()
const
{
CAF_ASSERT
(
vtbl_
.
type_name
!=
nullptr
);
return
vtbl_
.
type_name
();
}
}
// namespace caf
libcaf_core/src/config_option_set.cpp
View file @
b1a512e2
...
...
@@ -18,6 +18,9 @@
#include "caf/config_option_set.hpp"
#include <map>
#include <set>
#include "caf/config_option.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/algorithms.hpp"
...
...
@@ -25,12 +28,94 @@
using
std
::
string
;
namespace
{
struct
string_builder
{
std
::
string
result
;
};
template
<
size_t
N
>
string_builder
&
operator
<<
(
string_builder
&
builder
,
const
char
(
&
cstr
)[
N
])
{
builder
.
result
.
append
(
cstr
,
N
-
1
);
return
builder
;
}
string_builder
&
operator
<<
(
string_builder
&
builder
,
char
c
)
{
builder
.
result
+=
c
;
return
builder
;
}
string_builder
&
operator
<<
(
string_builder
&
builder
,
const
std
::
string
&
str
)
{
builder
.
result
+=
str
;
return
builder
;
}
void
insert
(
string_builder
&
builder
,
size_t
count
,
char
ch
)
{
builder
.
result
.
insert
(
builder
.
result
.
end
(),
count
,
ch
);
}
}
// namespace <anonymous>
namespace
caf
{
config_option_set
::
config_option_set
()
{
// nop
}
std
::
string
config_option_set
::
help_text
(
bool
global_only
)
const
{
//<--- argument --------> <---- desciption ---->
// (-w|--write) <string> : output file
auto
build_argument
=
[](
const
config_option
&
x
)
{
string_builder
sb
;
if
(
x
.
short_names
().
empty
())
{
sb
<<
" --"
;
if
(
x
.
category
()
!=
"global"
)
sb
<<
x
.
category
()
<<
'.'
;
sb
<<
x
.
long_name
();
if
(
!
x
.
is_flag
())
sb
<<
'='
;
}
else
{
sb
<<
" ("
;
for
(
auto
c
:
x
.
short_names
())
sb
<<
'-'
<<
c
<<
'|'
;
sb
<<
"--"
;
if
(
x
.
category
()
!=
"global"
)
sb
<<
x
.
category
()
<<
'.'
;
sb
<<
x
.
long_name
()
<<
") "
;
}
if
(
!
x
.
is_flag
())
sb
<<
"<"
<<
x
.
type_name
()
<<
'>'
;
return
std
::
move
(
sb
.
result
);
};
// Sort argument + description by category.
using
pair
=
std
::
pair
<
std
::
string
,
option_pointer
>
;
std
::
set
<
std
::
string
>
categories
;
std
::
multimap
<
std
::
string
,
pair
>
args
;
size_t
max_arg_size
=
0
;
for
(
auto
&
opt
:
opts_
)
{
if
(
!
global_only
||
opt
.
category
()
==
"global"
)
{
auto
arg
=
build_argument
(
opt
);
max_arg_size
=
std
::
max
(
max_arg_size
,
arg
.
size
());
categories
.
emplace
(
opt
.
category
());
args
.
emplace
(
opt
.
category
(),
std
::
make_pair
(
std
::
move
(
arg
),
&
opt
));
}
}
// Build help text by iterating over all categories in the multimap.
string_builder
builder
;
for
(
auto
&
category
:
categories
)
{
auto
rng
=
args
.
equal_range
(
category
);
builder
<<
category
<<
" options:
\n
"
;
for
(
auto
i
=
rng
.
first
;
i
!=
rng
.
second
;
++
i
)
{
builder
<<
i
->
second
.
first
;
CAF_ASSERT
(
max_arg_size
>=
i
->
second
.
first
.
size
());
insert
(
builder
,
max_arg_size
-
i
->
second
.
first
.
size
(),
' '
);
builder
<<
" : "
<<
i
->
second
.
second
->
description
()
<<
'\n'
;
}
builder
<<
'\n'
;
}
return
std
::
move
(
builder
.
result
);
}
auto
config_option_set
::
parse
(
config_map
&
config
,
argument_iterator
first
,
argument_iterator
last
)
const
->
std
::
pair
<
pec
,
argument_iterator
>
{
...
...
@@ -75,12 +160,17 @@ auto config_option_set::parse(config_map& config, argument_iterator first,
if
(
i
->
compare
(
0
,
2
,
"--"
)
==
0
)
{
// Long options use the syntax "--<name>=<value>" and consume only a
// single argument.
auto
assign_op
=
i
->
find
(
'='
);
//std::find(i->begin(), i->end(), '=');
auto
name
=
i
->
substr
(
2
,
assign_op
-
2
);
static
constexpr
auto
npos
=
std
::
string
::
npos
;
auto
assign_op
=
i
->
find
(
'='
);
auto
name
=
assign_op
==
npos
?
i
->
substr
(
2
)
:
i
->
substr
(
2
,
assign_op
-
2
);
auto
opt
=
cli_long_name_lookup
(
name
);
if
(
opt
==
nullptr
)
return
{
pec
::
not_an_option
,
i
};
auto
code
=
consume
(
*
opt
,
i
->
begin
()
+
assign_op
+
1
,
i
->
end
());
auto
code
=
consume
(
*
opt
,
assign_op
==
npos
?
i
->
end
()
:
i
->
begin
()
+
assign_op
+
1
,
i
->
end
());
if
(
code
!=
pec
::
success
)
return
{
code
,
i
};
++
i
;
...
...
libcaf_core/test/config_option_set.cpp
View file @
b1a512e2
...
...
@@ -100,4 +100,18 @@ CAF_TEST(parse with ref syncing) {
CAF_CHECK_EQUAL
(
get
<
int
>
(
cfg
,
"foo.i"
),
42
);
}
CAF_TEST
(
implicit
global
)
{
opts
.
add
<
int
>
(
"global"
,
"value"
).
add
<
bool
>
(
"global"
,
"help"
);
CAF_MESSAGE
(
"test long option with argument"
);
std
::
map
<
std
::
string
,
config_value
::
dictionary
>
cfg
;
auto
res
=
opts
.
parse
(
cfg
,
{
"--value=42"
});
CAF_CHECK_EQUAL
(
res
.
first
,
pec
::
success
);
CAF_CHECK_EQUAL
(
get_if
<
int
>
(
&
cfg
,
"global.value"
),
42
);
CAF_MESSAGE
(
"test long option flag"
);
cfg
.
clear
();
res
=
opts
.
parse
(
cfg
,
{
"--help"
});
CAF_CHECK_EQUAL
(
res
.
first
,
pec
::
success
);
CAF_CHECK_EQUAL
(
get_or
(
cfg
,
"global.help"
,
false
),
true
);
}
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