Moved string stuff to new files

This commit is contained in:
matthias@arch 2022-09-26 20:31:55 +02:00
parent e7ec7f61f4
commit 1fad554a1f
7 changed files with 708 additions and 210 deletions

31
src/util/string.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "string.hpp"
#include <sstream>
namespace gz::util {
std::vector<std::string> splitStringInVector(std::string& s, char separator) {
// remove linebreaks from the end
if (*(s.end()) == '\n') { s.erase(s.end()); }
/* std::unique_ptr<std::unordered_map<Entity, std::string>> params (new std::unordered_map<Entity, std::string>); */
std::vector<std::string> v;
std::stringstream ss(s);
std::string temp;
while (std::getline(ss, temp, separator)) {
// if has "=": store latter part in vector
if (temp.find("=") != std::string::npos) {
int eqPos = temp.find("=");
v.emplace_back(temp.substr(eqPos + 1, temp.length()));
}
else {
v.emplace_back(temp);
}
}
return v;
}
} // namespace gz::util

38
src/util/string.hpp Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
namespace gz::util {
/**
* @todo document
*/
std::vector<std::string> splitStringInVector(std::string& s, char separator = ',');
/**
* @name Map with string type as key, works with strings, string_view and char*
* @{
*/
struct string_hash
{
using hash_type = std::hash<std::string_view>;
using is_transparent = void;
size_t operator()(const char* str) const { return hash_type{}(str); }
size_t operator()(std::string_view str) const { return hash_type{}(str); }
size_t operator()(std::string const& str) const { return hash_type{}(str); }
};
template<typename T>
using unordered_string_map = std::unordered_map<std::string, T, util::string_hash, std::equal_to<>>;
/**
* @}
*/
} // namespace gz::util
/**
* @file
* @brief Contains utility for strings
*/

View File

@ -0,0 +1,99 @@
#pragma once
#include <concepts>
#include <string>
#include <string_view>
namespace gz::util {
//
// CONVERT TO STRING CONCEPTS
//
// ELEMENTARY TYPES
/// is (similar or convertible to) std::string
template<typename T>
concept Stringy = std::same_as<T, std::string> || std::convertible_to<T, std::string_view>;
/// has .to_string() const member
template<typename T>
concept HasToStringMember = !Stringy<T> && requires(const T& t) { { t.to_string() }-> Stringy; };
/// works with std::to_string(), except bool
template<typename T>
concept WorksWithStdToString = !std::same_as<T, bool> && !Stringy<T> && !HasToStringMember<T> && requires(const T& t) { { std::to_string(t) } -> Stringy; };
template<typename T>
concept _ElementaryTypeConvertibleToString = Stringy<T> || HasToStringMember<T> || WorksWithStdToString<T>;
// CONTAINER
/// Forward range having string-convertible elements
template<typename T>
concept ContainerConvertibleToString = !_ElementaryTypeConvertibleToString<T> and std::ranges::forward_range<T> and _ElementaryTypeConvertibleToString<std::ranges::range_reference_t<T>>;
template<typename T>
concept _ElementaryTypeOrForwardRangeConvertibleToString = _ElementaryTypeConvertibleToString<T> || ContainerConvertibleToString<T>;
/// Pair having string-convertible elements
template<typename T>
concept PairConvertibleToString = !ContainerConvertibleToString<T> and requires(const T& p) {
requires _ElementaryTypeOrForwardRangeConvertibleToString<decltype(p.first)>;
requires _ElementaryTypeOrForwardRangeConvertibleToString<decltype(p.second)>;
};
/// Container having string-convertible pairs
template<typename T>
concept MapConvertibleToString = !PairConvertibleToString<T> and !_ElementaryTypeOrForwardRangeConvertibleToString<T> and
std::ranges::forward_range<T> and PairConvertibleToString<std::ranges::range_reference_t<T>>;
template<typename T>
concept _ContainerTypeConvertibleToString = PairConvertibleToString<T> || ContainerConvertibleToString<T> || MapConvertibleToString<T>;
template<typename T>
concept _ElementaryTypeOrContainerConvertibleToString = _ElementaryTypeConvertibleToString<T> || _ContainerTypeConvertibleToString<T>;
// VECTOR
/// Type having string-convertible x, y members
template<typename T>
concept Vector2ConvertibleToString = !_ElementaryTypeOrContainerConvertibleToString<T> &&
requires(T t) {
{ t.x } -> _ElementaryTypeOrContainerConvertibleToString;
{ t.y } -> _ElementaryTypeOrContainerConvertibleToString;
requires sizeof(t.x) * 2 == sizeof(T);
};
/// Type having string-convertible x, y, z members
template<typename T>
concept Vector3ConvertibleToString = !_ElementaryTypeOrContainerConvertibleToString<T> &&
requires(T t) {
{ t.x } -> _ElementaryTypeOrContainerConvertibleToString;
{ t.y } -> _ElementaryTypeOrContainerConvertibleToString;
{ t.z } -> _ElementaryTypeOrContainerConvertibleToString;
requires sizeof(t.x) * 3 == sizeof(T);
};
/// Type having string-convertible x, y, z, w members
template<typename T>
concept Vector4ConvertibleToString = !_ElementaryTypeOrContainerConvertibleToString<T> &&
requires(T t) {
{ t.x } -> _ElementaryTypeOrContainerConvertibleToString;
{ t.y } -> _ElementaryTypeOrContainerConvertibleToString;
{ t.z } -> _ElementaryTypeOrContainerConvertibleToString;
{ t.w } -> _ElementaryTypeOrContainerConvertibleToString;
requires sizeof(t.x) * 4 == sizeof(T);
};
// POINTER
/// Everything from string-convertibleNoPtr but "behind" a pointer
template<typename T>
concept PointerConvertibleToString = requires(const T t) { { *t } -> _ElementaryTypeOrContainerConvertibleToString; };
} // namespace gz::util
namespace gz {
}
/**
* @file
* @brief Concepts used for the to_string() functions
* @details
* These concepts are used
*/

