Improve parameter-passing in some string conversion functions

* Allow using a range as input of joinStrings()
* Use `std::string_view` instead of `const std::string &` to pass read-only
  parameters to joinStrings() and splitString*() to avoid constructing an
  `std::string` from `const char *` parameters
* Use auto for return types of toMultiline() and toArrayOfLines()
* Does not affect BC because those are template functions
* Should not affect source compatibility; at least uses in my main projects
  seem to be unaffected
This commit is contained in:
Martchus 2021-03-05 23:01:30 +01:00
parent 6968716d5c
commit cc63c8c250
1 changed files with 28 additions and 9 deletions

View File

@ -18,6 +18,10 @@
#include <system_error> #include <system_error>
#include <vector> #include <vector>
#if __cplusplus >= 201709
#include <ranges>
#endif
namespace CppUtilities { namespace CppUtilities {
/*! /*!
@ -59,6 +63,20 @@ CPP_UTILITIES_EXPORT WideStringData convertMultiByteToWide(const std::string &in
CPP_UTILITIES_EXPORT void truncateString(std::string &str, char terminationChar = '\0'); CPP_UTILITIES_EXPORT void truncateString(std::string &str, char terminationChar = '\0');
/// \cond
namespace Detail {
#if __cplusplus >= 201709
template <class Container>
using ContainerValueType = typename std::conditional_t<std::ranges::range<Container>,
std::iterator_traits<std::remove_cvref_t<std::ranges::iterator_t<Container>>>, Container>::value_type;
#else
template <class Container> using ContainerValueType = typename Container::value_type;
#endif
template <class Container> using DefaultReturnTypeForContainer = ContainerValueType<Container>;
template <class Container> using StringParamForContainer = std::basic_string_view<typename ContainerValueType<Container>::value_type>;
} // namespace Detail
/// \endcond
/*! /*!
* \brief Joins the given \a strings using the specified \a delimiter. * \brief Joins the given \a strings using the specified \a delimiter.
* *
@ -69,13 +87,14 @@ CPP_UTILITIES_EXPORT void truncateString(std::string &str, char terminationChar
* \param omitEmpty Indicates whether empty part should be omitted. * \param omitEmpty Indicates whether empty part should be omitted.
* \param leftClosure Specifies a string to be inserted before each string (empty string by default). * \param leftClosure Specifies a string to be inserted before each string (empty string by default).
* \param rightClosure Specifies a string to be appendend after each string (empty string by default). * \param rightClosure Specifies a string to be appendend after each string (empty string by default).
* \tparam Container The STL-container used to provide the \a strings. * \tparam Container Container The STL-container used to provide the \a strings.
* \tparam ReturnType Type to store the result; defaults to the container's element type.
* \returns Returns the joined string. * \returns Returns the joined string.
*/ */
template <class Container = std::initializer_list<std::string>, class ReturnType = typename Container::value_type> template <class Container = std::initializer_list<std::string>, class ReturnType = Detail::DefaultReturnTypeForContainer<Container>>
ReturnType joinStrings(const Container &strings, const typename Container::value_type &delimiter = typename Container::value_type(), ReturnType joinStrings(const Container &strings, Detail::StringParamForContainer<Container> delimiter = Detail::StringParamForContainer<Container>(),
bool omitEmpty = false, const typename Container::value_type &leftClosure = typename Container::value_type(), bool omitEmpty = false, Detail::StringParamForContainer<Container> leftClosure = Detail::StringParamForContainer<Container>(),
const typename Container::value_type &rightClosure = typename Container::value_type()) Detail::StringParamForContainer<Container> rightClosure = Detail::StringParamForContainer<Container>())
{ {
ReturnType res; ReturnType res;
if (!strings.size()) { if (!strings.size()) {
@ -111,7 +130,7 @@ ReturnType joinStrings(const Container &strings, const typename Container::value
/*! /*!
* \brief Converts the specified \a arrayOfLines to a multiline string. * \brief Converts the specified \a arrayOfLines to a multiline string.
*/ */
template <class Container = std::initializer_list<std::string>> inline std::vector<std::string> toMultiline(const Container &arrayOfLines) template <class Container = std::initializer_list<std::string>> inline auto toMultiline(const Container &arrayOfLines)
{ {
return joinStrings(arrayOfLines, "\n", false); return joinStrings(arrayOfLines, "\n", false);
} }
@ -135,7 +154,7 @@ enum class EmptyPartsTreat {
* \returns Returns the parts. * \returns Returns the parts.
*/ */
template <class Container = std::list<std::string>> template <class Container = std::list<std::string>>
Container splitString(const typename Container::value_type &string, const typename Container::value_type &delimiter, Container splitString(Detail::StringParamForContainer<Container> string, Detail::StringParamForContainer<Container> delimiter,
EmptyPartsTreat emptyPartsRole = EmptyPartsTreat::Keep, int maxParts = -1) EmptyPartsTreat emptyPartsRole = EmptyPartsTreat::Keep, int maxParts = -1)
{ {
--maxParts; --maxParts;
@ -183,7 +202,7 @@ Container splitString(const typename Container::value_type &string, const typena
* \remarks This is a simplified version of splitString() where emptyPartsRole is always EmptyPartsTreat::Keep. * \remarks This is a simplified version of splitString() where emptyPartsRole is always EmptyPartsTreat::Keep.
*/ */
template <class Container = std::list<std::string>> template <class Container = std::list<std::string>>
Container splitStringSimple(const typename Container::value_type &string, const typename Container::value_type &delimiter, int maxParts = -1) Container splitStringSimple(Detail::StringParamForContainer<Container> string, Detail::StringParamForContainer<Container> delimiter, int maxParts = -1)
{ {
--maxParts; --maxParts;
Container res; Container res;
@ -211,7 +230,7 @@ Container splitStringSimple(const typename Container::value_type &string, const
/*! /*!
* \brief Converts the specified \a multilineString to an array of lines. * \brief Converts the specified \a multilineString to an array of lines.
*/ */
template <class Container = std::vector<std::string>> inline std::vector<std::string> toArrayOfLines(const std::string &multilineString) template <class Container = std::vector<std::string>> inline auto toArrayOfLines(const std::string &multilineString)
{ {
return splitString<Container>(multilineString, "\n", EmptyPartsTreat::Keep); return splitString<Container>(multilineString, "\n", EmptyPartsTreat::Keep);
} }