Moved string stuff to new files
This commit is contained in:
parent
e7ec7f61f4
commit
1fad554a1f
31
src/util/string.cpp
Normal file
31
src/util/string.cpp
Normal 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
38
src/util/string.hpp
Normal 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
|
||||||
|
*/
|
99
src/util/string_concepts.hpp
Normal file
99
src/util/string_concepts.hpp
Normal 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
|
||||||
|
*/
|
119
src/util/string_conversion.cpp
Normal file
119
src/util/string_conversion.cpp
Normal 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
|
398
src/util/string_conversion.hpp
Normal file
398
src/util/string_conversion.hpp
Normal 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
|
@ -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
|
|
@ -1,96 +1,56 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <concepts>
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
|
|
||||||
namespace gz::util {
|
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
|
// INDEX UTILITY
|
||||||
//
|
//
|
||||||
|
/**
|
||||||
|
* @brief Increment an index. Up to containerSize, then restart at 0
|
||||||
|
*/
|
||||||
template<std::unsigned_integral I, std::unsigned_integral S>
|
template<std::unsigned_integral I, std::unsigned_integral S>
|
||||||
inline void incrementIndex(I& i, const S containerSize) {
|
inline void incrementIndex(I& i, const S containerSize) {
|
||||||
if (i < containerSize - 1) { i++; }
|
if (i < containerSize - 1) { i++; }
|
||||||
else { i = 0; }
|
else { i = 0; }
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @brief Decrement an index. Down to 0, then restart at containerSize - 1
|
||||||
|
*/
|
||||||
template<std::unsigned_integral I, std::unsigned_integral S>
|
template<std::unsigned_integral I, std::unsigned_integral S>
|
||||||
inline void decrementIndex(I& i, const S containerSize) {
|
inline void decrementIndex(I& i, const S containerSize) {
|
||||||
if (i > 0) { i--; }
|
if (i > 0) { i--; }
|
||||||
else { i = containerSize - 1; }
|
else { i = containerSize - 1; }
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @brief Like incrementIndex, but returns a new number
|
||||||
|
*/
|
||||||
template<std::unsigned_integral I, std::unsigned_integral S>
|
template<std::unsigned_integral I, std::unsigned_integral S>
|
||||||
inline I getIncrementedIndex(const I i, const S containerSize) {
|
inline I getIncrementedIndex(const I i, const S containerSize) {
|
||||||
if (i < containerSize - 1) { return i + 1; }
|
if (i < containerSize - 1) { return i + 1; }
|
||||||
else { return 0; }
|
else { return 0; }
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @brief Like decrementIndex, but returns a new number
|
||||||
|
*/
|
||||||
template<std::unsigned_integral I, std::unsigned_integral S>
|
template<std::unsigned_integral I, std::unsigned_integral S>
|
||||||
inline I getDecrementedIndex(const I i, const S containerSize) {
|
inline I getDecrementedIndex(const I i, const S containerSize) {
|
||||||
if (i > 0) { return i - 1; }
|
if (i > 0) { return i - 1; }
|
||||||
else { return containerSize - 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>
|
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) {
|
if (i < 0) {
|
||||||
return containerSize - (-i) % containerSize - 1;
|
return (containerSize - 1) - (-i) % containerSize;
|
||||||
}
|
}
|
||||||
else if (i >= static_cast<int>(containerSize)) {
|
else if (i >= static_cast<int>(containerSize)) {
|
||||||
return i % containerSize;
|
return i % containerSize;
|
||||||
@ -98,31 +58,9 @@ namespace gz::util {
|
|||||||
return i;
|
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
|
} // namespace gz::util
|
||||||
|
|
||||||
#undef umap
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* @brief Various utilites
|
* @brief Various utilites
|
||||||
|
Loading…
Reference in New Issue
Block a user