View File

@ -0,0 +1,119 @@
#include "string_conversion.hpp"
#include "../exceptions.hpp"
#include "regex.hpp"
namespace gz {
bool isInt(const std::string& s) {
return std::regex_match(s, re::types::intT);
}
bool isInt(const std::string_view& s) {
return re::regex_match(s, re::types::intT);
}
bool isUInt(const std::string& s) {
return std::regex_match(s, re::types::uintT);
}
bool isUInt(const std::string_view& s) {
return re::regex_match(s, re::types::uintT);
}
bool isFloal(const std::string& s) {
return std::regex_match(s, re::types::floatT);
}
bool isFloat(const std::string_view& s) {
return re::regex_match(s, re::types::floatT);
}
int getIntOr(const std::string& s, int fallback) noexcept {
try {
fallback = std::stoi(s);
}
catch (...) {}
return fallback;
}
unsigned int getUnsignedIntOr(const std::string& s, unsigned int fallback) noexcept {
try {
fallback = std::stoul(s);
}
catch (...) {}
return fallback;
}
double getDoubleOr(const std::string& s, double fallback) noexcept {
try {
fallback = std::stod(s);
}
catch (...) {}
return fallback;
}
float getFloatOr(const std::string& s, float fallback) noexcept {
try {
fallback = std::stof(s);
}
catch (...) {}
return fallback;
}
bool getBoolOr(const std::string& s, bool fallback) noexcept {
if (s == "true" or s == "True" or s == "1") {
fallback = true;
}
else if (s == "false" or s == "False" or s == "0") {
fallback = false;
}
return fallback;
}
std::string getStringOr(const std::string& s, const std::string& fallback) noexcept {
if (s == "") { return fallback; }
else { return s; }
}
// TODO: remove?
/* // int = 0, double = 1, string = 2 */
/* std::variant<std::string, int, double, bool> getVariant(std::string value, GetVariantType type, bool bFallback, int iFallback, double dFallback, const char* sFallback) { */
/* std::variant<std::string, int, double, bool> val = value; */
/* /1* cout << "id-attr" << id << attr << "val: " << std::get<string>(val); *1/ */
/* switch (type) { */
/* // to integer */
/* case INT: */
/* val = getIntOr(value, iFallback); */
/* break; */
/* case DOUBLE: */
/* val = getDoubleOr(value, dFallback); */
/* break; */
/* case BOOL: */
/* val = getBoolOr(value, bFallback); */
/* break; */
/* case STRING: */
/* val = getStringOr(value, sFallback); */
/* break; */
/* } */
/* return val; */
/* } */
//
// CONVERT FROM STRING
//
template<>
bool from_string<bool>(const std::string& s) {
if (s == "true" or s == "True" or s == "1") {
return true;
}
else if (s == "false" or s == "False" or s == "0") {
return false;
}
throw InvalidArgument("s is not a bool: '" + s + "'", "from_string<bool>");
}
} // namespace gz

