2016-06-11 19:09:14 +02:00
|
|
|
#ifndef CONVERSION_UTILITIES_STRINGCONVERSION_H
|
|
|
|
#define CONVERSION_UTILITIES_STRINGCONVERSION_H
|
2015-04-22 18:36:40 +02:00
|
|
|
|
2015-09-06 20:19:09 +02:00
|
|
|
#include "./binaryconversion.h"
|
2017-05-01 03:13:11 +02:00
|
|
|
#include "./conversionexception.h"
|
2015-04-22 18:36:40 +02:00
|
|
|
|
2016-11-13 23:06:03 +01:00
|
|
|
#include "../misc/traits.h"
|
|
|
|
|
2018-07-13 13:54:53 +02:00
|
|
|
#include <cstdlib>
|
2016-08-03 17:31:28 +02:00
|
|
|
#include <cstring>
|
2015-04-22 18:36:40 +02:00
|
|
|
#include <initializer_list>
|
2017-05-01 03:13:11 +02:00
|
|
|
#include <iomanip>
|
2015-04-22 18:36:40 +02:00
|
|
|
#include <list>
|
2015-09-01 16:06:37 +02:00
|
|
|
#include <memory>
|
2017-05-01 03:13:11 +02:00
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
2020-09-19 15:40:32 +02:00
|
|
|
#include <string_view>
|
2020-02-14 15:15:59 +01:00
|
|
|
#include <system_error>
|
2017-05-01 03:13:11 +02:00
|
|
|
#include <vector>
|
2015-04-22 18:36:40 +02:00
|
|
|
|
2021-05-16 19:21:58 +02:00
|
|
|
#if __cplusplus >= 201709 && !defined(REFLECTIVE_RAPIDJSON_GENERATOR)
|
|
|
|
#ifndef CPP_UTILITIES_USE_RANGES
|
|
|
|
#define CPP_UTILITIES_USE_RANGES
|
|
|
|
#endif
|
2021-03-05 23:01:30 +01:00
|
|
|
#include <ranges>
|
|
|
|
#endif
|
|
|
|
|
2019-06-10 21:56:46 +02:00
|
|
|
namespace CppUtilities {
|
2015-04-22 18:36:40 +02:00
|
|
|
|
2016-07-27 18:24:37 +02:00
|
|
|
/*!
|
|
|
|
* \brief The StringDataDeleter struct deletes the data of a StringData instance.
|
|
|
|
*/
|
2016-08-29 15:35:48 +02:00
|
|
|
struct CPP_UTILITIES_EXPORT StringDataDeleter {
|
2016-07-27 18:24:37 +02:00
|
|
|
/*!
|
|
|
|
* \brief Deletes the specified \a stringData with std::free(), because the memory has been
|
|
|
|
* allocated using std::malloc()/std::realloc().
|
|
|
|
*/
|
|
|
|
void operator()(char *stringData)
|
|
|
|
{
|
2017-05-01 03:13:11 +02:00
|
|
|
std::free(stringData);
|
2016-07-27 18:24:37 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Type used to return string encoding conversion result.
|
|
|
|
*/
|
2018-09-22 16:41:33 +02:00
|
|
|
using StringData = std::pair<std::unique_ptr<char[], StringDataDeleter>, std::size_t>;
|
|
|
|
//using StringData = std::pair<std::unique_ptr<char>, std::size_t>; // might work too
|
2016-07-27 18:24:37 +02:00
|
|
|
|
2017-05-01 03:13:11 +02:00
|
|
|
CPP_UTILITIES_EXPORT StringData convertString(
|
|
|
|
const char *fromCharset, const char *toCharset, const char *inputBuffer, std::size_t inputBufferSize, float outputBufferSizeFactor = 1.0f);
|
2016-08-29 15:35:48 +02:00
|
|
|
CPP_UTILITIES_EXPORT StringData convertUtf8ToUtf16LE(const char *inputBuffer, std::size_t inputBufferSize);
|
|
|
|
CPP_UTILITIES_EXPORT StringData convertUtf16LEToUtf8(const char *inputBuffer, std::size_t inputBufferSize);
|
|
|
|
CPP_UTILITIES_EXPORT StringData convertUtf8ToUtf16BE(const char *inputBuffer, std::size_t inputBufferSize);
|
|
|
|
CPP_UTILITIES_EXPORT StringData convertUtf16BEToUtf8(const char *inputBuffer, std::size_t inputBufferSize);
|
|
|
|
CPP_UTILITIES_EXPORT StringData convertLatin1ToUtf8(const char *inputBuffer, std::size_t inputBufferSize);
|
|
|
|
CPP_UTILITIES_EXPORT StringData convertUtf8ToLatin1(const char *inputBuffer, std::size_t inputBufferSize);
|
2016-07-27 18:24:37 +02:00
|
|
|
|
2018-10-03 21:26:00 +02:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2018-10-03 22:15:08 +02:00
|
|
|
using WideStringData = std::pair<std::unique_ptr<wchar_t[]>, int>;
|
2022-03-17 22:31:11 +01:00
|
|
|
CPP_UTILITIES_EXPORT std::wstring convertMultiByteToWide(std::error_code &ec, std::string_view inputBuffer);
|
2020-02-14 15:15:59 +01:00
|
|
|
CPP_UTILITIES_EXPORT WideStringData convertMultiByteToWide(std::error_code &ec, const char *inputBuffer, int inputBufferSize = -1);
|
|
|
|
CPP_UTILITIES_EXPORT WideStringData convertMultiByteToWide(std::error_code &ec, const std::string &inputBuffer);
|
2018-10-03 22:15:08 +02:00
|
|
|
CPP_UTILITIES_EXPORT WideStringData convertMultiByteToWide(const char *inputBuffer, int inputBufferSize = -1);
|
|
|
|
CPP_UTILITIES_EXPORT WideStringData convertMultiByteToWide(const std::string &inputBuffer);
|
2018-10-03 21:26:00 +02:00
|
|
|
#endif
|
|
|
|
|
2016-08-29 15:35:48 +02:00
|
|
|
CPP_UTILITIES_EXPORT void truncateString(std::string &str, char terminationChar = '\0');
|
2015-04-22 18:36:40 +02:00
|
|
|
|
2021-03-05 23:01:30 +01:00
|
|
|
/// \cond
|
|
|
|
namespace Detail {
|
2021-05-16 19:21:58 +02:00
|
|
|
#ifdef CPP_UTILITIES_USE_RANGES
|
2021-03-05 23:01:30 +01:00
|
|
|
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
|
|
|
|
|
2015-04-22 18:36:40 +02:00
|
|
|
/*!
|
|
|
|
* \brief Joins the given \a strings using the specified \a delimiter.
|
|
|
|
*
|
|
|
|
* The strings will be enclosed using the provided closures \a leftClosure and \a rightClosure.
|
|
|
|
*
|
|
|
|
* \param strings The string parts to be joined.
|
|
|
|
* \param delimiter Specifies a delimiter to be used (empty string by default).
|
|
|
|
* \param omitEmpty Indicates whether empty part should be omitted.
|
|
|
|
* \param leftClosure Specifies a string to be inserted before each string (empty string by default).
|
2021-07-03 19:07:49 +02:00
|
|
|
* \param rightClosure Specifies a string to be appended after each string (empty string by default).
|
2021-03-05 23:01:30 +01:00
|
|
|
* \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.
|
2015-04-22 18:36:40 +02:00
|
|
|
* \returns Returns the joined string.
|
|
|
|
*/
|
2021-03-05 23:01:30 +01:00
|
|
|
template <class Container = std::initializer_list<std::string>, class ReturnType = Detail::DefaultReturnTypeForContainer<Container>>
|
|
|
|
ReturnType joinStrings(const Container &strings, Detail::StringParamForContainer<Container> delimiter = Detail::StringParamForContainer<Container>(),
|
|
|
|
bool omitEmpty = false, Detail::StringParamForContainer<Container> leftClosure = Detail::StringParamForContainer<Container>(),
|
|
|
|
Detail::StringParamForContainer<Container> rightClosure = Detail::StringParamForContainer<Container>())
|
2015-04-22 18:36:40 +02:00
|
|
|
{
|
2020-07-25 22:53:46 +02:00
|
|
|
ReturnType res;
|
2018-07-01 23:21:06 +02:00
|
|
|
if (!strings.size()) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
std::size_t entries = 0, size = 0;
|
|
|
|
for (const auto &str : strings) {
|
|
|
|
if (omitEmpty && str.empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
size += str.size();
|
|
|
|
++entries;
|
|
|
|
}
|
|
|
|
if (!entries) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
size += (entries * leftClosure.size()) + (entries * rightClosure.size()) + ((entries - 1) * delimiter.size());
|
|
|
|
res.reserve(size);
|
|
|
|
for (const auto &str : strings) {
|
|
|
|
if (omitEmpty && str.empty()) {
|
|
|
|
continue;
|
2015-04-22 18:36:40 +02:00
|
|
|
}
|
2018-07-01 23:21:06 +02:00
|
|
|
if (!res.empty()) {
|
|
|
|
res.append(delimiter);
|
2015-04-22 18:36:40 +02:00
|
|
|
}
|
2018-07-01 23:21:06 +02:00
|
|
|
res.append(leftClosure);
|
|
|
|
res.append(str);
|
|
|
|
res.append(rightClosure);
|
2015-04-22 18:36:40 +02:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2017-10-23 01:09:59 +02:00
|
|
|
/*!
|
|
|
|
* \brief Converts the specified \a arrayOfLines to a multiline string.
|
|
|
|
*/
|
2021-03-05 23:01:30 +01:00
|
|
|
template <class Container = std::initializer_list<std::string>> inline auto toMultiline(const Container &arrayOfLines)
|
2017-10-23 01:09:59 +02:00
|
|
|
{
|
|
|
|
return joinStrings(arrayOfLines, "\n", false);
|
|
|
|
}
|
|
|
|
|
2015-04-22 18:36:40 +02:00
|
|
|
/*!
|
|
|
|
* \brief Specifies the role of empty parts when splitting strings.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
enum class EmptyPartsTreat {
|
2015-04-22 18:36:40 +02:00
|
|
|
Keep, /**< empty parts are kept */
|
|
|
|
Omit, /**< empty parts are omitted */
|
|
|
|
Merge /**< empty parts are omitted but cause the adjacent parts being joined using the delimiter */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Splits the given \a string at the specified \a delimiter.
|
2021-07-03 19:07:49 +02:00
|
|
|
* \param string The string to be split.
|
2021-07-24 23:38:12 +02:00
|
|
|
* \param delimiter Specifies the delimiter which must not be empty.
|
2016-06-10 14:08:56 +02:00
|
|
|
* \param emptyPartsRole Specifies the treatment of empty parts.
|
2015-04-22 18:36:40 +02:00
|
|
|
* \param maxParts Specifies the maximal number of parts. Values less or equal zero indicate an unlimited number of parts.
|
|
|
|
* \tparam Container The STL-container used to return the parts.
|
|
|
|
* \returns Returns the parts.
|
|
|
|
*/
|
2017-05-04 22:44:00 +02:00
|
|
|
template <class Container = std::list<std::string>>
|
2021-03-05 23:01:30 +01:00
|
|
|
Container splitString(Detail::StringParamForContainer<Container> string, Detail::StringParamForContainer<Container> delimiter,
|
2017-05-01 03:13:11 +02:00
|
|
|
EmptyPartsTreat emptyPartsRole = EmptyPartsTreat::Keep, int maxParts = -1)
|
2015-04-22 18:36:40 +02:00
|
|
|
{
|
|
|
|
--maxParts;
|
|
|
|
Container res;
|
2021-02-23 20:54:04 +01:00
|
|
|
typename Container::value_type *last = nullptr;
|
2015-04-22 18:36:40 +02:00
|
|
|
bool merge = false;
|
2021-05-09 18:36:51 +02:00
|
|
|
typename Container::value_type::size_type i = 0, end = string.size();
|
|
|
|
for (typename Container::value_type::size_type delimPos; i < end; i = delimPos + delimiter.size()) {
|
2015-04-22 18:36:40 +02:00
|
|
|
delimPos = string.find(delimiter, i);
|
2017-05-01 03:13:11 +02:00
|
|
|
if (!merge && maxParts >= 0 && res.size() == static_cast<typename Container::value_type::size_type>(maxParts)) {
|
|
|
|
if (delimPos == i && emptyPartsRole == EmptyPartsTreat::Merge) {
|
2021-02-23 20:54:04 +01:00
|
|
|
if (last) {
|
2015-04-22 18:36:40 +02:00
|
|
|
merge = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delimPos = Container::value_type::npos;
|
|
|
|
}
|
2017-05-01 03:13:11 +02:00
|
|
|
if (delimPos == Container::value_type::npos) {
|
2015-04-22 18:36:40 +02:00
|
|
|
delimPos = string.size();
|
|
|
|
}
|
2017-05-01 03:13:11 +02:00
|
|
|
if (emptyPartsRole == EmptyPartsTreat::Keep || i != delimPos) {
|
|
|
|
if (merge) {
|
2021-02-23 20:54:04 +01:00
|
|
|
last->append(delimiter);
|
|
|
|
last->append(string, i, delimPos - i);
|
2015-04-22 18:36:40 +02:00
|
|
|
merge = false;
|
|
|
|
} else {
|
2021-02-23 20:54:04 +01:00
|
|
|
last = &res.emplace_back(string, i, delimPos - i);
|
2015-04-22 18:36:40 +02:00
|
|
|
}
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (emptyPartsRole == EmptyPartsTreat::Merge) {
|
2021-02-23 20:54:04 +01:00
|
|
|
if (last) {
|
2015-04-22 18:36:40 +02:00
|
|
|
merge = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-09 18:36:51 +02:00
|
|
|
if (i == end && emptyPartsRole == EmptyPartsTreat::Keep) {
|
|
|
|
res.emplace_back();
|
|
|
|
}
|
2015-04-22 18:36:40 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2018-02-28 18:03:07 +01:00
|
|
|
/*!
|
|
|
|
* \brief Splits the given \a string (which might also be a string view) at the specified \a delimiter.
|
2021-07-03 19:07:49 +02:00
|
|
|
* \param string The string to be split.
|
2021-07-24 23:38:12 +02:00
|
|
|
* \param delimiter Specifies the delimiter which must not be empty.
|
2018-02-28 18:03:07 +01:00
|
|
|
* \param maxParts Specifies the maximal number of parts. Values less or equal zero indicate an unlimited number of parts.
|
|
|
|
* \tparam Container The STL-container used to return the parts.
|
|
|
|
* \returns Returns the parts.
|
|
|
|
* \remarks This is a simplified version of splitString() where emptyPartsRole is always EmptyPartsTreat::Keep.
|
|
|
|
*/
|
|
|
|
template <class Container = std::list<std::string>>
|
2021-03-05 23:14:54 +01:00
|
|
|
Container splitStringSimple(
|
|
|
|
Detail::StringParamForContainer<Container> string, Detail::StringParamForContainer<Container> delimiter, int maxParts = -1)
|
2018-02-28 18:03:07 +01:00
|
|
|
{
|
|
|
|
--maxParts;
|
|
|
|
Container res;
|
2021-05-09 18:36:51 +02:00
|
|
|
typename Container::value_type::size_type i = 0, end = string.size();
|
|
|
|
for (typename Container::value_type::size_type delimPos; i < end; i = delimPos + delimiter.size()) {
|
2018-02-28 18:03:07 +01:00
|
|
|
delimPos = string.find(delimiter, i);
|
|
|
|
if (maxParts >= 0 && res.size() == static_cast<typename Container::value_type::size_type>(maxParts)) {
|
|
|
|
delimPos = Container::value_type::npos;
|
|
|
|
}
|
|
|
|
if (delimPos == Container::value_type::npos) {
|
|
|
|
delimPos = string.size();
|
|
|
|
}
|
2021-02-09 00:22:20 +01:00
|
|
|
#if __cplusplus >= 201709
|
2021-02-08 22:53:38 +01:00
|
|
|
if constexpr (requires { res.emplace_back(string); }) {
|
|
|
|
#endif
|
2021-02-23 20:54:04 +01:00
|
|
|
res.emplace_back(string.data() + i, delimPos - i);
|
2021-02-09 00:22:20 +01:00
|
|
|
#if __cplusplus >= 201709
|
2021-02-08 22:53:38 +01:00
|
|
|
} else {
|
2021-02-23 20:54:04 +01:00
|
|
|
res.emplace(string.data() + i, delimPos - i);
|
2021-02-08 22:53:38 +01:00
|
|
|
}
|
2021-05-09 18:36:51 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if (i == end) {
|
|
|
|
#if __cplusplus >= 201709
|
|
|
|
if constexpr (requires { res.emplace_back(); }) {
|
|
|
|
#endif
|
|
|
|
res.emplace_back();
|
|
|
|
#if __cplusplus >= 201709
|
|
|
|
} else {
|
|
|
|
res.emplace();
|
|
|
|
}
|
2021-02-08 22:53:38 +01:00
|
|
|
#endif
|
2018-02-28 18:03:07 +01:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2017-10-23 01:09:59 +02:00
|
|
|
/*!
|
|
|
|
* \brief Converts the specified \a multilineString to an array of lines.
|
|
|
|
*/
|
2021-03-05 23:01:30 +01:00
|
|
|
template <class Container = std::vector<std::string>> inline auto toArrayOfLines(const std::string &multilineString)
|
2017-10-23 01:09:59 +02:00
|
|
|
{
|
|
|
|
return splitString<Container>(multilineString, "\n", EmptyPartsTreat::Keep);
|
|
|
|
}
|
|
|
|
|
2015-04-22 18:36:40 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns whether \a str starts with \a phrase.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename StringType> bool startsWith(const StringType &str, const StringType &phrase)
|
2015-04-22 18:36:40 +02:00
|
|
|
{
|
2017-05-01 03:13:11 +02:00
|
|
|
if (str.size() < phrase.size()) {
|
2015-04-22 18:36:40 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-10-27 15:43:44 +01:00
|
|
|
for (auto stri = str.cbegin(), strend = str.cend(), phrasei = phrase.cbegin(), phraseend = phrase.cend();; ++stri, ++phrasei) {
|
2017-05-01 03:13:11 +02:00
|
|
|
if (phrasei == phraseend) {
|
2015-04-22 18:36:40 +02:00
|
|
|
return true;
|
2019-10-27 15:43:44 +01:00
|
|
|
} else if (stri == strend) {
|
|
|
|
return false;
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (*stri != *phrasei) {
|
2015-04-22 18:36:40 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-08-03 17:31:28 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns whether \a str starts with \a phrase.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename StringType> bool startsWith(const StringType &str, const typename StringType::value_type *phrase)
|
2016-08-03 17:31:28 +02:00
|
|
|
{
|
2019-10-27 15:43:44 +01:00
|
|
|
for (auto stri = str.cbegin(), strend = str.cend();; ++stri, ++phrase) {
|
2017-05-01 03:13:11 +02:00
|
|
|
if (!*phrase) {
|
2016-08-03 17:31:28 +02:00
|
|
|
return true;
|
2019-10-27 15:43:44 +01:00
|
|
|
} else if (stri == strend) {
|
|
|
|
return false;
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (*stri != *phrase) {
|
2016-08-03 17:31:28 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-30 20:34:16 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns whether \a str ends with \a phrase.
|
|
|
|
*/
|
|
|
|
template <typename StringType> bool endsWith(const StringType &str, const StringType &phrase)
|
|
|
|
{
|
|
|
|
if (str.size() < phrase.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-03-19 23:09:01 +01:00
|
|
|
for (auto stri = str.cend() - static_cast<typename StringType::difference_type>(phrase.size()), strend = str.cend(), phrasei = phrase.cbegin();
|
|
|
|
stri != strend; ++stri, ++phrasei) {
|
2019-10-30 20:34:16 +01:00
|
|
|
if (*stri != *phrasei) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether \a str ends with \a phrase.
|
|
|
|
*/
|
|
|
|
template <typename StringType> bool endsWith(const StringType &str, const typename StringType::value_type *phrase)
|
|
|
|
{
|
|
|
|
const auto phraseSize = std::strlen(phrase);
|
|
|
|
if (str.size() < phraseSize) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-03-19 23:09:01 +01:00
|
|
|
for (auto stri = str.cend() - static_cast<typename StringType::difference_type>(phraseSize), strend = str.cend(); stri != strend;
|
|
|
|
++stri, ++phrase) {
|
2019-10-30 20:34:16 +01:00
|
|
|
if (*stri != *phrase) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-03 17:31:28 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns whether \a str contains the specified \a substrings.
|
|
|
|
* \remarks The \a substrings must occur in the specified order.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename StringType> bool containsSubstrings(const StringType &str, std::initializer_list<StringType> substrings)
|
2016-08-03 17:31:28 +02:00
|
|
|
{
|
|
|
|
typename StringType::size_type currentPos = 0;
|
2017-05-01 03:13:11 +02:00
|
|
|
for (const auto &substr : substrings) {
|
|
|
|
if ((currentPos = str.find(substr, currentPos)) == StringType::npos) {
|
2016-08-03 17:31:28 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
currentPos += substr.size();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether \a str contains the specified \a substrings.
|
|
|
|
* \remarks The \a substrings must occur in the specified order.
|
|
|
|
*/
|
2016-11-13 23:06:03 +01:00
|
|
|
template <typename StringType>
|
|
|
|
bool containsSubstrings(const StringType &str, std::initializer_list<const typename StringType::value_type *> substrings)
|
2016-08-03 17:31:28 +02:00
|
|
|
{
|
|
|
|
typename StringType::size_type currentPos = 0;
|
2017-05-01 03:13:11 +02:00
|
|
|
for (const auto *substr : substrings) {
|
|
|
|
if ((currentPos = str.find(substr, currentPos)) == StringType::npos) {
|
2016-08-03 17:31:28 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
currentPos += std::strlen(substr);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-07 00:52:06 +02:00
|
|
|
/*!
|
2021-07-03 19:07:49 +02:00
|
|
|
* \brief Replaces all occurrences of \a find with \a relpace in the specified \a str.
|
2015-07-07 00:52:06 +02:00
|
|
|
*/
|
2020-09-19 15:40:32 +02:00
|
|
|
template <typename StringType1, typename StringType2, typename StringType3>
|
|
|
|
void findAndReplace(StringType1 &str, const StringType2 &find, const StringType3 &replace)
|
2015-07-07 00:52:06 +02:00
|
|
|
{
|
2020-09-19 15:40:32 +02:00
|
|
|
for (typename StringType1::size_type i = 0; (i = str.find(find, i)) != StringType1::npos; i += replace.size()) {
|
2015-07-07 00:52:06 +02:00
|
|
|
str.replace(i, find.size(), replace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-19 15:40:32 +02:00
|
|
|
/*!
|
2021-07-03 19:07:49 +02:00
|
|
|
* \brief Replaces all occurrences of \a find with \a relpace in the specified \a str.
|
2020-09-19 15:40:32 +02:00
|
|
|
*/
|
|
|
|
template <typename StringType>
|
|
|
|
inline void findAndReplace(StringType &str, const typename StringType::value_type *find, const typename StringType::value_type *replace)
|
|
|
|
{
|
|
|
|
findAndReplace(
|
|
|
|
str, std::basic_string_view<typename StringType::value_type>(find), std::basic_string_view<typename StringType::value_type>(replace));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-07-03 19:07:49 +02:00
|
|
|
* \brief Replaces all occurrences of \a find with \a relpace in the specified \a str.
|
2020-09-19 15:40:32 +02:00
|
|
|
*/
|
|
|
|
template <typename StringType1, typename StringType2>
|
|
|
|
inline void findAndReplace(StringType1 &str, const StringType2 &find, const typename StringType1::value_type *replace)
|
|
|
|
{
|
|
|
|
findAndReplace(str, find, std::basic_string_view<typename StringType1::value_type>(replace));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-07-03 19:07:49 +02:00
|
|
|
* \brief Replaces all occurrences of \a find with \a relpace in the specified \a str.
|
2020-09-19 15:40:32 +02:00
|
|
|
*/
|
|
|
|
template <typename StringType1, typename StringType2>
|
|
|
|
inline void findAndReplace(StringType1 &str, const typename StringType1::value_type *find, const StringType2 &replace)
|
|
|
|
{
|
|
|
|
findAndReplace(str, std::basic_string_view<typename StringType1::value_type>(find), replace);
|
|
|
|
}
|
|
|
|
|
2016-11-13 23:06:03 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the character representation of the specified \a digit.
|
|
|
|
* \remarks
|
|
|
|
* - Uses capital letters.
|
|
|
|
* - Valid values for \a digit: 0 <= \a digit <= 35
|
|
|
|
*/
|
2017-06-29 18:24:11 +02:00
|
|
|
template <typename CharType> constexpr CharType digitToChar(CharType digit)
|
2016-11-13 23:06:03 +01:00
|
|
|
{
|
2017-06-29 18:24:11 +02:00
|
|
|
return digit <= 9 ? (digit + '0') : (digit + 'A' - 10);
|
2016-11-13 23:06:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Converts the given \a number to its equivalent string representation using the specified \a base.
|
2018-09-22 16:42:00 +02:00
|
|
|
* \tparam IntegralType The data type of the given number.
|
2016-11-13 23:06:03 +01:00
|
|
|
* \tparam StringType The string type (should be an instantiation of the basic_string class template).
|
|
|
|
* \sa stringToNumber()
|
|
|
|
*/
|
2021-03-22 12:27:40 +01:00
|
|
|
template <typename IntegralType, class StringType = std::string, typename BaseType = IntegralType,
|
2019-06-10 21:56:46 +02:00
|
|
|
CppUtilities::Traits::EnableIf<std::is_integral<IntegralType>, std::is_unsigned<IntegralType>> * = nullptr>
|
2021-03-22 12:27:40 +01:00
|
|
|
StringType numberToString(IntegralType number, BaseType base = 10)
|
2016-11-13 23:06:03 +01:00
|
|
|
{
|
|
|
|
std::size_t resSize = 0;
|
2021-03-22 12:27:40 +01:00
|
|
|
for (auto n = number; n; n /= static_cast<IntegralType>(base), ++resSize)
|
2017-05-01 03:13:11 +02:00
|
|
|
;
|
2016-11-13 23:06:03 +01:00
|
|
|
StringType res;
|
|
|
|
res.reserve(resSize);
|
2017-03-07 00:28:46 +01:00
|
|
|
do {
|
2021-03-19 23:09:01 +01:00
|
|
|
res.insert(res.begin(), digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % base)));
|
2021-03-22 12:27:40 +01:00
|
|
|
number /= static_cast<IntegralType>(base);
|
2017-05-01 03:13:11 +02:00
|
|
|
} while (number);
|
2016-11-13 23:06:03 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-04-22 18:36:40 +02:00
|
|
|
/*!
|
2016-07-27 18:24:37 +02:00
|
|
|
* \brief Converts the given \a number to its equivalent string representation using the specified \a base.
|
2018-09-22 16:42:00 +02:00
|
|
|
* \tparam IntegralType The data type of the given number.
|
2015-04-22 18:36:40 +02:00
|
|
|
* \tparam StringType The string type (should be an instantiation of the basic_string class template).
|
|
|
|
* \sa stringToNumber()
|
|
|
|
*/
|
2021-03-22 12:27:40 +01:00
|
|
|
template <typename IntegralType, class StringType = std::string, typename BaseType = IntegralType,
|
2018-05-08 00:35:51 +02:00
|
|
|
Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>> * = nullptr>
|
2021-03-22 12:27:40 +01:00
|
|
|
StringType numberToString(IntegralType number, BaseType base = 10)
|
2016-11-13 23:06:03 +01:00
|
|
|
{
|
|
|
|
const bool negative = number < 0;
|
|
|
|
std::size_t resSize;
|
2017-05-01 03:13:11 +02:00
|
|
|
if (negative) {
|
2016-11-13 23:06:03 +01:00
|
|
|
number = -number, resSize = 1;
|
|
|
|
} else {
|
|
|
|
resSize = 0;
|
|
|
|
}
|
2021-03-22 12:27:40 +01:00
|
|
|
for (auto n = number; n; n /= static_cast<IntegralType>(base), ++resSize)
|
2017-05-01 03:13:11 +02:00
|
|
|
;
|
2016-11-13 23:06:03 +01:00
|
|
|
StringType res;
|
|
|
|
res.reserve(resSize);
|
2017-03-07 00:28:46 +01:00
|
|
|
do {
|
2021-03-22 12:27:40 +01:00
|
|
|
res.insert(res.begin(),
|
|
|
|
digitToChar<typename StringType::value_type>(static_cast<typename StringType::value_type>(number % static_cast<IntegralType>(base))));
|
|
|
|
number /= static_cast<IntegralType>(base);
|
2017-05-01 03:13:11 +02:00
|
|
|
} while (number);
|
|
|
|
if (negative) {
|
2016-11-13 23:06:03 +01:00
|
|
|
res.insert(res.begin(), '-');
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Converts the given \a number to its equivalent string representation using the specified \a base.
|
2018-09-22 16:42:00 +02:00
|
|
|
* \tparam FloatingType The data type of the given number.
|
2016-11-13 23:06:03 +01:00
|
|
|
* \tparam StringType The string type (should be an instantiation of the basic_string class template).
|
2021-07-03 19:07:49 +02:00
|
|
|
* \remarks This function is using std::basic_stringstream internally and hence also has its limitations (eg. regarding
|
2016-11-13 23:06:03 +01:00
|
|
|
* \a base and types).
|
2017-06-08 00:40:59 +02:00
|
|
|
* \sa stringToNumber(), bufferToNumber()
|
2016-11-13 23:06:03 +01:00
|
|
|
*/
|
2018-05-08 00:35:51 +02:00
|
|
|
template <typename FloatingType, class StringType = std::string, Traits::EnableIf<std::is_floating_point<FloatingType>> * = nullptr>
|
2021-03-19 23:09:01 +01:00
|
|
|
StringType numberToString(FloatingType number, int base = 10)
|
2015-04-22 18:36:40 +02:00
|
|
|
{
|
|
|
|
std::basic_stringstream<typename StringType::value_type> ss;
|
|
|
|
ss << std::setbase(base) << number;
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2016-11-13 23:06:03 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns number/digit of the specified \a character representation using the specified \a base.
|
|
|
|
* \throws A ConversionException will be thrown if the provided \a character does not represent a valid digit for the specified \a base.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename CharType> CharType charToDigit(CharType character, CharType base)
|
2016-11-13 23:06:03 +01:00
|
|
|
{
|
2018-05-31 22:28:38 +02:00
|
|
|
CharType res = base;
|
2017-05-01 03:13:11 +02:00
|
|
|
if (character >= '0' && character <= '9') {
|
2016-11-13 23:06:03 +01:00
|
|
|
res = character - '0';
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (character >= 'a' && character <= 'z') {
|
2016-11-13 23:06:03 +01:00
|
|
|
res = character - 'a' + 10;
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (character >= 'A' && character <= 'Z') {
|
2016-11-13 23:06:03 +01:00
|
|
|
res = character - 'A' + 10;
|
|
|
|
}
|
2018-05-31 22:28:38 +02:00
|
|
|
if (res < base) {
|
|
|
|
return res;
|
2016-11-13 23:06:03 +01:00
|
|
|
}
|
2018-05-31 22:28:38 +02:00
|
|
|
std::string errorMsg;
|
|
|
|
errorMsg.reserve(36);
|
|
|
|
errorMsg += "The character \"";
|
2021-03-19 23:09:01 +01:00
|
|
|
errorMsg += character >= ' ' && character <= '~' ? static_cast<std::string::value_type>(character) : '?';
|
2018-05-31 22:28:38 +02:00
|
|
|
errorMsg += "\" is no valid digit.";
|
|
|
|
throw ConversionException(std::move(errorMsg));
|
2016-11-13 23:06:03 +01:00
|
|
|
}
|
|
|
|
|
2021-05-24 19:16:49 +02:00
|
|
|
/// \cond
|
|
|
|
namespace Detail {
|
|
|
|
template <typename IntegralType, typename CharType, typename BaseType = IntegralType>
|
|
|
|
void raiseAndAdd(IntegralType &result, BaseType base, CharType character)
|
|
|
|
{
|
|
|
|
if (character == ' ') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#ifdef __GNUC__ // overflow detection only supported on GCC and Clang
|
|
|
|
if (__builtin_mul_overflow(result, base, &result)
|
|
|
|
|| __builtin_add_overflow(result, charToDigit(character, static_cast<CharType>(base)), &result)) {
|
|
|
|
throw ConversionException("Number exceeds limit.");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
result *= static_cast<IntegralType>(base);
|
|
|
|
result += static_cast<IntegralType>(charToDigit<CharType>(character, static_cast<CharType>(base)));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
} // namespace Detail
|
|
|
|
/// \endcond
|
|
|
|
|
2015-04-22 18:36:40 +02:00
|
|
|
/*!
|
2021-05-24 19:28:39 +02:00
|
|
|
* \brief Converts the given \a string of \a size characters to an unsigned numeric value using the specified \a base.
|
2018-09-22 16:42:00 +02:00
|
|
|
* \tparam IntegralType The data type used to store the converted value.
|
2021-05-24 19:28:39 +02:00
|
|
|
* \tparam CharType The character type.
|
2016-11-13 23:06:03 +01:00
|
|
|
* \throws A ConversionException will be thrown if the provided \a string is not a valid number.
|
2021-05-24 19:28:39 +02:00
|
|
|
* \sa numberToString(), stringToNumber()
|
2015-04-22 18:36:40 +02:00
|
|
|
*/
|
2021-05-24 19:28:39 +02:00
|
|
|
template <typename IntegralType, class CharType, typename BaseType = IntegralType,
|
|
|
|
Traits::EnableIf<std::is_integral<IntegralType>, std::is_unsigned<IntegralType>> * = nullptr>
|
|
|
|
IntegralType bufferToNumber(const CharType *string, std::size_t size, BaseType base = 10)
|
2016-11-13 23:06:03 +01:00
|
|
|
{
|
|
|
|
IntegralType result = 0;
|
2021-05-24 19:28:39 +02:00
|
|
|
for (const CharType *end = string + size; string != end; ++string) {
|
|
|
|
Detail::raiseAndAdd(result, base, *string);
|
2016-11-13 23:06:03 +01:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-05-24 19:28:39 +02:00
|
|
|
* \brief Converts the given \a string of \a size characters to a signed numeric value using the specified \a base.
|
2018-09-22 16:42:00 +02:00
|
|
|
* \tparam IntegralType The data type used to store the converted value.
|
2021-05-24 19:28:39 +02:00
|
|
|
* \tparam CharType The character type.
|
2016-11-13 23:06:03 +01:00
|
|
|
* \throws A ConversionException will be thrown if the provided \a string is not a valid number.
|
2021-05-24 19:28:39 +02:00
|
|
|
* \sa numberToString(), stringToNumber()
|
2016-11-13 23:06:03 +01:00
|
|
|
*/
|
2021-05-24 19:28:39 +02:00
|
|
|
template <typename IntegralType, typename CharType, typename BaseType = IntegralType,
|
|
|
|
Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>> * = nullptr>
|
|
|
|
IntegralType bufferToNumber(const CharType *string, std::size_t size, BaseType base = 10)
|
2016-11-13 23:06:03 +01:00
|
|
|
{
|
2021-05-24 19:28:39 +02:00
|
|
|
if (!size) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
const CharType *end = string + size;
|
|
|
|
for (; string != end && *string == ' '; ++string)
|
2017-06-08 00:39:54 +02:00
|
|
|
;
|
2021-05-24 19:28:39 +02:00
|
|
|
if (string == end) {
|
2016-11-13 23:06:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2021-05-24 19:28:39 +02:00
|
|
|
const bool negative = (*string == '-');
|
2017-05-01 03:13:11 +02:00
|
|
|
if (negative) {
|
2021-05-24 19:28:39 +02:00
|
|
|
++string;
|
2016-11-13 23:06:03 +01:00
|
|
|
}
|
|
|
|
IntegralType result = 0;
|
2021-05-24 19:28:39 +02:00
|
|
|
for (; string != end; ++string) {
|
|
|
|
Detail::raiseAndAdd(result, base, *string);
|
2016-11-13 23:06:03 +01:00
|
|
|
}
|
|
|
|
return negative ? -result : result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2021-05-24 19:28:39 +02:00
|
|
|
* \brief Converts the given \a string to an unsigned/signed number assuming \a string uses the specified \a base.
|
|
|
|
* \tparam IntegralType The data type used to store the converted value.
|
2016-11-13 23:06:03 +01:00
|
|
|
* \tparam StringType The string type (should be an instantiation of the basic_string class template).
|
|
|
|
* \throws A ConversionException will be thrown if the provided \a string is not a valid number.
|
2021-05-24 19:28:39 +02:00
|
|
|
* \sa numberToString(), bufferToNumber()
|
|
|
|
*/
|
|
|
|
template <typename IntegralType, class StringType, typename BaseType = IntegralType,
|
|
|
|
Traits::EnableIf<std::is_integral<IntegralType>, Traits::Not<std::is_scalar<std::decay_t<StringType>>>> * = nullptr>
|
|
|
|
IntegralType stringToNumber(const StringType &string, BaseType base = 10)
|
|
|
|
{
|
|
|
|
return bufferToNumber<IntegralType, typename StringType::value_type, BaseType>(string.data(), string.size(), base);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Converts the given \a stringView to a number assuming \a stringView uses the specified \a base.
|
|
|
|
* \tparam FloatingType The data type used to store the converted value.
|
|
|
|
* \tparam StringViewType The string view type (must be an instantiation of the basic_string_view class template).
|
|
|
|
* \throws A ConversionException will be thrown if the provided \a string is not a valid number.
|
2021-07-03 19:07:49 +02:00
|
|
|
* \remarks This function is using std::basic_stringstream internally and hence also has its limitations (eg. regarding
|
2016-11-13 23:06:03 +01:00
|
|
|
* \a base and types).
|
2017-06-08 00:40:59 +02:00
|
|
|
* \sa numberToString(), bufferToNumber()
|
2016-11-13 23:06:03 +01:00
|
|
|
*/
|
2021-05-24 19:28:39 +02:00
|
|
|
template <typename FloatingType, class StringViewType,
|
|
|
|
Traits::EnableIf<std::is_floating_point<FloatingType>, Traits::IsSpecializationOf<StringViewType, std::basic_string_view>> * = nullptr>
|
|
|
|
FloatingType stringToNumber(StringViewType stringView, int base = 10)
|
2015-04-22 18:36:40 +02:00
|
|
|
{
|
2021-05-24 19:28:39 +02:00
|
|
|
std::basic_stringstream<typename StringViewType::value_type> ss;
|
|
|
|
ss << std::setbase(base) << stringView;
|
2016-11-13 23:06:03 +01:00
|
|
|
FloatingType result;
|
2017-05-01 03:13:11 +02:00
|
|
|
if ((ss >> result) && ss.eof()) {
|
2015-04-22 18:36:40 +02:00
|
|
|
return result;
|
|
|
|
}
|
2018-05-31 22:28:38 +02:00
|
|
|
std::string errorMsg;
|
2021-05-24 19:28:39 +02:00
|
|
|
errorMsg.reserve(48 + stringView.size());
|
2018-05-31 22:28:38 +02:00
|
|
|
errorMsg += "The string \"";
|
2021-05-24 19:28:39 +02:00
|
|
|
errorMsg += stringView;
|
2021-05-23 19:01:22 +02:00
|
|
|
errorMsg += "\" is no valid floating point number.";
|
2018-05-31 22:28:38 +02:00
|
|
|
throw ConversionException(errorMsg);
|
2015-04-22 18:36:40 +02:00
|
|
|
}
|
|
|
|
|
2021-05-24 19:28:39 +02:00
|
|
|
/*!
|
|
|
|
* \brief Converts the given \a string to a number assuming \a string uses the specified \a base.
|
|
|
|
* \tparam FloatingType The data type used to store the converted value.
|
|
|
|
* \tparam StringType The string type (should be an instantiation of the basic_string class template).
|
|
|
|
* \throws A ConversionException will be thrown if the provided \a string is not a valid number.
|
2021-07-03 19:07:49 +02:00
|
|
|
* \remarks This function is using std::basic_stringstream internally and hence also has its limitations (eg. regarding
|
2021-05-24 19:28:39 +02:00
|
|
|
* \a base and types).
|
|
|
|
* \sa numberToString(), bufferToNumber()
|
|
|
|
*/
|
|
|
|
template <typename FloatingType, class StringType,
|
|
|
|
Traits::EnableIf<std::is_floating_point<FloatingType>, Traits::Not<std::is_scalar<std::decay_t<StringType>>>,
|
|
|
|
Traits::Not<Traits::IsSpecializationOf<StringType, std::basic_string_view>>> * = nullptr>
|
|
|
|
FloatingType stringToNumber(const StringType &string, int base = 10)
|
|
|
|
{
|
|
|
|
using StringViewType = std::basic_string_view<typename StringType::value_type>;
|
|
|
|
return stringToNumber<FloatingType, StringViewType>(StringViewType(string.data(), string.size()), base);
|
|
|
|
}
|
|
|
|
|
2016-06-12 01:56:57 +02:00
|
|
|
/*!
|
2017-06-08 00:40:59 +02:00
|
|
|
* \brief Converts the given null-terminated \a string to an unsigned numeric value using the specified \a base.
|
2018-09-22 16:42:00 +02:00
|
|
|
* \tparam IntegralType The data type used to store the converted value.
|
|
|
|
* \tparam CharType The character type.
|
2016-11-13 23:06:03 +01:00
|
|
|
* \throws A ConversionException will be thrown if the provided \a string is not a valid number.
|
2017-06-08 00:40:59 +02:00
|
|
|
* \sa numberToString(), bufferToNumber()
|
2016-06-12 01:56:57 +02:00
|
|
|
*/
|
2021-03-22 12:27:40 +01:00
|
|
|
template <typename IntegralType, typename CharType, typename BaseType = IntegralType,
|
|
|
|
Traits::EnableIf<std::is_integral<IntegralType>, std::is_unsigned<IntegralType>> * = nullptr>
|
|
|
|
IntegralType stringToNumber(const CharType *string, BaseType base = 10)
|
2016-06-12 01:56:57 +02:00
|
|
|
{
|
2016-11-13 23:06:03 +01:00
|
|
|
IntegralType result = 0;
|
2017-05-01 03:13:11 +02:00
|
|
|
for (; *string; ++string) {
|
2021-05-24 19:16:49 +02:00
|
|
|
Detail::raiseAndAdd(result, base, *string);
|
2016-11-13 23:06:03 +01:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-09-22 16:47:44 +02:00
|
|
|
/*!
|
|
|
|
* \brief Converts the given null-terminated \a string to a number assuming \a string uses the specified \a base.
|
|
|
|
* \tparam FloatingType The data type used to store the converted value.
|
|
|
|
* \tparam CharType The character type.
|
|
|
|
* \throws A ConversionException will be thrown if the provided \a string is not a valid number.
|
2021-07-03 19:07:49 +02:00
|
|
|
* \remarks This function is using std::basic_stringstream internally and hence also has its limitations (eg. regarding
|
2018-09-22 16:47:44 +02:00
|
|
|
* \a base and types).
|
|
|
|
* \sa numberToString(), bufferToNumber()
|
|
|
|
*/
|
|
|
|
template <typename FloatingType, class CharType, Traits::EnableIf<std::is_floating_point<FloatingType>> * = nullptr>
|
2021-03-19 23:09:01 +01:00
|
|
|
FloatingType stringToNumber(const CharType *string, int base = 10)
|
2018-09-22 16:47:44 +02:00
|
|
|
{
|
2021-05-24 19:28:39 +02:00
|
|
|
return stringToNumber<FloatingType, std::basic_string_view<CharType>>(string, base);
|
2017-06-08 00:40:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Converts the given null-terminated \a string to a signed numeric value using the specified \a base.
|
2018-09-22 16:42:00 +02:00
|
|
|
* \tparam IntegralType The data type used to store the converted value.
|
|
|
|
* \tparam CharType The character type.
|
2017-06-08 00:40:59 +02:00
|
|
|
* \throws A ConversionException will be thrown if the provided \a string is not a valid number.
|
|
|
|
* \sa numberToString(), bufferToNumber()
|
2016-11-13 23:06:03 +01:00
|
|
|
*/
|
2021-03-22 12:27:40 +01:00
|
|
|
template <typename IntegralType, typename CharType, typename BaseType = IntegralType,
|
|
|
|
Traits::EnableIf<std::is_integral<IntegralType>, std::is_signed<IntegralType>> * = nullptr>
|
2021-03-19 23:09:01 +01:00
|
|
|
IntegralType stringToNumber(const CharType *string, IntegralType base = 10)
|
2016-11-13 23:06:03 +01:00
|
|
|
{
|
2017-05-01 03:13:11 +02:00
|
|
|
if (!*string) {
|
2016-11-13 23:06:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2017-06-08 00:39:54 +02:00
|
|
|
for (; *string && *string == ' '; ++string)
|
|
|
|
;
|
|
|
|
if (!*string) {
|
|
|
|
return 0;
|
|
|
|
}
|
2016-11-13 23:06:03 +01:00
|
|
|
const bool negative = (*string == '-');
|
2017-05-01 03:13:11 +02:00
|
|
|
if (negative) {
|
2016-11-13 23:06:03 +01:00
|
|
|
++string;
|
|
|
|
}
|
|
|
|
IntegralType result = 0;
|
2017-05-01 03:13:11 +02:00
|
|
|
for (; *string; ++string) {
|
2021-05-24 19:16:49 +02:00
|
|
|
Detail::raiseAndAdd(result, base, *string);
|
2016-06-12 01:56:57 +02:00
|
|
|
}
|
2016-11-13 23:06:03 +01:00
|
|
|
return negative ? -result : result;
|
2016-06-12 01:56:57 +02:00
|
|
|
}
|
|
|
|
|
2015-04-22 18:36:40 +02:00
|
|
|
/*!
|
|
|
|
* \brief Interprets the given \a integer at the specified position as std::string using the specified byte order.
|
|
|
|
*
|
2016-07-27 18:24:37 +02:00
|
|
|
* Example: interpretation of ID3v2 frame IDs (stored as 32-bit integer) as string
|
2015-07-07 00:52:06 +02:00
|
|
|
* - 0x54495432/1414091826 will be interpreted as "TIT2".
|
2016-07-27 18:24:37 +02:00
|
|
|
* - 0x00545432/5526578 will be interpreted as "TT2" using start offset 1 to omit the first byte.
|
2015-04-22 18:36:40 +02:00
|
|
|
*
|
|
|
|
* \tparam T The data type of the integer to be interpreted.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename T> std::string interpretIntegerAsString(T integer, int startOffset = 0)
|
2015-04-22 18:36:40 +02:00
|
|
|
{
|
|
|
|
char buffer[sizeof(T)];
|
2019-06-10 21:56:46 +02:00
|
|
|
BE::getBytes(integer, buffer);
|
2021-03-19 23:09:01 +01:00
|
|
|
return std::string(buffer + startOffset, sizeof(T) - static_cast<std::size_t>(startOffset));
|
2015-04-22 18:36:40 +02:00
|
|
|
}
|
|
|
|
|
2019-03-13 19:00:37 +01:00
|
|
|
CPP_UTILITIES_EXPORT std::string dataSizeToString(std::uint64_t sizeInByte, bool includeByte = false);
|
2016-08-29 15:35:48 +02:00
|
|
|
CPP_UTILITIES_EXPORT std::string bitrateToString(double speedInKbitsPerSecond, bool useByteInsteadOfBits = false);
|
2019-03-13 19:00:37 +01:00
|
|
|
CPP_UTILITIES_EXPORT std::string encodeBase64(const std::uint8_t *data, std::uint32_t dataSize);
|
|
|
|
CPP_UTILITIES_EXPORT std::pair<std::unique_ptr<std::uint8_t[]>, std::uint32_t> decodeBase64(const char *encodedStr, const std::uint32_t strSize);
|
2019-06-10 21:56:46 +02:00
|
|
|
} // namespace CppUtilities
|
2015-04-22 18:36:40 +02:00
|
|
|
|
2016-06-11 19:09:14 +02:00
|
|
|
#endif // CONVERSION_UTILITIES_STRINGCONVERSION_H
|