Skip to content

Commit

Permalink
Merge pull request #52 from smehringer/debug_stream_alternative
Browse files Browse the repository at this point in the history
[MISC] Remove seqan3::debug_stream and seqan3::detail::to_string.
  • Loading branch information
eseiler authored Mar 10, 2022
2 parents 3acbd1d + 230376c commit b86e79e
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 36 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ If possible, provide tooling that performs the changes, e.g. a shell-script.

## API changes

#### I/O
#### General

* Custom option types must not only model `sharg::istreamable` (`stream >> option`)
but must also model `sharg::ostreamable` in order to be used in `parser.add_option()` calls.
All standard types as well as types that overload `sharg::named_enumeration` are not affected.

#### Validators

* In order to avoid using the seqan3 I/O module, you now have to give a list of file extensions explicitly to
`sharg::input_file_validator` and `sharg::output_file_validator`:
Expand Down
10 changes: 5 additions & 5 deletions include/sharg/auxiliary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

#include <unordered_map>
#include <vector>
#include <iostream>

#include <seqan3/core/debug_stream/debug_stream_type.hpp>
#include <seqan3/core/detail/customisation_point.hpp>

#include <sharg/platform.hpp>
Expand Down Expand Up @@ -291,11 +291,11 @@ struct argument_parser_meta_data // holds all meta information
} // namespace sharg

//!\cond
namespace seqan3
namespace std
{
template <typename char_t, typename option_type>
template <typename option_type>
requires sharg::named_enumeration<std::remove_cvref_t<option_type>>
inline debug_stream_type<char_t> & operator<<(debug_stream_type<char_t> & s, option_type && op)
inline ostream & operator<<(ostream & s, option_type && op)
{
for (auto & [key, value] : sharg::enumeration_names<option_type>)
{
Expand All @@ -305,5 +305,5 @@ inline debug_stream_type<char_t> & operator<<(debug_stream_type<char_t> & s, opt

return s << "<UNKNOWN_VALUE>";
}
}
} // namespace std
//!\endcond
23 changes: 22 additions & 1 deletion include/sharg/concept.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ concept istreamable = requires (std::istream & is, value_type & val)
SHARG_RETURN_TYPE_CONSTRAINT(is >> val, std::same_as, std::istream&);
};

/*!\concept sharg::ostreamable
* \ingroup argument_parser
* \brief Concept for types that can be parsed into a std::ostream via the stream operator.
* \tparam type The type to check whether it's stremable via std::ostream or it's a container over streamable values.
*
* ### Requirements
*
* `std::ostream` must support the (un)formatted output function (`operator<<`) for an l-value of a given `type` or
* for an l-value of `type::reference`.
*/
template <typename type>
concept ostreamable = requires (std::ostream & os, type & val)
{
SHARG_RETURN_TYPE_CONSTRAINT(os << val, std::same_as, std::ostream&);
} ||
requires (std::ostream & os, type & con)
{
SHARG_RETURN_TYPE_CONSTRAINT(os << con[0], std::same_as, std::ostream&);
};

