#pragma once
#include <util/system/defaults.h>
#include <util/stream/str.h>
#include <util/generic/maybe.h>
#include <util/generic/string.h>
#include <util/generic/strbuf.h>
#include <util/generic/typetraits.h>
#include <util/generic/yexception.h>
/*
* specialized for all arithmetic types
*/
template <class T>
size_t ToStringImpl(T t, char* buf, size_t len);
/**
* Converts @c t to string writing not more than @c len bytes to output buffer @c buf.
* No NULL terminator appended! Throws exception on buffer overflow.
* @return number of bytes written
*/
template <class T>
inline size_t ToString(const T& t, char* buf, size_t len) {
using TParam = typename TTypeTraits<T>::TFuncParam;
return ToStringImpl<TParam>(t, buf, len);
}
/**
* Floating point to string conversion mode, values are enforced by `dtoa_impl.cpp`.
*/
enum EFloatToStringMode {
/** 0.1f -> "0.1", 0.12345678f -> "0.12345678", ignores ndigits. */
PREC_AUTO = 0,
/** "%g" mode, writes up to the given number of significant digits:
* 0.1f -> "0.1", 0.12345678f -> "0.123457" for ndigits=6, 1.2e-06f -> "1.2e-06" */
PREC_NDIGITS = 2,
/** "%f" mode, writes the given number of digits after decimal point:
* 0.1f -> "0.100000", 1.2e-06f -> "0.000001" for ndigits=6 */
PREC_POINT_DIGITS = 3,
/** same as PREC_POINT_DIGITS, but stripping trailing zeroes:
* 0.1f for ndgigits=6 -> "0.1" */
PREC_POINT_DIGITS_STRIP_ZEROES = 4
};
size_t FloatToString(float t, char* buf, size_t len, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0);
size_t FloatToString(double t, char* buf, size_t len, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0);
template <typename T>
inline TString FloatToString(const T& t, EFloatToStringMode mode = PREC_AUTO, int ndigits = 0) {
char buf[512]; // Max<double>() with mode = PREC_POINT_DIGITS has 309 digits before the decimal point
size_t count = FloatToString(t, buf, sizeof(buf), mode, ndigits);
return TString(buf, count);
}
namespace NPrivate {
template <class T, bool isSimple>
struct TToString {
static inline TString Cvt(const T& t) {
char buf[512];
return TString(buf, ToString<T>(t, buf, sizeof(buf)));
}
};
template <class T>
struct TToString<T, false> {
static inline TString Cvt(const T& t) {
TString s;
TStringOutput o(s);
o << t;
return s;
}
};
}
/*
* some clever implementations...
*/
template <class T>
inline TString ToString(const T& t) {
using TR = std::remove_cv_t<T>;
return ::NPrivate::TToString<TR, std::is_arithmetic<TR>::value>::Cvt((const TR&)t);
}
inline const TString& ToString(const TString& s) noexcept {
return s;
}
inline const TString& ToString(TString& s) noexcept {
return s;
}
inline TString ToString(const char* s) {
return s;
}
inline TString ToString(char* s) {
return s;
}
/*
* Wrapper for wide strings.
*/
template <class T>
inline TUtf16String ToWtring(const T& t) {
return TUtf16String::FromAscii(ToString(t));
}
inline const TUtf16String& ToWtring(const TUtf16String& w) {
return w;
}
inline const TUtf16String& ToWtring(TUtf16String& w) {
return w;
}
struct TFromStringException: public TBadCastException {
};
/*
* specialized for:
* bool
* short
* unsigned short
* int
* unsigned int
* long
* unsigned long
* long long
* unsigned long long
* float
* double
* long double
*/
template <typename T, typename TChar>
T FromStringImpl(const TChar* data, size_t len);
template <typename T, typename TChar>
inline T FromString(const TChar* data, size_t len) {
return ::FromStringImpl<T>(data, len);
}
template <typename T, typename TChar>
inline T FromString(const TChar* data) {
return ::FromString<T>(data, std::char_traits<TChar>::length(data));
}
template <class T>
inline T FromString(const TStringBuf& s) {
return ::FromString<T>(s.data(), s.size());
}
template <class T>
inline T FromString(const TString& s) {
return ::FromString<T>(s.data(), s.size());
}
template <class T>
inline T FromString(const std::string& s) {
return ::FromString<T>(s.data(), s.size());
}
template <>
inline TString FromString<TString>(const TString& s) {
return s;
}
template <class T>
inline T FromString(const TWtringBuf& s) {
return ::FromString<T, typename TWtringBuf::char_type>(s.data(), s.size());
}
template <class T>
inline T FromString(const TUtf16String& s) {
return ::FromString<T, wchar16>(s.data(), s.size());
}
namespace NPrivate {
template <typename TChar>
class TFromString {
const TChar* const Data;
const size_t Len;
public:
inline TFromString(const TChar* data, size_t len)
: Data(data)
, Len(len)
{
}
template <typename T>
inline operator T() const {
return FromString<T, TChar>(Data, Len);
}
};
}
template <typename TChar>
inline ::NPrivate::TFromString<TChar> FromString(const TChar* data, size_t len) {
return ::NPrivate::TFromString<TChar>(data, len);
}
template <typename TChar>
inline ::NPrivate::TFromString<TChar> FromString(const TChar* data) {
return ::NPrivate::TFromString<TChar>(data, std::char_traits<TChar>::length(data));
}
template <typename T>
inline ::NPrivate::TFromString<typename T::TChar> FromString(const T& s) {
return ::NPrivate::TFromString<typename T::TChar>(s.data(), s.size());
}
// Conversion exception free versions
template <typename T, typename TChar>
bool TryFromStringImpl(const TChar* data, size_t len, T& result);
/**
* @param data Source string buffer pointer
* @param len Source string length, in characters
* @param result Place to store conversion result value.
* If conversion error occurs, no value stored in @c result
* @return @c true in case of successful conversion, @c false otherwise
**/
template <typename T, typename TChar>
inline bool TryFromString(const TChar* data, size_t len, T& result) {
return TryFromStringImpl<T>(data, len, result);
}
template <typename T, typename TChar>
inline bool TryFromString(const TChar* data, T& result) {
return TryFromString<T>(data, std::char_traits<TChar>::length(data), result);
}
template <class T, class TChar>
inline bool TryFromString(const TChar* data, const size_t len, T& result, const T& def) {
if (TryFromString<T>(data, len, result)) {
return true;
}
result = def;
return false;
}
template <class T>
inline bool TryFromString(const TStringBuf& s, T& result) {
return TryFromString<T>(s.data(), s.size(), result);
}
template <class T>
inline bool TryFromString(const TString& s, T& result) {
return TryFromString<T>(s.data(), s.size(), result);
}
template <class T>
inline bool TryFromString(const std::string& s, T& result) {
return TryFromString<T>(s.data(), s.size(), result);
}
template <class T>
inline bool TryFromString(const TWtringBuf& s, T& result) {
return TryFromString<T>(s.data(), s.size(), result);
}
template <class T>
inline bool TryFromString(const TUtf16String& s, T& result) {
return TryFromString<T>(s.data(), s.size(), result);
}
template <class T, class TChar>
inline TMaybe<T> TryFromString(TBasicStringBuf<TChar> s) {
TMaybe<T> result{NMaybe::TInPlace{}};
if (!TryFromString<T>(s, *result)) {
result.Clear();
}
return result;
}
template <class T, class TChar>
inline TMaybe<T> TryFromString(const TChar* data) {
return TryFromString<T>(TBasicStringBuf<TChar>(data));
}
template <class T>
inline TMaybe<T> TryFromString(const TString& s) {
return TryFromString<T>(TStringBuf(s));
}
template <class T>
inline TMaybe<T> TryFromString(const std::string& s) {
return TryFromString<T>(TStringBuf(s));
}
template <class T>
inline TMaybe<T> TryFromString(const TUtf16String& s) {
return TryFromString<T>(TWtringBuf(s));
}
template <class T, class TStringType>
inline bool TryFromStringWithDefault(const TStringType& s, T& result, const T& def) {
return TryFromString<T>(s.data(), s.size(), result, def);
}
template <class T>
inline bool TryFromStringWithDefault(const char* s, T& result, const T& def) {
return TryFromStringWithDefault<T>(TStringBuf(s), result, def);
}
template <class T, class TStringType>
inline bool TryFromStringWithDefault(const TStringType& s, T& result) {
return TryFromStringWithDefault<T>(s, result, T());
}
// FromString methods with default value if data is invalid
template <class T, class TChar>
inline T FromString(const TChar* data, const size_t len, const T& def) {
T result;
TryFromString<T>(data, len, result, def);
return result;
}
template <class T, class TStringType>
inline T FromStringWithDefault(const TStringType& s, const T& def) {
return FromString<T>(s.data(), s.size(), def);
}
template <class T>
inline T FromStringWithDefault(const char* s, const T& def) {
return FromStringWithDefault<T>(TStringBuf(s), def);
}
template <class T, class TStringType>
inline T FromStringWithDefault(const TStringType& s) {
return FromStringWithDefault<T>(s, T());
}
double StrToD(const char* b, char** se);
double StrToD(const char* b, const char* e, char** se);
template <int base, class T>
size_t IntToString(T t, char* buf, size_t len);
template <int base, class T>
inline TString IntToString(T t) {
static_assert(std::is_arithmetic<std::remove_cv_t<T>>::value, "expect std::is_arithmetic<std::remove_cv_t<T>>::value");
char buf[256];
return TString(buf, IntToString<base>(t, buf, sizeof(buf)));
}
template <int base, class TInt, class TChar>
bool TryIntFromString(const TChar* data, size_t len, TInt& result);
template <int base, class TInt, class TStringType>
inline bool TryIntFromString(const TStringType& s, TInt& result) {
return TryIntFromString<base>(s.data(), s.size(), result);
}
template <class TInt, int base, class TChar>
TInt IntFromString(const TChar* str, size_t len);
template <class TInt, int base, class TChar>
inline TInt IntFromString(const TChar* str) {
return IntFromString<TInt, base>(str, std::char_traits<TChar>::length(str));
}
template <class TInt, int base, class TStringType>
inline TInt IntFromString(const TStringType& str) {
return IntFromString<TInt, base>(str.data(), str.size());
}
static inline TString ToString(const TStringBuf str) {
return TString(str);
}
static inline TUtf16String ToWtring(const TWtringBuf wtr) {
return TUtf16String(wtr);
}
static inline TUtf32String ToUtf32String(const TUtf32StringBuf wtr) {
return TUtf32String(wtr);
}