mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
upd: [imp] fmt_context
This commit is contained in:
parent
36b380f80f
commit
30588a7085
@ -11,13 +11,26 @@ namespace {
|
|||||||
|
|
||||||
void imp_fmt_string(benchmark::State &state) {
|
void imp_fmt_string(benchmark::State &state) {
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
std::ignore = imp::fmt("hello world. hello world. hello world. hello world. hello world.");
|
std::ignore = imp::fmt("hello world.hello world.hello world.hello world.hello world.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void imp_fmt_multi_string(benchmark::State &state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
std::ignore = imp::fmt("hello world.", "hello world.", "hello world.", "hello world.", "hello world.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fmt_format_string(benchmark::State &state) {
|
void fmt_format_string(benchmark::State &state) {
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
std::ignore = fmt::format("hello world. hello world. hello world. hello world. hello world.");
|
std::ignore = fmt::format("hello world.hello world.hello world.hello world.hello world.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmt_format_multi_string(benchmark::State &state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
std::ignore = fmt::format("{}{}{}{}{}",
|
||||||
|
"hello world.", " hello world.", " hello world.", " hello world.", " hello world.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,24 +40,48 @@ void imp_fmt_int(benchmark::State &state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void imp_fmt_multi_int(benchmark::State &state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
std::ignore = imp::fmt(654321, 654321, 654321, 654321, 654321);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void fmt_format_int(benchmark::State &state) {
|
void fmt_format_int(benchmark::State &state) {
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
std::ignore = fmt::format("{}", 654321);
|
std::ignore = fmt::format("{}", 654321);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fmt_format_multi_int(benchmark::State &state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
std::ignore = fmt::format("{}{}{}{}{}", 654321, 654321, 654321, 654321, 654321);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void imp_fmt_float(benchmark::State &state) {
|
void imp_fmt_float(benchmark::State &state) {
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
std::ignore = imp::fmt(654.321);
|
std::ignore = imp::fmt(654.321);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void imp_fmt_multi_float(benchmark::State &state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
std::ignore = imp::fmt(654.321, 654.321, 654.321, 654.321, 654.321);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void fmt_format_float(benchmark::State &state) {
|
void fmt_format_float(benchmark::State &state) {
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
std::ignore = fmt::format("{}", 654.321);
|
std::ignore = fmt::format("{}", 654.321);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fmt_format_multi_float(benchmark::State &state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
std::ignore = fmt::format("{}{}{}{}{}", 654.321, 654.321, 654.321, 654.321, 654.321);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void imp_fmt_chrono(benchmark::State &state) {
|
void imp_fmt_chrono(benchmark::State &state) {
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
std::ignore = imp::fmt(std::chrono::system_clock::now());
|
std::ignore = imp::fmt(std::chrono::system_clock::now());
|
||||||
@ -65,5 +102,13 @@ BENCHMARK(imp_fmt_int);
|
|||||||
BENCHMARK(fmt_format_int);
|
BENCHMARK(fmt_format_int);
|
||||||
BENCHMARK(imp_fmt_float);
|
BENCHMARK(imp_fmt_float);
|
||||||
BENCHMARK(fmt_format_float);
|
BENCHMARK(fmt_format_float);
|
||||||
|
|
||||||
|
BENCHMARK(imp_fmt_multi_string);
|
||||||
|
BENCHMARK(fmt_format_multi_string);
|
||||||
|
BENCHMARK(imp_fmt_multi_int);
|
||||||
|
BENCHMARK(fmt_format_multi_int);
|
||||||
|
BENCHMARK(imp_fmt_multi_float);
|
||||||
|
BENCHMARK(fmt_format_multi_float);
|
||||||
|
|
||||||
BENCHMARK(imp_fmt_chrono);
|
BENCHMARK(imp_fmt_chrono);
|
||||||
BENCHMARK(fmt_format_chrono);
|
BENCHMARK(fmt_format_chrono);
|
||||||
|
|||||||
@ -164,17 +164,17 @@ auto as_bytes(span<T> s) noexcept -> span<Byte> {
|
|||||||
return {byte_cast(s.data()), s.size_bytes()};
|
return {byte_cast(s.data()), s.size_bytes()};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Custom defined fmt_to_string method for imp::fmt
|
/// @brief Custom defined fmt_to method for imp::fmt
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
inline std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), ::LIBIMP::byte b) {
|
inline bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, ::LIBIMP::byte b) {
|
||||||
return ::LIBIMP::to_string(static_cast<std::uint8_t>(b), "02x");
|
return ::LIBIMP::to_string(ctx, static_cast<std::uint8_t>(b), "02x");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename = std::enable_if_t<std::is_same<std::decay_t<T>, ::LIBIMP::byte>::value>>
|
typename = std::enable_if_t<std::is_same<std::decay_t<T>, ::LIBIMP::byte>::value>>
|
||||||
std::string tag_invoke(fmt_to_string_t, fmt_ref<T> arg) noexcept {
|
bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, fmt_ref<T> arg) noexcept {
|
||||||
return ::LIBIMP::to_string(static_cast<std::uint8_t>(arg.param), arg.fstr);
|
return ::LIBIMP::to_string(ctx, static_cast<std::uint8_t>(arg.param), arg.fstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|||||||
@ -49,66 +49,62 @@ auto spec(char const (&fstr)[N]) noexcept {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief String formatting function.
|
/**
|
||||||
|
* @brief String formatting function.
|
||||||
template <typename A>
|
*
|
||||||
LIBIMP_NODISCARD std::string fmt(A &&a) {
|
* @param args arguments that support the fmt output
|
||||||
return fmt_to_string(std::forward<A>(a));
|
* @return an empty string if the fmt output fails
|
||||||
|
*/
|
||||||
|
template <typename... A>
|
||||||
|
LIBIMP_NODISCARD std::string fmt(A &&...args) {
|
||||||
|
std::string joined;
|
||||||
|
fmt_context ctx(joined);
|
||||||
|
if (fmt_to(ctx, std::forward<A>(args)...)) {
|
||||||
|
return ctx.finish() ? joined : "";
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename A1, typename... A>
|
/// @brief String types.
|
||||||
LIBIMP_NODISCARD std::string fmt(A1 &&a1, A &&...args) {
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, char const * a) noexcept;
|
||||||
std::string joined(fmt(std::forward<A1>(a1)));
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, std::string const &a) noexcept;
|
||||||
LIBIMP_UNUSED auto unfold = {
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, char const * a, span<char const> fstr) noexcept;
|
||||||
joined.append(fmt_to_string(std::forward<A>(args)))...
|
inline bool to_string(fmt_context &ctx, std::string const &a, span<char const> fstr) noexcept { return to_string(ctx, a.c_str(), fstr); }
|
||||||
};
|
|
||||||
return joined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Return the string directly.
|
|
||||||
inline char const *to_string(char const * a) noexcept { return (a == nullptr) ? "" : a; }
|
|
||||||
inline std::string to_string(std::string const &a) noexcept { return a; }
|
|
||||||
inline std::string to_string(std::string && a) noexcept { return std::move(a); }
|
|
||||||
LIBIMP_EXPORT std::string to_string(char const * a, span<char const> fstr) noexcept;
|
|
||||||
inline std::string to_string(std::string const &a, span<char const> fstr) noexcept { return to_string(a.c_str(), fstr); }
|
|
||||||
|
|
||||||
/// @brief Character to string conversion.
|
/// @brief Character to string conversion.
|
||||||
/// @return an empty string if the conversion fails
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, char a) noexcept;
|
||||||
inline std::string to_string(char a) noexcept { return {a}; }
|
|
||||||
#if defined(LIBIMP_CPP_20)
|
#if defined(LIBIMP_CPP_20)
|
||||||
inline std::string to_string(char8_t a) noexcept { return to_string((char)a); }
|
inline bool to_string(fmt_context &ctx, char8_t a) noexcept { return to_string(ctx, (char)a); }
|
||||||
#endif // defined(LIBIMP_CPP_20)
|
#endif // defined(LIBIMP_CPP_20)
|
||||||
LIBIMP_EXPORT std::string to_string(wchar_t a) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, wchar_t a) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string(char16_t a) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, char16_t a) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string(char32_t a) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, char32_t a) noexcept;
|
||||||
|
|
||||||
/// @brief Conversion of numeric types to strings.
|
/// @brief Conversion of numeric types to strings.
|
||||||
/// @return an empty string if the conversion fails
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, signed short a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string( signed short a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, unsigned short a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string(unsigned short a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, signed int a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string( signed int a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, unsigned int a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string(unsigned int a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, signed long a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string( signed long a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, unsigned long a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string(unsigned long a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, signed long long a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string( signed long long a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, unsigned long long a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string(unsigned long long a, span<char const> fstr = {}) noexcept;
|
inline bool to_string(fmt_context &ctx, signed char a, span<char const> fstr = {}) noexcept { return to_string(ctx, (int)a, fstr); }
|
||||||
inline std::string to_string( signed char a, span<char const> fstr = {}) noexcept { return to_string( (int)a, fstr); }
|
inline bool to_string(fmt_context &ctx, unsigned char a, span<char const> fstr = {}) noexcept { return to_string(ctx, (unsigned)a, fstr); }
|
||||||
inline std::string to_string(unsigned char a, span<char const> fstr = {}) noexcept { return to_string((unsigned)a, fstr); }
|
|
||||||
|
|
||||||
/// @brief Conversion of floating point type to strings.
|
/// @brief Conversion of floating point type to strings.
|
||||||
/// @return an empty string if the conversion fails
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, double a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string( double a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, long double a, span<char const> fstr = {}) noexcept;
|
||||||
LIBIMP_EXPORT std::string to_string(long double a, span<char const> fstr = {}) noexcept;
|
inline bool to_string(fmt_context &ctx, float a, span<char const> fstr = {}) noexcept { return to_string(ctx, (double)a, fstr); }
|
||||||
inline std::string to_string(float a, span<char const> fstr = {}) noexcept { return to_string((double)a, fstr); }
|
|
||||||
|
|
||||||
/// @brief Pointer.
|
/// @brief Pointer.
|
||||||
inline std::string to_string(std::nullptr_t) noexcept { return "null"; }
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, std::nullptr_t) noexcept;
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename = std::enable_if_t<std::is_same<T, void>::value>>
|
typename = std::enable_if_t<std::is_same<T, void>::value>>
|
||||||
LIBIMP_EXPORT std::string to_string(T const volatile *a) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, T const volatile *a) noexcept;
|
||||||
|
|
||||||
/// @brief Date and time.
|
/// @brief Date and time.
|
||||||
LIBIMP_EXPORT std::string to_string(std::tm const &a, span<char const> fstr = {}) noexcept;
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, std::tm const &a, span<char const> fstr = {}) noexcept;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
@ -116,53 +112,55 @@ namespace detail {
|
|||||||
* @brief Convert std::time_t to std::string.
|
* @brief Convert std::time_t to std::string.
|
||||||
* @return an empty string if the conversion fails
|
* @return an empty string if the conversion fails
|
||||||
*/
|
*/
|
||||||
inline std::string time_to_string(std::time_t tt, span<char const> fstr) noexcept {
|
inline bool time_to_string(fmt_context &ctx, std::time_t tt, span<char const> fstr) noexcept {
|
||||||
#if defined(LIBIMP_CC_MSVC)
|
#if defined(LIBIMP_CC_MSVC)
|
||||||
/// @see https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-s-localtime32-s-localtime64-s
|
/// @see https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-s-localtime32-s-localtime64-s
|
||||||
std::tm tm {};
|
std::tm tm {};
|
||||||
if (::localtime_s(&tm, &tt) != 0) {
|
if (::localtime_s(&tm, &tt) != 0) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return to_string(tm, fstr);
|
return to_string(ctx, tm, fstr);
|
||||||
#else
|
#else
|
||||||
return to_string(*std::localtime(&tt), fstr);
|
return to_string(ctx, *std::localtime(&tt), fstr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <class Clock, class Duration>
|
template <class Clock, class Duration>
|
||||||
std::string to_string(std::chrono::time_point<Clock, Duration> const &a, span<char const> fstr = {}) noexcept {
|
bool to_string(fmt_context &ctx, std::chrono::time_point<Clock, Duration> const &a, span<char const> fstr = {}) noexcept {
|
||||||
return detail::time_to_string(std::chrono::system_clock::to_time_t(a), fstr);
|
return detail::time_to_string(ctx, std::chrono::system_clock::to_time_t(a), fstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Predefined fmt_to_string method
|
* @brief Predefined fmt_to method
|
||||||
*/
|
*/
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto tag_invoke(fmt_to_string_t, T &&arg) noexcept
|
auto tag_invoke(fmt_to_t, fmt_context &ctx, T &&arg) noexcept
|
||||||
-> decltype(::LIBIMP::to_string(std::forward<T>(arg))) {
|
-> decltype(::LIBIMP::to_string(ctx, std::forward<T>(arg))) {
|
||||||
return ::LIBIMP::to_string(std::forward<T>(arg));
|
return ::LIBIMP::to_string(ctx, std::forward<T>(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto tag_invoke(fmt_to_string_t, fmt_ref<T> arg) noexcept
|
auto tag_invoke(fmt_to_t, fmt_context &ctx, fmt_ref<T> arg) noexcept
|
||||||
-> decltype(::LIBIMP::to_string(static_cast<T>(arg.param), arg.fstr)) {
|
-> decltype(::LIBIMP::to_string(ctx, static_cast<T>(arg.param), arg.fstr)) {
|
||||||
return ::LIBIMP::to_string(static_cast<T>(arg.param), arg.fstr);
|
return ::LIBIMP::to_string(ctx, static_cast<T>(arg.param), arg.fstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), span<T> s) {
|
bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, span<T> s) {
|
||||||
if (s.empty()) {
|
if (s.empty()) {
|
||||||
return {};
|
return false;
|
||||||
|
}
|
||||||
|
if (!fmt_to(ctx, s[0])) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
auto appender = fmt(s[0]);
|
|
||||||
for (std::size_t i = 1; i < s.size(); ++i) {
|
for (std::size_t i = 1; i < s.size(); ++i) {
|
||||||
appender += fmt(' ', s[i]);
|
if (!fmt_to(ctx, ' ', s[i])) return false;
|
||||||
}
|
}
|
||||||
return appender;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|||||||
@ -7,26 +7,66 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#include "libimp/def.h"
|
#include "libimp/def.h"
|
||||||
#include "libimp/generic.h"
|
#include "libimp/generic.h"
|
||||||
|
#include "libimp/detect_plat.h"
|
||||||
|
#include "libimp/span.h"
|
||||||
|
#include "libimp/export.h"
|
||||||
|
|
||||||
LIBIMP_NAMESPACE_BEG_
|
LIBIMP_NAMESPACE_BEG_
|
||||||
|
|
||||||
|
constexpr std::size_t fmt_context_aligned_size = 512U;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Supports custom fmt_to_string methods for imp::fmt.
|
* @brief The context of fmt.
|
||||||
|
*/
|
||||||
|
class LIBIMP_EXPORT fmt_context {
|
||||||
|
std::array<char, fmt_context_aligned_size> sbuf_;
|
||||||
|
|
||||||
|
std::string &joined_;
|
||||||
|
std::size_t offset_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
fmt_context(std::string &j) noexcept;
|
||||||
|
|
||||||
|
std::size_t capacity() noexcept;
|
||||||
|
void reset() noexcept;
|
||||||
|
bool finish() noexcept;
|
||||||
|
bool resize(std::size_t sz) noexcept;
|
||||||
|
span<char> buffer() noexcept;
|
||||||
|
bool expend(std::size_t sz) noexcept;
|
||||||
|
bool append(std::string const &str) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Supports custom fmt_to methods for imp::fmt.
|
||||||
*/
|
*/
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
struct fmt_to_string_t {
|
class fmt_to_t {
|
||||||
template <typename T>
|
template <typename A1>
|
||||||
std::string operator()(T &&arg) const {
|
bool get_result(fmt_context &ctx, A1 && a1) const {
|
||||||
return ::LIBIMP::tag_invoke(fmt_to_string_t{}, std::forward<T>(arg));
|
return ::LIBIMP::tag_invoke(fmt_to_t{}, ctx, std::forward<A1>(a1));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A1, typename... A>
|
||||||
|
bool get_result(fmt_context &ctx, A1 && a1, A &&...args) const {
|
||||||
|
return get_result(ctx, std::forward<A1>(a1))
|
||||||
|
&& get_result(ctx, std::forward<A>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename... A>
|
||||||
|
bool operator()(fmt_context &ctx, A &&...args) const {
|
||||||
|
return get_result(ctx, std::forward<A>(args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
constexpr detail::fmt_to_string_t fmt_to_string {};
|
constexpr detail::fmt_to_t fmt_to {};
|
||||||
|
|
||||||
LIBIMP_NAMESPACE_END_
|
LIBIMP_NAMESPACE_END_
|
||||||
|
|||||||
@ -37,11 +37,12 @@ struct context {
|
|||||||
};
|
};
|
||||||
|
|
||||||
LIBIMP_EXPORT std::string to_string(context &&) noexcept;
|
LIBIMP_EXPORT std::string to_string(context &&) noexcept;
|
||||||
|
LIBIMP_EXPORT bool to_string(fmt_context &ctx, context &&) noexcept;
|
||||||
|
|
||||||
/// @brief Custom defined fmt_to_string method for imp::fmt
|
/// @brief Custom defined fmt_to method for imp::fmt
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), context &&arg) noexcept {
|
bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, context &&arg) noexcept {
|
||||||
return ::LIBIMP::log::to_string(std::move(arg));
|
return ::LIBIMP::log::to_string(ctx, std::move(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace log
|
} // namespace log
|
||||||
|
|||||||
@ -155,16 +155,16 @@ public:
|
|||||||
friend bool operator!=(result const &lhs, result const &rhs) noexcept { return lhs.code_ != rhs.code_; }
|
friend bool operator!=(result const &lhs, result const &rhs) noexcept { return lhs.code_ != rhs.code_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Custom defined fmt_to_string method for imp::fmt
|
/// @brief Custom defined fmt_to method for imp::fmt
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
inline std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), result_code r) {
|
inline bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, result_code r) {
|
||||||
return fmt("[", (r ? "succ" : "fail"), ", value = ", *r, "]");
|
return fmt_to(ctx, "[", (r ? "succ" : "fail"), ", value = ", *r, "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename D>
|
template <typename T, typename D>
|
||||||
std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), result<T, D> r) {
|
bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, result<T, D> r) {
|
||||||
return fmt("[", (r ? "succ" : "fail"), ", value = ", result<T, D>::default_traits_t::format(r), "]");
|
return fmt_to(ctx, "[", (r ? "succ" : "fail"), ", value = ", result<T, D>::default_traits_t::format(r), "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|||||||
@ -234,7 +234,7 @@ auto make_span(T (&arr)[E]) noexcept -> span<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t E>
|
template <typename T, std::size_t E>
|
||||||
auto make_span(std::array<T, E> const &arr) noexcept -> span<T> {
|
auto make_span(std::array<T, E> &arr) noexcept -> span<T> {
|
||||||
return {arr};
|
return {arr};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -50,10 +50,8 @@ public:
|
|||||||
|
|
||||||
std::string str() const noexcept;
|
std::string str() const noexcept;
|
||||||
|
|
||||||
friend bool operator==(error const &lhs, error const &rhs) noexcept;
|
friend LIBIMP_EXPORT bool operator==(error const &lhs, error const &rhs) noexcept;
|
||||||
friend bool operator!=(error const &lhs, error const &rhs) noexcept;
|
friend LIBIMP_EXPORT bool operator!=(error const &lhs, error const &rhs) noexcept;
|
||||||
|
|
||||||
friend std::ostream &operator<<(std::ostream &o, error const &e);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,10 +63,10 @@ enum class info : std::int32_t {
|
|||||||
LIBIMP_EXPORT result<std::int64_t> conf(info) noexcept;
|
LIBIMP_EXPORT result<std::int64_t> conf(info) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief @brief Custom defined fmt_to_string method for imp::fmt
|
* @brief @brief Custom defined fmt_to method for imp::fmt
|
||||||
*/
|
*/
|
||||||
inline std::string tag_invoke(decltype(::LIBIMP::fmt_to_string), error r) noexcept {
|
inline bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, error r) noexcept {
|
||||||
return error_msg(r.code());
|
return fmt_to(ctx, error_msg(r.code()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sys
|
} // namespace sys
|
||||||
|
|||||||
@ -19,12 +19,16 @@ LIBIMP_NAMESPACE_BEG_
|
|||||||
*/
|
*/
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
span<char const> normalize(span<char const> a) {
|
constexpr std::size_t roundup(std::size_t sz) noexcept {
|
||||||
|
return (sz & ~(fmt_context_aligned_size - 1)) + fmt_context_aligned_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
span<char const> normalize(span<char const> const &a) {
|
||||||
if (a.empty()) return {};
|
if (a.empty()) return {};
|
||||||
return a.first(a.size() - (a.back() == '\0' ? 1 : 0));
|
return a.first(a.size() - (a.back() == '\0' ? 1 : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
span<char> smem_cpy(span<char> sbuf, span<char const> a) noexcept {
|
span<char> smem_cpy(span<char> const &sbuf, span<char const> a) noexcept {
|
||||||
if (sbuf.empty()) return {};
|
if (sbuf.empty()) return {};
|
||||||
a = normalize(a);
|
a = normalize(a);
|
||||||
auto sz = (std::min)(sbuf.size() - 1, a.size());
|
auto sz = (std::min)(sbuf.size() - 1, a.size());
|
||||||
@ -32,13 +36,13 @@ span<char> smem_cpy(span<char> sbuf, span<char const> a) noexcept {
|
|||||||
return sbuf.first(sz);
|
return sbuf.first(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
span<char> sbuf_cpy(span<char> sbuf, span<char const> a) noexcept {
|
span<char> sbuf_cpy(span<char> sbuf, span<char const> const &a) noexcept {
|
||||||
sbuf = smem_cpy(sbuf, a);
|
sbuf = smem_cpy(sbuf, a);
|
||||||
*sbuf.end() = '\0';
|
*sbuf.end() = '\0';
|
||||||
return sbuf;
|
return sbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
span<char> sbuf_cat(span<char> sbuf, std::initializer_list<span<char const>> args) noexcept {
|
span<char> sbuf_cat(span<char> const &sbuf, std::initializer_list<span<char const>> args) noexcept {
|
||||||
std::size_t remain = sbuf.size();
|
std::size_t remain = sbuf.size();
|
||||||
for (auto s : args) {
|
for (auto s : args) {
|
||||||
remain -= smem_cpy(sbuf.last(remain), s).size();
|
remain -= smem_cpy(sbuf.last(remain), s).size();
|
||||||
@ -49,21 +53,21 @@ span<char> sbuf_cat(span<char> sbuf, std::initializer_list<span<char const>> arg
|
|||||||
}
|
}
|
||||||
|
|
||||||
span<char> local_fmt_str() noexcept {
|
span<char> local_fmt_str() noexcept {
|
||||||
thread_local std::array<char, 512> sbuf;
|
thread_local std::array<char, fmt_context_aligned_size> sbuf;
|
||||||
return sbuf;
|
return sbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const *as_cstr(span<char const> a) {
|
char const *as_cstr(span<char const> const &a) {
|
||||||
if (a.empty()) return "";
|
if (a.empty()) return "";
|
||||||
if (a.back() == '\0') return a.data();
|
if (a.back() == '\0') return a.data();
|
||||||
return sbuf_cpy(local_fmt_str(), a).data();
|
return sbuf_cpy(local_fmt_str(), a).data();
|
||||||
}
|
}
|
||||||
|
|
||||||
span<char> fmt_of(span<char const> fstr, span<char const> s) {
|
span<char> fmt_of(span<char const> const &fstr, span<char const> const &s) {
|
||||||
return sbuf_cat(local_fmt_str(), {"%", fstr, s});
|
return sbuf_cat(local_fmt_str(), {"%", fstr, s});
|
||||||
}
|
}
|
||||||
|
|
||||||
span<char> fmt_of_unsigned(span<char const> fstr, span<char const> l) {
|
span<char> fmt_of_unsigned(span<char const> fstr, span<char const> const &l) {
|
||||||
if (fstr.empty()) {
|
if (fstr.empty()) {
|
||||||
return fmt_of(l, "u");
|
return fmt_of(l, "u");
|
||||||
}
|
}
|
||||||
@ -77,7 +81,7 @@ span<char> fmt_of_unsigned(span<char const> fstr, span<char const> l) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span<char> fmt_of_signed(span<char const> fstr, span<char const> l) {
|
span<char> fmt_of_signed(span<char const> fstr, span<char const> const &l) {
|
||||||
if (fstr.empty()) {
|
if (fstr.empty()) {
|
||||||
return fmt_of(l, "d");
|
return fmt_of(l, "d");
|
||||||
}
|
}
|
||||||
@ -91,7 +95,7 @@ span<char> fmt_of_signed(span<char const> fstr, span<char const> l) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span<char> fmt_of_float(span<char const> fstr, span<char const> l) {
|
span<char> fmt_of_float(span<char const> fstr, span<char const> const &l) {
|
||||||
if (fstr.empty()) {
|
if (fstr.empty()) {
|
||||||
return fmt_of(l, "f");
|
return fmt_of(l, "f");
|
||||||
}
|
}
|
||||||
@ -106,125 +110,206 @@ span<char> fmt_of_float(span<char const> fstr, span<char const> l) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename A /*a fundamental or pointer type*/>
|
template <typename A /*a fundamental or pointer type*/>
|
||||||
std::string sprintf(span<char const> sfmt, A a) {
|
int sprintf(fmt_context &ctx, span<char const> const &sfmt, A a) {
|
||||||
std::array<char, 512> sbuf;
|
for (;;) {
|
||||||
auto sz = std::snprintf(sbuf.data(), sbuf.size(), sfmt.data(), a);
|
auto sbuf = ctx.buffer();
|
||||||
if (sz <= 0) return {};
|
auto sz = std::snprintf(sbuf.data(), sbuf.size(), sfmt.data(), a);
|
||||||
if (sz < sbuf.size()) {
|
if (sz <= 0) {
|
||||||
return std::string(sbuf.data(), sz);
|
return sz;
|
||||||
|
}
|
||||||
|
if (sz < sbuf.size()) {
|
||||||
|
return ctx.expend(sz) ? sz : -1;
|
||||||
|
}
|
||||||
|
if (!ctx.resize(sz + 1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::string des;
|
|
||||||
des.resize(sz + 1);
|
|
||||||
if (std::snprintf(&des[0], des.size(), sfmt.data(), a) < 0) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
des.pop_back(); // remove the terminated null character
|
|
||||||
return des;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F /*a function pointer*/,
|
template <typename F /*a function pointer*/,
|
||||||
typename A /*a fundamental or pointer type*/>
|
typename A /*a fundamental or pointer type*/>
|
||||||
std::string sprintf(F fop, span<char const> fstr, span<char const> s, A a) noexcept {
|
bool sprintf(fmt_context &ctx, F fop, span<char const> const &fstr, span<char const> const &s, A a) noexcept {
|
||||||
LIBIMP_TRY {
|
LIBIMP_TRY {
|
||||||
return ::LIBIMP::sprintf(fop(fstr, s), a);
|
return ::LIBIMP::sprintf(ctx, fop(fstr, s), a) >= 0;
|
||||||
} LIBIMP_CATCH(...) {
|
} LIBIMP_CATCH(...) {
|
||||||
return {};
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::string to_string(char const *a, span<char const> fstr) noexcept {
|
/// @brief The context of fmt.
|
||||||
if (a == nullptr) return {};
|
|
||||||
return ::LIBIMP::sprintf(fmt_of, fstr, "s", a);
|
fmt_context::fmt_context(std::string &j) noexcept
|
||||||
|
: joined_(j)
|
||||||
|
, offset_(0) {}
|
||||||
|
|
||||||
|
std::size_t fmt_context::capacity() noexcept {
|
||||||
|
return (offset_ < sbuf_.size()) ? sbuf_.size() : joined_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(wchar_t a) noexcept {
|
void fmt_context::reset() noexcept {
|
||||||
|
offset_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fmt_context::finish() noexcept {
|
||||||
|
LIBIMP_TRY {
|
||||||
|
if (offset_ < sbuf_.size()) {
|
||||||
|
joined_.assign(sbuf_.data(), offset_);
|
||||||
|
} else {
|
||||||
|
joined_.resize(offset_);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} LIBIMP_CATCH(...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fmt_context::resize(std::size_t sz) noexcept {
|
||||||
|
LIBIMP_TRY {
|
||||||
|
if (sz < sbuf_.size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
joined_.resize(roundup(sz));
|
||||||
|
return true;
|
||||||
|
} LIBIMP_CATCH(...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span<char> fmt_context::buffer() noexcept {
|
||||||
|
if (offset_ < sbuf_.size()) {
|
||||||
|
return make_span(sbuf_).subspan(offset_);
|
||||||
|
} else {
|
||||||
|
return {&joined_[offset_], joined_.size() - offset_};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fmt_context::expend(std::size_t sz) noexcept {
|
||||||
|
if ((offset_ += sz) < sbuf_.size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (offset_ < joined_.size()) || resize(offset_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fmt_context::append(std::string const &str) noexcept {
|
||||||
|
if ((buffer().size() < str.size()) && !resize(offset_ + str.size())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::memcpy(buffer().data(), str.data(), str.size());
|
||||||
|
offset_ += str.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief To string conversion.
|
||||||
|
|
||||||
|
bool to_string(fmt_context &ctx, char const *a) noexcept {
|
||||||
|
return to_string(ctx, a, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool to_string(fmt_context &ctx, std::string const &a) noexcept {
|
||||||
|
return ctx.append(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool to_string(fmt_context &ctx, char const *a, span<char const> fstr) noexcept {
|
||||||
|
if (a == nullptr) return false;
|
||||||
|
return ::LIBIMP::sprintf(ctx, fmt_of, fstr, "s", a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool to_string(fmt_context &ctx, char a) noexcept {
|
||||||
|
return ::LIBIMP::sprintf(ctx, fmt_of, {}, "c", a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool to_string(fmt_context &ctx, wchar_t a) noexcept {
|
||||||
LIBIMP_TRY {
|
LIBIMP_TRY {
|
||||||
std::string des;
|
std::string des;
|
||||||
cvt_sstr(std::wstring{a}, des);
|
cvt_sstr(std::wstring{a}, des);
|
||||||
return des;
|
return ctx.append(des);
|
||||||
} LIBIMP_CATCH(...) {
|
} LIBIMP_CATCH(...) {
|
||||||
return {};
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(char16_t a) noexcept {
|
bool to_string(fmt_context &ctx, char16_t a) noexcept {
|
||||||
LIBIMP_TRY {
|
LIBIMP_TRY {
|
||||||
std::string des;
|
std::string des;
|
||||||
cvt_sstr(std::u16string{a}, des);
|
cvt_sstr(std::u16string{a}, des);
|
||||||
return des;
|
return ctx.append(des);
|
||||||
} LIBIMP_CATCH(...) {
|
} LIBIMP_CATCH(...) {
|
||||||
return {};
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(char32_t a) noexcept {
|
bool to_string(fmt_context &ctx, char32_t a) noexcept {
|
||||||
LIBIMP_TRY {
|
LIBIMP_TRY {
|
||||||
std::string des;
|
std::string des;
|
||||||
cvt_sstr(std::u32string{a}, des);
|
cvt_sstr(std::u32string{a}, des);
|
||||||
return des;
|
return ctx.append(des);
|
||||||
} LIBIMP_CATCH(...) {
|
} LIBIMP_CATCH(...) {
|
||||||
return {};
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(signed short a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, signed short a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_signed, fstr, "h", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_signed, fstr, "h", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(unsigned short a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, unsigned short a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_unsigned, fstr, "h", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_unsigned, fstr, "h", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(signed int a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, signed int a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_signed, fstr, "", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_signed, fstr, "", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(unsigned int a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, unsigned int a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_unsigned, fstr, "", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_unsigned, fstr, "", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(signed long a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, signed long a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_signed, fstr, "l", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_signed, fstr, "l", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(unsigned long a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, unsigned long a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_unsigned, fstr, "l", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_unsigned, fstr, "l", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(signed long long a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, signed long long a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_signed, fstr, "ll", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_signed, fstr, "ll", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(unsigned long long a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, unsigned long long a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_unsigned, fstr, "ll", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_unsigned, fstr, "ll", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(double a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, double a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_float, fstr, "", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_float, fstr, "", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(long double a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, long double a, span<char const> fstr) noexcept {
|
||||||
return ::LIBIMP::sprintf(fmt_of_float, fstr, "L", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of_float, fstr, "L", a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool to_string(fmt_context &ctx, std::nullptr_t) noexcept {
|
||||||
|
return ctx.append("null");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
std::string to_string<void, void>(void const volatile *a) noexcept {
|
bool to_string<void, void>(fmt_context &ctx, void const volatile *a) noexcept {
|
||||||
if (a == nullptr) {
|
if (a == nullptr) {
|
||||||
return to_string(nullptr);
|
return to_string(ctx, nullptr);
|
||||||
}
|
}
|
||||||
return ::LIBIMP::sprintf(fmt_of, "", "p", a);
|
return ::LIBIMP::sprintf(ctx, fmt_of, "", "p", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(std::tm const &a, span<char const> fstr) noexcept {
|
bool to_string(fmt_context &ctx, std::tm const &a, span<char const> fstr) noexcept {
|
||||||
if (fstr.empty()) {
|
if (fstr.empty()) {
|
||||||
fstr = "%Y-%m-%d %H:%M:%S";
|
fstr = "%Y-%m-%d %H:%M:%S";
|
||||||
}
|
}
|
||||||
LIBIMP_TRY {
|
LIBIMP_TRY {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << std::put_time(&a, as_cstr(fstr));
|
ss << std::put_time(&a, as_cstr(fstr));
|
||||||
return ss.str();
|
return ctx.append(ss.str());
|
||||||
} LIBIMP_CATCH(...) {
|
} LIBIMP_CATCH(...) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,19 +6,28 @@
|
|||||||
LIBIMP_NAMESPACE_BEG_
|
LIBIMP_NAMESPACE_BEG_
|
||||||
namespace log {
|
namespace log {
|
||||||
|
|
||||||
std::string to_string(context &&ctx) noexcept {
|
bool to_string(fmt_context &f_ctx, context &&l_ctx) noexcept {
|
||||||
constexpr static char types[] = {
|
constexpr static char types[] = {
|
||||||
'T', 'D', 'I', 'W', 'E', 'F',
|
'T', 'D', 'I', 'W', 'E', 'F',
|
||||||
};
|
};
|
||||||
LIBIMP_TRY {
|
LIBIMP_TRY {
|
||||||
auto ms = std::chrono::time_point_cast<std::chrono::milliseconds>(ctx.tp).time_since_epoch().count() % 1000;
|
auto ms = std::chrono::time_point_cast<std::chrono::milliseconds>(l_ctx.tp).time_since_epoch().count() % 1000;
|
||||||
return fmt("[", types[enum_cast(ctx.level)], "][", ctx.tp, ".", spec("03")(ms), "][", ctx.func, "] ", ctx.text);
|
return fmt_to(f_ctx, "[", types[enum_cast(l_ctx.level)], "][", l_ctx.tp, ".", spec("03")(ms), "][", l_ctx.func, "] ", l_ctx.text);
|
||||||
} LIBIMP_CATCH(std::exception const &e) {
|
} LIBIMP_CATCH(std::exception const &) {
|
||||||
/// @remark [TBD] std::string constructor may throw an exception
|
return false;
|
||||||
return e.what();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string to_string(context &&ctx) noexcept {
|
||||||
|
std::string log_txt;
|
||||||
|
fmt_context f_ctx(log_txt);
|
||||||
|
if (!to_string(f_ctx, std::move(ctx))) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
f_ctx.finish();
|
||||||
|
return log_txt;
|
||||||
|
}
|
||||||
|
|
||||||
printer::operator bool() const noexcept {
|
printer::operator bool() const noexcept {
|
||||||
return (objp_ != nullptr) && (vtable_ != nullptr);
|
return (objp_ != nullptr) && (vtable_ != nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,10 +49,5 @@ bool operator!=(error const &lhs, error const &rhs) noexcept {
|
|||||||
return lhs.code() != rhs.code();
|
return lhs.code() != rhs.code();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &o, error const &e) {
|
|
||||||
o << error_msg(e.code());
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sys
|
} // namespace sys
|
||||||
LIBIMP_NAMESPACE_END_
|
LIBIMP_NAMESPACE_END_
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#define _CRT_SECURE_NO_WARNINGS
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
@ -13,68 +14,82 @@ TEST(fmt, spec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(fmt, to_string) {
|
TEST(fmt, to_string) {
|
||||||
|
std::string joined;
|
||||||
|
imp::fmt_context ctx(joined);
|
||||||
|
|
||||||
/// @brief string
|
/// @brief string
|
||||||
EXPECT_STREQ(imp::to_string(""), "");
|
EXPECT_TRUE(imp::to_string(ctx, "")); ctx.finish();
|
||||||
EXPECT_STREQ(imp::to_string("%what%"), "%what%");
|
EXPECT_EQ(joined, "");
|
||||||
EXPECT_EQ(imp::to_string("%what%", "10") , " %what%");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, "%what%")); ctx.finish();
|
||||||
EXPECT_EQ(imp::to_string("%what%", "-10"), "%what% ");
|
EXPECT_EQ(joined, "%what%");
|
||||||
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, "%what%", "10")); ctx.finish();
|
||||||
|
EXPECT_EQ(joined, " %what%");
|
||||||
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, "%what%", "-10")); ctx.finish();
|
||||||
|
EXPECT_EQ(joined, "%what% ");
|
||||||
|
|
||||||
/// @brief character
|
/// @brief character
|
||||||
EXPECT_EQ(imp::to_string('A'), "A");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 'A')); ctx.finish();
|
||||||
EXPECT_EQ(imp::to_string(L'A'), "A");
|
EXPECT_EQ(joined, "A");
|
||||||
EXPECT_EQ(imp::to_string(u'A'), "A");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, L'A')); ctx.finish();
|
||||||
EXPECT_EQ(imp::to_string(U'A'), "A");
|
EXPECT_EQ(joined, "A");
|
||||||
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, u'A')); ctx.finish();
|
||||||
|
EXPECT_EQ(joined, "A");
|
||||||
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, U'A')); ctx.finish();
|
||||||
|
EXPECT_EQ(joined, "A");
|
||||||
|
|
||||||
/// @brief numeric
|
/// @brief numeric
|
||||||
EXPECT_EQ(imp::to_string((signed char)123), "123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (signed char)123)); ctx.finish(); EXPECT_EQ(joined, "123");
|
||||||
EXPECT_EQ(imp::to_string((signed char)-321), "-65");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (signed char)-321)); ctx.finish(); EXPECT_EQ(joined, "-65");
|
||||||
EXPECT_EQ(imp::to_string((unsigned char)123), "123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (unsigned char)123)); ctx.finish(); EXPECT_EQ(joined, "123");
|
||||||
EXPECT_EQ(imp::to_string((unsigned char)321), "65");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (unsigned char)321)); ctx.finish(); EXPECT_EQ(joined, "65");
|
||||||
EXPECT_EQ(imp::to_string((short)123), "123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (short)123)); ctx.finish(); EXPECT_EQ(joined, "123");
|
||||||
EXPECT_EQ(imp::to_string((short)-321), "-321");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (short)-321)); ctx.finish(); EXPECT_EQ(joined, "-321");
|
||||||
EXPECT_EQ(imp::to_string((unsigned short)123), "123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (unsigned short)123)); ctx.finish(); EXPECT_EQ(joined, "123");
|
||||||
EXPECT_EQ(imp::to_string((unsigned short)321), "321");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (unsigned short)321)); ctx.finish(); EXPECT_EQ(joined, "321");
|
||||||
EXPECT_EQ(imp::to_string((short)123123), "-7949");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (short)123123)); ctx.finish(); EXPECT_EQ(joined, "-7949");
|
||||||
EXPECT_EQ(imp::to_string((short)-321321), "6359");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (short)-321321)); ctx.finish(); EXPECT_EQ(joined, "6359");
|
||||||
EXPECT_EQ(imp::to_string((unsigned short)123123), "57587");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (unsigned short)123123)); ctx.finish(); EXPECT_EQ(joined, "57587");
|
||||||
EXPECT_EQ(imp::to_string((unsigned short)321321), "59177");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (unsigned short)321321)); ctx.finish(); EXPECT_EQ(joined, "59177");
|
||||||
EXPECT_EQ(imp::to_string(123123), "123123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123123)); ctx.finish(); EXPECT_EQ(joined, "123123");
|
||||||
EXPECT_EQ(imp::to_string(-321321), "-321321");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, -321321)); ctx.finish(); EXPECT_EQ(joined, "-321321");
|
||||||
EXPECT_EQ(imp::to_string(123123u), "123123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123123u)); ctx.finish(); EXPECT_EQ(joined, "123123");
|
||||||
EXPECT_EQ(imp::to_string(321321u), "321321");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 321321u)); ctx.finish(); EXPECT_EQ(joined, "321321");
|
||||||
EXPECT_EQ(imp::to_string(123123ll), "123123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123123ll)); ctx.finish(); EXPECT_EQ(joined, "123123");
|
||||||
EXPECT_EQ(imp::to_string(-321321ll), "-321321");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, -321321ll)); ctx.finish(); EXPECT_EQ(joined, "-321321");
|
||||||
EXPECT_EQ(imp::to_string(123123ull), "123123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123123ull)); ctx.finish(); EXPECT_EQ(joined, "123123");
|
||||||
EXPECT_EQ(imp::to_string(321321ull), "321321");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 321321ull)); ctx.finish(); EXPECT_EQ(joined, "321321");
|
||||||
EXPECT_EQ(imp::to_string(123123, "x"), "1e0f3");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123123, "x")); ctx.finish(); EXPECT_EQ(joined, "1e0f3");
|
||||||
EXPECT_EQ(imp::to_string(123123u, "x"), "1e0f3");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123123u, "x")); ctx.finish(); EXPECT_EQ(joined, "1e0f3");
|
||||||
EXPECT_EQ(imp::to_string(123123123123ll, "X"), "1CAAB5C3B3");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123123123123ll, "X")); ctx.finish(); EXPECT_EQ(joined, "1CAAB5C3B3");
|
||||||
EXPECT_EQ(imp::to_string(123123123123ull, "X"), "1CAAB5C3B3");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123123123123ull, "X")); ctx.finish(); EXPECT_EQ(joined, "1CAAB5C3B3");
|
||||||
|
|
||||||
/// @brief floating point
|
/// @brief floating point
|
||||||
EXPECT_EQ(imp::to_string(123.123f, ".3"), "123.123");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123.123f, ".3")); ctx.finish(); EXPECT_EQ(joined, "123.123");
|
||||||
EXPECT_EQ(imp::to_string(123.123, "010.5"), "0123.12300");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123.123, "010.5")); ctx.finish(); EXPECT_EQ(joined, "0123.12300");
|
||||||
EXPECT_EQ(imp::to_string(123.123l, "010.6"), "123.123000");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 123.123l, "010.6")); ctx.finish(); EXPECT_EQ(joined, "123.123000");
|
||||||
EXPECT_EQ(imp::to_string(1.5, "e"), "1.500000e+00");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 1.5, "e")); ctx.finish(); EXPECT_EQ(joined, "1.500000e+00");
|
||||||
EXPECT_EQ(imp::to_string(1.5, "E"), "1.500000E+00");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 1.5, "E")); ctx.finish(); EXPECT_EQ(joined, "1.500000E+00");
|
||||||
double r = 0.0;
|
double r = 0.0;
|
||||||
std::cout << imp::to_string(0.0/r) << "\n";
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 0.0/r)); ctx.finish();
|
||||||
std::cout << imp::to_string(1.0/r) << "\n";
|
std::cout << joined << "\n";
|
||||||
SUCCEED();
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, 1.0/r)); ctx.finish();
|
||||||
|
std::cout << joined << "\n";
|
||||||
|
|
||||||
/// @brief pointer
|
/// @brief pointer
|
||||||
EXPECT_EQ(imp::to_string(nullptr), "null");
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, nullptr)); ctx.finish(); EXPECT_EQ(joined, "null");
|
||||||
int *p = (int *)0x0f013a04;
|
int *p = (int *)0x0f013a04;
|
||||||
std::cout << imp::to_string((void *)p) << "\n";
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, (void *)p)); ctx.finish();
|
||||||
SUCCEED();
|
std::cout << joined << "\n";
|
||||||
|
|
||||||
/// @brief date and time
|
/// @brief date and time
|
||||||
auto tp = std::chrono::system_clock::now();
|
auto tp = std::chrono::system_clock::now();
|
||||||
auto tt = std::chrono::system_clock::to_time_t(tp);
|
auto tt = std::chrono::system_clock::to_time_t(tp);
|
||||||
auto tm = *std::localtime(&tt);
|
auto tm = *std::localtime(&tt);
|
||||||
std::cout << imp::to_string(tm) << "\n";
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, tm)); ctx.finish();
|
||||||
EXPECT_EQ(imp::to_string(tm), imp::to_string(tp));
|
std::cout << joined << "\n";
|
||||||
SUCCEED();
|
std::string tm_str = joined;
|
||||||
|
ctx.reset(); EXPECT_TRUE(imp::to_string(ctx, tp)); ctx.finish();
|
||||||
|
EXPECT_EQ(tm_str, joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(fmt, fmt) {
|
TEST(fmt, fmt) {
|
||||||
@ -87,7 +102,7 @@ namespace {
|
|||||||
|
|
||||||
class foo {};
|
class foo {};
|
||||||
|
|
||||||
std::string tag_invoke(decltype(imp::fmt_to_string), foo arg) noexcept(false) {
|
bool tag_invoke(decltype(imp::fmt_to), imp::fmt_context &, foo arg) noexcept(false) {
|
||||||
throw arg;
|
throw arg;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -95,5 +110,5 @@ std::string tag_invoke(decltype(imp::fmt_to_string), foo arg) noexcept(false) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST(fmt, throw) {
|
TEST(fmt, throw) {
|
||||||
EXPECT_THROW(imp::fmt(foo{}), foo);
|
EXPECT_THROW(std::ignore = imp::fmt(foo{}), foo);
|
||||||
}
|
}
|
||||||
@ -26,9 +26,6 @@ TEST(system, error_code) {
|
|||||||
imp::sys::error e_obj {err};
|
imp::sys::error e_obj {err};
|
||||||
EXPECT_EQ(err.value(), e_obj.value());
|
EXPECT_EQ(err.value(), e_obj.value());
|
||||||
auto e_msg = imp::fmt(imp::sys::error_msg(imp::sys::error_code()));
|
auto e_msg = imp::fmt(imp::sys::error_msg(imp::sys::error_code()));
|
||||||
std::stringstream ss;
|
|
||||||
ss << imp::sys::error{};
|
|
||||||
EXPECT_EQ(e_msg, ss.str());
|
|
||||||
EXPECT_EQ(e_msg, imp::fmt(imp::sys::error()));
|
EXPECT_EQ(e_msg, imp::fmt(imp::sys::error()));
|
||||||
std::cout << e_msg << "\n";
|
std::cout << e_msg << "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user