/*!\concept sharg::argument_parser_compatible_option
* \brief Checks whether the the type can be used in an add_(positional_)option call on the argument parser.
* \ingroup argument_parser
Expand All @@ -47,6 +67,7 @@ concept istreamable = requires (std::istream & is, value_type & val)
* \remark For a complete overview, take a look at \ref argument_parser
*/
template <typename option_type>
concept argument_parser_compatible_option = sharg::istreamable<option_type> || named_enumeration<option_type>;
concept argument_parser_compatible_option = (sharg::istreamable<option_type> && sharg::ostreamable<option_type>) ||
named_enumeration<option_type>;

} // namespace sharg
8 changes: 4 additions & 4 deletions include/sharg/detail/format_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ class format_help_base : public format_base
{
std::string id = prep_id_for_help(short_id, long_id) + " " + option_type_and_list_info(value);
std::string info{desc};
info += ((spec & option_spec::required) ? std::string{" "} : seqan3::detail::to_string(" Default: ", value, ". "));
info += ((spec & option_spec::required) ? std::string{" "} : detail::to_string(" Default: ", value, ". "));
info += option_validator.get_help_page_message();
store_help_page_element([this, id, info] () { derived_t().print_list_item(id, info); }, spec);
}
Expand Down Expand Up @@ -253,12 +253,12 @@ class format_help_base : public format_base
positional_option_calls.push_back([this, &value, desc, msg] ()
{
++positional_option_count;
derived_t().print_list_item(seqan3::detail::to_string("\\fBARGUMENT-", positional_option_count, "\\fP ",
option_type_and_list_info(value)),
derived_t().print_list_item(detail::to_string("\\fBARGUMENT-", positional_option_count, "\\fP ",
option_type_and_list_info(value)),
desc +
// a list at the end may be empty and thus have a default value
((detail::is_container_option<option_type>)
? seqan3::detail::to_string(" Default: ", value, ". ")
? detail::to_string(" Default: ", value, ". ")
: std::string{" "}) +
msg);
});
Expand Down
67 changes: 67 additions & 0 deletions include/sharg/detail/to_string.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// -----------------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2021, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/sharg-parser/blob/master/LICENSE.md
// -----------------------------------------------------------------------------------------------------------

/*!\file
* \author Svenja Mehringer <svenja.mehringer AT fu-berlin.de>
* \brief Provides sharg::detail::to_string.
*/

#pragma once

#include <sstream>

#include <sharg/detail/concept.hpp>
#include <sharg/concept.hpp>

namespace sharg::detail
{

/*!\brief Streams all parameters via std::ostringstream and returns a concatenated string.
* \tparam value_types Must be sharg::ostreamable (stream << value).
* \param[in] values Variable number of parameters of any type that implement the stream operator.
* \returns A concatenated string of all values (no separator in between is added).
*/
template <typename ...value_types>
requires (ostreamable<value_types> && ...)
std::string to_string(value_types && ...values)
{
std::stringstream stream;

auto print = [&stream] (auto val)
{
if constexpr (is_container_option<decltype(val)>)
{
if (val.empty())
{
stream << "[]";
}
else
{
stream << '[';
stream << val[0];
for (size_t i = 1; i < val.size(); ++i)
stream << ", " << val[i];
stream << ']';
}
}
else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, int8_t> ||
std::is_same_v<std::remove_cvref_t<decltype(val)>, uint8_t>)
{
stream << static_cast<int16_t>(val);
}
else
{
stream << val;
}
};

(print(std::forward<value_types>(values)),...);

return stream.str();
}

} // namespace sharg::detail
31 changes: 9 additions & 22 deletions include/sharg/validators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
#include <fstream>
#include <regex>

#include <seqan3/core/debug_stream/detail/to_string.hpp>
#include <seqan3/core/debug_stream/range.hpp>
#include <seqan3/std/concepts>
#include <seqan3/std/ranges>

#include <sharg/detail/safe_filesystem_entry.hpp>
#include <sharg/detail/to_string.hpp>
#include <sharg/exceptions.hpp>