View File

@ -0,0 +1,398 @@
#pragma once
#include "string_concepts.hpp"
#include <string>
namespace gz {
/**
* @name Functions that determine if s is a string representation of a certain type, using regex.
* @{
*/
bool isInt(const std::string& s);
bool isInt(const std::string_view& s);
bool isUInt(const std::string& s);
bool isUInt(const std::string_view& s);
bool isFloat(const std::string& s);
bool isFloat(const std::string_view& s);
/**
* @}
*/
/**
* @name Convert to type or return fallback
* @todo Use string_views wothout constructing a std::string
* @{
*/
int getIntOr(const std::string& s, int fallback=0) noexcept;
inline int getIntOr(const std::string_view& s, int fallback=0) noexcept { return getIntOr(std::string(s), fallback); }
unsigned int getUnsignedIntOr(const std::string& s, unsigned int fallback=0) noexcept;
/* inline unsigned int getUnsignedIntOr(const std::string&& s, unsigned int fallback=0) { return getUnsignedIntOr(s, fallback); } */
inline unsigned int getUnsignedIntOr(const std::string_view& s, unsigned int fallback=0) noexcept { return getUnsignedIntOr(std::string(s), fallback); }
double getDoubleOr(const std::string& s, double fallback=0) noexcept;
/* inline double getDoubleOr(const std::string&& s, double fallback=0) { return getDoubleOr(s, fallback); } */
inline double getDoubleOr(const std::string_view& s, double fallback=0) noexcept { return getDoubleOr(std::string(s), fallback); }
float getFloatOr(const std::string& s, float fallback=0) noexcept;
/* inline float getFloatOr(const std::string&& s, float fallback=0) { return getDoubleOr(s, fallback); } */
inline float getFloatOr(const std::string_view& s, float fallback=0) noexcept { return getDoubleOr(std::string(s), fallback); }
bool getBoolOr(const std::string& s, bool fallback=false) noexcept;
/* inline bool getBoolOr(const std::string&& s, bool fallback=false) { return getBoolOr(s, fallback); } */
inline bool getBoolOr(const std::string_view& s, bool fallback=false) noexcept { return getBoolOr(std::string(s), fallback); }
/**
* @brief Returns the string or fallback if string is empty.
*/
std::string getStringOr(const std::string& s, const std::string& fallback="none") noexcept;
/**
* @}
*/
// TODO: remove?
/* enum GetVariantType { */
/* INT, DOUBLE, STRING, BOOL, */
/* }; */
/*
* @brief Converts the given string to the requested type and puts returns it in a variant
* @details
* Tries to convert the string to the specified type.
* If that fails a default value is returned.
* This is either 1 for int or double or "none" for strings.
*
* @param value String which should be converted
* @param type GetVariantType datatype to return in the variant
*
* @returns Variant containing the value in the given datatype.
*/
/* std::variant<std::string, int, double, bool> getVariant(std::string value, GetVariantType type=STRING, bool bFallback=false, int iFallback=0, double dFallback=0, const char* sFallback="none"); */
//
// CONVERT TO STRING
//
/**
* @name Converting a type to string
* @{
*/
/**
* @brief Construct a string from a string like-type
*/
template<util::Stringy T>
inline std::string to_string(const T& t) {
return t;
}
/**
* @overload
* @brief Construct a string from a type having a to_string() const member function
*/
template<util::HasToStringMember T>
inline std::string to_string(const T& t) {
return t.to_string();
}
/**
* @overload
* @brief Construct a string from a number
* @returns std::to_string(t)
*/
template<util::WorksWithStdToString T>
inline std::string to_string(const T& t) {
return std::to_string(t);
}
/**
* @brief Construct a string from a boolean
* @details
* Unlike std::to_string(bool), which returns 0 or 1, this function returns "true" or "false"
* @returns "true" or "false"
*/
inline std::string to_string(const bool& b) {
return b ? "true" : "false";
}
/**
* @overload
* @brief Construct a string from a forward range
*/
template<util::ContainerConvertibleToString T>
std::string to_string(const T& t) {
std::string s = "[ ";
for (auto it = t.begin(); it != t.end(); it++) {
s += to_string(*it) + ", ";
}
if (s.size() > 2) {
s.erase(s.size() - 2);
}
s += " ]";
return s;
}
/**
* @overload
* @brief Construct a string from a pair
*/
template<util::PairConvertibleToString T>
inline std::string to_string(const T& t) {
return "{ " + to_string(t.first) + ", " + to_string(t.second) + " }";
}
/**
* @overload
* @brief Construct a string from a forward range holding a pair, eg a map
*/
template<util::MapConvertibleToString T>
std::string to_string(const T& t) {
std::string s = "{ ";
for (const auto& [k, v] : t) {
s += to_string(k) + ": ";
s += to_string(v) + ", ";
}
if (s.size() > 2) {
s.erase(s.size() - 2);
}
s += " }";
return s;
}
/**
* @overload
* @brief Construct a string from the element the pointer points at
*/
template<util::PointerConvertibleToString T>
inline std::string to_string(const T& t) {
return to_string(*t);
}
/**
* @overload
* @brief Construct a string from a vector with x, y members
*/
template<util::Vector2ConvertibleToString T>
inline std::string to_string(const T& t) {
std::string s = "( ";
s += to_string(t.x) + ", ";
s += to_string(t.z) + " )";
return s;
}
/**
* @overload
* @brief Construct a string from a vector with x, y members
*/
template<util::Vector3ConvertibleToString T>
inline std::string to_string(const T& t) {
std::string s = "( ";
s += to_string(t.x) + ", ";
s += to_string(t.y) + ", ";
s += to_string(t.z) + " )";
return s;
}
/**
* @overload
* @brief Construct a string from a vector with x, y, z, w members
*/
template<util::Vector4ConvertibleToString T>
inline std::string to_string(const T& t) {
std::string s = "( ";
s += to_string(t.x) + ", ";
s += to_string(t.y) + ", ";
s += to_string(t.z) + ", ";
s += to_string(t.w) + " )";
return s;
}
/**
* @}
*/
//
// CONVERT FROM STRING
//
/**
* @name Construct a type from a string
* @note
* The from_string()functions (except for the bool one) simply return std::stoXX. These can throw std::invalid_argument and std::out_of_range.
* See https://en.cppreference.com/w/cpp/string/basic_string/stol
*/
template<typename T>
concept GetTypeFromStringImplemented =
std::same_as<T, int> or
std::same_as<T, long> or
std::same_as<T, long long> or
std::same_as<T, unsigned int> or
std::same_as<T, unsigned long> or
std::same_as<T, unsigned long long> or
std::same_as<T, float> or
std::same_as<T, double> or
std::same_as<T, long double> or
std::same_as<T, bool>;
template<GetTypeFromStringImplemented T>
T from_string(const std::string& s);
/// @returns std::stoi(s)
template<> inline int from_string<int>(const std::string& s) {
return std::stoi(s);
}
/// @returns std::stol(s)
template<> inline long from_string<long>(const std::string& s) {
return std::stol(s);
}
/// @returns std::stoll(s)
template<> inline long long from_string<long long>(const std::string& s) {
return std::stoll(s);
}
/// @returns std::stoul(s)
template<> inline unsigned int from_string<unsigned int>(const std::string& s) {
return std::stoul(s);
}
/// @returns std::stoul(s)
template<> inline unsigned long from_string<unsigned long>(const std::string& s) {
return std::stoul(s);
}
/// @returns std::stoull(s)
template<> inline unsigned long long from_string<unsigned long long>(const std::string& s) {
return std::stoull(s);
}
/// @returns std::stof(s)
template<> inline float from_string<float>(const std::string& s) {
return std::stof(s);
}
/// @returns std::stod(s)
template<> inline double from_string<double>(const std::string& s) {
return std::stod(s);
}
/// @returns std::stold(s)
template<> inline long double from_string<long double>(const std::string& s) {
return std::stold(s);
}
/**
* @brief Convert a string to bool
* @details
* - returns true if s = "true" or "True" or "1"
* - returns false if s = "false" or "False" or "0"
* - throws InvalidArgument otherwise
*/
template<> bool from_string<bool>(const std::string& s);
/**
* @}
*/
//
// CONCEPTS
//
/**
* @brief Any type where to_string(t) const exists returns a string-like type
* @note The function only has to exist, it does not have to be noexcept!
*/
template<typename T>
concept ConvertibleToString = requires(const T& t) { { to_string(t) } -> util::Stringy; };
/* concept CovertibleToString = requires(const T& t) { { to_string(t) }; }; */
/**
* @brief Any type where from_string(string) exists and returns T
* @note The function only has to exist, it does not have to be noexcept!
*/
template<typename T>
concept ConstructibleFromString = requires(const std::string& s) {
{ from_string<T>(s) } -> std::same_as<T>;
};
/**
* @brief Any type where to_string(t) and from_string(string) exist
*/
template<typename T>
concept StringConvertible = ConvertibleToString<T> and ConstructibleFromString<T>;
} // namespace gz
/**
* @file
* @brief Contains utilities for type conversions from string
*/
namespace gz {
/**
* @page string_conversion String conversion
* @section sc_about About
* This library provides utility for string conversion, from and to std::string.
*
* There also three important concepts, ConvertibleToString, ConstructibleFromString and @ref StringConvertible which are
* used in the @ref Log "logger" and the @ref SettingsManager "settings manager" to log and store types.
*
* If you want to use your own data type with one of these,
* you can easily @ref sc_overloads "write your own string conversion" function for your custom datatype.
*
* @section sc_to_string Convert to string
* You can use the to_string() function to turn certain types into strings.
* Concepts are used to determine the correct overload of the function.
*
* The concept ConvertibleToString is satisfied for types that can be converted to string
* using to_string().
*
* @section sc_from_string Construct from string
* You can use the from_string() function to create certain types from a string.
*
* The concept ConstructibleFromString is satisfied for types that can be constructed from a string with from_string().
*
* When constructing something from a string, there is of course the problem that errors occur at runtime when
* the string is unsuitable for construction. In this case, the from_string functions from this library throw a InvalidArgument exception.
*
* @section sc_overloads Overloading the string conversion functions
* @subsection sc_to_string_ov Overload for to_string
* If you want your custom type to be convertible to string, you have different options.
* You can either add an <code>to_string() const</code> member to your class or overload
* <code>std::string to_string(const T&)</code>.
* Example for a class called <code>Custom</code>
* @code
* std::string to_string(const Custom& c) {
* std::string s;
* ...
* return s;
* }
* @endcode
* To satisfy the concept, this overload has of course to visible by the compiler,
* so you have to at least declare it in a header file.
*
* @subsection sc_from_string_ov Overload for from_string
* Writing an overload for from_string needs a little bit more boiler plate.
* Since from_string is a templated function, you need to declare it as such.
* The function declaration in this library uses a concept so that it is only
* declared for the types that are actully implemented.
* Example for a class called <code>Custom</code>
* @code
* // declare as template, but only for Custom
* template<std::same_as<Custom> T>
* Custom from_string(const std::string& s);
*
* // instantiation/definition, but only for Custom
* template<>
* Custom from_string<Custom>(const std::string& s) {
* ...
* return Custom(...);
* };
* @endcode
*
* @subsection sc_notes Notes
* You should write your function so that the output of one can be used as input of the other.
* In other words:
* @code
* Custom c1;
* Custom c2 = from_string(to_string(c1));
* assert(c1 == c2);
* @endcode
*
* SettingsManager expects the strings from to_string() to be a single line.
* If it has multiple lines, it will not load it correctly when loading from a file.
*
* @todo Implement from_string for vectors that hold ConstructibleFromString types
* @todo Make from_string throw InvalidArgument, write docs
* @todo Make macro for all types/concepts where someone would want to implement from_string and to_string explicitly, eg vectors
*/
} // namespace gz

View File

@ -1,125 +0,0 @@
#include "util.hpp"
#include "gz_regex.hpp"
namespace gz::util {
//
// Type Conversion
//
bool isInt(std::string& s) {
return std::regex_match(s, re::types::intT);
}
bool isInt(std::string_view& s) {
return re::regex_match(s, re::types::intT);
}
int getInt(std::string& s, int fallback) {
try {
fallback = std::stoi(s);
}
catch (std::invalid_argument& e) {}
return fallback;
}
bool isUInt(std::string& s) {
return std::regex_match(s, re::types::uintT);
}
bool isUInt(std::string_view& s) {
return re::regex_match(s, re::types::uintT);
}
unsigned int getUnsignedInt(std::string& s, unsigned int fallback) {
try {
fallback = std::stoul(s);
}
catch (std::invalid_argument& e) {}
return fallback;
}
double getDouble(std::string& s, double fallback) {
try {
fallback = std::stod(s);
}
catch (std::invalid_argument& e) {}
return fallback;
}
bool isFloal(std::string& s) {
return std::regex_match(s, re::types::floatT);
}
bool isFloat(std::string_view& s) {
return re::regex_match(s, re::types::floatT);
}
float getFloat(std::string& s, float fallback) {
try {
fallback = std::stof(s);
}
catch (std::invalid_argument& e) {}
return fallback;
}
bool getBool(std::string& s, bool fallback) {
if (s == "true" or s == "True" or s == "1") {
fallback = true;
}
return fallback;
}
std::string getString(std::string s, std::string fallback) {
if (s == "") { return fallback; }
else { return s; }
}
// int = 0, double = 1, string = 2
std::variant<std::string, int, double, bool> getVariant(std::string value, Type type, bool bFallback, int iFallback, double dFallback, const char* sFallback) {
std::variant<std::string, int, double, bool> val = value;
/* cout << "id-attr" << id << attr << "val: " << std::get<string>(val); */
switch (type) {
// to integer
case INT:
val = getInt(value, iFallback);
break;
case DOUBLE:
val = getDouble(value, dFallback);
break;
case BOOL:
val = getBool(value, bFallback);
break;
default:
val = getString(value, sFallback);
break;
}
return val;
}
std::vector<std::string> splitStringInVector(std::string& s, char separator) {
// remove linebreaks from the end
if (*(s.end()) == '\n') { s.erase(s.end()); }
/* std::unique_ptr<std::unordered_map<Entity, std::string>> params (new std::unordered_map<Entity, std::string>); */
std::vector<std::string> v;
std::stringstream ss(s);
std::string temp;
while (std::getline(ss, temp, separator)) {
// if has "=": store latter part in vector
if (temp.find("=") != std::string::npos) {
int eqPos = temp.find("=");
v.emplace_back(temp.substr(eqPos + 1, temp.length()));
}
else {
v.emplace_back(temp);
}
}
return v;
}
} // namespace gz::util