namespace sharg
Expand Down Expand Up @@ -131,7 +132,7 @@ class arithmetic_range_validator
/*!\brief A validator that checks whether a value is inside a list of valid values.
* \ingroup argument_parser
* \implements sharg::validator
* \tparam option_value_t \copybrief sharg::value_list_validator::option_value_type
* \tparam option_value_t The type the validator is called on. Must model sharg::argument_parser_compatible_option.
*
* \details
*
Expand All @@ -147,7 +148,7 @@ class arithmetic_range_validator
*
* \remark For a complete overview, take a look at \ref argument_parser
*/
template <typename option_value_t>
template <argument_parser_compatible_option option_value_t>
class value_list_validator
{
public:
Expand Down Expand Up @@ -201,7 +202,7 @@ class value_list_validator
void operator()(option_value_type const & cmp) const
{
if (!(std::find(values.begin(), values.end(), cmp) != values.end()))
throw validation_error{seqan3::detail::to_string("Value ", cmp, " is not one of ", std::views::all(values), ".")};
throw validation_error{detail::to_string("Value ", cmp, " is not one of ", values,".")};
}

/*!\brief Tests whether every element in \p range lies inside values.
Expand All @@ -221,11 +222,10 @@ class value_list_validator
//!\brief Returns a message that can be appended to the (positional) options help page info.
std::string get_help_page_message() const
{
return seqan3::detail::to_string("Value must be one of ", std::views::all(values), ".");
return detail::to_string("Value must be one of ", values, ".");
}

private:

//!\brief Minimum of the range to test.
std::vector<option_value_type> values{};
};
Expand Down Expand Up @@ -437,19 +437,6 @@ class file_validator_base
return true;
}

//!\brief Creates a std::string from the extensions list, e.g. "[ext, ext2]".
std::string const create_extensions_str() const
{
if (extensions.empty())
return "[]";

std::string result{'['};
for (std::string const & ext : extensions)
result += ext + ", ";
result.replace(result.size() - 2, 2, "]"); // replace last ", " by "]"
return result;
}

//!\brief Stores the extensions.
std::vector<std::string> extensions{};

Expand Down Expand Up @@ -501,8 +488,8 @@ class input_file_validator : public file_validator_base
*/
explicit input_file_validator(std::vector<std::string> extensions) : file_validator_base{}
{
file_validator_base::extensions_str = detail::to_string(extensions);
file_validator_base::extensions = std::move(extensions);
file_validator_base::extensions_str = create_extensions_str();
}

// Import base class constructor.
Expand Down Expand Up @@ -613,8 +600,8 @@ class output_file_validator : public file_validator_base
explicit output_file_validator(output_file_open_options const mode, std::vector<std::string> extensions = {})
: file_validator_base{}, mode{mode}
{
file_validator_base::extensions_str = detail::to_string(extensions);
file_validator_base::extensions = std::move(extensions);
file_validator_base::extensions_str = create_extensions_str();
}

// Import base constructor.
Expand Down
6 changes: 4 additions & 2 deletions test/unit/detail/format_help_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include <gtest/gtest.h>

#include <seqan3/std/ranges>

#include <sharg/argument_parser.hpp>

// reused global variables
Expand Down Expand Up @@ -449,8 +451,8 @@ TEST(help_page_printing, full_information)
" -i, --int (signed 32 bit integer)\n"
" this is a int option. Default: 5.\n"
" -e, --enum (foo)\n"
" this is an enum option. Default: one. Value must be one of\n"
" [three,two,one].\n"
" this is an enum option. Default: one. Value must be one of [three,\n"
" two, one].\n"
" -r, --required-int (signed 8 bit integer)\n"
" this is another int option.\n"
"\n"
Expand Down
2 changes: 2 additions & 0 deletions test/unit/format_parse_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include <gtest/gtest.h>

#include <seqan3/std/ranges>

#include <sharg/argument_parser.hpp>

TEST(parse_type_test, add_option_short_id)
Expand Down
9 changes: 8 additions & 1 deletion test/unit/format_parse_validators_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include <gtest/gtest.h>

#include <seqan3/std/ranges>

#include <sharg/argument_parser.hpp>
#include <sharg/test/file_access.hpp>
#include <sharg/test/tmp_filename.hpp>
Expand Down Expand Up @@ -830,6 +832,11 @@ enum class foo
three
};

auto enumeration_names(foo)
{
return std::unordered_map<std::string_view, foo>{{"one", foo::one}, {"two", foo::two}, {"three", foo::three}};
}

TEST(validator_test, value_list_validator_success)
{
// type deduction
Expand Down Expand Up @@ -951,7 +958,7 @@ TEST(validator_test, value_list_validator_success)
"\n" +
basic_options_str +
" -i, --int-option (List of signed 32 bit integer)\n"
" desc Default: []. Value must be one of [-10,48,50].\n\n" +
" desc Default: []. Value must be one of [-10, 48, 50].\n\n" +
basic_version_str);
EXPECT_EQ(my_stdout, expected);
}
Expand Down

1 comment on commit b86e79e

@vercel
Copy link

@vercel vercel bot commented on b86e79e Mar 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.