View File

@ -1,96 +1,56 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <variant>
#include <concepts>
namespace gz::util {
//
// Type conversion
//
enum Type {
UINT, INT, DOUBLE, FLOAT, STRING, BOOL,
};
bool isInt(std::string& s);
bool isInt(std::string_view& s);
int getInt(std::string& s, int fallback=0);
inline int getInt(std::string&& s, int fallback=0) { return getInt(s, fallback); }
/**
* @todo Find a way to convert string_view to int without creating a string from it
*/
inline int getInt(std::string_view s, int fallback=0) { return getInt(std::string(s), fallback); }
bool isUInt(std::string& s);
bool isUInt(std::string_view& s);
unsigned int getUnsignedInt(std::string& s, unsigned int fallback=0);
inline unsigned int getUnsignedInt(std::string&& s, unsigned int fallback=0) { return getUnsignedInt(s, fallback); }
inline unsigned int getUnsignedInt(std::string_view s, unsigned int fallback=0) { return getUnsignedInt(std::string(s), fallback); }
double getDouble(std::string& s, double fallback=0);
inline double getDouble(std::string&& s, double fallback=0) { return getDouble(s, fallback); }
inline double getDouble(std::string_view s, double fallback=0) { return getDouble(std::string(s), fallback); }
bool isFloat(std::string& s);
bool isFloat(std::string_view& s);
float getFloat(std::string& s, float fallback=0);
inline float getFloat(std::string&& s, float fallback=0) { return getDouble(s, fallback); }
inline float getFloat(std::string_view s, float fallback=0) { return getDouble(std::string(s), fallback); }
bool getBool(std::string& s, bool fallback=false);
inline bool getBool(std::string&& s, bool fallback=false) { return getBool(s, fallback); }
inline bool getBool(std::string_view s, bool fallback=false) { return getBool(std::string(s), fallback); }
/**
* @brief Returns the string or fallback if string is empty.
*/
std::string getString(std::string s, std::string fallback="none");
/**
* @brief Converts the given string to the requested type and puts returns it in a variant
* @details
* Tries to convert the string to the specified type.
* If that fails a default value is returned.
* This is either 1 for int or double or "none" for strings.
*
* @param value String which should be converted
* @param type Datatype: 0 = int, 1 = double, 2 = string (default when wrong numer is given)
*
* @returns Variant containing the value in the given datatype.
* @warning Make sure to use the correct type when extracting the value from the returned variant!
*/
std::variant<std::string, int, double, bool> getVariant(std::string value, Type type=STRING, bool bFallback=false, int iFallback=0, double dFallback=0, const char* sFallback="none");
//
// INDEX UTILITY
//
/**
* @brief Increment an index. Up to containerSize, then restart at 0
*/
template<std::unsigned_integral I, std::unsigned_integral S>
inline void incrementIndex(I& i, const S containerSize) {
if (i < containerSize - 1) { i++; }
else { i = 0; }
}
/**
* @brief Decrement an index. Down to 0, then restart at containerSize - 1
*/
template<std::unsigned_integral I, std::unsigned_integral S>
inline void decrementIndex(I& i, const S containerSize) {
if (i > 0) { i--; }
else { i = containerSize - 1; }
}
/**
* @brief Like incrementIndex, but returns a new number
*/
template<std::unsigned_integral I, std::unsigned_integral S>
inline I getIncrementedIndex(const I i, const S containerSize) {
if (i < containerSize - 1) { return i + 1; }
else { return 0; }
}
/**
* @brief Like decrementIndex, but returns a new number
*/
template<std::unsigned_integral I, std::unsigned_integral S>
inline I getDecrementedIndex(const I i, const S containerSize) {
if (i > 0) { return i - 1; }
else { return containerSize - 1; }
}
/// Make wrap incices around: i = size + 2 -> i = 2, i = -2 -> i = size - 2
/**
* @brief Wrap an index around, to make it valid
* @details
* Example:
* - i = containerSize + 2 -> return 2
* - i = -2 -> return (containerSize - 1) - 2
*/
template<std::integral I, std::unsigned_integral S>
size_t getValidIndex(const I i, const S containerSize) {
std::size_t getValidIndex(const I i, const S containerSize) {
if (i < 0) {
return containerSize - (-i) % containerSize - 1;
return (containerSize - 1) - (-i) % containerSize;
}
else if (i >= static_cast<int>(containerSize)) {
return i % containerSize;
@ -98,31 +58,9 @@ namespace gz::util {
return i;
}
//
// STRING
//
std::vector<std::string> splitStringInVector(std::string& s, char separator = '|');
/**
* @name Map with string type as key, works with strings, string_view and char*
* @{
*/
struct string_hash
{
using hash_type = std::hash<std::string_view>;
using is_transparent = void;
size_t operator()(const char* str) const { return hash_type{}(str); }
size_t operator()(std::string_view str) const { return hash_type{}(str); }
size_t operator()(std::string const& str) const { return hash_type{}(str); }
};
template<typename T>
using string_map = std::unordered_map<std::string, T, util::string_hash, std::equal_to<>>;
} // namespace gz::util
#undef umap
/**
* @file
* @brief Various utilites