mirror of https://github.com/trapexit/mergerfs.git
Browse Source
Rework thread pool for increased stability + config and doc updates (#1453)
Rework thread pool for increased stability + config and doc updates (#1453)
Also updates fmt to 11.2.0 and replaced syslog usage with a wrapper leveraging fmt.master
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
58 changed files with 9040 additions and 23963 deletions
-
2Makefile
-
9libfuse/Makefile
-
163libfuse/include/fmt/args.h
-
2989libfuse/include/fmt/base.h
-
1488libfuse/include/fmt/chrono.h
-
394libfuse/include/fmt/color.h
-
188libfuse/include/fmt/compile.h
-
5libfuse/include/fmt/core.h
-
396libfuse/include/fmt/format-inl.h
-
3059libfuse/include/fmt/format.h
-
272libfuse/include/fmt/os.h
-
167libfuse/include/fmt/ostream.h
-
412libfuse/include/fmt/printf.h
-
604libfuse/include/fmt/ranges.h
-
728libfuse/include/fmt/std.h
-
369libfuse/include/fmt/xchar.h
-
346libfuse/include/invocable.h
-
113libfuse/include/syslog.hpp
-
493libfuse/include/thread_pool.hpp
-
234libfuse/lib/fmt/args.h
-
2069libfuse/lib/fmt/chrono.h
-
651libfuse/lib/fmt/color.h
-
611libfuse/lib/fmt/compile.h
-
3323libfuse/lib/fmt/core.h
-
1723libfuse/lib/fmt/format-inl.h
-
4217libfuse/lib/fmt/format.h
-
478libfuse/lib/fmt/os.h
-
237libfuse/lib/fmt/ostream.h
-
640libfuse/lib/fmt/printf.h
-
722libfuse/lib/fmt/ranges.h
-
171libfuse/lib/fmt/std.h
-
229libfuse/lib/fmt/xchar.h
-
9libfuse/lib/format.cpp
-
387libfuse/lib/fuse_loop.cpp
-
361libfuse/lib/os.cpp
-
217libfuse/lib/pin_threads.cpp
-
28libfuse/lib/pin_threads.hpp
-
14mkdocs/docs/config/func_readdir.md
-
72mkdocs/docs/config/threads.md
-
1mkdocs/mkdocs.yml
-
4src/branches.cpp
-
4src/config.cpp
-
2969src/fmt/core.h
-
245src/fmt/ostream.h
-
537src/fmt/std.h
-
259src/fmt/xchar.h
-
43src/format.cpp
-
12src/fs_wait_for_mount.cpp
-
40src/fuse_init.cpp
-
2src/fuse_readdir_base.hpp
-
5src/fuse_readdir_cor.cpp
-
4src/fuse_readdir_cor.hpp
-
4src/fuse_readdir_cosr.cpp
-
73src/fuse_readdir_factory.cpp
-
66src/mergerfs.cpp
-
2src/option_parser.cpp
-
112src/syslog.cpp
-
31src/syslog.hpp
2989
libfuse/include/fmt/base.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1488
libfuse/include/fmt/chrono.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,5 @@ |
|||
// This file is only provided for compatibility and may be removed in future |
|||
// versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h |
|||
// otherwise. |
|||
|
|||
#include "format.h" |
3059
libfuse/include/fmt/format.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,167 @@ |
|||
// Formatting library for C++ - std::ostream support |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_OSTREAM_H_ |
|||
#define FMT_OSTREAM_H_ |
|||
|
|||
#ifndef FMT_MODULE |
|||
# include <fstream> // std::filebuf |
|||
#endif |
|||
|
|||
#ifdef _WIN32 |
|||
# ifdef __GLIBCXX__ |
|||
# include <ext/stdio_filebuf.h> |
|||
# include <ext/stdio_sync_filebuf.h> |
|||
# endif |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
#include "chrono.h" // formatbuf |
|||
|
|||
#ifdef _MSVC_STL_UPDATE |
|||
# define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE |
|||
#elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5 |
|||
# define FMT_MSVC_STL_UPDATE _MSVC_LANG |
|||
#else |
|||
# define FMT_MSVC_STL_UPDATE 0 |
|||
#endif |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
// Generate a unique explicit instantion in every translation unit using a tag |
|||
// type in an anonymous namespace. |
|||
namespace { |
|||
struct file_access_tag {}; |
|||
} // namespace |
|||
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr> |
|||
class file_access { |
|||
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } |
|||
}; |
|||
|
|||
#if FMT_MSVC_STL_UPDATE |
|||
template class file_access<file_access_tag, std::filebuf, |
|||
&std::filebuf::_Myfile>; |
|||
auto get_file(std::filebuf&) -> FILE*; |
|||
#endif |
|||
|
|||
// Write the content of buf to os. |
|||
// It is a separate function rather than a part of vprint to simplify testing. |
|||
template <typename Char> |
|||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { |
|||
const Char* buf_data = buf.data(); |
|||
using unsigned_streamsize = make_unsigned_t<std::streamsize>; |
|||
unsigned_streamsize size = buf.size(); |
|||
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); |
|||
do { |
|||
unsigned_streamsize n = size <= max_size ? size : max_size; |
|||
os.write(buf_data, static_cast<std::streamsize>(n)); |
|||
buf_data += n; |
|||
size -= n; |
|||
} while (size != 0); |
|||
} |
|||
|
|||
template <typename T> struct streamed_view { |
|||
const T& value; |
|||
}; |
|||
} // namespace detail |
|||
|
|||
// Formats an object of type T that has an overloaded ostream operator<<. |
|||
template <typename Char> |
|||
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> { |
|||
void set_debug_format() = delete; |
|||
|
|||
template <typename T, typename Context> |
|||
auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) { |
|||
auto buffer = basic_memory_buffer<Char>(); |
|||
auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer); |
|||
auto&& output = std::basic_ostream<Char>(&formatbuf); |
|||
output.imbue(std::locale::classic()); // The default is always unlocalized. |
|||
output << value; |
|||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit); |
|||
return formatter<basic_string_view<Char>, Char>::format( |
|||
{buffer.data(), buffer.size()}, ctx); |
|||
} |
|||
}; |
|||
|
|||
using ostream_formatter = basic_ostream_formatter<char>; |
|||
|
|||
template <typename T, typename Char> |
|||
struct formatter<detail::streamed_view<T>, Char> |
|||
: basic_ostream_formatter<Char> { |
|||
template <typename Context> |
|||
auto format(detail::streamed_view<T> view, Context& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return basic_ostream_formatter<Char>::format(view.value, ctx); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Returns a view that formats `value` via an ostream `operator<<`. |
|||
* |
|||
* **Example**: |
|||
* |
|||
* fmt::print("Current thread id: {}\n", |
|||
* fmt::streamed(std::this_thread::get_id())); |
|||
*/ |
|||
template <typename T> |
|||
constexpr auto streamed(const T& value) -> detail::streamed_view<T> { |
|||
return {value}; |
|||
} |
|||
|
|||
inline void vprint(std::ostream& os, string_view fmt, format_args args) { |
|||
auto buffer = memory_buffer(); |
|||
detail::vformat_to(buffer, fmt, args); |
|||
FILE* f = nullptr; |
|||
#if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI |
|||
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf())) |
|||
f = detail::get_file(*buf); |
|||
#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI |
|||
auto* rdbuf = os.rdbuf(); |
|||
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf)) |
|||
f = sfbuf->file(); |
|||
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf)) |
|||
f = fbuf->file(); |
|||
#endif |
|||
#ifdef _WIN32 |
|||
if (f) { |
|||
int fd = _fileno(f); |
|||
if (_isatty(fd)) { |
|||
os.flush(); |
|||
if (detail::write_console(fd, {buffer.data(), buffer.size()})) return; |
|||
} |
|||
} |
|||
#endif |
|||
detail::ignore_unused(f); |
|||
detail::write_buffer(os, buffer); |
|||
} |
|||
|
|||
/** |
|||
* Prints formatted data to the stream `os`. |
|||
* |
|||
* **Example**: |
|||
* |
|||
* fmt::print(cerr, "Don't {}!", "panic"); |
|||
*/ |
|||
FMT_EXPORT template <typename... T> |
|||
void print(std::ostream& os, format_string<T...> fmt, T&&... args) { |
|||
fmt::vargs<T...> vargs = {{args...}}; |
|||
if (detail::const_check(detail::use_utf8)) return vprint(os, fmt.str, vargs); |
|||
auto buffer = memory_buffer(); |
|||
detail::vformat_to(buffer, fmt.str, vargs); |
|||
detail::write_buffer(os, buffer); |
|||
} |
|||
|
|||
FMT_EXPORT template <typename... T> |
|||
void println(std::ostream& os, format_string<T...> fmt, T&&... args) { |
|||
fmt::print(os, FMT_STRING("{}\n"), |
|||
fmt::format(fmt, std::forward<T>(args)...)); |
|||
} |
|||
|
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_OSTREAM_H_ |
@ -0,0 +1,728 @@ |
|||
// Formatting library for C++ - formatters for standard library types |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_STD_H_ |
|||
#define FMT_STD_H_ |
|||
|
|||
#include "format.h" |
|||
#include "ostream.h" |
|||
|
|||
#ifndef FMT_MODULE |
|||
# include <atomic> |
|||
# include <bitset> |
|||
# include <complex> |
|||
# include <cstdlib> |
|||
# include <exception> |
|||
# include <functional> |
|||
# include <memory> |
|||
# include <thread> |
|||
# include <type_traits> |
|||
# include <typeinfo> |
|||
# include <utility> |
|||
# include <vector> |
|||
|
|||
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC. |
|||
# if FMT_CPLUSPLUS >= 201703L |
|||
# if FMT_HAS_INCLUDE(<filesystem>) && \ |
|||
(!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0) |
|||
# include <filesystem> |
|||
# endif |
|||
# if FMT_HAS_INCLUDE(<variant>) |
|||
# include <variant> |
|||
# endif |
|||
# if FMT_HAS_INCLUDE(<optional>) |
|||
# include <optional> |
|||
# endif |
|||
# endif |
|||
// Use > instead of >= in the version check because <source_location> may be |
|||
// available after C++17 but before C++20 is marked as implemented. |
|||
# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>) |
|||
# include <source_location> |
|||
# endif |
|||
# if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE(<expected>) |
|||
# include <expected> |
|||
# endif |
|||
#endif // FMT_MODULE |
|||
|
|||
#if FMT_HAS_INCLUDE(<version>) |
|||
# include <version> |
|||
#endif |
|||
|
|||
// GCC 4 does not support FMT_HAS_INCLUDE. |
|||
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__) |
|||
# include <cxxabi.h> |
|||
// Android NDK with gabi++ library on some architectures does not implement |
|||
// abi::__cxa_demangle(). |
|||
# ifndef __GABIXX_CXXABI_H__ |
|||
# define FMT_HAS_ABI_CXA_DEMANGLE |
|||
# endif |
|||
#endif |
|||
|
|||
// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined. |
|||
#ifndef FMT_CPP_LIB_FILESYSTEM |
|||
# ifdef __cpp_lib_filesystem |
|||
# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem |
|||
# else |
|||
# define FMT_CPP_LIB_FILESYSTEM 0 |
|||
# endif |
|||
#endif |
|||
|
|||
#ifndef FMT_CPP_LIB_VARIANT |
|||
# ifdef __cpp_lib_variant |
|||
# define FMT_CPP_LIB_VARIANT __cpp_lib_variant |
|||
# else |
|||
# define FMT_CPP_LIB_VARIANT 0 |
|||
# endif |
|||
#endif |
|||
|
|||
#if FMT_CPP_LIB_FILESYSTEM |
|||
FMT_BEGIN_NAMESPACE |
|||
|
|||
namespace detail { |
|||
|
|||
template <typename Char, typename PathChar> |
|||
auto get_path_string(const std::filesystem::path& p, |
|||
const std::basic_string<PathChar>& native) { |
|||
if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>) |
|||
return to_utf8<wchar_t>(native, to_utf8_error_policy::replace); |
|||
else |
|||
return p.string<Char>(); |
|||
} |
|||
|
|||
template <typename Char, typename PathChar> |
|||
void write_escaped_path(basic_memory_buffer<Char>& quoted, |
|||
const std::filesystem::path& p, |
|||
const std::basic_string<PathChar>& native) { |
|||
if constexpr (std::is_same_v<Char, char> && |
|||
std::is_same_v<PathChar, wchar_t>) { |
|||
auto buf = basic_memory_buffer<wchar_t>(); |
|||
write_escaped_string<wchar_t>(std::back_inserter(buf), native); |
|||
bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}); |
|||
FMT_ASSERT(valid, "invalid utf16"); |
|||
} else if constexpr (std::is_same_v<Char, PathChar>) { |
|||
write_escaped_string<std::filesystem::path::value_type>( |
|||
std::back_inserter(quoted), native); |
|||
} else { |
|||
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>()); |
|||
} |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
template <typename Char> struct formatter<std::filesystem::path, Char> { |
|||
private: |
|||
format_specs specs_; |
|||
detail::arg_ref<Char> width_ref_; |
|||
bool debug_ = false; |
|||
char path_type_ = 0; |
|||
|
|||
public: |
|||
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } |
|||
|
|||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) { |
|||
auto it = ctx.begin(), end = ctx.end(); |
|||
if (it == end) return it; |
|||
|
|||
it = detail::parse_align(it, end, specs_); |
|||
if (it == end) return it; |
|||
|
|||
Char c = *it; |
|||
if ((c >= '0' && c <= '9') || c == '{') |
|||
it = detail::parse_width(it, end, specs_, width_ref_, ctx); |
|||
if (it != end && *it == '?') { |
|||
debug_ = true; |
|||
++it; |
|||
} |
|||
if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++); |
|||
return it; |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::filesystem::path& p, FormatContext& ctx) const { |
|||
auto specs = specs_; |
|||
auto path_string = |
|||
!path_type_ ? p.native() |
|||
: p.generic_string<std::filesystem::path::value_type>(); |
|||
|
|||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, |
|||
ctx); |
|||
if (!debug_) { |
|||
auto s = detail::get_path_string<Char>(p, path_string); |
|||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs); |
|||
} |
|||
auto quoted = basic_memory_buffer<Char>(); |
|||
detail::write_escaped_path(quoted, p, path_string); |
|||
return detail::write(ctx.out(), |
|||
basic_string_view<Char>(quoted.data(), quoted.size()), |
|||
specs); |
|||
} |
|||
}; |
|||
|
|||
class path : public std::filesystem::path { |
|||
public: |
|||
auto display_string() const -> std::string { |
|||
const std::filesystem::path& base = *this; |
|||
return fmt::format(FMT_STRING("{}"), base); |
|||
} |
|||
auto system_string() const -> std::string { return string(); } |
|||
|
|||
auto generic_display_string() const -> std::string { |
|||
const std::filesystem::path& base = *this; |
|||
return fmt::format(FMT_STRING("{:g}"), base); |
|||
} |
|||
auto generic_system_string() const -> std::string { return generic_string(); } |
|||
}; |
|||
|
|||
FMT_END_NAMESPACE |
|||
#endif // FMT_CPP_LIB_FILESYSTEM |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
template <std::size_t N, typename Char> |
|||
struct formatter<std::bitset<N>, Char> |
|||
: nested_formatter<basic_string_view<Char>, Char> { |
|||
private: |
|||
// Functor because C++11 doesn't support generic lambdas. |
|||
struct writer { |
|||
const std::bitset<N>& bs; |
|||
|
|||
template <typename OutputIt> |
|||
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { |
|||
for (auto pos = N; pos > 0; --pos) { |
|||
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0')); |
|||
} |
|||
|
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
public: |
|||
template <typename FormatContext> |
|||
auto format(const std::bitset<N>& bs, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return this->write_padded(ctx, writer{bs}); |
|||
} |
|||
}; |
|||
|
|||
template <typename Char> |
|||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {}; |
|||
FMT_END_NAMESPACE |
|||
|
|||
#ifdef __cpp_lib_optional |
|||
FMT_BEGIN_NAMESPACE |
|||
template <typename T, typename Char> |
|||
struct formatter<std::optional<T>, Char, |
|||
std::enable_if_t<is_formattable<T, Char>::value>> { |
|||
private: |
|||
formatter<T, Char> underlying_; |
|||
static constexpr basic_string_view<Char> optional = |
|||
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l', |
|||
'('>{}; |
|||
static constexpr basic_string_view<Char> none = |
|||
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{}; |
|||
|
|||
template <class U> |
|||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) |
|||
-> decltype(u.set_debug_format(set)) { |
|||
u.set_debug_format(set); |
|||
} |
|||
|
|||
template <class U> |
|||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} |
|||
|
|||
public: |
|||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) { |
|||
maybe_set_debug_format(underlying_, true); |
|||
return underlying_.parse(ctx); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::optional<T>& opt, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
if (!opt) return detail::write<Char>(ctx.out(), none); |
|||
|
|||
auto out = ctx.out(); |
|||
out = detail::write<Char>(out, optional); |
|||
ctx.advance_to(out); |
|||
out = underlying_.format(*opt, ctx); |
|||
return detail::write(out, ')'); |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif // __cpp_lib_optional |
|||
|
|||
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
template <typename Char, typename OutputIt, typename T> |
|||
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt { |
|||
if constexpr (has_to_string_view<T>::value) |
|||
return write_escaped_string<Char>(out, detail::to_string_view(v)); |
|||
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v); |
|||
return write<Char>(out, v); |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
FMT_END_NAMESPACE |
|||
#endif |
|||
|
|||
#ifdef __cpp_lib_expected |
|||
FMT_BEGIN_NAMESPACE |
|||
|
|||
template <typename T, typename E, typename Char> |
|||
struct formatter<std::expected<T, E>, Char, |
|||
std::enable_if_t<(std::is_void<T>::value || |
|||
is_formattable<T, Char>::value) && |
|||
is_formattable<E, Char>::value>> { |
|||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::expected<T, E>& value, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
|
|||
if (value.has_value()) { |
|||
out = detail::write<Char>(out, "expected("); |
|||
if constexpr (!std::is_void<T>::value) |
|||
out = detail::write_escaped_alternative<Char>(out, *value); |
|||
} else { |
|||
out = detail::write<Char>(out, "unexpected("); |
|||
out = detail::write_escaped_alternative<Char>(out, value.error()); |
|||
} |
|||
*out++ = ')'; |
|||
return out; |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif // __cpp_lib_expected |
|||
|
|||
#ifdef __cpp_lib_source_location |
|||
FMT_BEGIN_NAMESPACE |
|||
template <> struct formatter<std::source_location> { |
|||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); } |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::source_location& loc, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
out = detail::write(out, loc.file_name()); |
|||
out = detail::write(out, ':'); |
|||
out = detail::write<char>(out, loc.line()); |
|||
out = detail::write(out, ':'); |
|||
out = detail::write<char>(out, loc.column()); |
|||
out = detail::write(out, ": "); |
|||
out = detail::write(out, loc.function_name()); |
|||
return out; |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif |
|||
|
|||
#if FMT_CPP_LIB_VARIANT |
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
template <typename T> |
|||
using variant_index_sequence = |
|||
std::make_index_sequence<std::variant_size<T>::value>; |
|||
|
|||
template <typename> struct is_variant_like_ : std::false_type {}; |
|||
template <typename... Types> |
|||
struct is_variant_like_<std::variant<Types...>> : std::true_type {}; |
|||
|
|||
// formattable element check. |
|||
template <typename T, typename C> class is_variant_formattable_ { |
|||
template <std::size_t... Is> |
|||
static std::conjunction< |
|||
is_formattable<std::variant_alternative_t<Is, T>, C>...> |
|||
check(std::index_sequence<Is...>); |
|||
|
|||
public: |
|||
static constexpr const bool value = |
|||
decltype(check(variant_index_sequence<T>{}))::value; |
|||
}; |
|||
|
|||
} // namespace detail |
|||
|
|||
template <typename T> struct is_variant_like { |
|||
static constexpr const bool value = detail::is_variant_like_<T>::value; |
|||
}; |
|||
|
|||
template <typename T, typename C> struct is_variant_formattable { |
|||
static constexpr const bool value = |
|||
detail::is_variant_formattable_<T, C>::value; |
|||
}; |
|||
|
|||
template <typename Char> struct formatter<std::monostate, Char> { |
|||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::monostate&, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return detail::write<Char>(ctx.out(), "monostate"); |
|||
} |
|||
}; |
|||
|
|||
template <typename Variant, typename Char> |
|||
struct formatter< |
|||
Variant, Char, |
|||
std::enable_if_t<std::conjunction_v< |
|||
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> { |
|||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const Variant& value, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
|
|||
out = detail::write<Char>(out, "variant("); |
|||
FMT_TRY { |
|||
std::visit( |
|||
[&](const auto& v) { |
|||
out = detail::write_escaped_alternative<Char>(out, v); |
|||
}, |
|||
value); |
|||
} |
|||
FMT_CATCH(const std::bad_variant_access&) { |
|||
detail::write<Char>(out, "valueless by exception"); |
|||
} |
|||
*out++ = ')'; |
|||
return out; |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif // FMT_CPP_LIB_VARIANT |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
template <> struct formatter<std::error_code> { |
|||
private: |
|||
format_specs specs_; |
|||
detail::arg_ref<char> width_ref_; |
|||
bool debug_ = false; |
|||
|
|||
public: |
|||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* { |
|||
auto it = ctx.begin(), end = ctx.end(); |
|||
if (it == end) return it; |
|||
|
|||
it = detail::parse_align(it, end, specs_); |
|||
|
|||
char c = *it; |
|||
if (it != end && ((c >= '0' && c <= '9') || c == '{')) |
|||
it = detail::parse_width(it, end, specs_, width_ref_, ctx); |
|||
|
|||
if (it != end && *it == '?') { |
|||
debug_ = true; |
|||
++it; |
|||
} |
|||
if (it != end && *it == 's') { |
|||
specs_.set_type(presentation_type::string); |
|||
++it; |
|||
} |
|||
return it; |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
FMT_CONSTEXPR20 auto format(const std::error_code& ec, |
|||
FormatContext& ctx) const -> decltype(ctx.out()) { |
|||
auto specs = specs_; |
|||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, |
|||
ctx); |
|||
auto buf = memory_buffer(); |
|||
if (specs_.type() == presentation_type::string) { |
|||
buf.append(ec.message()); |
|||
} else { |
|||
buf.append(string_view(ec.category().name())); |
|||
buf.push_back(':'); |
|||
detail::write<char>(appender(buf), ec.value()); |
|||
} |
|||
auto quoted = memory_buffer(); |
|||
auto str = string_view(buf.data(), buf.size()); |
|||
if (debug_) { |
|||
detail::write_escaped_string<char>(std::back_inserter(quoted), str); |
|||
str = string_view(quoted.data(), quoted.size()); |
|||
} |
|||
return detail::write<char>(ctx.out(), str, specs); |
|||
} |
|||
}; |
|||
|
|||
#if FMT_USE_RTTI |
|||
namespace detail { |
|||
|
|||
template <typename Char, typename OutputIt> |
|||
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { |
|||
# ifdef FMT_HAS_ABI_CXA_DEMANGLE |
|||
int status = 0; |
|||
std::size_t size = 0; |
|||
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr( |
|||
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); |
|||
|
|||
string_view demangled_name_view; |
|||
if (demangled_name_ptr) { |
|||
demangled_name_view = demangled_name_ptr.get(); |
|||
|
|||
// Normalization of stdlib inline namespace names. |
|||
// libc++ inline namespaces. |
|||
// std::__1::* -> std::* |
|||
// std::__1::__fs::* -> std::* |
|||
// libstdc++ inline namespaces. |
|||
// std::__cxx11::* -> std::* |
|||
// std::filesystem::__cxx11::* -> std::filesystem::* |
|||
if (demangled_name_view.starts_with("std::")) { |
|||
char* begin = demangled_name_ptr.get(); |
|||
char* to = begin + 5; // std:: |
|||
for (char *from = to, *end = begin + demangled_name_view.size(); |
|||
from < end;) { |
|||
// This is safe, because demangled_name is NUL-terminated. |
|||
if (from[0] == '_' && from[1] == '_') { |
|||
char* next = from + 1; |
|||
while (next < end && *next != ':') next++; |
|||
if (next[0] == ':' && next[1] == ':') { |
|||
from = next + 2; |
|||
continue; |
|||
} |
|||
} |
|||
*to++ = *from++; |
|||
} |
|||
demangled_name_view = {begin, detail::to_unsigned(to - begin)}; |
|||
} |
|||
} else { |
|||
demangled_name_view = string_view(ti.name()); |
|||
} |
|||
return detail::write_bytes<Char>(out, demangled_name_view); |
|||
# elif FMT_MSC_VERSION |
|||
const string_view demangled_name(ti.name()); |
|||
for (std::size_t i = 0; i < demangled_name.size(); ++i) { |
|||
auto sub = demangled_name; |
|||
sub.remove_prefix(i); |
|||
if (sub.starts_with("enum ")) { |
|||
i += 4; |
|||
continue; |
|||
} |
|||
if (sub.starts_with("class ") || sub.starts_with("union ")) { |
|||
i += 5; |
|||
continue; |
|||
} |
|||
if (sub.starts_with("struct ")) { |
|||
i += 6; |
|||
continue; |
|||
} |
|||
if (*sub.begin() != ' ') *out++ = *sub.begin(); |
|||
} |
|||
return out; |
|||
# else |
|||
return detail::write_bytes<Char>(out, string_view(ti.name())); |
|||
# endif |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
template <typename Char> |
|||
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types. |
|||
> { |
|||
public: |
|||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename Context> |
|||
auto format(const std::type_info& ti, Context& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return detail::write_demangled_name<Char>(ctx.out(), ti); |
|||
} |
|||
}; |
|||
#endif |
|||
|
|||
template <typename T, typename Char> |
|||
struct formatter< |
|||
T, Char, // DEPRECATED! Mixing code unit types. |
|||
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> { |
|||
private: |
|||
bool with_typename_ = false; |
|||
|
|||
public: |
|||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { |
|||
auto it = ctx.begin(); |
|||
auto end = ctx.end(); |
|||
if (it == end || *it == '}') return it; |
|||
if (*it == 't') { |
|||
++it; |
|||
with_typename_ = FMT_USE_RTTI != 0; |
|||
} |
|||
return it; |
|||
} |
|||
|
|||
template <typename Context> |
|||
auto format(const std::exception& ex, Context& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
#if FMT_USE_RTTI |
|||
if (with_typename_) { |
|||
out = detail::write_demangled_name<Char>(out, typeid(ex)); |
|||
*out++ = ':'; |
|||
*out++ = ' '; |
|||
} |
|||
#endif |
|||
return detail::write_bytes<Char>(out, string_view(ex.what())); |
|||
} |
|||
}; |
|||
|
|||
namespace detail { |
|||
|
|||
template <typename T, typename Enable = void> |
|||
struct has_flip : std::false_type {}; |
|||
|
|||
template <typename T> |
|||
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>> |
|||
: std::true_type {}; |
|||
|
|||
template <typename T> struct is_bit_reference_like { |
|||
static constexpr const bool value = |
|||
std::is_convertible<T, bool>::value && |
|||
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value; |
|||
}; |
|||
|
|||
#ifdef _LIBCPP_VERSION |
|||
|
|||
// Workaround for libc++ incompatibility with C++ standard. |
|||
// According to the Standard, `bitset::operator[] const` returns bool. |
|||
template <typename C> |
|||
struct is_bit_reference_like<std::__bit_const_reference<C>> { |
|||
static constexpr const bool value = true; |
|||
}; |
|||
|
|||
#endif |
|||
|
|||
} // namespace detail |
|||
|
|||
// We can't use std::vector<bool, Allocator>::reference and |
|||
// std::bitset<N>::reference because the compiler can't deduce Allocator and N |
|||
// in partial specialization. |
|||
template <typename BitRef, typename Char> |
|||
struct formatter<BitRef, Char, |
|||
enable_if_t<detail::is_bit_reference_like<BitRef>::value>> |
|||
: formatter<bool, Char> { |
|||
template <typename FormatContext> |
|||
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return formatter<bool, Char>::format(v, ctx); |
|||
} |
|||
}; |
|||
|
|||
template <typename T, typename Deleter> |
|||
auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* { |
|||
return p.get(); |
|||
} |
|||
template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* { |
|||
return p.get(); |
|||
} |
|||
|
|||
template <typename T, typename Char> |
|||
struct formatter<std::atomic<T>, Char, |
|||
enable_if_t<is_formattable<T, Char>::value>> |
|||
: formatter<T, Char> { |
|||
template <typename FormatContext> |
|||
auto format(const std::atomic<T>& v, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return formatter<T, Char>::format(v.load(), ctx); |
|||
} |
|||
}; |
|||
|
|||
#ifdef __cpp_lib_atomic_flag_test |
|||
template <typename Char> |
|||
struct formatter<std::atomic_flag, Char> : formatter<bool, Char> { |
|||
template <typename FormatContext> |
|||
auto format(const std::atomic_flag& v, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return formatter<bool, Char>::format(v.test(), ctx); |
|||
} |
|||
}; |
|||
#endif // __cpp_lib_atomic_flag_test |
|||
|
|||
template <typename T, typename Char> struct formatter<std::complex<T>, Char> { |
|||
private: |
|||
detail::dynamic_format_specs<Char> specs_; |
|||
|
|||
template <typename FormatContext, typename OutputIt> |
|||
FMT_CONSTEXPR auto do_format(const std::complex<T>& c, |
|||
detail::dynamic_format_specs<Char>& specs, |
|||
FormatContext& ctx, OutputIt out) const |
|||
-> OutputIt { |
|||
if (c.real() != 0) { |
|||
*out++ = Char('('); |
|||
out = detail::write<Char>(out, c.real(), specs, ctx.locale()); |
|||
specs.set_sign(sign::plus); |
|||
out = detail::write<Char>(out, c.imag(), specs, ctx.locale()); |
|||
if (!detail::isfinite(c.imag())) *out++ = Char(' '); |
|||
*out++ = Char('i'); |
|||
*out++ = Char(')'); |
|||
return out; |
|||
} |
|||
out = detail::write<Char>(out, c.imag(), specs, ctx.locale()); |
|||
if (!detail::isfinite(c.imag())) *out++ = Char(' '); |
|||
*out++ = Char('i'); |
|||
return out; |
|||
} |
|||
|
|||
public: |
|||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { |
|||
if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); |
|||
return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, |
|||
detail::type_constant<T, Char>::value); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::complex<T>& c, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto specs = specs_; |
|||
if (specs.dynamic()) { |
|||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, |
|||
specs.width_ref, ctx); |
|||
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, |
|||
specs.precision_ref, ctx); |
|||
} |
|||
|
|||
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out()); |
|||
auto buf = basic_memory_buffer<Char>(); |
|||
|
|||
auto outer_specs = format_specs(); |
|||
outer_specs.width = specs.width; |
|||
outer_specs.copy_fill_from(specs); |
|||
outer_specs.set_align(specs.align()); |
|||
|
|||
specs.width = 0; |
|||
specs.set_fill({}); |
|||
specs.set_align(align::none); |
|||
|
|||
do_format(c, specs, ctx, basic_appender<Char>(buf)); |
|||
return detail::write<Char>(ctx.out(), |
|||
basic_string_view<Char>(buf.data(), buf.size()), |
|||
outer_specs); |
|||
} |
|||
}; |
|||
|
|||
template <typename T, typename Char> |
|||
struct formatter<std::reference_wrapper<T>, Char, |
|||
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>> |
|||
: formatter<remove_cvref_t<T>, Char> { |
|||
template <typename FormatContext> |
|||
auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx); |
|||
} |
|||
}; |
|||
|
|||
FMT_END_NAMESPACE |
|||
#endif // FMT_STD_H_ |
@ -0,0 +1,369 @@ |
|||
// Formatting library for C++ - optional wchar_t and exotic character support |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_XCHAR_H_ |
|||
#define FMT_XCHAR_H_ |
|||
|
|||
#include "color.h" |
|||
#include "format.h" |
|||
#include "ostream.h" |
|||
#include "ranges.h" |
|||
|
|||
#ifndef FMT_MODULE |
|||
# include <cwchar> |
|||
# if FMT_USE_LOCALE |
|||
# include <locale> |
|||
# endif |
|||
#endif |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
template <typename T> |
|||
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; |
|||
|
|||
template <typename S, typename = void> struct format_string_char {}; |
|||
|
|||
template <typename S> |
|||
struct format_string_char< |
|||
S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> { |
|||
using type = char_t<S>; |
|||
}; |
|||
|
|||
template <typename S> |
|||
struct format_string_char< |
|||
S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> { |
|||
using type = typename S::char_type; |
|||
}; |
|||
|
|||
template <typename S> |
|||
using format_string_char_t = typename format_string_char<S>::type; |
|||
|
|||
inline auto write_loc(basic_appender<wchar_t> out, loc_value value, |
|||
const format_specs& specs, locale_ref loc) -> bool { |
|||
#if FMT_USE_LOCALE |
|||
auto& numpunct = |
|||
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>()); |
|||
auto separator = std::wstring(); |
|||
auto grouping = numpunct.grouping(); |
|||
if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); |
|||
return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}}); |
|||
#endif |
|||
return false; |
|||
} |
|||
} // namespace detail |
|||
|
|||
FMT_BEGIN_EXPORT |
|||
|
|||
using wstring_view = basic_string_view<wchar_t>; |
|||
using wformat_parse_context = parse_context<wchar_t>; |
|||
using wformat_context = buffered_context<wchar_t>; |
|||
using wformat_args = basic_format_args<wformat_context>; |
|||
using wmemory_buffer = basic_memory_buffer<wchar_t>; |
|||
|
|||
template <typename Char, typename... T> struct basic_fstring { |
|||
private: |
|||
basic_string_view<Char> str_; |
|||
|
|||
static constexpr int num_static_named_args = |
|||
detail::count_static_named_args<T...>(); |
|||
|
|||
using checker = detail::format_string_checker< |
|||
Char, static_cast<int>(sizeof...(T)), num_static_named_args, |
|||
num_static_named_args != detail::count_named_args<T...>()>; |
|||
|
|||
using arg_pack = detail::arg_pack<T...>; |
|||
|
|||
public: |
|||
using t = basic_fstring; |
|||
|
|||
template <typename S, |
|||
FMT_ENABLE_IF( |
|||
std::is_convertible<const S&, basic_string_view<Char>>::value)> |
|||
FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) { |
|||
if (FMT_USE_CONSTEVAL) |
|||
detail::parse_format_string<Char>(s, checker(s, arg_pack())); |
|||
} |
|||
template <typename S, |
|||
FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&& |
|||
std::is_same<typename S::char_type, Char>::value)> |
|||
FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) { |
|||
FMT_CONSTEXPR auto sv = basic_string_view<Char>(S()); |
|||
FMT_CONSTEXPR int ignore = |
|||
(parse_format_string(sv, checker(sv, arg_pack())), 0); |
|||
detail::ignore_unused(ignore); |
|||
} |
|||
basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {} |
|||
|
|||
operator basic_string_view<Char>() const { return str_; } |
|||
auto get() const -> basic_string_view<Char> { return str_; } |
|||
}; |
|||
|
|||
template <typename Char, typename... T> |
|||
using basic_format_string = basic_fstring<Char, T...>; |
|||
|
|||
template <typename... T> |
|||
using wformat_string = typename basic_format_string<wchar_t, T...>::t; |
|||
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> { |
|||
return {{s}}; |
|||
} |
|||
|
|||
#ifdef __cpp_char8_t |
|||
template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {}; |
|||
#endif |
|||
|
|||
template <typename... T> |
|||
constexpr auto make_wformat_args(T&... args) |
|||
-> decltype(fmt::make_format_args<wformat_context>(args...)) { |
|||
return fmt::make_format_args<wformat_context>(args...); |
|||
} |
|||
|
|||
#if !FMT_USE_NONTYPE_TEMPLATE_ARGS |
|||
inline namespace literals { |
|||
inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> { |
|||
return {s}; |
|||
} |
|||
} // namespace literals |
|||
#endif |
|||
|
|||
template <typename It, typename Sentinel> |
|||
auto join(It begin, Sentinel end, wstring_view sep) |
|||
-> join_view<It, Sentinel, wchar_t> { |
|||
return {begin, end, sep}; |
|||
} |
|||
|
|||
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)> |
|||
auto join(Range&& range, wstring_view sep) |
|||
-> join_view<decltype(std::begin(range)), decltype(std::end(range)), |
|||
wchar_t> { |
|||
return join(std::begin(range), std::end(range), sep); |
|||
} |
|||
|
|||
template <typename T> |
|||
auto join(std::initializer_list<T> list, wstring_view sep) |
|||
-> join_view<const T*, const T*, wchar_t> { |
|||
return join(std::begin(list), std::end(list), sep); |
|||
} |
|||
|
|||
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)> |
|||
auto join(const Tuple& tuple, basic_string_view<wchar_t> sep) |
|||
-> tuple_join_view<wchar_t, Tuple> { |
|||
return {tuple, sep}; |
|||
} |
|||
|
|||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> |
|||
auto vformat(basic_string_view<Char> fmt, |
|||
typename detail::vformat_args<Char>::type args) |
|||
-> std::basic_string<Char> { |
|||
auto buf = basic_memory_buffer<Char>(); |
|||
detail::vformat_to(buf, fmt, args); |
|||
return {buf.data(), buf.size()}; |
|||
} |
|||
|
|||
template <typename... T> |
|||
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring { |
|||
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
template <typename OutputIt, typename... T> |
|||
auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args) |
|||
-> OutputIt { |
|||
return vformat_to(out, fmt::wstring_view(fmt), |
|||
fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
// Pass char_t as a default template parameter instead of using |
|||
// std::basic_string<char_t<S>> to reduce the symbol size. |
|||
template <typename S, typename... T, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
FMT_ENABLE_IF(!std::is_same<Char, char>::value && |
|||
!std::is_same<Char, wchar_t>::value)> |
|||
auto format(const S& fmt, T&&... args) -> std::basic_string<Char> { |
|||
return vformat(detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffered_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename Locale, typename S, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat(const Locale& loc, const S& fmt, |
|||
typename detail::vformat_args<Char>::type args) |
|||
-> std::basic_string<Char> { |
|||
auto buf = basic_memory_buffer<Char>(); |
|||
detail::vformat_to(buf, detail::to_string_view(fmt), args, |
|||
detail::locale_ref(loc)); |
|||
return {buf.data(), buf.size()}; |
|||
} |
|||
|
|||
template <typename Locale, typename S, typename... T, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto format(const Locale& loc, const S& fmt, T&&... args) |
|||
-> std::basic_string<Char> { |
|||
return vformat(loc, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffered_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
auto vformat_to(OutputIt out, const S& fmt, |
|||
typename detail::vformat_args<Char>::type args) -> OutputIt { |
|||
auto&& buf = detail::get_buffer<Char>(out); |
|||
detail::vformat_to(buf, detail::to_string_view(fmt), args); |
|||
return detail::get_iterator(buf, out); |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename... T, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value && |
|||
!std::is_same<Char, char>::value && |
|||
!std::is_same<Char, wchar_t>::value)> |
|||
inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { |
|||
return vformat_to(out, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffered_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename Locale, typename S, typename OutputIt, typename... Args, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat_to(OutputIt out, const Locale& loc, const S& fmt, |
|||
typename detail::vformat_args<Char>::type args) |
|||
-> OutputIt { |
|||
auto&& buf = detail::get_buffer<Char>(out); |
|||
vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc)); |
|||
return detail::get_iterator(buf, out); |
|||
} |
|||
|
|||
template <typename Locale, typename OutputIt, typename S, typename... T, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
bool enable = detail::is_output_iterator<OutputIt, Char>::value && |
|||
detail::is_locale<Locale>::value && |
|||
detail::is_exotic_char<Char>::value> |
|||
inline auto format_to(OutputIt out, const Locale& loc, const S& fmt, |
|||
T&&... args) -> |
|||
typename std::enable_if<enable, OutputIt>::type { |
|||
return vformat_to(out, loc, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffered_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename OutputIt, typename Char, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt, |
|||
typename detail::vformat_args<Char>::type args) |
|||
-> format_to_n_result<OutputIt> { |
|||
using traits = detail::fixed_buffer_traits; |
|||
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n); |
|||
detail::vformat_to(buf, fmt, args); |
|||
return {buf.out(), buf.count()}; |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename... T, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) |
|||
-> format_to_n_result<OutputIt> { |
|||
return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt), |
|||
fmt::make_format_args<buffered_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename S, typename... T, |
|||
typename Char = detail::format_string_char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> |
|||
inline auto formatted_size(const S& fmt, T&&... args) -> size_t { |
|||
auto buf = detail::counting_buffer<Char>(); |
|||
detail::vformat_to(buf, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffered_context<Char>>(args...)); |
|||
return buf.count(); |
|||
} |
|||
|
|||
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { |
|||
auto buf = wmemory_buffer(); |
|||
detail::vformat_to(buf, fmt, args); |
|||
buf.push_back(L'\0'); |
|||
if (std::fputws(buf.data(), f) == -1) |
|||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); |
|||
} |
|||
|
|||
inline void vprint(wstring_view fmt, wformat_args args) { |
|||
vprint(stdout, fmt, args); |
|||
} |
|||
|
|||
template <typename... T> |
|||
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { |
|||
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { |
|||
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
template <typename... T> |
|||
void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) { |
|||
return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); |
|||
} |
|||
|
|||
template <typename... T> void println(wformat_string<T...> fmt, T&&... args) { |
|||
return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); |
|||
} |
|||
|
|||
inline auto vformat(text_style ts, wstring_view fmt, wformat_args args) |
|||
-> std::wstring { |
|||
auto buf = wmemory_buffer(); |
|||
detail::vformat_to(buf, ts, fmt, args); |
|||
return {buf.data(), buf.size()}; |
|||
} |
|||
|
|||
template <typename... T> |
|||
inline auto format(text_style ts, wformat_string<T...> fmt, T&&... args) |
|||
-> std::wstring { |
|||
return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
template <typename... T> |
|||
FMT_DEPRECATED void print(std::FILE* f, text_style ts, wformat_string<T...> fmt, |
|||
const T&... args) { |
|||
vprint(f, ts, fmt, fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
template <typename... T> |
|||
FMT_DEPRECATED void print(text_style ts, wformat_string<T...> fmt, |
|||
const T&... args) { |
|||
return print(stdout, ts, fmt, args...); |
|||
} |
|||
|
|||
inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) { |
|||
auto buffer = basic_memory_buffer<wchar_t>(); |
|||
detail::vformat_to(buffer, fmt, args); |
|||
detail::write_buffer(os, buffer); |
|||
} |
|||
|
|||
template <typename... T> |
|||
void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) { |
|||
vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...)); |
|||
} |
|||
|
|||
template <typename... T> |
|||
void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) { |
|||
print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); |
|||
} |
|||
|
|||
/// Converts `value` to `std::wstring` using the default format for type `T`. |
|||
template <typename T> inline auto to_wstring(const T& value) -> std::wstring { |
|||
return format(FMT_STRING(L"{}"), value); |
|||
} |
|||
FMT_END_EXPORT |
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_XCHAR_H_ |
@ -0,0 +1,346 @@ |
|||
#ifndef _ANY_INVOKABLE_H_ |
|||
#define _ANY_INVOKABLE_H_ |
|||
|
|||
#include <functional> |
|||
#include <memory> |
|||
#include <type_traits> |
|||
|
|||
// clang-format off |
|||
/* |
|||
namespace std { |
|||
template<class Sig> class any_invocable; // never defined |
|||
|
|||
template<class R, class... ArgTypes> |
|||
class any_invocable<R(ArgTypes...) cv ref noexcept(noex)> { |
|||
public: |
|||
using result_type = R; |
|||
|
|||
// SECTION.3, construct/copy/destroy |
|||
any_invocable() noexcept; |
|||
any_invocable(nullptr_t) noexcept; |
|||
any_invocable(any_invocable&&) noexcept; |
|||
template<class F> any_invocable(F&&); |
|||
|
|||
template<class T, class... Args> |
|||
explicit any_invocable(in_place_type_t<T>, Args&&...); |
|||
template<class T, class U, class... Args> |
|||
explicit any_invocable(in_place_type_t<T>, initializer_list<U>, Args&&...); |
|||
|
|||
any_invocable& operator=(any_invocable&&) noexcept; |
|||
any_invocable& operator=(nullptr_t) noexcept; |
|||
template<class F> any_invocable& operator=(F&&); |
|||
template<class F> any_invocable& operator=(reference_wrapper<F>) noexcept; |
|||
|
|||
~any_invocable(); |
|||
|
|||
// SECTION.4, any_invocable modifiers |
|||
void swap(any_invocable&) noexcept; |
|||
|
|||
// SECTION.5, any_invocable capacity |
|||
explicit operator bool() const noexcept; |
|||
|
|||
// SECTION.6, any_invocable invocation |
|||
R operator()(ArgTypes...) cv ref noexcept(noex); |
|||
|
|||
// SECTION.7, null pointer comparisons |
|||
friend bool operator==(const any_invocable&, nullptr_t) noexcept; |
|||
|
|||
// SECTION.8, specialized algorithms |
|||
friend void swap(any_invocable&, any_invocable&) noexcept; |
|||
}; |
|||
} |
|||
*/ |
|||
// clang-format on |
|||
|
|||
namespace ofats { |
|||
|
|||
namespace any_detail { |
|||
|
|||
using buffer = std::aligned_storage_t<sizeof(void*) * 2, alignof(void*)>; |
|||
|
|||
template <class T> |
|||
inline constexpr bool is_small_object_v = |
|||
sizeof(T) <= sizeof(buffer) && alignof(buffer) % alignof(T) == 0 && |
|||
std::is_nothrow_move_constructible_v<T>; |
|||
|
|||
union storage { |
|||
void* ptr_ = nullptr; |
|||
buffer buf_; |
|||
}; |
|||
|
|||
enum class action { destroy, move }; |
|||
|
|||
template <class R, class... ArgTypes> |
|||
struct handler_traits { |
|||
template <class Derived> |
|||
struct handler_base { |
|||
static void handle(action act, storage* current, storage* other = nullptr) { |
|||
switch (act) { |
|||
case (action::destroy): |
|||
Derived::destroy(*current); |
|||
break; |
|||
case (action::move): |
|||
Derived::move(*current, *other); |
|||
break; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
template <class T> |
|||
struct small_handler : handler_base<small_handler<T>> { |
|||
template <class... Args> |
|||
static void create(storage& s, Args&&... args) { |
|||
new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...); |
|||
} |
|||
|
|||
static void destroy(storage& s) noexcept { |
|||
T& value = *static_cast<T*>(static_cast<void*>(&s.buf_)); |
|||
value.~T(); |
|||
} |
|||
|
|||
static void move(storage& dst, storage& src) noexcept { |
|||
create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_)))); |
|||
destroy(src); |
|||
} |
|||
|
|||
static R call(const storage& s, ArgTypes... args) { |
|||
return std::invoke( |
|||
*static_cast<T*>(static_cast<void*>(&const_cast<storage&>(s).buf_)), |
|||
std::forward<ArgTypes>(args)...); |
|||
} |
|||
}; |
|||
|
|||
template <class T> |
|||
struct large_handler : handler_base<large_handler<T>> { |
|||
template <class... Args> |
|||
static void create(storage& s, Args&&... args) { |
|||
s.ptr_ = new T(std::forward<Args>(args)...); |
|||
} |
|||
|
|||
static void destroy(storage& s) noexcept { delete static_cast<T*>(s.ptr_); } |
|||
|
|||
static void move(storage& dst, storage& src) noexcept { |
|||
dst.ptr_ = src.ptr_; |
|||
} |
|||
|
|||
static R call(const storage& s, ArgTypes... args) { |
|||
return std::invoke(*static_cast<T*>(s.ptr_), |
|||
std::forward<ArgTypes>(args)...); |
|||
} |
|||
}; |
|||
|
|||
template <class T> |
|||
using handler = std::conditional_t<is_small_object_v<T>, small_handler<T>, |
|||
large_handler<T>>; |
|||
}; |
|||
|
|||
template <class T> |
|||
struct is_in_place_type : std::false_type {}; |
|||
|
|||
template <class T> |
|||
struct is_in_place_type<std::in_place_type_t<T>> : std::true_type {}; |
|||
|
|||
template <class T> |
|||
inline constexpr auto is_in_place_type_v = is_in_place_type<T>::value; |
|||
|
|||
template <class R, bool is_noexcept, class... ArgTypes> |
|||
class any_invocable_impl { |
|||
template <class T> |
|||
using handler = |
|||
typename any_detail::handler_traits<R, ArgTypes...>::template handler<T>; |
|||
|
|||
using storage = any_detail::storage; |
|||
using action = any_detail::action; |
|||
using handle_func = void (*)(any_detail::action, any_detail::storage*, |
|||
any_detail::storage*); |
|||
using call_func = R (*)(const any_detail::storage&, ArgTypes...); |
|||
|
|||
public: |
|||
using result_type = R; |
|||
|
|||
any_invocable_impl() noexcept = default; |
|||
any_invocable_impl(std::nullptr_t) noexcept {} |
|||
any_invocable_impl(any_invocable_impl&& rhs) noexcept { |
|||
if (rhs.handle_) { |
|||
handle_ = rhs.handle_; |
|||
handle_(action::move, &storage_, &rhs.storage_); |
|||
call_ = rhs.call_; |
|||
rhs.handle_ = nullptr; |
|||
} |
|||
} |
|||
|
|||
any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { |
|||
any_invocable_impl{std::move(rhs)}.swap(*this); |
|||
return *this; |
|||
} |
|||
any_invocable_impl& operator=(std::nullptr_t) noexcept { |
|||
destroy(); |
|||
return *this; |
|||
} |
|||
|
|||
~any_invocable_impl() { destroy(); } |
|||
|
|||
void swap(any_invocable_impl& rhs) noexcept { |
|||
if (handle_) { |
|||
if (rhs.handle_) { |
|||
storage tmp; |
|||
handle_(action::move, &tmp, &storage_); |
|||
rhs.handle_(action::move, &storage_, &rhs.storage_); |
|||
handle_(action::move, &rhs.storage_, &tmp); |
|||
std::swap(handle_, rhs.handle_); |
|||
std::swap(call_, rhs.call_); |
|||
} else { |
|||
rhs.swap(*this); |
|||
} |
|||
} else if (rhs.handle_) { |
|||
rhs.handle_(action::move, &storage_, &rhs.storage_); |
|||
handle_ = rhs.handle_; |
|||
call_ = rhs.call_; |
|||
rhs.handle_ = nullptr; |
|||
} |
|||
} |
|||
|
|||
explicit operator bool() const noexcept { return handle_ != nullptr; } |
|||
|
|||
protected: |
|||
template <class F, class... Args> |
|||
void create(Args&&... args) { |
|||
using hdl = handler<F>; |
|||
hdl::create(storage_, std::forward<Args>(args)...); |
|||
handle_ = &hdl::handle; |
|||
call_ = &hdl::call; |
|||
} |
|||
|
|||
void destroy() noexcept { |
|||
if (handle_) { |
|||
handle_(action::destroy, &storage_, nullptr); |
|||
handle_ = nullptr; |
|||
} |
|||
} |
|||
|
|||
R call(ArgTypes... args) const noexcept(is_noexcept) { |
|||
return call_(storage_, std::forward<ArgTypes>(args)...); |
|||
} |
|||
|
|||
friend bool operator==(const any_invocable_impl& f, std::nullptr_t) noexcept { |
|||
return !f; |
|||
} |
|||
friend bool operator==(std::nullptr_t, const any_invocable_impl& f) noexcept { |
|||
return !f; |
|||
} |
|||
friend bool operator!=(const any_invocable_impl& f, std::nullptr_t) noexcept { |
|||
return static_cast<bool>(f); |
|||
} |
|||
friend bool operator!=(std::nullptr_t, const any_invocable_impl& f) noexcept { |
|||
return static_cast<bool>(f); |
|||
} |
|||
|
|||
friend void swap(any_invocable_impl& lhs, any_invocable_impl& rhs) noexcept { |
|||
lhs.swap(rhs); |
|||
} |
|||
|
|||
private: |
|||
storage storage_; |
|||
handle_func handle_ = nullptr; |
|||
call_func call_; |
|||
}; |
|||
|
|||
template <class T> |
|||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; |
|||
|
|||
template <class AI, class F, bool noex, class R, class FCall, class... ArgTypes> |
|||
using can_convert = std::conjunction< |
|||
std::negation<std::is_same<remove_cvref_t<F>, AI>>, |
|||
std::negation<any_detail::is_in_place_type<remove_cvref_t<F>>>, |
|||
std::is_invocable_r<R, FCall, ArgTypes...>, |
|||
std::bool_constant<(!noex || |
|||
std::is_nothrow_invocable_r_v<R, FCall, ArgTypes...>)>, |
|||
std::is_constructible<std::decay_t<F>, F>>; |
|||
|
|||
} // namespace any_detail |
|||
|
|||
template <class Signature> |
|||
class any_invocable; |
|||
|
|||
#define __OFATS_ANY_INVOCABLE(cv, ref, noex, inv_quals) \ |
|||
template <class R, class... ArgTypes> \ |
|||
class any_invocable<R(ArgTypes...) cv ref noexcept(noex)> final \ |
|||
: public any_detail::any_invocable_impl<R, noex, ArgTypes...> { \ |
|||
using base_type = any_detail::any_invocable_impl<R, noex, ArgTypes...>; \ |
|||
\ |
|||
public: \ |
|||
using base_type::base_type; \ |
|||
\ |
|||
template < \ |
|||
class F, \ |
|||
class = std::enable_if_t<any_detail::can_convert< \ |
|||
any_invocable, F, noex, R, F inv_quals, ArgTypes...>::value>> \ |
|||
any_invocable(F&& f) { \ |
|||
base_type::template create<std::decay_t<F>>(std::forward<F>(f)); \ |
|||
} \ |
|||
\ |
|||
template <class T, class... Args, class VT = std::decay_t<T>, \ |
|||
class = std::enable_if_t< \ |
|||
std::is_move_constructible_v<VT> && \ |
|||
std::is_constructible_v<VT, Args...> && \ |
|||
std::is_invocable_r_v<R, VT inv_quals, ArgTypes...> && \ |
|||
(!noex || std::is_nothrow_invocable_r_v<R, VT inv_quals, \ |
|||
ArgTypes...>)>> \ |
|||
explicit any_invocable(std::in_place_type_t<T>, Args&&... args) { \ |
|||
base_type::template create<VT>(std::forward<Args>(args)...); \ |
|||
} \ |
|||
\ |
|||
template < \ |
|||
class T, class U, class... Args, class VT = std::decay_t<T>, \ |
|||
class = std::enable_if_t< \ |
|||
std::is_move_constructible_v<VT> && \ |
|||
std::is_constructible_v<VT, std::initializer_list<U>&, Args...> && \ |
|||
std::is_invocable_r_v<R, VT inv_quals, ArgTypes...> && \ |
|||
(!noex || \ |
|||
std::is_nothrow_invocable_r_v<R, VT inv_quals, ArgTypes...>)>> \ |
|||
explicit any_invocable(std::in_place_type_t<T>, \ |
|||
std::initializer_list<U> il, Args&&... args) { \ |
|||
base_type::template create<VT>(il, std::forward<Args>(args)...); \ |
|||
} \ |
|||
\ |
|||
template <class F, class FDec = std::decay_t<F>> \ |
|||
std::enable_if_t<!std::is_same_v<FDec, any_invocable> && \ |
|||
std::is_move_constructible_v<FDec>, \ |
|||
any_invocable&> \ |
|||
operator=(F&& f) { \ |
|||
any_invocable{std::forward<F>(f)}.swap(*this); \ |
|||
return *this; \ |
|||
} \ |
|||
template <class F> \ |
|||
any_invocable& operator=(std::reference_wrapper<F> f) { \ |
|||
any_invocable{f}.swap(*this); \ |
|||
return *this; \ |
|||
} \ |
|||
\ |
|||
R operator()(ArgTypes... args) cv ref noexcept(noex) { \ |
|||
return base_type::call(std::forward<ArgTypes>(args)...); \ |
|||
} \ |
|||
} |
|||
|
|||
// cv -> {`empty`, const} |
|||
// ref -> {`empty`, &, &&} |
|||
// noex -> {true, false} |
|||
// inv_quals -> (is_empty(ref) ? & : ref) |
|||
__OFATS_ANY_INVOCABLE(, , false, &); // 000 |
|||
__OFATS_ANY_INVOCABLE(, , true, &); // 001 |
|||
__OFATS_ANY_INVOCABLE(, &, false, &); // 010 |
|||
__OFATS_ANY_INVOCABLE(, &, true, &); // 011 |
|||
__OFATS_ANY_INVOCABLE(, &&, false, &&); // 020 |
|||
__OFATS_ANY_INVOCABLE(, &&, true, &&); // 021 |
|||
__OFATS_ANY_INVOCABLE(const, , false, const&); // 100 |
|||
__OFATS_ANY_INVOCABLE(const, , true, const&); // 101 |
|||
__OFATS_ANY_INVOCABLE(const, &, false, const&); // 110 |
|||
__OFATS_ANY_INVOCABLE(const, &, true, const&); // 111 |
|||
__OFATS_ANY_INVOCABLE(const, &&, false, const&&); // 120 |
|||
__OFATS_ANY_INVOCABLE(const, &&, true, const&&); // 121 |
|||
|
|||
#undef __OFATS_ANY_INVOCABLE |
|||
|
|||
} // namespace ofats |
|||
|
|||
#endif // _ANY_INVOKABLE_H_ |
@ -0,0 +1,113 @@ |
|||
/*
|
|||
ISC License |
|||
|
|||
Copyright (c) 2025, Antonio SJ Musumeci <trapexit@spawn.link> |
|||
|
|||
Permission to use, copy, modify, and/or distribute this software for any |
|||
purpose with or without fee is hereby granted, provided that the above |
|||
copyright notice and this permission notice appear in all copies. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
*/ |
|||
|
|||
#pragma once
|
|||
|
|||
#include "fmt/core.h"
|
|||
#include "fmt/format.h"
|
|||
|
|||
#include <syslog.h>
|
|||
|
|||
namespace SysLog |
|||
{ |
|||
static |
|||
inline |
|||
void |
|||
open() |
|||
{ |
|||
const char *ident = "mergerfs"; |
|||
const int option = (LOG_CONS|LOG_PID); |
|||
const int facility = LOG_USER; |
|||
|
|||
openlog(ident,option,facility); |
|||
} |
|||
|
|||
static |
|||
inline |
|||
void |
|||
close() |
|||
{ |
|||
closelog(); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
void |
|||
log(int priority_, |
|||
fmt::format_string<Args...> format_, |
|||
Args&&... args) |
|||
{ |
|||
auto msg = fmt::format(format_,std::forward<Args>(args)...); |
|||
::syslog(priority_,"%s",msg.c_str()); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
void |
|||
info(fmt::format_string<Args...> format_, |
|||
Args&&... args) |
|||
{ |
|||
SysLog::log(LOG_INFO,format_,std::forward<Args>(args)...); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
void |
|||
debug(fmt::format_string<Args...> format_, |
|||
Args&&... args) |
|||
{ |
|||
SysLog::log(LOG_DEBUG,format_,std::forward<Args>(args)...); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
void |
|||
notice(fmt::format_string<Args...> format_, |
|||
Args&&... args) |
|||
{ |
|||
SysLog::log(LOG_NOTICE,format_,std::forward<Args>(args)...); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
void |
|||
warning(fmt::format_string<Args...> format_, |
|||
Args&&... args) |
|||
{ |
|||
SysLog::log(LOG_WARNING,format_,std::forward<Args>(args)...); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
void |
|||
error(fmt::format_string<Args...> format_, |
|||
Args&&... args) |
|||
{ |
|||
SysLog::log(LOG_ERR,format_,std::forward<Args>(args)...); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
void |
|||
alert(fmt::format_string<Args...> format_, |
|||
Args&&... args) |
|||
{ |
|||
SysLog::log(LOG_ALERT,format_,std::forward<Args>(args)...); |
|||
} |
|||
|
|||
template<typename... Args> |
|||
void |
|||
crit(fmt::format_string<Args...> format_, |
|||
Args&&... args) |
|||
{ |
|||
SysLog::log(LOG_CRIT,format_,std::forward<Args>(args)...); |
|||
} |
|||
} |
@ -1,234 +0,0 @@ |
|||
// Formatting library for C++ - dynamic format arguments |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_ARGS_H_ |
|||
#define FMT_ARGS_H_ |
|||
|
|||
#include <functional> // std::reference_wrapper |
|||
#include <memory> // std::unique_ptr |
|||
#include <vector> |
|||
|
|||
#include "core.h" |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
|
|||
namespace detail { |
|||
|
|||
template <typename T> struct is_reference_wrapper : std::false_type {}; |
|||
template <typename T> |
|||
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; |
|||
|
|||
template <typename T> const T& unwrap(const T& v) { return v; } |
|||
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) { |
|||
return static_cast<const T&>(v); |
|||
} |
|||
|
|||
class dynamic_arg_list { |
|||
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for |
|||
// templates it doesn't complain about inability to deduce single translation |
|||
// unit for placing vtable. So storage_node_base is made a fake template. |
|||
template <typename = void> struct node { |
|||
virtual ~node() = default; |
|||
std::unique_ptr<node<>> next; |
|||
}; |
|||
|
|||
template <typename T> struct typed_node : node<> { |
|||
T value; |
|||
|
|||
template <typename Arg> |
|||
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} |
|||
|
|||
template <typename Char> |
|||
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg) |
|||
: value(arg.data(), arg.size()) {} |
|||
}; |
|||
|
|||
std::unique_ptr<node<>> head_; |
|||
|
|||
public: |
|||
template <typename T, typename Arg> const T& push(const Arg& arg) { |
|||
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg)); |
|||
auto& value = new_node->value; |
|||
new_node->next = std::move(head_); |
|||
head_ = std::move(new_node); |
|||
return value; |
|||
} |
|||
}; |
|||
} // namespace detail |
|||
|
|||
/** |
|||
\rst |
|||
A dynamic version of `fmt::format_arg_store`. |
|||
It's equipped with a storage to potentially temporary objects which lifetimes |
|||
could be shorter than the format arguments object. |
|||
|
|||
It can be implicitly converted into `~fmt::basic_format_args` for passing |
|||
into type-erased formatting functions such as `~fmt::vformat`. |
|||
\endrst |
|||
*/ |
|||
template <typename Context> |
|||
class dynamic_format_arg_store |
|||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 |
|||
// Workaround a GCC template argument substitution bug. |
|||
: public basic_format_args<Context> |
|||
#endif |
|||
{ |
|||
private: |
|||
using char_type = typename Context::char_type; |
|||
|
|||
template <typename T> struct need_copy { |
|||
static constexpr detail::type mapped_type = |
|||
detail::mapped_type_constant<T, Context>::value; |
|||
|
|||
enum { |
|||
value = !(detail::is_reference_wrapper<T>::value || |
|||
std::is_same<T, basic_string_view<char_type>>::value || |
|||
std::is_same<T, detail::std_string_view<char_type>>::value || |
|||
(mapped_type != detail::type::cstring_type && |
|||
mapped_type != detail::type::string_type && |
|||
mapped_type != detail::type::custom_type)) |
|||
}; |
|||
}; |
|||
|
|||
template <typename T> |
|||
using stored_type = conditional_t< |
|||
std::is_convertible<T, std::basic_string<char_type>>::value && |
|||
!detail::is_reference_wrapper<T>::value, |
|||
std::basic_string<char_type>, T>; |
|||
|
|||
// Storage of basic_format_arg must be contiguous. |
|||
std::vector<basic_format_arg<Context>> data_; |
|||
std::vector<detail::named_arg_info<char_type>> named_info_; |
|||
|
|||
// Storage of arguments not fitting into basic_format_arg must grow |
|||
// without relocation because items in data_ refer to it. |
|||
detail::dynamic_arg_list dynamic_args_; |
|||
|
|||
friend class basic_format_args<Context>; |
|||
|
|||
unsigned long long get_types() const { |
|||
return detail::is_unpacked_bit | data_.size() | |
|||
(named_info_.empty() |
|||
? 0ULL |
|||
: static_cast<unsigned long long>(detail::has_named_args_bit)); |
|||
} |
|||
|
|||
const basic_format_arg<Context>* data() const { |
|||
return named_info_.empty() ? data_.data() : data_.data() + 1; |
|||
} |
|||
|
|||
template <typename T> void emplace_arg(const T& arg) { |
|||
data_.emplace_back(detail::make_arg<Context>(arg)); |
|||
} |
|||
|
|||
template <typename T> |
|||
void emplace_arg(const detail::named_arg<char_type, T>& arg) { |
|||
if (named_info_.empty()) { |
|||
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr}; |
|||
data_.insert(data_.begin(), {zero_ptr, 0}); |
|||
} |
|||
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value))); |
|||
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) { |
|||
data->pop_back(); |
|||
}; |
|||
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)> |
|||
guard{&data_, pop_one}; |
|||
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)}); |
|||
data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; |
|||
guard.release(); |
|||
} |
|||
|
|||
public: |
|||
constexpr dynamic_format_arg_store() = default; |
|||
|
|||
/** |
|||
\rst |
|||
Adds an argument into the dynamic store for later passing to a formatting |
|||
function. |
|||
|
|||
Note that custom types and string types (but not string views) are copied |
|||
into the store dynamically allocating memory if necessary. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::dynamic_format_arg_store<fmt::format_context> store; |
|||
store.push_back(42); |
|||
store.push_back("abc"); |
|||
store.push_back(1.5f); |
|||
std::string result = fmt::vformat("{} and {} and {}", store); |
|||
\endrst |
|||
*/ |
|||
template <typename T> void push_back(const T& arg) { |
|||
if (detail::const_check(need_copy<T>::value)) |
|||
emplace_arg(dynamic_args_.push<stored_type<T>>(arg)); |
|||
else |
|||
emplace_arg(detail::unwrap(arg)); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Adds a reference to the argument into the dynamic store for later passing to |
|||
a formatting function. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::dynamic_format_arg_store<fmt::format_context> store; |
|||
char band[] = "Rolling Stones"; |
|||
store.push_back(std::cref(band)); |
|||
band[9] = 'c'; // Changing str affects the output. |
|||
std::string result = fmt::vformat("{}", store); |
|||
// result == "Rolling Scones" |
|||
\endrst |
|||
*/ |
|||
template <typename T> void push_back(std::reference_wrapper<T> arg) { |
|||
static_assert( |
|||
need_copy<T>::value, |
|||
"objects of built-in types and string views are always copied"); |
|||
emplace_arg(arg.get()); |
|||
} |
|||
|
|||
/** |
|||
Adds named argument into the dynamic store for later passing to a formatting |
|||
function. ``std::reference_wrapper`` is supported to avoid copying of the |
|||
argument. The name is always copied into the store. |
|||
*/ |
|||
template <typename T> |
|||
void push_back(const detail::named_arg<char_type, T>& arg) { |
|||
const char_type* arg_name = |
|||
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str(); |
|||
if (detail::const_check(need_copy<T>::value)) { |
|||
emplace_arg( |
|||
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value))); |
|||
} else { |
|||
emplace_arg(fmt::arg(arg_name, arg.value)); |
|||
} |
|||
} |
|||
|
|||
/** Erase all elements from the store */ |
|||
void clear() { |
|||
data_.clear(); |
|||
named_info_.clear(); |
|||
dynamic_args_ = detail::dynamic_arg_list(); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Reserves space to store at least *new_cap* arguments including |
|||
*new_cap_named* named arguments. |
|||
\endrst |
|||
*/ |
|||
void reserve(size_t new_cap, size_t new_cap_named) { |
|||
FMT_ASSERT(new_cap >= new_cap_named, |
|||
"Set of arguments includes set of named arguments"); |
|||
data_.reserve(new_cap); |
|||
named_info_.reserve(new_cap_named); |
|||
} |
|||
}; |
|||
|
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_ARGS_H_ |
2069
libfuse/lib/fmt/chrono.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,651 +0,0 @@ |
|||
// Formatting library for C++ - color support |
|||
// |
|||
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_COLOR_H_ |
|||
#define FMT_COLOR_H_ |
|||
|
|||
#include "format.h" |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
FMT_MODULE_EXPORT_BEGIN |
|||
|
|||
enum class color : uint32_t { |
|||
alice_blue = 0xF0F8FF, // rgb(240,248,255) |
|||
antique_white = 0xFAEBD7, // rgb(250,235,215) |
|||
aqua = 0x00FFFF, // rgb(0,255,255) |
|||
aquamarine = 0x7FFFD4, // rgb(127,255,212) |
|||
azure = 0xF0FFFF, // rgb(240,255,255) |
|||
beige = 0xF5F5DC, // rgb(245,245,220) |
|||
bisque = 0xFFE4C4, // rgb(255,228,196) |
|||
black = 0x000000, // rgb(0,0,0) |
|||
blanched_almond = 0xFFEBCD, // rgb(255,235,205) |
|||
blue = 0x0000FF, // rgb(0,0,255) |
|||
blue_violet = 0x8A2BE2, // rgb(138,43,226) |
|||
brown = 0xA52A2A, // rgb(165,42,42) |
|||
burly_wood = 0xDEB887, // rgb(222,184,135) |
|||
cadet_blue = 0x5F9EA0, // rgb(95,158,160) |
|||
chartreuse = 0x7FFF00, // rgb(127,255,0) |
|||
chocolate = 0xD2691E, // rgb(210,105,30) |
|||
coral = 0xFF7F50, // rgb(255,127,80) |
|||
cornflower_blue = 0x6495ED, // rgb(100,149,237) |
|||
cornsilk = 0xFFF8DC, // rgb(255,248,220) |
|||
crimson = 0xDC143C, // rgb(220,20,60) |
|||
cyan = 0x00FFFF, // rgb(0,255,255) |
|||
dark_blue = 0x00008B, // rgb(0,0,139) |
|||
dark_cyan = 0x008B8B, // rgb(0,139,139) |
|||
dark_golden_rod = 0xB8860B, // rgb(184,134,11) |
|||
dark_gray = 0xA9A9A9, // rgb(169,169,169) |
|||
dark_green = 0x006400, // rgb(0,100,0) |
|||
dark_khaki = 0xBDB76B, // rgb(189,183,107) |
|||
dark_magenta = 0x8B008B, // rgb(139,0,139) |
|||
dark_olive_green = 0x556B2F, // rgb(85,107,47) |
|||
dark_orange = 0xFF8C00, // rgb(255,140,0) |
|||
dark_orchid = 0x9932CC, // rgb(153,50,204) |
|||
dark_red = 0x8B0000, // rgb(139,0,0) |
|||
dark_salmon = 0xE9967A, // rgb(233,150,122) |
|||
dark_sea_green = 0x8FBC8F, // rgb(143,188,143) |
|||
dark_slate_blue = 0x483D8B, // rgb(72,61,139) |
|||
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) |
|||
dark_turquoise = 0x00CED1, // rgb(0,206,209) |
|||
dark_violet = 0x9400D3, // rgb(148,0,211) |
|||
deep_pink = 0xFF1493, // rgb(255,20,147) |
|||
deep_sky_blue = 0x00BFFF, // rgb(0,191,255) |
|||
dim_gray = 0x696969, // rgb(105,105,105) |
|||
dodger_blue = 0x1E90FF, // rgb(30,144,255) |
|||
fire_brick = 0xB22222, // rgb(178,34,34) |
|||
floral_white = 0xFFFAF0, // rgb(255,250,240) |
|||
forest_green = 0x228B22, // rgb(34,139,34) |
|||
fuchsia = 0xFF00FF, // rgb(255,0,255) |
|||
gainsboro = 0xDCDCDC, // rgb(220,220,220) |
|||
ghost_white = 0xF8F8FF, // rgb(248,248,255) |
|||
gold = 0xFFD700, // rgb(255,215,0) |
|||
golden_rod = 0xDAA520, // rgb(218,165,32) |
|||
gray = 0x808080, // rgb(128,128,128) |
|||
green = 0x008000, // rgb(0,128,0) |
|||
green_yellow = 0xADFF2F, // rgb(173,255,47) |
|||
honey_dew = 0xF0FFF0, // rgb(240,255,240) |
|||
hot_pink = 0xFF69B4, // rgb(255,105,180) |
|||
indian_red = 0xCD5C5C, // rgb(205,92,92) |
|||
indigo = 0x4B0082, // rgb(75,0,130) |
|||
ivory = 0xFFFFF0, // rgb(255,255,240) |
|||
khaki = 0xF0E68C, // rgb(240,230,140) |
|||
lavender = 0xE6E6FA, // rgb(230,230,250) |
|||
lavender_blush = 0xFFF0F5, // rgb(255,240,245) |
|||
lawn_green = 0x7CFC00, // rgb(124,252,0) |
|||
lemon_chiffon = 0xFFFACD, // rgb(255,250,205) |
|||
light_blue = 0xADD8E6, // rgb(173,216,230) |
|||
light_coral = 0xF08080, // rgb(240,128,128) |
|||
light_cyan = 0xE0FFFF, // rgb(224,255,255) |
|||
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) |
|||
light_gray = 0xD3D3D3, // rgb(211,211,211) |
|||
light_green = 0x90EE90, // rgb(144,238,144) |
|||
light_pink = 0xFFB6C1, // rgb(255,182,193) |
|||
light_salmon = 0xFFA07A, // rgb(255,160,122) |
|||
light_sea_green = 0x20B2AA, // rgb(32,178,170) |
|||
light_sky_blue = 0x87CEFA, // rgb(135,206,250) |
|||
light_slate_gray = 0x778899, // rgb(119,136,153) |
|||
light_steel_blue = 0xB0C4DE, // rgb(176,196,222) |
|||
light_yellow = 0xFFFFE0, // rgb(255,255,224) |
|||
lime = 0x00FF00, // rgb(0,255,0) |
|||
lime_green = 0x32CD32, // rgb(50,205,50) |
|||
linen = 0xFAF0E6, // rgb(250,240,230) |
|||
magenta = 0xFF00FF, // rgb(255,0,255) |
|||
maroon = 0x800000, // rgb(128,0,0) |
|||
medium_aquamarine = 0x66CDAA, // rgb(102,205,170) |
|||
medium_blue = 0x0000CD, // rgb(0,0,205) |
|||
medium_orchid = 0xBA55D3, // rgb(186,85,211) |
|||
medium_purple = 0x9370DB, // rgb(147,112,219) |
|||
medium_sea_green = 0x3CB371, // rgb(60,179,113) |
|||
medium_slate_blue = 0x7B68EE, // rgb(123,104,238) |
|||
medium_spring_green = 0x00FA9A, // rgb(0,250,154) |
|||
medium_turquoise = 0x48D1CC, // rgb(72,209,204) |
|||
medium_violet_red = 0xC71585, // rgb(199,21,133) |
|||
midnight_blue = 0x191970, // rgb(25,25,112) |
|||
mint_cream = 0xF5FFFA, // rgb(245,255,250) |
|||
misty_rose = 0xFFE4E1, // rgb(255,228,225) |
|||
moccasin = 0xFFE4B5, // rgb(255,228,181) |
|||
navajo_white = 0xFFDEAD, // rgb(255,222,173) |
|||
navy = 0x000080, // rgb(0,0,128) |
|||
old_lace = 0xFDF5E6, // rgb(253,245,230) |
|||
olive = 0x808000, // rgb(128,128,0) |
|||
olive_drab = 0x6B8E23, // rgb(107,142,35) |
|||
orange = 0xFFA500, // rgb(255,165,0) |
|||
orange_red = 0xFF4500, // rgb(255,69,0) |
|||
orchid = 0xDA70D6, // rgb(218,112,214) |
|||
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) |
|||
pale_green = 0x98FB98, // rgb(152,251,152) |
|||
pale_turquoise = 0xAFEEEE, // rgb(175,238,238) |
|||
pale_violet_red = 0xDB7093, // rgb(219,112,147) |
|||
papaya_whip = 0xFFEFD5, // rgb(255,239,213) |
|||
peach_puff = 0xFFDAB9, // rgb(255,218,185) |
|||
peru = 0xCD853F, // rgb(205,133,63) |
|||
pink = 0xFFC0CB, // rgb(255,192,203) |
|||
plum = 0xDDA0DD, // rgb(221,160,221) |
|||
powder_blue = 0xB0E0E6, // rgb(176,224,230) |
|||
purple = 0x800080, // rgb(128,0,128) |
|||
rebecca_purple = 0x663399, // rgb(102,51,153) |
|||
red = 0xFF0000, // rgb(255,0,0) |
|||
rosy_brown = 0xBC8F8F, // rgb(188,143,143) |
|||
royal_blue = 0x4169E1, // rgb(65,105,225) |
|||
saddle_brown = 0x8B4513, // rgb(139,69,19) |
|||
salmon = 0xFA8072, // rgb(250,128,114) |
|||
sandy_brown = 0xF4A460, // rgb(244,164,96) |
|||
sea_green = 0x2E8B57, // rgb(46,139,87) |
|||
sea_shell = 0xFFF5EE, // rgb(255,245,238) |
|||
sienna = 0xA0522D, // rgb(160,82,45) |
|||
silver = 0xC0C0C0, // rgb(192,192,192) |
|||
sky_blue = 0x87CEEB, // rgb(135,206,235) |
|||
slate_blue = 0x6A5ACD, // rgb(106,90,205) |
|||
slate_gray = 0x708090, // rgb(112,128,144) |
|||
snow = 0xFFFAFA, // rgb(255,250,250) |
|||
spring_green = 0x00FF7F, // rgb(0,255,127) |
|||
steel_blue = 0x4682B4, // rgb(70,130,180) |
|||
tan = 0xD2B48C, // rgb(210,180,140) |
|||
teal = 0x008080, // rgb(0,128,128) |
|||
thistle = 0xD8BFD8, // rgb(216,191,216) |
|||
tomato = 0xFF6347, // rgb(255,99,71) |
|||
turquoise = 0x40E0D0, // rgb(64,224,208) |
|||
violet = 0xEE82EE, // rgb(238,130,238) |
|||
wheat = 0xF5DEB3, // rgb(245,222,179) |
|||
white = 0xFFFFFF, // rgb(255,255,255) |
|||
white_smoke = 0xF5F5F5, // rgb(245,245,245) |
|||
yellow = 0xFFFF00, // rgb(255,255,0) |
|||
yellow_green = 0x9ACD32 // rgb(154,205,50) |
|||
}; // enum class color |
|||
|
|||
enum class terminal_color : uint8_t { |
|||
black = 30, |
|||
red, |
|||
green, |
|||
yellow, |
|||
blue, |
|||
magenta, |
|||
cyan, |
|||
white, |
|||
bright_black = 90, |
|||
bright_red, |
|||
bright_green, |
|||
bright_yellow, |
|||
bright_blue, |
|||
bright_magenta, |
|||
bright_cyan, |
|||
bright_white |
|||
}; |
|||
|
|||
enum class emphasis : uint8_t { |
|||
bold = 1, |
|||
faint = 1 << 1, |
|||
italic = 1 << 2, |
|||
underline = 1 << 3, |
|||
blink = 1 << 4, |
|||
reverse = 1 << 5, |
|||
conceal = 1 << 6, |
|||
strikethrough = 1 << 7, |
|||
}; |
|||
|
|||
// rgb is a struct for red, green and blue colors. |
|||
// Using the name "rgb" makes some editors show the color in a tooltip. |
|||
struct rgb { |
|||
FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} |
|||
FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} |
|||
FMT_CONSTEXPR rgb(uint32_t hex) |
|||
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} |
|||
FMT_CONSTEXPR rgb(color hex) |
|||
: r((uint32_t(hex) >> 16) & 0xFF), |
|||
g((uint32_t(hex) >> 8) & 0xFF), |
|||
b(uint32_t(hex) & 0xFF) {} |
|||
uint8_t r; |
|||
uint8_t g; |
|||
uint8_t b; |
|||
}; |
|||
|
|||
FMT_BEGIN_DETAIL_NAMESPACE |
|||
|
|||
// color is a struct of either a rgb color or a terminal color. |
|||
struct color_type { |
|||
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} |
|||
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { |
|||
value.rgb_color = static_cast<uint32_t>(rgb_color); |
|||
} |
|||
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} { |
|||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) | |
|||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b; |
|||
} |
|||
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept |
|||
: is_rgb(), value{} { |
|||
value.term_color = static_cast<uint8_t>(term_color); |
|||
} |
|||
bool is_rgb; |
|||
union color_union { |
|||
uint8_t term_color; |
|||
uint32_t rgb_color; |
|||
} value; |
|||
}; |
|||
|
|||
FMT_END_DETAIL_NAMESPACE |
|||
|
|||
/** A text style consisting of foreground and background colors and emphasis. */ |
|||
class text_style { |
|||
public: |
|||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept |
|||
: set_foreground_color(), set_background_color(), ems(em) {} |
|||
|
|||
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { |
|||
if (!set_foreground_color) { |
|||
set_foreground_color = rhs.set_foreground_color; |
|||
foreground_color = rhs.foreground_color; |
|||
} else if (rhs.set_foreground_color) { |
|||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) |
|||
FMT_THROW(format_error("can't OR a terminal color")); |
|||
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; |
|||
} |
|||
|
|||
if (!set_background_color) { |
|||
set_background_color = rhs.set_background_color; |
|||
background_color = rhs.background_color; |
|||
} else if (rhs.set_background_color) { |
|||
if (!background_color.is_rgb || !rhs.background_color.is_rgb) |
|||
FMT_THROW(format_error("can't OR a terminal color")); |
|||
background_color.value.rgb_color |= rhs.background_color.value.rgb_color; |
|||
} |
|||
|
|||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) | |
|||
static_cast<uint8_t>(rhs.ems)); |
|||
return *this; |
|||
} |
|||
|
|||
friend FMT_CONSTEXPR text_style operator|(text_style lhs, |
|||
const text_style& rhs) { |
|||
return lhs |= rhs; |
|||
} |
|||
|
|||
FMT_CONSTEXPR bool has_foreground() const noexcept { |
|||
return set_foreground_color; |
|||
} |
|||
FMT_CONSTEXPR bool has_background() const noexcept { |
|||
return set_background_color; |
|||
} |
|||
FMT_CONSTEXPR bool has_emphasis() const noexcept { |
|||
return static_cast<uint8_t>(ems) != 0; |
|||
} |
|||
FMT_CONSTEXPR detail::color_type get_foreground() const noexcept { |
|||
FMT_ASSERT(has_foreground(), "no foreground specified for this style"); |
|||
return foreground_color; |
|||
} |
|||
FMT_CONSTEXPR detail::color_type get_background() const noexcept { |
|||
FMT_ASSERT(has_background(), "no background specified for this style"); |
|||
return background_color; |
|||
} |
|||
FMT_CONSTEXPR emphasis get_emphasis() const noexcept { |
|||
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); |
|||
return ems; |
|||
} |
|||
|
|||
private: |
|||
FMT_CONSTEXPR text_style(bool is_foreground, |
|||
detail::color_type text_color) noexcept |
|||
: set_foreground_color(), set_background_color(), ems() { |
|||
if (is_foreground) { |
|||
foreground_color = text_color; |
|||
set_foreground_color = true; |
|||
} else { |
|||
background_color = text_color; |
|||
set_background_color = true; |
|||
} |
|||
} |
|||
|
|||
friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept; |
|||
|
|||
friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept; |
|||
|
|||
detail::color_type foreground_color; |
|||
detail::color_type background_color; |
|||
bool set_foreground_color; |
|||
bool set_background_color; |
|||
emphasis ems; |
|||
}; |
|||
|
|||
/** Creates a text style from the foreground (text) color. */ |
|||
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept { |
|||
return text_style(true, foreground); |
|||
} |
|||
|
|||
/** Creates a text style from the background color. */ |
|||
FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept { |
|||
return text_style(false, background); |
|||
} |
|||
|
|||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept { |
|||
return text_style(lhs) | rhs; |
|||
} |
|||
|
|||
FMT_BEGIN_DETAIL_NAMESPACE |
|||
|
|||
template <typename Char> struct ansi_color_escape { |
|||
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, |
|||
const char* esc) noexcept { |
|||
// If we have a terminal color, we need to output another escape code |
|||
// sequence. |
|||
if (!text_color.is_rgb) { |
|||
bool is_background = esc == string_view("\x1b[48;2;"); |
|||
uint32_t value = text_color.value.term_color; |
|||
// Background ASCII codes are the same as the foreground ones but with |
|||
// 10 more. |
|||
if (is_background) value += 10u; |
|||
|
|||
size_t index = 0; |
|||
buffer[index++] = static_cast<Char>('\x1b'); |
|||
buffer[index++] = static_cast<Char>('['); |
|||
|
|||
if (value >= 100u) { |
|||
buffer[index++] = static_cast<Char>('1'); |
|||
value %= 100u; |
|||
} |
|||
buffer[index++] = static_cast<Char>('0' + value / 10u); |
|||
buffer[index++] = static_cast<Char>('0' + value % 10u); |
|||
|
|||
buffer[index++] = static_cast<Char>('m'); |
|||
buffer[index++] = static_cast<Char>('\0'); |
|||
return; |
|||
} |
|||
|
|||
for (int i = 0; i < 7; i++) { |
|||
buffer[i] = static_cast<Char>(esc[i]); |
|||
} |
|||
rgb color(text_color.value.rgb_color); |
|||
to_esc(color.r, buffer + 7, ';'); |
|||
to_esc(color.g, buffer + 11, ';'); |
|||
to_esc(color.b, buffer + 15, 'm'); |
|||
buffer[19] = static_cast<Char>(0); |
|||
} |
|||
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept { |
|||
uint8_t em_codes[num_emphases] = {}; |
|||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; |
|||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; |
|||
if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; |
|||
if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; |
|||
if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; |
|||
if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; |
|||
if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; |
|||
if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; |
|||
|
|||
size_t index = 0; |
|||
for (size_t i = 0; i < num_emphases; ++i) { |
|||
if (!em_codes[i]) continue; |
|||
buffer[index++] = static_cast<Char>('\x1b'); |
|||
buffer[index++] = static_cast<Char>('['); |
|||
buffer[index++] = static_cast<Char>('0' + em_codes[i]); |
|||
buffer[index++] = static_cast<Char>('m'); |
|||
} |
|||
buffer[index++] = static_cast<Char>(0); |
|||
} |
|||
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } |
|||
|
|||
FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; } |
|||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept { |
|||
return buffer + std::char_traits<Char>::length(buffer); |
|||
} |
|||
|
|||
private: |
|||
static constexpr size_t num_emphases = 8; |
|||
Char buffer[7u + 3u * num_emphases + 1u]; |
|||
|
|||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, |
|||
char delimiter) noexcept { |
|||
out[0] = static_cast<Char>('0' + c / 100); |
|||
out[1] = static_cast<Char>('0' + c / 10 % 10); |
|||
out[2] = static_cast<Char>('0' + c % 10); |
|||
out[3] = static_cast<Char>(delimiter); |
|||
} |
|||
static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept { |
|||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask); |
|||
} |
|||
}; |
|||
|
|||
template <typename Char> |
|||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color( |
|||
detail::color_type foreground) noexcept { |
|||
return ansi_color_escape<Char>(foreground, "\x1b[38;2;"); |
|||
} |
|||
|
|||
template <typename Char> |
|||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color( |
|||
detail::color_type background) noexcept { |
|||
return ansi_color_escape<Char>(background, "\x1b[48;2;"); |
|||
} |
|||
|
|||
template <typename Char> |
|||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept { |
|||
return ansi_color_escape<Char>(em); |
|||
} |
|||
|
|||
template <typename Char> inline void fputs(const Char* chars, FILE* stream) { |
|||
int result = std::fputs(chars, stream); |
|||
if (result < 0) |
|||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); |
|||
} |
|||
|
|||
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) { |
|||
int result = std::fputws(chars, stream); |
|||
if (result < 0) |
|||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); |
|||
} |
|||
|
|||
template <typename Char> inline void reset_color(FILE* stream) { |
|||
fputs("\x1b[0m", stream); |
|||
} |
|||
|
|||
template <> inline void reset_color<wchar_t>(FILE* stream) { |
|||
fputs(L"\x1b[0m", stream); |
|||
} |
|||
|
|||
template <typename Char> inline void reset_color(buffer<Char>& buffer) { |
|||
auto reset_color = string_view("\x1b[0m"); |
|||
buffer.append(reset_color.begin(), reset_color.end()); |
|||
} |
|||
|
|||
template <typename T> struct styled_arg { |
|||
const T& value; |
|||
text_style style; |
|||
}; |
|||
|
|||
template <typename Char> |
|||
void vformat_to(buffer<Char>& buf, const text_style& ts, |
|||
basic_string_view<Char> format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) { |
|||
bool has_style = false; |
|||
if (ts.has_emphasis()) { |
|||
has_style = true; |
|||
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis()); |
|||
buf.append(emphasis.begin(), emphasis.end()); |
|||
} |
|||
if (ts.has_foreground()) { |
|||
has_style = true; |
|||
auto foreground = detail::make_foreground_color<Char>(ts.get_foreground()); |
|||
buf.append(foreground.begin(), foreground.end()); |
|||
} |
|||
if (ts.has_background()) { |
|||
has_style = true; |
|||
auto background = detail::make_background_color<Char>(ts.get_background()); |
|||
buf.append(background.begin(), background.end()); |
|||
} |
|||
detail::vformat_to(buf, format_str, args, {}); |
|||
if (has_style) detail::reset_color<Char>(buf); |
|||
} |
|||
|
|||
FMT_END_DETAIL_NAMESPACE |
|||
|
|||
template <typename S, typename Char = char_t<S>> |
|||
void vprint(std::FILE* f, const text_style& ts, const S& format, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) { |
|||
basic_memory_buffer<Char> buf; |
|||
detail::vformat_to(buf, ts, detail::to_string_view(format), args); |
|||
if (detail::is_utf8()) { |
|||
detail::print(f, basic_string_view<Char>(buf.begin(), buf.size())); |
|||
} else { |
|||
buf.push_back(Char(0)); |
|||
detail::fputs(buf.data(), f); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Formats a string and prints it to the specified file stream using ANSI |
|||
escape sequences to specify text formatting. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red), |
|||
"Elapsed time: {0:.2f} seconds", 1.23); |
|||
\endrst |
|||
*/ |
|||
template <typename S, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_string<S>::value)> |
|||
void print(std::FILE* f, const text_style& ts, const S& format_str, |
|||
const Args&... args) { |
|||
vprint(f, ts, format_str, |
|||
fmt::make_format_args<buffer_context<char_t<S>>>(args...)); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Formats a string and prints it to stdout using ANSI escape sequences to |
|||
specify text formatting. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red), |
|||
"Elapsed time: {0:.2f} seconds", 1.23); |
|||
\endrst |
|||
*/ |
|||
template <typename S, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_string<S>::value)> |
|||
void print(const text_style& ts, const S& format_str, const Args&... args) { |
|||
return print(stdout, ts, format_str, args...); |
|||
} |
|||
|
|||
template <typename S, typename Char = char_t<S>> |
|||
inline std::basic_string<Char> vformat( |
|||
const text_style& ts, const S& format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) { |
|||
basic_memory_buffer<Char> buf; |
|||
detail::vformat_to(buf, ts, detail::to_string_view(format_str), args); |
|||
return fmt::to_string(buf); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Formats arguments and returns the result as a string using ANSI |
|||
escape sequences to specify text formatting. |
|||
|
|||
**Example**:: |
|||
|
|||
#include <fmt/color.h> |
|||
std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), |
|||
"The answer is {}", 42); |
|||
\endrst |
|||
*/ |
|||
template <typename S, typename... Args, typename Char = char_t<S>> |
|||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str, |
|||
const Args&... args) { |
|||
return fmt::vformat(ts, detail::to_string_view(format_str), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
/** |
|||
Formats a string with the given text_style and writes the output to ``out``. |
|||
*/ |
|||
template <typename OutputIt, typename Char, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)> |
|||
OutputIt vformat_to( |
|||
OutputIt out, const text_style& ts, basic_string_view<Char> format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) { |
|||
auto&& buf = detail::get_buffer<Char>(out); |
|||
detail::vformat_to(buf, ts, format_str, args); |
|||
return detail::get_iterator(buf); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Formats arguments with the given text_style, writes the result to the output |
|||
iterator ``out`` and returns the iterator past the end of the output range. |
|||
|
|||
**Example**:: |
|||
|
|||
std::vector<char> out; |
|||
fmt::format_to(std::back_inserter(out), |
|||
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); |
|||
\endrst |
|||
*/ |
|||
template <typename OutputIt, typename S, typename... Args, |
|||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&& |
|||
detail::is_string<S>::value> |
|||
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, |
|||
Args&&... args) -> |
|||
typename std::enable_if<enable, OutputIt>::type { |
|||
return vformat_to(out, ts, detail::to_string_view(format_str), |
|||
fmt::make_format_args<buffer_context<char_t<S>>>(args...)); |
|||
} |
|||
|
|||
template <typename T, typename Char> |
|||
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> { |
|||
template <typename FormatContext> |
|||
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
const auto& ts = arg.style; |
|||
const auto& value = arg.value; |
|||
auto out = ctx.out(); |
|||
|
|||
bool has_style = false; |
|||
if (ts.has_emphasis()) { |
|||
has_style = true; |
|||
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis()); |
|||
out = std::copy(emphasis.begin(), emphasis.end(), out); |
|||
} |
|||
if (ts.has_foreground()) { |
|||
has_style = true; |
|||
auto foreground = |
|||
detail::make_foreground_color<Char>(ts.get_foreground()); |
|||
out = std::copy(foreground.begin(), foreground.end(), out); |
|||
} |
|||
if (ts.has_background()) { |
|||
has_style = true; |
|||
auto background = |
|||
detail::make_background_color<Char>(ts.get_background()); |
|||
out = std::copy(background.begin(), background.end(), out); |
|||
} |
|||
out = formatter<T, Char>::format(value, ctx); |
|||
if (has_style) { |
|||
auto reset_color = string_view("\x1b[0m"); |
|||
out = std::copy(reset_color.begin(), reset_color.end(), out); |
|||
} |
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
\rst |
|||
Returns an argument that will be formatted using ANSI escape sequences, |
|||
to be used in a formatting function. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::print("Elapsed time: {0:.2f} seconds", |
|||
fmt::styled(1.23, fmt::fg(fmt::color::green) | |
|||
fmt::bg(fmt::color::blue))); |
|||
\endrst |
|||
*/ |
|||
template <typename T> |
|||
FMT_CONSTEXPR auto styled(const T& value, text_style ts) |
|||
-> detail::styled_arg<remove_cvref_t<T>> { |
|||
return detail::styled_arg<remove_cvref_t<T>>{value, ts}; |
|||
} |
|||
|
|||
FMT_MODULE_EXPORT_END |
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_COLOR_H_ |
@ -1,611 +0,0 @@ |
|||
// Formatting library for C++ - experimental format string compilation |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_COMPILE_H_ |
|||
#define FMT_COMPILE_H_ |
|||
|
|||
#include "format.h" |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
template <typename Char, typename InputIt> |
|||
FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end, |
|||
counting_iterator it) { |
|||
return it + (end - begin); |
|||
} |
|||
|
|||
template <typename OutputIt> class truncating_iterator_base { |
|||
protected: |
|||
OutputIt out_; |
|||
size_t limit_; |
|||
size_t count_ = 0; |
|||
|
|||
truncating_iterator_base() : out_(), limit_(0) {} |
|||
|
|||
truncating_iterator_base(OutputIt out, size_t limit) |
|||
: out_(out), limit_(limit) {} |
|||
|
|||
public: |
|||
using iterator_category = std::output_iterator_tag; |
|||
using value_type = typename std::iterator_traits<OutputIt>::value_type; |
|||
using difference_type = std::ptrdiff_t; |
|||
using pointer = void; |
|||
using reference = void; |
|||
FMT_UNCHECKED_ITERATOR(truncating_iterator_base); |
|||
|
|||
OutputIt base() const { return out_; } |
|||
size_t count() const { return count_; } |
|||
}; |
|||
|
|||
// An output iterator that truncates the output and counts the number of objects |
|||
// written to it. |
|||
template <typename OutputIt, |
|||
typename Enable = typename std::is_void< |
|||
typename std::iterator_traits<OutputIt>::value_type>::type> |
|||
class truncating_iterator; |
|||
|
|||
template <typename OutputIt> |
|||
class truncating_iterator<OutputIt, std::false_type> |
|||
: public truncating_iterator_base<OutputIt> { |
|||
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_; |
|||
|
|||
public: |
|||
using value_type = typename truncating_iterator_base<OutputIt>::value_type; |
|||
|
|||
truncating_iterator() = default; |
|||
|
|||
truncating_iterator(OutputIt out, size_t limit) |
|||
: truncating_iterator_base<OutputIt>(out, limit) {} |
|||
|
|||
truncating_iterator& operator++() { |
|||
if (this->count_++ < this->limit_) ++this->out_; |
|||
return *this; |
|||
} |
|||
|
|||
truncating_iterator operator++(int) { |
|||
auto it = *this; |
|||
++*this; |
|||
return it; |
|||
} |
|||
|
|||
value_type& operator*() const { |
|||
return this->count_ < this->limit_ ? *this->out_ : blackhole_; |
|||
} |
|||
}; |
|||
|
|||
template <typename OutputIt> |
|||
class truncating_iterator<OutputIt, std::true_type> |
|||
: public truncating_iterator_base<OutputIt> { |
|||
public: |
|||
truncating_iterator() = default; |
|||
|
|||
truncating_iterator(OutputIt out, size_t limit) |
|||
: truncating_iterator_base<OutputIt>(out, limit) {} |
|||
|
|||
template <typename T> truncating_iterator& operator=(T val) { |
|||
if (this->count_++ < this->limit_) *this->out_++ = val; |
|||
return *this; |
|||
} |
|||
|
|||
truncating_iterator& operator++() { return *this; } |
|||
truncating_iterator& operator++(int) { return *this; } |
|||
truncating_iterator& operator*() { return *this; } |
|||
}; |
|||
|
|||
// A compile-time string which is compiled into fast formatting code. |
|||
class compiled_string {}; |
|||
|
|||
template <typename S> |
|||
struct is_compiled_string : std::is_base_of<compiled_string, S> {}; |
|||
|
|||
/** |
|||
\rst |
|||
Converts a string literal *s* into a format string that will be parsed at |
|||
compile time and converted into efficient formatting code. Requires C++17 |
|||
``constexpr if`` compiler support. |
|||
|
|||
**Example**:: |
|||
|
|||
// Converts 42 into std::string using the most efficient method and no |
|||
// runtime format string processing. |
|||
std::string s = fmt::format(FMT_COMPILE("{}"), 42); |
|||
\endrst |
|||
*/ |
|||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) |
|||
# define FMT_COMPILE(s) \ |
|||
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) |
|||
#else |
|||
# define FMT_COMPILE(s) FMT_STRING(s) |
|||
#endif |
|||
|
|||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS |
|||
template <typename Char, size_t N, |
|||
fmt::detail_exported::fixed_string<Char, N> Str> |
|||
struct udl_compiled_string : compiled_string { |
|||
using char_type = Char; |
|||
explicit constexpr operator basic_string_view<char_type>() const { |
|||
return {Str.data, N - 1}; |
|||
} |
|||
}; |
|||
#endif |
|||
|
|||
template <typename T, typename... Tail> |
|||
const T& first(const T& value, const Tail&...) { |
|||
return value; |
|||
} |
|||
|
|||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) |
|||
template <typename... Args> struct type_list {}; |
|||
|
|||
// Returns a reference to the argument at index N from [first, rest...]. |
|||
template <int N, typename T, typename... Args> |
|||
constexpr const auto& get([[maybe_unused]] const T& first, |
|||
[[maybe_unused]] const Args&... rest) { |
|||
static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); |
|||
if constexpr (N == 0) |
|||
return first; |
|||
else |
|||
return detail::get<N - 1>(rest...); |
|||
} |
|||
|
|||
template <typename Char, typename... Args> |
|||
constexpr int get_arg_index_by_name(basic_string_view<Char> name, |
|||
type_list<Args...>) { |
|||
return get_arg_index_by_name<Args...>(name); |
|||
} |
|||
|
|||
template <int N, typename> struct get_type_impl; |
|||
|
|||
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> { |
|||
using type = |
|||
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>; |
|||
}; |
|||
|
|||
template <int N, typename T> |
|||
using get_type = typename get_type_impl<N, T>::type; |
|||
|
|||
template <typename T> struct is_compiled_format : std::false_type {}; |
|||
|
|||
template <typename Char> struct text { |
|||
basic_string_view<Char> data; |
|||
using char_type = Char; |
|||
|
|||
template <typename OutputIt, typename... Args> |
|||
constexpr OutputIt format(OutputIt out, const Args&...) const { |
|||
return write<Char>(out, data); |
|||
} |
|||
}; |
|||
|
|||
template <typename Char> |
|||
struct is_compiled_format<text<Char>> : std::true_type {}; |
|||
|
|||
template <typename Char> |
|||
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos, |
|||
size_t size) { |
|||
return {{&s[pos], size}}; |
|||
} |
|||
|
|||
template <typename Char> struct code_unit { |
|||
Char value; |
|||
using char_type = Char; |
|||
|
|||
template <typename OutputIt, typename... Args> |
|||
constexpr OutputIt format(OutputIt out, const Args&...) const { |
|||
return write<Char>(out, value); |
|||
} |
|||
}; |
|||
|
|||
// This ensures that the argument type is convertible to `const T&`. |
|||
template <typename T, int N, typename... Args> |
|||
constexpr const T& get_arg_checked(const Args&... args) { |
|||
const auto& arg = detail::get<N>(args...); |
|||
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) { |
|||
return arg.value; |
|||
} else { |
|||
return arg; |
|||
} |
|||
} |
|||
|
|||
template <typename Char> |
|||
struct is_compiled_format<code_unit<Char>> : std::true_type {}; |
|||
|
|||
// A replacement field that refers to argument N. |
|||
template <typename Char, typename T, int N> struct field { |
|||
using char_type = Char; |
|||
|
|||
template <typename OutputIt, typename... Args> |
|||
constexpr OutputIt format(OutputIt out, const Args&... args) const { |
|||
return write<Char>(out, get_arg_checked<T, N>(args...)); |
|||
} |
|||
}; |
|||
|
|||
template <typename Char, typename T, int N> |
|||
struct is_compiled_format<field<Char, T, N>> : std::true_type {}; |
|||
|
|||
// A replacement field that refers to argument with name. |
|||
template <typename Char> struct runtime_named_field { |
|||
using char_type = Char; |
|||
basic_string_view<Char> name; |
|||
|
|||
template <typename OutputIt, typename T> |
|||
constexpr static bool try_format_argument( |
|||
OutputIt& out, |
|||
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 |
|||
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) { |
|||
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) { |
|||
if (arg_name == arg.name) { |
|||
out = write<Char>(out, arg.value); |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
template <typename OutputIt, typename... Args> |
|||
constexpr OutputIt format(OutputIt out, const Args&... args) const { |
|||
bool found = (try_format_argument(out, name, args) || ...); |
|||
if (!found) { |
|||
FMT_THROW(format_error("argument with specified name is not found")); |
|||
} |
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
template <typename Char> |
|||
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {}; |
|||
|
|||
// A replacement field that refers to argument N and has format specifiers. |
|||
template <typename Char, typename T, int N> struct spec_field { |
|||
using char_type = Char; |
|||
formatter<T, Char> fmt; |
|||
|
|||
template <typename OutputIt, typename... Args> |
|||
constexpr FMT_INLINE OutputIt format(OutputIt out, |
|||
const Args&... args) const { |
|||
const auto& vargs = |
|||
fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...); |
|||
basic_format_context<OutputIt, Char> ctx(out, vargs); |
|||
return fmt.format(get_arg_checked<T, N>(args...), ctx); |
|||
} |
|||
}; |
|||
|
|||
template <typename Char, typename T, int N> |
|||
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {}; |
|||
|
|||
template <typename L, typename R> struct concat { |
|||
L lhs; |
|||
R rhs; |
|||
using char_type = typename L::char_type; |
|||
|
|||
template <typename OutputIt, typename... Args> |
|||
constexpr OutputIt format(OutputIt out, const Args&... args) const { |
|||
out = lhs.format(out, args...); |
|||
return rhs.format(out, args...); |
|||
} |
|||
}; |
|||
|
|||
template <typename L, typename R> |
|||
struct is_compiled_format<concat<L, R>> : std::true_type {}; |
|||
|
|||
template <typename L, typename R> |
|||
constexpr concat<L, R> make_concat(L lhs, R rhs) { |
|||
return {lhs, rhs}; |
|||
} |
|||
|
|||
struct unknown_format {}; |
|||
|
|||
template <typename Char> |
|||
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) { |
|||
for (size_t size = str.size(); pos != size; ++pos) { |
|||
if (str[pos] == '{' || str[pos] == '}') break; |
|||
} |
|||
return pos; |
|||
} |
|||
|
|||
template <typename Args, size_t POS, int ID, typename S> |
|||
constexpr auto compile_format_string(S format_str); |
|||
|
|||
template <typename Args, size_t POS, int ID, typename T, typename S> |
|||
constexpr auto parse_tail(T head, S format_str) { |
|||
if constexpr (POS != |
|||
basic_string_view<typename S::char_type>(format_str).size()) { |
|||
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str); |
|||
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>, |
|||
unknown_format>()) |
|||
return tail; |
|||
else |
|||
return make_concat(head, tail); |
|||
} else { |
|||
return head; |
|||
} |
|||
} |
|||
|
|||
template <typename T, typename Char> struct parse_specs_result { |
|||
formatter<T, Char> fmt; |
|||
size_t end; |
|||
int next_arg_id; |
|||
}; |
|||
|
|||
constexpr int manual_indexing_id = -1; |
|||
|
|||
template <typename T, typename Char> |
|||
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str, |
|||
size_t pos, int next_arg_id) { |
|||
str.remove_prefix(pos); |
|||
auto ctx = compile_parse_context<Char>(str, max_value<int>(), nullptr, {}, |
|||
next_arg_id); |
|||
auto f = formatter<T, Char>(); |
|||
auto end = f.parse(ctx); |
|||
return {f, pos + fmt::detail::to_unsigned(end - str.data()), |
|||
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; |
|||
} |
|||
|
|||
template <typename Char> struct arg_id_handler { |
|||
arg_ref<Char> arg_id; |
|||
|
|||
constexpr int operator()() { |
|||
FMT_ASSERT(false, "handler cannot be used with automatic indexing"); |
|||
return 0; |
|||
} |
|||
constexpr int operator()(int id) { |
|||
arg_id = arg_ref<Char>(id); |
|||
return 0; |
|||
} |
|||
constexpr int operator()(basic_string_view<Char> id) { |
|||
arg_id = arg_ref<Char>(id); |
|||
return 0; |
|||
} |
|||
|
|||
constexpr void on_error(const char* message) { |
|||
FMT_THROW(format_error(message)); |
|||
} |
|||
}; |
|||
|
|||
template <typename Char> struct parse_arg_id_result { |
|||
arg_ref<Char> arg_id; |
|||
const Char* arg_id_end; |
|||
}; |
|||
|
|||
template <int ID, typename Char> |
|||
constexpr auto parse_arg_id(const Char* begin, const Char* end) { |
|||
auto handler = arg_id_handler<Char>{arg_ref<Char>{}}; |
|||
auto arg_id_end = parse_arg_id(begin, end, handler); |
|||
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end}; |
|||
} |
|||
|
|||
template <typename T, typename Enable = void> struct field_type { |
|||
using type = remove_cvref_t<T>; |
|||
}; |
|||
|
|||
template <typename T> |
|||
struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> { |
|||
using type = remove_cvref_t<decltype(T::value)>; |
|||
}; |
|||
|
|||
template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID, |
|||
typename S> |
|||
constexpr auto parse_replacement_field_then_tail(S format_str) { |
|||
using char_type = typename S::char_type; |
|||
constexpr auto str = basic_string_view<char_type>(format_str); |
|||
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); |
|||
if constexpr (c == '}') { |
|||
return parse_tail<Args, END_POS + 1, NEXT_ID>( |
|||
field<char_type, typename field_type<T>::type, ARG_INDEX>(), |
|||
format_str); |
|||
} else if constexpr (c != ':') { |
|||
FMT_THROW(format_error("expected ':'")); |
|||
} else { |
|||
constexpr auto result = parse_specs<typename field_type<T>::type>( |
|||
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); |
|||
if constexpr (result.end >= str.size() || str[result.end] != '}') { |
|||
FMT_THROW(format_error("expected '}'")); |
|||
return 0; |
|||
} else { |
|||
return parse_tail<Args, result.end + 1, result.next_arg_id>( |
|||
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{ |
|||
result.fmt}, |
|||
format_str); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Compiles a non-empty format string and returns the compiled representation |
|||
// or unknown_format() on unrecognized input. |
|||
template <typename Args, size_t POS, int ID, typename S> |
|||
constexpr auto compile_format_string(S format_str) { |
|||
using char_type = typename S::char_type; |
|||
constexpr auto str = basic_string_view<char_type>(format_str); |
|||
if constexpr (str[POS] == '{') { |
|||
if constexpr (POS + 1 == str.size()) |
|||
FMT_THROW(format_error("unmatched '{' in format string")); |
|||
if constexpr (str[POS + 1] == '{') { |
|||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); |
|||
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { |
|||
static_assert(ID != manual_indexing_id, |
|||
"cannot switch from manual to automatic argument indexing"); |
|||
constexpr auto next_id = |
|||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id; |
|||
return parse_replacement_field_then_tail<get_type<ID, Args>, Args, |
|||
POS + 1, ID, next_id>( |
|||
format_str); |
|||
} else { |
|||
constexpr auto arg_id_result = |
|||
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size()); |
|||
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); |
|||
constexpr char_type c = |
|||
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); |
|||
static_assert(c == '}' || c == ':', "missing '}' in format string"); |
|||
if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { |
|||
static_assert( |
|||
ID == manual_indexing_id || ID == 0, |
|||
"cannot switch from automatic to manual argument indexing"); |
|||
constexpr auto arg_index = arg_id_result.arg_id.val.index; |
|||
return parse_replacement_field_then_tail<get_type<arg_index, Args>, |
|||
Args, arg_id_end_pos, |
|||
arg_index, manual_indexing_id>( |
|||
format_str); |
|||
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { |
|||
constexpr auto arg_index = |
|||
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); |
|||
if constexpr (arg_index != invalid_arg_index) { |
|||
constexpr auto next_id = |
|||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id; |
|||
return parse_replacement_field_then_tail< |
|||
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos, |
|||
arg_index, next_id>(format_str); |
|||
} else { |
|||
if constexpr (c == '}') { |
|||
return parse_tail<Args, arg_id_end_pos + 1, ID>( |
|||
runtime_named_field<char_type>{arg_id_result.arg_id.val.name}, |
|||
format_str); |
|||
} else if constexpr (c == ':') { |
|||
return unknown_format(); // no type info for specs parsing |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} else if constexpr (str[POS] == '}') { |
|||
if constexpr (POS + 1 == str.size()) |
|||
FMT_THROW(format_error("unmatched '}' in format string")); |
|||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); |
|||
} else { |
|||
constexpr auto end = parse_text(str, POS + 1); |
|||
if constexpr (end - POS > 1) { |
|||
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS), |
|||
format_str); |
|||
} else { |
|||
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, |
|||
format_str); |
|||
} |
|||
} |
|||
} |
|||
|
|||
template <typename... Args, typename S, |
|||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> |
|||
constexpr auto compile(S format_str) { |
|||
constexpr auto str = basic_string_view<typename S::char_type>(format_str); |
|||
if constexpr (str.size() == 0) { |
|||
return detail::make_text(str, 0, 0); |
|||
} else { |
|||
constexpr auto result = |
|||
detail::compile_format_string<detail::type_list<Args...>, 0, 0>( |
|||
format_str); |
|||
return result; |
|||
} |
|||
} |
|||
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) |
|||
} // namespace detail |
|||
|
|||
FMT_MODULE_EXPORT_BEGIN |
|||
|
|||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) |
|||
|
|||
template <typename CompiledFormat, typename... Args, |
|||
typename Char = typename CompiledFormat::char_type, |
|||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> |
|||
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf, |
|||
const Args&... args) { |
|||
auto s = std::basic_string<Char>(); |
|||
cf.format(std::back_inserter(s), args...); |
|||
return s; |
|||
} |
|||
|
|||
template <typename OutputIt, typename CompiledFormat, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> |
|||
constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, |
|||
const Args&... args) { |
|||
return cf.format(out, args...); |
|||
} |
|||
|
|||
template <typename S, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> |
|||
FMT_INLINE std::basic_string<typename S::char_type> format(const S&, |
|||
Args&&... args) { |
|||
if constexpr (std::is_same<typename S::char_type, char>::value) { |
|||
constexpr auto str = basic_string_view<typename S::char_type>(S()); |
|||
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { |
|||
const auto& first = detail::first(args...); |
|||
if constexpr (detail::is_named_arg< |
|||
remove_cvref_t<decltype(first)>>::value) { |
|||
return fmt::to_string(first.value); |
|||
} else { |
|||
return fmt::to_string(first); |
|||
} |
|||
} |
|||
} |
|||
constexpr auto compiled = detail::compile<Args...>(S()); |
|||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>, |
|||
detail::unknown_format>()) { |
|||
return fmt::format( |
|||
static_cast<basic_string_view<typename S::char_type>>(S()), |
|||
std::forward<Args>(args)...); |
|||
} else { |
|||
return fmt::format(compiled, std::forward<Args>(args)...); |
|||
} |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> |
|||
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { |
|||
constexpr auto compiled = detail::compile<Args...>(S()); |
|||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>, |
|||
detail::unknown_format>()) { |
|||
return fmt::format_to( |
|||
out, static_cast<basic_string_view<typename S::char_type>>(S()), |
|||
std::forward<Args>(args)...); |
|||
} else { |
|||
return fmt::format_to(out, compiled, std::forward<Args>(args)...); |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
template <typename OutputIt, typename S, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> |
|||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, |
|||
const S& format_str, Args&&... args) { |
|||
auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n), |
|||
format_str, std::forward<Args>(args)...); |
|||
return {it.base(), it.count()}; |
|||
} |
|||
|
|||
template <typename S, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> |
|||
FMT_CONSTEXPR20 size_t formatted_size(const S& format_str, |
|||
const Args&... args) { |
|||
return fmt::format_to(detail::counting_iterator(), format_str, args...) |
|||
.count(); |
|||
} |
|||
|
|||
template <typename S, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> |
|||
void print(std::FILE* f, const S& format_str, const Args&... args) { |
|||
memory_buffer buffer; |
|||
fmt::format_to(std::back_inserter(buffer), format_str, args...); |
|||
detail::print(f, {buffer.data(), buffer.size()}); |
|||
} |
|||
|
|||
template <typename S, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> |
|||
void print(const S& format_str, const Args&... args) { |
|||
print(stdout, format_str, args...); |
|||
} |
|||
|
|||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS |
|||
inline namespace literals { |
|||
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() { |
|||
using char_t = remove_cvref_t<decltype(Str.data[0])>; |
|||
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t), |
|||
Str>(); |
|||
} |
|||
} // namespace literals |
|||
#endif |
|||
|
|||
FMT_MODULE_EXPORT_END |
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_COMPILE_H_ |
3323
libfuse/lib/fmt/core.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1723
libfuse/lib/fmt/format-inl.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
4217
libfuse/lib/fmt/format.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,478 +0,0 @@ |
|||
// Formatting library for C++ - optional OS-specific functionality |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_OS_H_ |
|||
#define FMT_OS_H_ |
|||
|
|||
#include <cerrno> |
|||
#include <cstddef> |
|||
#include <cstdio> |
|||
#include <system_error> // std::system_error |
|||
|
|||
#if defined __APPLE__ || defined(__FreeBSD__) |
|||
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X |
|||
#endif |
|||
|
|||
#include "format.h" |
|||
|
|||
#ifndef FMT_USE_FCNTL |
|||
// UWP doesn't provide _pipe. |
|||
# if FMT_HAS_INCLUDE("winapifamily.h") |
|||
# include <winapifamily.h> |
|||
# endif |
|||
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \ |
|||
defined(__linux__)) && \ |
|||
(!defined(WINAPI_FAMILY) || \ |
|||
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) |
|||
# include <fcntl.h> // for O_RDONLY |
|||
# define FMT_USE_FCNTL 1 |
|||
# else |
|||
# define FMT_USE_FCNTL 0 |
|||
# endif |
|||
#endif |
|||
|
|||
#ifndef FMT_POSIX |
|||
# if defined(_WIN32) && !defined(__MINGW32__) |
|||
// Fix warnings about deprecated symbols. |
|||
# define FMT_POSIX(call) _##call |
|||
# else |
|||
# define FMT_POSIX(call) call |
|||
# endif |
|||
#endif |
|||
|
|||
// Calls to system functions are wrapped in FMT_SYSTEM for testability. |
|||
#ifdef FMT_SYSTEM |
|||
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) |
|||
#else |
|||
# define FMT_SYSTEM(call) ::call |
|||
# ifdef _WIN32 |
|||
// Fix warnings about deprecated symbols. |
|||
# define FMT_POSIX_CALL(call) ::_##call |
|||
# else |
|||
# define FMT_POSIX_CALL(call) ::call |
|||
# endif |
|||
#endif |
|||
|
|||
// Retries the expression while it evaluates to error_result and errno |
|||
// equals to EINTR. |
|||
#ifndef _WIN32 |
|||
# define FMT_RETRY_VAL(result, expression, error_result) \ |
|||
do { \ |
|||
(result) = (expression); \ |
|||
} while ((result) == (error_result) && errno == EINTR) |
|||
#else |
|||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) |
|||
#endif |
|||
|
|||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
FMT_MODULE_EXPORT_BEGIN |
|||
|
|||
/** |
|||
\rst |
|||
A reference to a null-terminated string. It can be constructed from a C |
|||
string or ``std::string``. |
|||
|
|||
You can use one of the following type aliases for common character types: |
|||
|
|||
+---------------+-----------------------------+ |
|||
| Type | Definition | |
|||
+===============+=============================+ |
|||
| cstring_view | basic_cstring_view<char> | |
|||
+---------------+-----------------------------+ |
|||
| wcstring_view | basic_cstring_view<wchar_t> | |
|||
+---------------+-----------------------------+ |
|||
|
|||
This class is most useful as a parameter type to allow passing |
|||
different types of strings to a function, for example:: |
|||
|
|||
template <typename... Args> |
|||
std::string format(cstring_view format_str, const Args & ... args); |
|||
|
|||
format("{}", 42); |
|||
format(std::string("{}"), 42); |
|||
\endrst |
|||
*/ |
|||
template <typename Char> class basic_cstring_view { |
|||
private: |
|||
const Char* data_; |
|||
|
|||
public: |
|||
/** Constructs a string reference object from a C string. */ |
|||
basic_cstring_view(const Char* s) : data_(s) {} |
|||
|
|||
/** |
|||
\rst |
|||
Constructs a string reference from an ``std::string`` object. |
|||
\endrst |
|||
*/ |
|||
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {} |
|||
|
|||
/** Returns the pointer to a C string. */ |
|||
const Char* c_str() const { return data_; } |
|||
}; |
|||
|
|||
using cstring_view = basic_cstring_view<char>; |
|||
using wcstring_view = basic_cstring_view<wchar_t>; |
|||
|
|||
template <typename Char> struct formatter<std::error_code, Char> { |
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
out = detail::write_bytes(out, ec.category().name(), |
|||
basic_format_specs<Char>()); |
|||
out = detail::write<Char>(out, Char(':')); |
|||
out = detail::write<Char>(out, ec.value()); |
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
#ifdef _WIN32 |
|||
FMT_API const std::error_category& system_category() noexcept; |
|||
|
|||
FMT_BEGIN_DETAIL_NAMESPACE |
|||
// A converter from UTF-16 to UTF-8. |
|||
// It is only provided for Windows since other systems support UTF-8 natively. |
|||
class utf16_to_utf8 { |
|||
private: |
|||
memory_buffer buffer_; |
|||
|
|||
public: |
|||
utf16_to_utf8() {} |
|||
FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s); |
|||
operator string_view() const { return string_view(&buffer_[0], size()); } |
|||
size_t size() const { return buffer_.size() - 1; } |
|||
const char* c_str() const { return &buffer_[0]; } |
|||
std::string str() const { return std::string(&buffer_[0], size()); } |
|||
|
|||
// Performs conversion returning a system error code instead of |
|||
// throwing exception on conversion error. This method may still throw |
|||
// in case of memory allocation error. |
|||
FMT_API int convert(basic_string_view<wchar_t> s); |
|||
}; |
|||
|
|||
FMT_API void format_windows_error(buffer<char>& out, int error_code, |
|||
const char* message) noexcept; |
|||
FMT_END_DETAIL_NAMESPACE |
|||
|
|||
FMT_API std::system_error vwindows_error(int error_code, string_view format_str, |
|||
format_args args); |
|||
|
|||
/** |
|||
\rst |
|||
Constructs a :class:`std::system_error` object with the description |
|||
of the form |
|||
|
|||
.. parsed-literal:: |
|||
*<message>*: *<system-message>* |
|||
|
|||
where *<message>* is the formatted message and *<system-message>* is the |
|||
system message corresponding to the error code. |
|||
*error_code* is a Windows error code as given by ``GetLastError``. |
|||
If *error_code* is not a valid error code such as -1, the system message |
|||
will look like "error -1". |
|||
|
|||
**Example**:: |
|||
|
|||
// This throws a system_error with the description |
|||
// cannot open file 'madeup': The system cannot find the file specified. |
|||
// or similar (system message may vary). |
|||
const char *filename = "madeup"; |
|||
LPOFSTRUCT of = LPOFSTRUCT(); |
|||
HFILE file = OpenFile(filename, &of, OF_READ); |
|||
if (file == HFILE_ERROR) { |
|||
throw fmt::windows_error(GetLastError(), |
|||
"cannot open file '{}'", filename); |
|||
} |
|||
\endrst |
|||
*/ |
|||
template <typename... Args> |
|||
std::system_error windows_error(int error_code, string_view message, |
|||
const Args&... args) { |
|||
return vwindows_error(error_code, message, fmt::make_format_args(args...)); |
|||
} |
|||
|
|||
// Reports a Windows error without throwing an exception. |
|||
// Can be used to report errors from destructors. |
|||
FMT_API void report_windows_error(int error_code, const char* message) noexcept; |
|||
#else |
|||
inline const std::error_category& system_category() noexcept { |
|||
return std::system_category(); |
|||
} |
|||
#endif // _WIN32 |
|||
|
|||
// std::system is not available on some platforms such as iOS (#2248). |
|||
#ifdef __OSX__ |
|||
template <typename S, typename... Args, typename Char = char_t<S>> |
|||
void say(const S& format_str, Args&&... args) { |
|||
std::system(format("say \"{}\"", format(format_str, args...)).c_str()); |
|||
} |
|||
#endif |
|||
|
|||
// A buffered file. |
|||
class buffered_file { |
|||
private: |
|||
FILE* file_; |
|||
|
|||
friend class file; |
|||
|
|||
explicit buffered_file(FILE* f) : file_(f) {} |
|||
|
|||
public: |
|||
buffered_file(const buffered_file&) = delete; |
|||
void operator=(const buffered_file&) = delete; |
|||
|
|||
// Constructs a buffered_file object which doesn't represent any file. |
|||
buffered_file() noexcept : file_(nullptr) {} |
|||
|
|||
// Destroys the object closing the file it represents if any. |
|||
FMT_API ~buffered_file() noexcept; |
|||
|
|||
public: |
|||
buffered_file(buffered_file&& other) noexcept : file_(other.file_) { |
|||
other.file_ = nullptr; |
|||
} |
|||
|
|||
buffered_file& operator=(buffered_file&& other) { |
|||
close(); |
|||
file_ = other.file_; |
|||
other.file_ = nullptr; |
|||
return *this; |
|||
} |
|||
|
|||
// Opens a file. |
|||
FMT_API buffered_file(cstring_view filename, cstring_view mode); |
|||
|
|||
// Closes the file. |
|||
FMT_API void close(); |
|||
|
|||
// Returns the pointer to a FILE object representing this file. |
|||
FILE* get() const noexcept { return file_; } |
|||
|
|||
FMT_API int descriptor() const; |
|||
|
|||
void vprint(string_view format_str, format_args args) { |
|||
fmt::vprint(file_, format_str, args); |
|||
} |
|||
|
|||
template <typename... Args> |
|||
inline void print(string_view format_str, const Args&... args) { |
|||
vprint(format_str, fmt::make_format_args(args...)); |
|||
} |
|||
}; |
|||
|
|||
#if FMT_USE_FCNTL |
|||
// A file. Closed file is represented by a file object with descriptor -1. |
|||
// Methods that are not declared with noexcept may throw |
|||
// fmt::system_error in case of failure. Note that some errors such as |
|||
// closing the file multiple times will cause a crash on Windows rather |
|||
// than an exception. You can get standard behavior by overriding the |
|||
// invalid parameter handler with _set_invalid_parameter_handler. |
|||
class FMT_API file { |
|||
private: |
|||
int fd_; // File descriptor. |
|||
|
|||
// Constructs a file object with a given descriptor. |
|||
explicit file(int fd) : fd_(fd) {} |
|||
|
|||
public: |
|||
// Possible values for the oflag argument to the constructor. |
|||
enum { |
|||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. |
|||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. |
|||
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. |
|||
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. |
|||
APPEND = FMT_POSIX(O_APPEND), // Open in append mode. |
|||
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. |
|||
}; |
|||
|
|||
// Constructs a file object which doesn't represent any file. |
|||
file() noexcept : fd_(-1) {} |
|||
|
|||
// Opens a file and constructs a file object representing this file. |
|||
file(cstring_view path, int oflag); |
|||
|
|||
public: |
|||
file(const file&) = delete; |
|||
void operator=(const file&) = delete; |
|||
|
|||
file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } |
|||
|
|||
// Move assignment is not noexcept because close may throw. |
|||
file& operator=(file&& other) { |
|||
close(); |
|||
fd_ = other.fd_; |
|||
other.fd_ = -1; |
|||
return *this; |
|||
} |
|||
|
|||
// Destroys the object closing the file it represents if any. |
|||
~file() noexcept; |
|||
|
|||
// Returns the file descriptor. |
|||
int descriptor() const noexcept { return fd_; } |
|||
|
|||
// Closes the file. |
|||
void close(); |
|||
|
|||
// Returns the file size. The size has signed type for consistency with |
|||
// stat::st_size. |
|||
long long size() const; |
|||
|
|||
// Attempts to read count bytes from the file into the specified buffer. |
|||
size_t read(void* buffer, size_t count); |
|||
|
|||
// Attempts to write count bytes from the specified buffer to the file. |
|||
size_t write(const void* buffer, size_t count); |
|||
|
|||
// Duplicates a file descriptor with the dup function and returns |
|||
// the duplicate as a file object. |
|||
static file dup(int fd); |
|||
|
|||
// Makes fd be the copy of this file descriptor, closing fd first if |
|||
// necessary. |
|||
void dup2(int fd); |
|||
|
|||
// Makes fd be the copy of this file descriptor, closing fd first if |
|||
// necessary. |
|||
void dup2(int fd, std::error_code& ec) noexcept; |
|||
|
|||
// Creates a pipe setting up read_end and write_end file objects for reading |
|||
// and writing respectively. |
|||
static void pipe(file& read_end, file& write_end); |
|||
|
|||
// Creates a buffered_file object associated with this file and detaches |
|||
// this file object from the file. |
|||
buffered_file fdopen(const char* mode); |
|||
}; |
|||
|
|||
// Returns the memory page size. |
|||
long getpagesize(); |
|||
|
|||
FMT_BEGIN_DETAIL_NAMESPACE |
|||
|
|||
struct buffer_size { |
|||
buffer_size() = default; |
|||
size_t value = 0; |
|||
buffer_size operator=(size_t val) const { |
|||
auto bs = buffer_size(); |
|||
bs.value = val; |
|||
return bs; |
|||
} |
|||
}; |
|||
|
|||
struct ostream_params { |
|||
int oflag = file::WRONLY | file::CREATE | file::TRUNC; |
|||
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; |
|||
|
|||
ostream_params() {} |
|||
|
|||
template <typename... T> |
|||
ostream_params(T... params, int new_oflag) : ostream_params(params...) { |
|||
oflag = new_oflag; |
|||
} |
|||
|
|||
template <typename... T> |
|||
ostream_params(T... params, detail::buffer_size bs) |
|||
: ostream_params(params...) { |
|||
this->buffer_size = bs.value; |
|||
} |
|||
|
|||
// Intel has a bug that results in failure to deduce a constructor |
|||
// for empty parameter packs. |
|||
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 |
|||
ostream_params(int new_oflag) : oflag(new_oflag) {} |
|||
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} |
|||
# endif |
|||
}; |
|||
|
|||
FMT_END_DETAIL_NAMESPACE |
|||
|
|||
// Added {} below to work around default constructor error known to |
|||
// occur in Xcode versions 7.2.1 and 8.2.1. |
|||
constexpr detail::buffer_size buffer_size{}; |
|||
|
|||
/** A fast output stream which is not thread-safe. */ |
|||
class FMT_API ostream final : private detail::buffer<char> { |
|||
private: |
|||
file file_; |
|||
|
|||
void grow(size_t) override; |
|||
|
|||
ostream(cstring_view path, const detail::ostream_params& params) |
|||
: file_(path, params.oflag) { |
|||
set(new char[params.buffer_size], params.buffer_size); |
|||
} |
|||
|
|||
public: |
|||
ostream(ostream&& other) |
|||
: detail::buffer<char>(other.data(), other.size(), other.capacity()), |
|||
file_(std::move(other.file_)) { |
|||
other.clear(); |
|||
other.set(nullptr, 0); |
|||
} |
|||
~ostream() { |
|||
flush(); |
|||
delete[] data(); |
|||
} |
|||
|
|||
void flush() { |
|||
if (size() == 0) return; |
|||
file_.write(data(), size()); |
|||
clear(); |
|||
} |
|||
|
|||
template <typename... T> |
|||
friend ostream output_file(cstring_view path, T... params); |
|||
|
|||
void close() { |
|||
flush(); |
|||
file_.close(); |
|||
} |
|||
|
|||
/** |
|||
Formats ``args`` according to specifications in ``fmt`` and writes the |
|||
output to the file. |
|||
*/ |
|||
template <typename... T> void print(format_string<T...> fmt, T&&... args) { |
|||
vformat_to(detail::buffer_appender<char>(*this), fmt, |
|||
fmt::make_format_args(args...)); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
\rst |
|||
Opens a file for writing. Supported parameters passed in *params*: |
|||
|
|||
* ``<integer>``: Flags passed to `open |
|||
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_ |
|||
(``file::WRONLY | file::CREATE | file::TRUNC`` by default) |
|||
* ``buffer_size=<integer>``: Output buffer size |
|||
|
|||
**Example**:: |
|||
|
|||
auto out = fmt::output_file("guide.txt"); |
|||
out.print("Don't {}", "Panic"); |
|||
\endrst |
|||
*/ |
|||
template <typename... T> |
|||
inline ostream output_file(cstring_view path, T... params) { |
|||
return {path, detail::ostream_params(params...)}; |
|||
} |
|||
#endif // FMT_USE_FCNTL |
|||
|
|||
FMT_MODULE_EXPORT_END |
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_OS_H_ |
@ -1,237 +0,0 @@ |
|||
// Formatting library for C++ - std::ostream support |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_OSTREAM_H_ |
|||
#define FMT_OSTREAM_H_ |
|||
|
|||
#include <fstream> |
|||
#include <ostream> |
|||
#if defined(_WIN32) && defined(__GLIBCXX__) |
|||
# include <ext/stdio_filebuf.h> |
|||
# include <ext/stdio_sync_filebuf.h> |
|||
#elif defined(_WIN32) && defined(_LIBCPP_VERSION) |
|||
# include <__std_stream> |
|||
#endif |
|||
|
|||
#include "format.h" |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
|
|||
template <typename OutputIt, typename Char> class basic_printf_context; |
|||
|
|||
namespace detail { |
|||
|
|||
// Checks if T has a user-defined operator<<. |
|||
template <typename T, typename Char, typename Enable = void> |
|||
class is_streamable { |
|||
private: |
|||
template <typename U> |
|||
static auto test(int) |
|||
-> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>() |
|||
<< std::declval<U>()) != 0>; |
|||
|
|||
template <typename> static auto test(...) -> std::false_type; |
|||
|
|||
using result = decltype(test<T>(0)); |
|||
|
|||
public: |
|||
is_streamable() = default; |
|||
|
|||
static const bool value = result::value; |
|||
}; |
|||
|
|||
// Formatting of built-in types and arrays is intentionally disabled because |
|||
// it's handled by standard (non-ostream) formatters. |
|||
template <typename T, typename Char> |
|||
struct is_streamable< |
|||
T, Char, |
|||
enable_if_t< |
|||
std::is_arithmetic<T>::value || std::is_array<T>::value || |
|||
std::is_pointer<T>::value || std::is_same<T, char8_type>::value || |
|||
std::is_convertible<T, fmt::basic_string_view<Char>>::value || |
|||
std::is_same<T, std_string_view<Char>>::value || |
|||
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>> |
|||
: std::false_type {}; |
|||
|
|||
// Generate a unique explicit instantion in every translation unit using a tag |
|||
// type in an anonymous namespace. |
|||
namespace { |
|||
struct file_access_tag {}; |
|||
} // namespace |
|||
template <class Tag, class BufType, FILE* BufType::*FileMemberPtr> |
|||
class file_access { |
|||
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } |
|||
}; |
|||
|
|||
#if FMT_MSC_VERSION |
|||
template class file_access<file_access_tag, std::filebuf, |
|||
&std::filebuf::_Myfile>; |
|||
auto get_file(std::filebuf&) -> FILE*; |
|||
#elif defined(_WIN32) && defined(_LIBCPP_VERSION) |
|||
template class file_access<file_access_tag, std::__stdoutbuf<char>, |
|||
&std::__stdoutbuf<char>::__file_>; |
|||
auto get_file(std::__stdoutbuf<char>&) -> FILE*; |
|||
#endif |
|||
|
|||
inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) { |
|||
#if FMT_MSC_VERSION |
|||
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf())) |
|||
if (FILE* f = get_file(*buf)) return write_console(f, data); |
|||
#elif defined(_WIN32) && defined(__GLIBCXX__) |
|||
auto* rdbuf = os.rdbuf(); |
|||
FILE* c_file; |
|||
if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf)) |
|||
c_file = fbuf->file(); |
|||
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf)) |
|||
c_file = fbuf->file(); |
|||
else |
|||
return false; |
|||
if (c_file) return write_console(c_file, data); |
|||
#elif defined(_WIN32) && defined(_LIBCPP_VERSION) |
|||
if (auto* buf = dynamic_cast<std::__stdoutbuf<char>*>(os.rdbuf())) |
|||
if (FILE* f = get_file(*buf)) return write_console(f, data); |
|||
#else |
|||
ignore_unused(os, data); |
|||
#endif |
|||
return false; |
|||
} |
|||
inline bool write_ostream_unicode(std::wostream&, |
|||
fmt::basic_string_view<wchar_t>) { |
|||
return false; |
|||
} |
|||
|
|||
// Write the content of buf to os. |
|||
// It is a separate function rather than a part of vprint to simplify testing. |
|||
template <typename Char> |
|||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { |
|||
const Char* buf_data = buf.data(); |
|||
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type; |
|||
unsigned_streamsize size = buf.size(); |
|||
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); |
|||
do { |
|||
unsigned_streamsize n = size <= max_size ? size : max_size; |
|||
os.write(buf_data, static_cast<std::streamsize>(n)); |
|||
buf_data += n; |
|||
size -= n; |
|||
} while (size != 0); |
|||
} |
|||
|
|||
template <typename Char, typename T> |
|||
void format_value(buffer<Char>& buf, const T& value, |
|||
locale_ref loc = locale_ref()) { |
|||
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf); |
|||
auto&& output = std::basic_ostream<Char>(&format_buf); |
|||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) |
|||
if (loc) output.imbue(loc.get<std::locale>()); |
|||
#endif |
|||
output << value; |
|||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit); |
|||
} |
|||
|
|||
template <typename T> struct streamed_view { const T& value; }; |
|||
|
|||
} // namespace detail |
|||
|
|||
// Formats an object of type T that has an overloaded ostream operator<<. |
|||
template <typename Char> |
|||
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> { |
|||
void set_debug_format() = delete; |
|||
|
|||
template <typename T, typename OutputIt> |
|||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const |
|||
-> OutputIt { |
|||
auto buffer = basic_memory_buffer<Char>(); |
|||
format_value(buffer, value, ctx.locale()); |
|||
return formatter<basic_string_view<Char>, Char>::format( |
|||
{buffer.data(), buffer.size()}, ctx); |
|||
} |
|||
}; |
|||
|
|||
using ostream_formatter = basic_ostream_formatter<char>; |
|||
|
|||
template <typename T, typename Char> |
|||
struct formatter<detail::streamed_view<T>, Char> |
|||
: basic_ostream_formatter<Char> { |
|||
template <typename OutputIt> |
|||
auto format(detail::streamed_view<T> view, |
|||
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt { |
|||
return basic_ostream_formatter<Char>::format(view.value, ctx); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
\rst |
|||
Returns a view that formats `value` via an ostream ``operator<<``. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::print("Current thread id: {}\n", |
|||
fmt::streamed(std::this_thread::get_id())); |
|||
\endrst |
|||
*/ |
|||
template <typename T> |
|||
auto streamed(const T& value) -> detail::streamed_view<T> { |
|||
return {value}; |
|||
} |
|||
|
|||
namespace detail { |
|||
|
|||
// Formats an object of type T that has an overloaded ostream operator<<. |
|||
template <typename T, typename Char> |
|||
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>> |
|||
: basic_ostream_formatter<Char> { |
|||
using basic_ostream_formatter<Char>::format; |
|||
}; |
|||
|
|||
inline void vprint_directly(std::ostream& os, string_view format_str, |
|||
format_args args) { |
|||
auto buffer = memory_buffer(); |
|||
detail::vformat_to(buffer, format_str, args); |
|||
detail::write_buffer(os, buffer); |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
FMT_MODULE_EXPORT template <typename Char> |
|||
void vprint(std::basic_ostream<Char>& os, |
|||
basic_string_view<type_identity_t<Char>> format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) { |
|||
auto buffer = basic_memory_buffer<Char>(); |
|||
detail::vformat_to(buffer, format_str, args); |
|||
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; |
|||
detail::write_buffer(os, buffer); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Prints formatted data to the stream *os*. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::print(cerr, "Don't {}!", "panic"); |
|||
\endrst |
|||
*/ |
|||
FMT_MODULE_EXPORT template <typename... T> |
|||
void print(std::ostream& os, format_string<T...> fmt, T&&... args) { |
|||
const auto& vargs = fmt::make_format_args(args...); |
|||
if (detail::is_utf8()) |
|||
vprint(os, fmt, vargs); |
|||
else |
|||
detail::vprint_directly(os, fmt, vargs); |
|||
} |
|||
|
|||
FMT_MODULE_EXPORT |
|||
template <typename... Args> |
|||
void print(std::wostream& os, |
|||
basic_format_string<wchar_t, type_identity_t<Args>...> fmt, |
|||
Args&&... args) { |
|||
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...)); |
|||
} |
|||
|
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_OSTREAM_H_ |
@ -1,640 +0,0 @@ |
|||
// Formatting library for C++ - legacy printf implementation |
|||
// |
|||
// Copyright (c) 2012 - 2016, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_PRINTF_H_ |
|||
#define FMT_PRINTF_H_ |
|||
|
|||
#include <algorithm> // std::max |
|||
#include <limits> // std::numeric_limits |
|||
|
|||
#include "format.h" |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
FMT_MODULE_EXPORT_BEGIN |
|||
|
|||
template <typename T> struct printf_formatter { printf_formatter() = delete; }; |
|||
|
|||
template <typename Char> |
|||
class basic_printf_parse_context : public basic_format_parse_context<Char> { |
|||
using basic_format_parse_context<Char>::basic_format_parse_context; |
|||
}; |
|||
|
|||
template <typename OutputIt, typename Char> class basic_printf_context { |
|||
private: |
|||
OutputIt out_; |
|||
basic_format_args<basic_printf_context> args_; |
|||
|
|||
public: |
|||
using char_type = Char; |
|||
using format_arg = basic_format_arg<basic_printf_context>; |
|||
using parse_context_type = basic_printf_parse_context<Char>; |
|||
template <typename T> using formatter_type = printf_formatter<T>; |
|||
|
|||
/** |
|||
\rst |
|||
Constructs a ``printf_context`` object. References to the arguments are |
|||
stored in the context object so make sure they have appropriate lifetimes. |
|||
\endrst |
|||
*/ |
|||
basic_printf_context(OutputIt out, |
|||
basic_format_args<basic_printf_context> args) |
|||
: out_(out), args_(args) {} |
|||
|
|||
OutputIt out() { return out_; } |
|||
void advance_to(OutputIt it) { out_ = it; } |
|||
|
|||
detail::locale_ref locale() { return {}; } |
|||
|
|||
format_arg arg(int id) const { return args_.get(id); } |
|||
|
|||
FMT_CONSTEXPR void on_error(const char* message) { |
|||
detail::error_handler().on_error(message); |
|||
} |
|||
}; |
|||
|
|||
FMT_BEGIN_DETAIL_NAMESPACE |
|||
|
|||
// Checks if a value fits in int - used to avoid warnings about comparing |
|||
// signed and unsigned integers. |
|||
template <bool IsSigned> struct int_checker { |
|||
template <typename T> static bool fits_in_int(T value) { |
|||
unsigned max = max_value<int>(); |
|||
return value <= max; |
|||
} |
|||
static bool fits_in_int(bool) { return true; } |
|||
}; |
|||
|
|||
template <> struct int_checker<true> { |
|||
template <typename T> static bool fits_in_int(T value) { |
|||
return value >= (std::numeric_limits<int>::min)() && |
|||
value <= max_value<int>(); |
|||
} |
|||
static bool fits_in_int(int) { return true; } |
|||
}; |
|||
|
|||
class printf_precision_handler { |
|||
public: |
|||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> |
|||
int operator()(T value) { |
|||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) |
|||
FMT_THROW(format_error("number is too big")); |
|||
return (std::max)(static_cast<int>(value), 0); |
|||
} |
|||
|
|||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> |
|||
int operator()(T) { |
|||
FMT_THROW(format_error("precision is not integer")); |
|||
return 0; |
|||
} |
|||
}; |
|||
|
|||
// An argument visitor that returns true iff arg is a zero integer. |
|||
class is_zero_int { |
|||
public: |
|||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> |
|||
bool operator()(T value) { |
|||
return value == 0; |
|||
} |
|||
|
|||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> |
|||
bool operator()(T) { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {}; |
|||
|
|||
template <> struct make_unsigned_or_bool<bool> { using type = bool; }; |
|||
|
|||
template <typename T, typename Context> class arg_converter { |
|||
private: |
|||
using char_type = typename Context::char_type; |
|||
|
|||
basic_format_arg<Context>& arg_; |
|||
char_type type_; |
|||
|
|||
public: |
|||
arg_converter(basic_format_arg<Context>& arg, char_type type) |
|||
: arg_(arg), type_(type) {} |
|||
|
|||
void operator()(bool value) { |
|||
if (type_ != 's') operator()<bool>(value); |
|||
} |
|||
|
|||
template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)> |
|||
void operator()(U value) { |
|||
bool is_signed = type_ == 'd' || type_ == 'i'; |
|||
using target_type = conditional_t<std::is_same<T, void>::value, U, T>; |
|||
if (const_check(sizeof(target_type) <= sizeof(int))) { |
|||
// Extra casts are used to silence warnings. |
|||
if (is_signed) { |
|||
arg_ = detail::make_arg<Context>( |
|||
static_cast<int>(static_cast<target_type>(value))); |
|||
} else { |
|||
using unsigned_type = typename make_unsigned_or_bool<target_type>::type; |
|||
arg_ = detail::make_arg<Context>( |
|||
static_cast<unsigned>(static_cast<unsigned_type>(value))); |
|||
} |
|||
} else { |
|||
if (is_signed) { |
|||
// glibc's printf doesn't sign extend arguments of smaller types: |
|||
// std::printf("%lld", -42); // prints "4294967254" |
|||
// but we don't have to do the same because it's a UB. |
|||
arg_ = detail::make_arg<Context>(static_cast<long long>(value)); |
|||
} else { |
|||
arg_ = detail::make_arg<Context>( |
|||
static_cast<typename make_unsigned_or_bool<U>::type>(value)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)> |
|||
void operator()(U) {} // No conversion needed for non-integral types. |
|||
}; |
|||
|
|||
// Converts an integer argument to T for printf, if T is an integral type. |
|||
// If T is void, the argument is converted to corresponding signed or unsigned |
|||
// type depending on the type specifier: 'd' and 'i' - signed, other - |
|||
// unsigned). |
|||
template <typename T, typename Context, typename Char> |
|||
void convert_arg(basic_format_arg<Context>& arg, Char type) { |
|||
visit_format_arg(arg_converter<T, Context>(arg, type), arg); |
|||
} |
|||
|
|||
// Converts an integer argument to char for printf. |
|||
template <typename Context> class char_converter { |
|||
private: |
|||
basic_format_arg<Context>& arg_; |
|||
|
|||
public: |
|||
explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {} |
|||
|
|||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> |
|||
void operator()(T value) { |
|||
arg_ = detail::make_arg<Context>( |
|||
static_cast<typename Context::char_type>(value)); |
|||
} |
|||
|
|||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> |
|||
void operator()(T) {} // No conversion needed for non-integral types. |
|||
}; |
|||
|
|||
// An argument visitor that return a pointer to a C string if argument is a |
|||
// string or null otherwise. |
|||
template <typename Char> struct get_cstring { |
|||
template <typename T> const Char* operator()(T) { return nullptr; } |
|||
const Char* operator()(const Char* s) { return s; } |
|||
}; |
|||
|
|||
// Checks if an argument is a valid printf width specifier and sets |
|||
// left alignment if it is negative. |
|||
template <typename Char> class printf_width_handler { |
|||
private: |
|||
using format_specs = basic_format_specs<Char>; |
|||
|
|||
format_specs& specs_; |
|||
|
|||
public: |
|||
explicit printf_width_handler(format_specs& specs) : specs_(specs) {} |
|||
|
|||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> |
|||
unsigned operator()(T value) { |
|||
auto width = static_cast<uint32_or_64_or_128_t<T>>(value); |
|||
if (detail::is_negative(value)) { |
|||
specs_.align = align::left; |
|||
width = 0 - width; |
|||
} |
|||
unsigned int_max = max_value<int>(); |
|||
if (width > int_max) FMT_THROW(format_error("number is too big")); |
|||
return static_cast<unsigned>(width); |
|||
} |
|||
|
|||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> |
|||
unsigned operator()(T) { |
|||
FMT_THROW(format_error("width is not integer")); |
|||
return 0; |
|||
} |
|||
}; |
|||
|
|||
// The ``printf`` argument formatter. |
|||
template <typename OutputIt, typename Char> |
|||
class printf_arg_formatter : public arg_formatter<Char> { |
|||
private: |
|||
using base = arg_formatter<Char>; |
|||
using context_type = basic_printf_context<OutputIt, Char>; |
|||
using format_specs = basic_format_specs<Char>; |
|||
|
|||
context_type& context_; |
|||
|
|||
OutputIt write_null_pointer(bool is_string = false) { |
|||
auto s = this->specs; |
|||
s.type = presentation_type::none; |
|||
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s); |
|||
} |
|||
|
|||
public: |
|||
printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx) |
|||
: base{iter, s, locale_ref()}, context_(ctx) {} |
|||
|
|||
OutputIt operator()(monostate value) { return base::operator()(value); } |
|||
|
|||
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)> |
|||
OutputIt operator()(T value) { |
|||
// MSVC2013 fails to compile separate overloads for bool and Char so use |
|||
// std::is_same instead. |
|||
if (std::is_same<T, Char>::value) { |
|||
format_specs fmt_specs = this->specs; |
|||
if (fmt_specs.type != presentation_type::none && |
|||
fmt_specs.type != presentation_type::chr) { |
|||
return (*this)(static_cast<int>(value)); |
|||
} |
|||
fmt_specs.sign = sign::none; |
|||
fmt_specs.alt = false; |
|||
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types. |
|||
// align::numeric needs to be overwritten here since the '0' flag is |
|||
// ignored for non-numeric types |
|||
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) |
|||
fmt_specs.align = align::right; |
|||
return write<Char>(this->out, static_cast<Char>(value), fmt_specs); |
|||
} |
|||
return base::operator()(value); |
|||
} |
|||
|
|||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> |
|||
OutputIt operator()(T value) { |
|||
return base::operator()(value); |
|||
} |
|||
|
|||
/** Formats a null-terminated C string. */ |
|||
OutputIt operator()(const char* value) { |
|||
if (value) return base::operator()(value); |
|||
return write_null_pointer(this->specs.type != presentation_type::pointer); |
|||
} |
|||
|
|||
/** Formats a null-terminated wide C string. */ |
|||
OutputIt operator()(const wchar_t* value) { |
|||
if (value) return base::operator()(value); |
|||
return write_null_pointer(this->specs.type != presentation_type::pointer); |
|||
} |
|||
|
|||
OutputIt operator()(basic_string_view<Char> value) { |
|||
return base::operator()(value); |
|||
} |
|||
|
|||
/** Formats a pointer. */ |
|||
OutputIt operator()(const void* value) { |
|||
return value ? base::operator()(value) : write_null_pointer(); |
|||
} |
|||
|
|||
/** Formats an argument of a custom (user-defined) type. */ |
|||
OutputIt operator()(typename basic_format_arg<context_type>::handle handle) { |
|||
auto parse_ctx = |
|||
basic_printf_parse_context<Char>(basic_string_view<Char>()); |
|||
handle.format(parse_ctx, context_); |
|||
return this->out; |
|||
} |
|||
}; |
|||
|
|||
template <typename Char> |
|||
void parse_flags(basic_format_specs<Char>& specs, const Char*& it, |
|||
const Char* end) { |
|||
for (; it != end; ++it) { |
|||
switch (*it) { |
|||
case '-': |
|||
specs.align = align::left; |
|||
break; |
|||
case '+': |
|||
specs.sign = sign::plus; |
|||
break; |
|||
case '0': |
|||
specs.fill[0] = '0'; |
|||
break; |
|||
case ' ': |
|||
if (specs.sign != sign::plus) { |
|||
specs.sign = sign::space; |
|||
} |
|||
break; |
|||
case '#': |
|||
specs.alt = true; |
|||
break; |
|||
default: |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
|
|||
template <typename Char, typename GetArg> |
|||
int parse_header(const Char*& it, const Char* end, |
|||
basic_format_specs<Char>& specs, GetArg get_arg) { |
|||
int arg_index = -1; |
|||
Char c = *it; |
|||
if (c >= '0' && c <= '9') { |
|||
// Parse an argument index (if followed by '$') or a width possibly |
|||
// preceded with '0' flag(s). |
|||
int value = parse_nonnegative_int(it, end, -1); |
|||
if (it != end && *it == '$') { // value is an argument index |
|||
++it; |
|||
arg_index = value != -1 ? value : max_value<int>(); |
|||
} else { |
|||
if (c == '0') specs.fill[0] = '0'; |
|||
if (value != 0) { |
|||
// Nonzero value means that we parsed width and don't need to |
|||
// parse it or flags again, so return now. |
|||
if (value == -1) FMT_THROW(format_error("number is too big")); |
|||
specs.width = value; |
|||
return arg_index; |
|||
} |
|||
} |
|||
} |
|||
parse_flags(specs, it, end); |
|||
// Parse width. |
|||
if (it != end) { |
|||
if (*it >= '0' && *it <= '9') { |
|||
specs.width = parse_nonnegative_int(it, end, -1); |
|||
if (specs.width == -1) FMT_THROW(format_error("number is too big")); |
|||
} else if (*it == '*') { |
|||
++it; |
|||
specs.width = static_cast<int>(visit_format_arg( |
|||
detail::printf_width_handler<Char>(specs), get_arg(-1))); |
|||
} |
|||
} |
|||
return arg_index; |
|||
} |
|||
|
|||
template <typename Char, typename Context> |
|||
void vprintf(buffer<Char>& buf, basic_string_view<Char> format, |
|||
basic_format_args<Context> args) { |
|||
using OutputIt = buffer_appender<Char>; |
|||
auto out = OutputIt(buf); |
|||
auto context = basic_printf_context<OutputIt, Char>(out, args); |
|||
auto parse_ctx = basic_printf_parse_context<Char>(format); |
|||
|
|||
// Returns the argument with specified index or, if arg_index is -1, the next |
|||
// argument. |
|||
auto get_arg = [&](int arg_index) { |
|||
if (arg_index < 0) |
|||
arg_index = parse_ctx.next_arg_id(); |
|||
else |
|||
parse_ctx.check_arg_id(--arg_index); |
|||
return detail::get_arg(context, arg_index); |
|||
}; |
|||
|
|||
const Char* start = parse_ctx.begin(); |
|||
const Char* end = parse_ctx.end(); |
|||
auto it = start; |
|||
while (it != end) { |
|||
if (!detail::find<false, Char>(it, end, '%', it)) { |
|||
it = end; // detail::find leaves it == nullptr if it doesn't find '%' |
|||
break; |
|||
} |
|||
Char c = *it++; |
|||
if (it != end && *it == c) { |
|||
out = detail::write( |
|||
out, basic_string_view<Char>(start, detail::to_unsigned(it - start))); |
|||
start = ++it; |
|||
continue; |
|||
} |
|||
out = detail::write(out, basic_string_view<Char>( |
|||
start, detail::to_unsigned(it - 1 - start))); |
|||
|
|||
basic_format_specs<Char> specs; |
|||
specs.align = align::right; |
|||
|
|||
// Parse argument index, flags and width. |
|||
int arg_index = parse_header(it, end, specs, get_arg); |
|||
if (arg_index == 0) parse_ctx.on_error("argument not found"); |
|||
|
|||
// Parse precision. |
|||
if (it != end && *it == '.') { |
|||
++it; |
|||
c = it != end ? *it : 0; |
|||
if ('0' <= c && c <= '9') { |
|||
specs.precision = parse_nonnegative_int(it, end, 0); |
|||
} else if (c == '*') { |
|||
++it; |
|||
specs.precision = static_cast<int>( |
|||
visit_format_arg(detail::printf_precision_handler(), get_arg(-1))); |
|||
} else { |
|||
specs.precision = 0; |
|||
} |
|||
} |
|||
|
|||
auto arg = get_arg(arg_index); |
|||
// For d, i, o, u, x, and X conversion specifiers, if a precision is |
|||
// specified, the '0' flag is ignored |
|||
if (specs.precision >= 0 && arg.is_integral()) |
|||
specs.fill[0] = |
|||
' '; // Ignore '0' flag for non-numeric types or if '-' present. |
|||
if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) { |
|||
auto str = visit_format_arg(detail::get_cstring<Char>(), arg); |
|||
auto str_end = str + specs.precision; |
|||
auto nul = std::find(str, str_end, Char()); |
|||
arg = detail::make_arg<basic_printf_context<OutputIt, Char>>( |
|||
basic_string_view<Char>( |
|||
str, detail::to_unsigned(nul != str_end ? nul - str |
|||
: specs.precision))); |
|||
} |
|||
if (specs.alt && visit_format_arg(detail::is_zero_int(), arg)) |
|||
specs.alt = false; |
|||
if (specs.fill[0] == '0') { |
|||
if (arg.is_arithmetic() && specs.align != align::left) |
|||
specs.align = align::numeric; |
|||
else |
|||
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-' |
|||
// flag is also present. |
|||
} |
|||
|
|||
// Parse length and convert the argument to the required type. |
|||
c = it != end ? *it++ : 0; |
|||
Char t = it != end ? *it : 0; |
|||
using detail::convert_arg; |
|||
switch (c) { |
|||
case 'h': |
|||
if (t == 'h') { |
|||
++it; |
|||
t = it != end ? *it : 0; |
|||
convert_arg<signed char>(arg, t); |
|||
} else { |
|||
convert_arg<short>(arg, t); |
|||
} |
|||
break; |
|||
case 'l': |
|||
if (t == 'l') { |
|||
++it; |
|||
t = it != end ? *it : 0; |
|||
convert_arg<long long>(arg, t); |
|||
} else { |
|||
convert_arg<long>(arg, t); |
|||
} |
|||
break; |
|||
case 'j': |
|||
convert_arg<intmax_t>(arg, t); |
|||
break; |
|||
case 'z': |
|||
convert_arg<size_t>(arg, t); |
|||
break; |
|||
case 't': |
|||
convert_arg<std::ptrdiff_t>(arg, t); |
|||
break; |
|||
case 'L': |
|||
// printf produces garbage when 'L' is omitted for long double, no |
|||
// need to do the same. |
|||
break; |
|||
default: |
|||
--it; |
|||
convert_arg<void>(arg, c); |
|||
} |
|||
|
|||
// Parse type. |
|||
if (it == end) FMT_THROW(format_error("invalid format string")); |
|||
char type = static_cast<char>(*it++); |
|||
if (arg.is_integral()) { |
|||
// Normalize type. |
|||
switch (type) { |
|||
case 'i': |
|||
case 'u': |
|||
type = 'd'; |
|||
break; |
|||
case 'c': |
|||
visit_format_arg( |
|||
detail::char_converter<basic_printf_context<OutputIt, Char>>(arg), |
|||
arg); |
|||
break; |
|||
} |
|||
} |
|||
specs.type = parse_presentation_type(type); |
|||
if (specs.type == presentation_type::none) |
|||
parse_ctx.on_error("invalid type specifier"); |
|||
|
|||
start = it; |
|||
|
|||
// Format argument. |
|||
out = visit_format_arg( |
|||
detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg); |
|||
} |
|||
detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start))); |
|||
} |
|||
FMT_END_DETAIL_NAMESPACE |
|||
|
|||
template <typename Char> |
|||
using basic_printf_context_t = |
|||
basic_printf_context<detail::buffer_appender<Char>, Char>; |
|||
|
|||
using printf_context = basic_printf_context_t<char>; |
|||
using wprintf_context = basic_printf_context_t<wchar_t>; |
|||
|
|||
using printf_args = basic_format_args<printf_context>; |
|||
using wprintf_args = basic_format_args<wprintf_context>; |
|||
|
|||
/** |
|||
\rst |
|||
Constructs an `~fmt::format_arg_store` object that contains references to |
|||
arguments and can be implicitly converted to `~fmt::printf_args`. |
|||
\endrst |
|||
*/ |
|||
template <typename... T> |
|||
inline auto make_printf_args(const T&... args) |
|||
-> format_arg_store<printf_context, T...> { |
|||
return {args...}; |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Constructs an `~fmt::format_arg_store` object that contains references to |
|||
arguments and can be implicitly converted to `~fmt::wprintf_args`. |
|||
\endrst |
|||
*/ |
|||
template <typename... T> |
|||
inline auto make_wprintf_args(const T&... args) |
|||
-> format_arg_store<wprintf_context, T...> { |
|||
return {args...}; |
|||
} |
|||
|
|||
template <typename S, typename Char = char_t<S>> |
|||
inline auto vsprintf( |
|||
const S& fmt, |
|||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) |
|||
-> std::basic_string<Char> { |
|||
basic_memory_buffer<Char> buffer; |
|||
vprintf(buffer, detail::to_string_view(fmt), args); |
|||
return to_string(buffer); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Formats arguments and returns the result as a string. |
|||
|
|||
**Example**:: |
|||
|
|||
std::string message = fmt::sprintf("The answer is %d", 42); |
|||
\endrst |
|||
*/ |
|||
template <typename S, typename... T, |
|||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> |
|||
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> { |
|||
using context = basic_printf_context_t<Char>; |
|||
return vsprintf(detail::to_string_view(fmt), |
|||
fmt::make_format_args<context>(args...)); |
|||
} |
|||
|
|||
template <typename S, typename Char = char_t<S>> |
|||
inline auto vfprintf( |
|||
std::FILE* f, const S& fmt, |
|||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) |
|||
-> int { |
|||
basic_memory_buffer<Char> buffer; |
|||
vprintf(buffer, detail::to_string_view(fmt), args); |
|||
size_t size = buffer.size(); |
|||
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size |
|||
? -1 |
|||
: static_cast<int>(size); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Prints formatted data to the file *f*. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::fprintf(stderr, "Don't %s!", "panic"); |
|||
\endrst |
|||
*/ |
|||
template <typename S, typename... T, typename Char = char_t<S>> |
|||
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { |
|||
using context = basic_printf_context_t<Char>; |
|||
return vfprintf(f, detail::to_string_view(fmt), |
|||
fmt::make_format_args<context>(args...)); |
|||
} |
|||
|
|||
template <typename S, typename Char = char_t<S>> |
|||
inline auto vprintf( |
|||
const S& fmt, |
|||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) |
|||
-> int { |
|||
return vfprintf(stdout, detail::to_string_view(fmt), args); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Prints formatted data to ``stdout``. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::printf("Elapsed time: %.2f seconds", 1.23); |
|||
\endrst |
|||
*/ |
|||
template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)> |
|||
inline auto printf(const S& fmt, const T&... args) -> int { |
|||
return vprintf( |
|||
detail::to_string_view(fmt), |
|||
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...)); |
|||
} |
|||
|
|||
FMT_MODULE_EXPORT_END |
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_PRINTF_H_ |
@ -1,722 +0,0 @@ |
|||
// Formatting library for C++ - experimental range support |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
// |
|||
// Copyright (c) 2018 - present, Remotion (Igor Schulz) |
|||
// All Rights Reserved |
|||
// {fmt} support for ranges, containers and types tuple interface. |
|||
|
|||
#ifndef FMT_RANGES_H_ |
|||
#define FMT_RANGES_H_ |
|||
|
|||
#include <initializer_list> |
|||
#include <tuple> |
|||
#include <type_traits> |
|||
|
|||
#include "format.h" |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
|
|||
namespace detail { |
|||
|
|||
template <typename RangeT, typename OutputIterator> |
|||
OutputIterator copy(const RangeT& range, OutputIterator out) { |
|||
for (auto it = range.begin(), end = range.end(); it != end; ++it) |
|||
*out++ = *it; |
|||
return out; |
|||
} |
|||
|
|||
template <typename OutputIterator> |
|||
OutputIterator copy(const char* str, OutputIterator out) { |
|||
while (*str) *out++ = *str++; |
|||
return out; |
|||
} |
|||
|
|||
template <typename OutputIterator> |
|||
OutputIterator copy(char ch, OutputIterator out) { |
|||
*out++ = ch; |
|||
return out; |
|||
} |
|||
|
|||
template <typename OutputIterator> |
|||
OutputIterator copy(wchar_t ch, OutputIterator out) { |
|||
*out++ = ch; |
|||
return out; |
|||
} |
|||
|
|||
// Returns true if T has a std::string-like interface, like std::string_view. |
|||
template <typename T> class is_std_string_like { |
|||
template <typename U> |
|||
static auto check(U* p) |
|||
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); |
|||
template <typename> static void check(...); |
|||
|
|||
public: |
|||
static constexpr const bool value = |
|||
is_string<T>::value || |
|||
std::is_convertible<T, std_string_view<char>>::value || |
|||
!std::is_void<decltype(check<T>(nullptr))>::value; |
|||
}; |
|||
|
|||
template <typename Char> |
|||
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {}; |
|||
|
|||
template <typename T> class is_map { |
|||
template <typename U> static auto check(U*) -> typename U::mapped_type; |
|||
template <typename> static void check(...); |
|||
|
|||
public: |
|||
#ifdef FMT_FORMAT_MAP_AS_LIST |
|||
static constexpr const bool value = false; |
|||
#else |
|||
static constexpr const bool value = |
|||
!std::is_void<decltype(check<T>(nullptr))>::value; |
|||
#endif |
|||
}; |
|||
|
|||
template <typename T> class is_set { |
|||
template <typename U> static auto check(U*) -> typename U::key_type; |
|||
template <typename> static void check(...); |
|||
|
|||
public: |
|||
#ifdef FMT_FORMAT_SET_AS_LIST |
|||
static constexpr const bool value = false; |
|||
#else |
|||
static constexpr const bool value = |
|||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value; |
|||
#endif |
|||
}; |
|||
|
|||
template <typename... Ts> struct conditional_helper {}; |
|||
|
|||
template <typename T, typename _ = void> struct is_range_ : std::false_type {}; |
|||
|
|||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800 |
|||
|
|||
# define FMT_DECLTYPE_RETURN(val) \ |
|||
->decltype(val) { return val; } \ |
|||
static_assert( \ |
|||
true, "") // This makes it so that a semicolon is required after the |
|||
// macro, which helps clang-format handle the formatting. |
|||
|
|||
// C array overload |
|||
template <typename T, std::size_t N> |
|||
auto range_begin(const T (&arr)[N]) -> const T* { |
|||
return arr; |
|||
} |
|||
template <typename T, std::size_t N> |
|||
auto range_end(const T (&arr)[N]) -> const T* { |
|||
return arr + N; |
|||
} |
|||
|
|||
template <typename T, typename Enable = void> |
|||
struct has_member_fn_begin_end_t : std::false_type {}; |
|||
|
|||
template <typename T> |
|||
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()), |
|||
decltype(std::declval<T>().end())>> |
|||
: std::true_type {}; |
|||
|
|||
// Member function overload |
|||
template <typename T> |
|||
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin()); |
|||
template <typename T> |
|||
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end()); |
|||
|
|||
// ADL overload. Only participates in overload resolution if member functions |
|||
// are not found. |
|||
template <typename T> |
|||
auto range_begin(T&& rng) |
|||
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value, |
|||
decltype(begin(static_cast<T&&>(rng)))> { |
|||
return begin(static_cast<T&&>(rng)); |
|||
} |
|||
template <typename T> |
|||
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value, |
|||
decltype(end(static_cast<T&&>(rng)))> { |
|||
return end(static_cast<T&&>(rng)); |
|||
} |
|||
|
|||
template <typename T, typename Enable = void> |
|||
struct has_const_begin_end : std::false_type {}; |
|||
template <typename T, typename Enable = void> |
|||
struct has_mutable_begin_end : std::false_type {}; |
|||
|
|||
template <typename T> |
|||
struct has_const_begin_end< |
|||
T, |
|||
void_t< |
|||
decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())), |
|||
decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>> |
|||
: std::true_type {}; |
|||
|
|||
template <typename T> |
|||
struct has_mutable_begin_end< |
|||
T, void_t<decltype(detail::range_begin(std::declval<T>())), |
|||
decltype(detail::range_end(std::declval<T>())), |
|||
enable_if_t<std::is_copy_constructible<T>::value>>> |
|||
: std::true_type {}; |
|||
|
|||
template <typename T> |
|||
struct is_range_<T, void> |
|||
: std::integral_constant<bool, (has_const_begin_end<T>::value || |
|||
has_mutable_begin_end<T>::value)> {}; |
|||
# undef FMT_DECLTYPE_RETURN |
|||
#endif |
|||
|
|||
// tuple_size and tuple_element check. |
|||
template <typename T> class is_tuple_like_ { |
|||
template <typename U> |
|||
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int()); |
|||
template <typename> static void check(...); |
|||
|
|||
public: |
|||
static constexpr const bool value = |
|||
!std::is_void<decltype(check<T>(nullptr))>::value; |
|||
}; |
|||
|
|||
// Check for integer_sequence |
|||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 |
|||
template <typename T, T... N> |
|||
using integer_sequence = std::integer_sequence<T, N...>; |
|||
template <size_t... N> using index_sequence = std::index_sequence<N...>; |
|||
template <size_t N> using make_index_sequence = std::make_index_sequence<N>; |
|||
#else |
|||
template <typename T, T... N> struct integer_sequence { |
|||
using value_type = T; |
|||
|
|||
static FMT_CONSTEXPR size_t size() { return sizeof...(N); } |
|||
}; |
|||
|
|||
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>; |
|||
|
|||
template <typename T, size_t N, T... Ns> |
|||
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {}; |
|||
template <typename T, T... Ns> |
|||
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {}; |
|||
|
|||
template <size_t N> |
|||
using make_index_sequence = make_integer_sequence<size_t, N>; |
|||
#endif |
|||
|
|||
template <typename T> |
|||
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>; |
|||
|
|||
template <typename T, typename C, bool = is_tuple_like_<T>::value> |
|||
class is_tuple_formattable_ { |
|||
public: |
|||
static constexpr const bool value = false; |
|||
}; |
|||
template <typename T, typename C> class is_tuple_formattable_<T, C, true> { |
|||
template <std::size_t... I> |
|||
static std::true_type check2(index_sequence<I...>, |
|||
integer_sequence<bool, (I == I)...>); |
|||
static std::false_type check2(...); |
|||
template <std::size_t... I> |
|||
static decltype(check2( |
|||
index_sequence<I...>{}, |
|||
integer_sequence< |
|||
bool, (is_formattable<typename std::tuple_element<I, T>::type, |
|||
C>::value)...>{})) check(index_sequence<I...>); |
|||
|
|||
public: |
|||
static constexpr const bool value = |
|||
decltype(check(tuple_index_sequence<T>{}))::value; |
|||
}; |
|||
|
|||
template <class Tuple, class F, size_t... Is> |
|||
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept { |
|||
using std::get; |
|||
// using free function get<I>(T) now. |
|||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; |
|||
(void)_; // blocks warnings |
|||
} |
|||
|
|||
template <class T> |
|||
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes( |
|||
T const&) { |
|||
return {}; |
|||
} |
|||
|
|||
template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) { |
|||
const auto indexes = get_indexes(tup); |
|||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); |
|||
} |
|||
|
|||
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920 |
|||
// Older MSVC doesn't get the reference type correctly for arrays. |
|||
template <typename R> struct range_reference_type_impl { |
|||
using type = decltype(*detail::range_begin(std::declval<R&>())); |
|||
}; |
|||
|
|||
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> { |
|||
using type = T&; |
|||
}; |
|||
|
|||
template <typename T> |
|||
using range_reference_type = typename range_reference_type_impl<T>::type; |
|||
#else |
|||
template <typename Range> |
|||
using range_reference_type = |
|||
decltype(*detail::range_begin(std::declval<Range&>())); |
|||
#endif |
|||
|
|||
// We don't use the Range's value_type for anything, but we do need the Range's |
|||
// reference type, with cv-ref stripped. |
|||
template <typename Range> |
|||
using uncvref_type = remove_cvref_t<range_reference_type<Range>>; |
|||
|
|||
template <typename Range> |
|||
using uncvref_first_type = |
|||
remove_cvref_t<decltype(std::declval<range_reference_type<Range>>().first)>; |
|||
|
|||
template <typename Range> |
|||
using uncvref_second_type = remove_cvref_t< |
|||
decltype(std::declval<range_reference_type<Range>>().second)>; |
|||
|
|||
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) { |
|||
*out++ = ','; |
|||
*out++ = ' '; |
|||
return out; |
|||
} |
|||
|
|||
template <typename Char, typename OutputIt> |
|||
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt { |
|||
return write_escaped_string(out, str); |
|||
} |
|||
|
|||
template <typename Char, typename OutputIt, typename T, |
|||
FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)> |
|||
inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt { |
|||
auto sv = std_string_view<Char>(str); |
|||
return write_range_entry<Char>(out, basic_string_view<Char>(sv)); |
|||
} |
|||
|
|||
template <typename Char, typename OutputIt, typename Arg, |
|||
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)> |
|||
OutputIt write_range_entry(OutputIt out, const Arg v) { |
|||
return write_escaped_char(out, v); |
|||
} |
|||
|
|||
template < |
|||
typename Char, typename OutputIt, typename Arg, |
|||
FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value && |
|||
!std::is_same<Arg, Char>::value)> |
|||
OutputIt write_range_entry(OutputIt out, const Arg& v) { |
|||
return write<Char>(out, v); |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
template <typename T> struct is_tuple_like { |
|||
static constexpr const bool value = |
|||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value; |
|||
}; |
|||
|
|||
template <typename T, typename C> struct is_tuple_formattable { |
|||
static constexpr const bool value = |
|||
detail::is_tuple_formattable_<T, C>::value; |
|||
}; |
|||
|
|||
template <typename TupleT, typename Char> |
|||
struct formatter<TupleT, Char, |
|||
enable_if_t<fmt::is_tuple_like<TupleT>::value && |
|||
fmt::is_tuple_formattable<TupleT, Char>::value>> { |
|||
private: |
|||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{}; |
|||
basic_string_view<Char> opening_bracket_ = |
|||
detail::string_literal<Char, '('>{}; |
|||
basic_string_view<Char> closing_bracket_ = |
|||
detail::string_literal<Char, ')'>{}; |
|||
|
|||
// C++11 generic lambda for format(). |
|||
template <typename FormatContext> struct format_each { |
|||
template <typename T> void operator()(const T& v) { |
|||
if (i > 0) out = detail::copy_str<Char>(separator, out); |
|||
out = detail::write_range_entry<Char>(out, v); |
|||
++i; |
|||
} |
|||
int i; |
|||
typename FormatContext::iterator& out; |
|||
basic_string_view<Char> separator; |
|||
}; |
|||
|
|||
public: |
|||
FMT_CONSTEXPR formatter() {} |
|||
|
|||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) { |
|||
separator_ = sep; |
|||
} |
|||
|
|||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open, |
|||
basic_string_view<Char> close) { |
|||
opening_bracket_ = open; |
|||
closing_bracket_ = close; |
|||
} |
|||
|
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext = format_context> |
|||
auto format(const TupleT& values, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
out = detail::copy_str<Char>(opening_bracket_, out); |
|||
detail::for_each(values, format_each<FormatContext>{0, out, separator_}); |
|||
out = detail::copy_str<Char>(closing_bracket_, out); |
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
template <typename T, typename Char> struct is_range { |
|||
static constexpr const bool value = |
|||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value && |
|||
!std::is_convertible<T, std::basic_string<Char>>::value && |
|||
!std::is_convertible<T, detail::std_string_view<Char>>::value; |
|||
}; |
|||
|
|||
namespace detail { |
|||
template <typename Context> struct range_mapper { |
|||
using mapper = arg_mapper<Context>; |
|||
|
|||
template <typename T, |
|||
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)> |
|||
static auto map(T&& value) -> T&& { |
|||
return static_cast<T&&>(value); |
|||
} |
|||
template <typename T, |
|||
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)> |
|||
static auto map(T&& value) |
|||
-> decltype(mapper().map(static_cast<T&&>(value))) { |
|||
return mapper().map(static_cast<T&&>(value)); |
|||
} |
|||
}; |
|||
|
|||
template <typename Char, typename Element> |
|||
using range_formatter_type = conditional_t< |
|||
is_formattable<Element, Char>::value, |
|||
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map( |
|||
std::declval<Element>()))>, |
|||
Char>, |
|||
fallback_formatter<Element, Char>>; |
|||
|
|||
template <typename R> |
|||
using maybe_const_range = |
|||
conditional_t<has_const_begin_end<R>::value, const R, R>; |
|||
|
|||
// Workaround a bug in MSVC 2015 and earlier. |
|||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 |
|||
template <typename R, typename Char> |
|||
struct is_formattable_delayed |
|||
: disjunction< |
|||
is_formattable<uncvref_type<maybe_const_range<R>>, Char>, |
|||
has_fallback_formatter<uncvref_type<maybe_const_range<R>>, Char>> {}; |
|||
#endif |
|||
|
|||
} // namespace detail |
|||
|
|||
template <typename T, typename Char, typename Enable = void> |
|||
struct range_formatter; |
|||
|
|||
template <typename T, typename Char> |
|||
struct range_formatter< |
|||
T, Char, |
|||
enable_if_t<conjunction< |
|||
std::is_same<T, remove_cvref_t<T>>, |
|||
disjunction<is_formattable<T, Char>, |
|||
detail::has_fallback_formatter<T, Char>>>::value>> { |
|||
private: |
|||
detail::range_formatter_type<Char, T> underlying_; |
|||
bool custom_specs_ = false; |
|||
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{}; |
|||
basic_string_view<Char> opening_bracket_ = |
|||
detail::string_literal<Char, '['>{}; |
|||
basic_string_view<Char> closing_bracket_ = |
|||
detail::string_literal<Char, ']'>{}; |
|||
|
|||
template <class U> |
|||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, int) |
|||
-> decltype(u.set_debug_format()) { |
|||
u.set_debug_format(); |
|||
} |
|||
|
|||
template <class U> |
|||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} |
|||
|
|||
FMT_CONSTEXPR void maybe_set_debug_format() { |
|||
maybe_set_debug_format(underlying_, 0); |
|||
} |
|||
|
|||
public: |
|||
FMT_CONSTEXPR range_formatter() {} |
|||
|
|||
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& { |
|||
return underlying_; |
|||
} |
|||
|
|||
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) { |
|||
separator_ = sep; |
|||
} |
|||
|
|||
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open, |
|||
basic_string_view<Char> close) { |
|||
opening_bracket_ = open; |
|||
closing_bracket_ = close; |
|||
} |
|||
|
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
auto it = ctx.begin(); |
|||
auto end = ctx.end(); |
|||
if (it == end || *it == '}') { |
|||
maybe_set_debug_format(); |
|||
return it; |
|||
} |
|||
|
|||
if (*it == 'n') { |
|||
set_brackets({}, {}); |
|||
++it; |
|||
} |
|||
|
|||
if (*it == '}') { |
|||
maybe_set_debug_format(); |
|||
return it; |
|||
} |
|||
|
|||
if (*it != ':') |
|||
FMT_THROW(format_error("no other top-level range formatters supported")); |
|||
|
|||
custom_specs_ = true; |
|||
++it; |
|||
ctx.advance_to(it); |
|||
return underlying_.parse(ctx); |
|||
} |
|||
|
|||
template <typename R, class FormatContext> |
|||
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { |
|||
detail::range_mapper<buffer_context<Char>> mapper; |
|||
auto out = ctx.out(); |
|||
out = detail::copy_str<Char>(opening_bracket_, out); |
|||
int i = 0; |
|||
auto it = detail::range_begin(range); |
|||
auto end = detail::range_end(range); |
|||
for (; it != end; ++it) { |
|||
if (i > 0) out = detail::copy_str<Char>(separator_, out); |
|||
; |
|||
ctx.advance_to(out); |
|||
out = underlying_.format(mapper.map(*it), ctx); |
|||
++i; |
|||
} |
|||
out = detail::copy_str<Char>(closing_bracket_, out); |
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
enum class range_format { disabled, map, set, sequence, string, debug_string }; |
|||
|
|||
namespace detail { |
|||
template <typename T> struct range_format_kind_ { |
|||
static constexpr auto value = std::is_same<range_reference_type<T>, T>::value |
|||
? range_format::disabled |
|||
: is_map<T>::value ? range_format::map |
|||
: is_set<T>::value ? range_format::set |
|||
: range_format::sequence; |
|||
}; |
|||
|
|||
template <range_format K, typename R, typename Char, typename Enable = void> |
|||
struct range_default_formatter; |
|||
|
|||
template <range_format K> |
|||
using range_format_constant = std::integral_constant<range_format, K>; |
|||
|
|||
template <range_format K, typename R, typename Char> |
|||
struct range_default_formatter< |
|||
K, R, Char, |
|||
enable_if_t<(K == range_format::sequence || K == range_format::map || |
|||
K == range_format::set)>> { |
|||
using range_type = detail::maybe_const_range<R>; |
|||
range_formatter<detail::uncvref_type<range_type>, Char> underlying_; |
|||
|
|||
FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); } |
|||
|
|||
FMT_CONSTEXPR void init(range_format_constant<range_format::set>) { |
|||
underlying_.set_brackets(detail::string_literal<Char, '{'>{}, |
|||
detail::string_literal<Char, '}'>{}); |
|||
} |
|||
|
|||
FMT_CONSTEXPR void init(range_format_constant<range_format::map>) { |
|||
underlying_.set_brackets(detail::string_literal<Char, '{'>{}, |
|||
detail::string_literal<Char, '}'>{}); |
|||
underlying_.underlying().set_brackets({}, {}); |
|||
underlying_.underlying().set_separator( |
|||
detail::string_literal<Char, ':', ' '>{}); |
|||
} |
|||
|
|||
FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {} |
|||
|
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return underlying_.parse(ctx); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(range_type& range, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return underlying_.format(range, ctx); |
|||
} |
|||
}; |
|||
} // namespace detail |
|||
|
|||
template <typename T, typename Char, typename Enable = void> |
|||
struct range_format_kind |
|||
: conditional_t< |
|||
is_range<T, Char>::value, detail::range_format_kind_<T>, |
|||
std::integral_constant<range_format, range_format::disabled>> {}; |
|||
|
|||
template <typename R, typename Char> |
|||
struct formatter< |
|||
R, Char, |
|||
enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value != |
|||
range_format::disabled> |
|||
// Workaround a bug in MSVC 2015 and earlier. |
|||
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 |
|||
, |
|||
detail::is_formattable_delayed<R, Char> |
|||
#endif |
|||
>::value>> |
|||
: detail::range_default_formatter<range_format_kind<R, Char>::value, R, |
|||
Char> { |
|||
}; |
|||
|
|||
template <typename Char, typename... T> struct tuple_join_view : detail::view { |
|||
const std::tuple<T...>& tuple; |
|||
basic_string_view<Char> sep; |
|||
|
|||
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s) |
|||
: tuple(t), sep{s} {} |
|||
}; |
|||
|
|||
template <typename Char, typename... T> |
|||
using tuple_arg_join = tuple_join_view<Char, T...>; |
|||
|
|||
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers |
|||
// support in tuple_join. It is disabled by default because of issues with |
|||
// the dynamic width and precision. |
|||
#ifndef FMT_TUPLE_JOIN_SPECIFIERS |
|||
# define FMT_TUPLE_JOIN_SPECIFIERS 0 |
|||
#endif |
|||
|
|||
template <typename Char, typename... T> |
|||
struct formatter<tuple_join_view<Char, T...>, Char> { |
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>()); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const tuple_join_view<Char, T...>& value, |
|||
FormatContext& ctx) const -> typename FormatContext::iterator { |
|||
return do_format(value, ctx, |
|||
std::integral_constant<size_t, sizeof...(T)>()); |
|||
} |
|||
|
|||
private: |
|||
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_; |
|||
|
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto do_parse(ParseContext& ctx, |
|||
std::integral_constant<size_t, 0>) |
|||
-> decltype(ctx.begin()) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename ParseContext, size_t N> |
|||
FMT_CONSTEXPR auto do_parse(ParseContext& ctx, |
|||
std::integral_constant<size_t, N>) |
|||
-> decltype(ctx.begin()) { |
|||
auto end = ctx.begin(); |
|||
#if FMT_TUPLE_JOIN_SPECIFIERS |
|||
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx); |
|||
if (N > 1) { |
|||
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>()); |
|||
if (end != end1) |
|||
FMT_THROW(format_error("incompatible format specs for tuple elements")); |
|||
} |
|||
#endif |
|||
return end; |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx, |
|||
std::integral_constant<size_t, 0>) const -> |
|||
typename FormatContext::iterator { |
|||
return ctx.out(); |
|||
} |
|||
|
|||
template <typename FormatContext, size_t N> |
|||
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx, |
|||
std::integral_constant<size_t, N>) const -> |
|||
typename FormatContext::iterator { |
|||
auto out = std::get<sizeof...(T) - N>(formatters_) |
|||
.format(std::get<sizeof...(T) - N>(value.tuple), ctx); |
|||
if (N > 1) { |
|||
out = std::copy(value.sep.begin(), value.sep.end(), out); |
|||
ctx.advance_to(out); |
|||
return do_format(value, ctx, std::integral_constant<size_t, N - 1>()); |
|||
} |
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
FMT_MODULE_EXPORT_BEGIN |
|||
|
|||
/** |
|||
\rst |
|||
Returns an object that formats `tuple` with elements separated by `sep`. |
|||
|
|||
**Example**:: |
|||
|
|||
std::tuple<int, char> t = {1, 'a'}; |
|||
fmt::print("{}", fmt::join(t, ", ")); |
|||
// Output: "1, a" |
|||
\endrst |
|||
*/ |
|||
template <typename... T> |
|||
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep) |
|||
-> tuple_join_view<char, T...> { |
|||
return {tuple, sep}; |
|||
} |
|||
|
|||
template <typename... T> |
|||
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, |
|||
basic_string_view<wchar_t> sep) |
|||
-> tuple_join_view<wchar_t, T...> { |
|||
return {tuple, sep}; |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Returns an object that formats `initializer_list` with elements separated by |
|||
`sep`. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::print("{}", fmt::join({1, 2, 3}, ", ")); |
|||
// Output: "1, 2, 3" |
|||
\endrst |
|||
*/ |
|||
template <typename T> |
|||
auto join(std::initializer_list<T> list, string_view sep) |
|||
-> join_view<const T*, const T*> { |
|||
return join(std::begin(list), std::end(list), sep); |
|||
} |
|||
|
|||
FMT_MODULE_EXPORT_END |
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_RANGES_H_ |
@ -1,171 +0,0 @@ |
|||
// Formatting library for C++ - formatters for standard library types |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_STD_H_ |
|||
#define FMT_STD_H_ |
|||
|
|||
#include <thread> |
|||
#include <type_traits> |
|||
#include <utility> |
|||
|
|||
#include "ostream.h" |
|||
|
|||
#if FMT_HAS_INCLUDE(<version>) |
|||
# include <version> |
|||
#endif |
|||
// Checking FMT_CPLUSPLUS for warning suppression in MSVC. |
|||
#if FMT_CPLUSPLUS >= 201703L |
|||
# if FMT_HAS_INCLUDE(<filesystem>) |
|||
# include <filesystem> |
|||
# endif |
|||
# if FMT_HAS_INCLUDE(<variant>) |
|||
# include <variant> |
|||
# endif |
|||
#endif |
|||
|
|||
#ifdef __cpp_lib_filesystem |
|||
FMT_BEGIN_NAMESPACE |
|||
|
|||
namespace detail { |
|||
|
|||
template <typename Char> |
|||
void write_escaped_path(basic_memory_buffer<Char>& quoted, |
|||
const std::filesystem::path& p) { |
|||
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>()); |
|||
} |
|||
# ifdef _WIN32 |
|||
template <> |
|||
inline void write_escaped_path<char>(basic_memory_buffer<char>& quoted, |
|||
const std::filesystem::path& p) { |
|||
auto s = p.u8string(); |
|||
write_escaped_string<char>( |
|||
std::back_inserter(quoted), |
|||
string_view(reinterpret_cast<const char*>(s.c_str()), s.size())); |
|||
} |
|||
# endif |
|||
template <> |
|||
inline void write_escaped_path<std::filesystem::path::value_type>( |
|||
basic_memory_buffer<std::filesystem::path::value_type>& quoted, |
|||
const std::filesystem::path& p) { |
|||
write_escaped_string<std::filesystem::path::value_type>( |
|||
std::back_inserter(quoted), p.native()); |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
template <typename Char> |
|||
struct formatter<std::filesystem::path, Char> |
|||
: formatter<basic_string_view<Char>> { |
|||
template <typename FormatContext> |
|||
auto format(const std::filesystem::path& p, FormatContext& ctx) const -> |
|||
typename FormatContext::iterator { |
|||
basic_memory_buffer<Char> quoted; |
|||
detail::write_escaped_path(quoted, p); |
|||
return formatter<basic_string_view<Char>>::format( |
|||
basic_string_view<Char>(quoted.data(), quoted.size()), ctx); |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
template <typename Char> |
|||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {}; |
|||
FMT_END_NAMESPACE |
|||
|
|||
#ifdef __cpp_lib_variant |
|||
FMT_BEGIN_NAMESPACE |
|||
template <typename Char> struct formatter<std::monostate, Char> { |
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::monostate&, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
out = detail::write<Char>(out, "monostate"); |
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
namespace detail { |
|||
|
|||
template <typename T> |
|||
using variant_index_sequence = |
|||
std::make_index_sequence<std::variant_size<T>::value>; |
|||
|
|||
// variant_size and variant_alternative check. |
|||
template <typename T, typename U = void> |
|||
struct is_variant_like_ : std::false_type {}; |
|||
template <typename T> |
|||
struct is_variant_like_<T, std::void_t<decltype(std::variant_size<T>::value)>> |
|||
: std::true_type {}; |
|||
|
|||
// formattable element check |
|||
template <typename T, typename C> class is_variant_formattable_ { |
|||
template <std::size_t... I> |
|||
static std::conjunction< |
|||
is_formattable<std::variant_alternative_t<I, T>, C>...> |
|||
check(std::index_sequence<I...>); |
|||
|
|||
public: |
|||
static constexpr const bool value = |
|||
decltype(check(variant_index_sequence<T>{}))::value; |
|||
}; |
|||
|
|||
template <typename Char, typename OutputIt, typename T> |
|||
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { |
|||
if constexpr (is_string<T>::value) |
|||
return write_escaped_string<Char>(out, detail::to_string_view(v)); |
|||
else if constexpr (std::is_same_v<T, Char>) |
|||
return write_escaped_char(out, v); |
|||
else |
|||
return write<Char>(out, v); |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
template <typename T> struct is_variant_like { |
|||
static constexpr const bool value = detail::is_variant_like_<T>::value; |
|||
}; |
|||
|
|||
template <typename T, typename C> struct is_variant_formattable { |
|||
static constexpr const bool value = |
|||
detail::is_variant_formattable_<T, C>::value; |
|||
}; |
|||
|
|||
template <typename Variant, typename Char> |
|||
struct formatter< |
|||
Variant, Char, |
|||
std::enable_if_t<std::conjunction_v< |
|||
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> { |
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const Variant& value, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
|
|||
out = detail::write<Char>(out, "variant("); |
|||
std::visit( |
|||
[&](const auto& v) { |
|||
out = detail::write_variant_alternative<Char>(out, v); |
|||
}, |
|||
value); |
|||
*out++ = ')'; |
|||
return out; |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif |
|||
|
|||
#endif // FMT_STD_H_ |
@ -1,229 +0,0 @@ |
|||
// Formatting library for C++ - optional wchar_t and exotic character support |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_XCHAR_H_ |
|||
#define FMT_XCHAR_H_ |
|||
|
|||
#include <cwchar> |
|||
|
|||
#include "format.h" |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
template <typename T> |
|||
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; |
|||
} |
|||
|
|||
FMT_MODULE_EXPORT_BEGIN |
|||
|
|||
using wstring_view = basic_string_view<wchar_t>; |
|||
using wformat_parse_context = basic_format_parse_context<wchar_t>; |
|||
using wformat_context = buffer_context<wchar_t>; |
|||
using wformat_args = basic_format_args<wformat_context>; |
|||
using wmemory_buffer = basic_memory_buffer<wchar_t>; |
|||
|
|||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 |
|||
// Workaround broken conversion on older gcc. |
|||
template <typename... Args> using wformat_string = wstring_view; |
|||
inline auto runtime(wstring_view s) -> wstring_view { return s; } |
|||
#else |
|||
template <typename... Args> |
|||
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>; |
|||
inline auto runtime(wstring_view s) -> basic_runtime<wchar_t> { return {{s}}; } |
|||
#endif |
|||
|
|||
template <> struct is_char<wchar_t> : std::true_type {}; |
|||
template <> struct is_char<detail::char8_type> : std::true_type {}; |
|||
template <> struct is_char<char16_t> : std::true_type {}; |
|||
template <> struct is_char<char32_t> : std::true_type {}; |
|||
|
|||
template <typename... Args> |
|||
constexpr format_arg_store<wformat_context, Args...> make_wformat_args( |
|||
const Args&... args) { |
|||
return {args...}; |
|||
} |
|||
|
|||
inline namespace literals { |
|||
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS |
|||
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) { |
|||
return {s}; |
|||
} |
|||
#endif |
|||
} // namespace literals |
|||
|
|||
template <typename It, typename Sentinel> |
|||
auto join(It begin, Sentinel end, wstring_view sep) |
|||
-> join_view<It, Sentinel, wchar_t> { |
|||
return {begin, end, sep}; |
|||
} |
|||
|
|||
template <typename Range> |
|||
auto join(Range&& range, wstring_view sep) |
|||
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>, |
|||
wchar_t> { |
|||
return join(std::begin(range), std::end(range), sep); |
|||
} |
|||
|
|||
template <typename T> |
|||
auto join(std::initializer_list<T> list, wstring_view sep) |
|||
-> join_view<const T*, const T*, wchar_t> { |
|||
return join(std::begin(list), std::end(list), sep); |
|||
} |
|||
|
|||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> |
|||
auto vformat(basic_string_view<Char> format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) |
|||
-> std::basic_string<Char> { |
|||
basic_memory_buffer<Char> buffer; |
|||
detail::vformat_to(buffer, format_str, args); |
|||
return to_string(buffer); |
|||
} |
|||
|
|||
template <typename... T> |
|||
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring { |
|||
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
// Pass char_t as a default template parameter instead of using |
|||
// std::basic_string<char_t<S>> to reduce the symbol size. |
|||
template <typename S, typename... Args, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(!std::is_same<Char, char>::value && |
|||
!std::is_same<Char, wchar_t>::value)> |
|||
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> { |
|||
return vformat(detail::to_string_view(format_str), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename Locale, typename S, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat( |
|||
const Locale& loc, const S& format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) |
|||
-> std::basic_string<Char> { |
|||
return detail::vformat(loc, detail::to_string_view(format_str), args); |
|||
} |
|||
|
|||
template <typename Locale, typename S, typename... Args, |
|||
typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto format(const Locale& loc, const S& format_str, Args&&... args) |
|||
-> std::basic_string<Char> { |
|||
return detail::vformat(loc, detail::to_string_view(format_str), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
auto vformat_to(OutputIt out, const S& format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) |
|||
-> OutputIt { |
|||
auto&& buf = detail::get_buffer<Char>(out); |
|||
detail::vformat_to(buf, detail::to_string_view(format_str), args); |
|||
return detail::get_iterator(buf); |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename... Args, |
|||
typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt { |
|||
return vformat_to(out, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename Locale, typename S, typename OutputIt, typename... Args, |
|||
typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat_to( |
|||
OutputIt out, const Locale& loc, const S& format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt { |
|||
auto&& buf = detail::get_buffer<Char>(out); |
|||
vformat_to(buf, detail::to_string_view(format_str), args, |
|||
detail::locale_ref(loc)); |
|||
return detail::get_iterator(buf); |
|||
} |
|||
|
|||
template < |
|||
typename OutputIt, typename Locale, typename S, typename... Args, |
|||
typename Char = char_t<S>, |
|||
bool enable = detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value> |
|||
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, |
|||
Args&&... args) -> |
|||
typename std::enable_if<enable, OutputIt>::type { |
|||
return vformat_to(out, loc, to_string_view(format_str), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename OutputIt, typename Char, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat_to_n( |
|||
OutputIt out, size_t n, basic_string_view<Char> format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) |
|||
-> format_to_n_result<OutputIt> { |
|||
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out, |
|||
n); |
|||
detail::vformat_to(buf, format_str, args); |
|||
return {buf.out(), buf.count()}; |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename... Args, |
|||
typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, |
|||
const Args&... args) -> format_to_n_result<OutputIt> { |
|||
return vformat_to_n(out, n, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename S, typename... Args, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> |
|||
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t { |
|||
detail::counting_buffer<Char> buf; |
|||
detail::vformat_to(buf, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
return buf.count(); |
|||
} |
|||
|
|||
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { |
|||
wmemory_buffer buffer; |
|||
detail::vformat_to(buffer, fmt, args); |
|||
buffer.push_back(L'\0'); |
|||
if (std::fputws(buffer.data(), f) == -1) |
|||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); |
|||
} |
|||
|
|||
inline void vprint(wstring_view fmt, wformat_args args) { |
|||
vprint(stdout, fmt, args); |
|||
} |
|||
|
|||
template <typename... T> |
|||
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { |
|||
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { |
|||
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
/** |
|||
Converts *value* to ``std::wstring`` using the default format for type *T*. |
|||
*/ |
|||
template <typename T> inline auto to_wstring(const T& value) -> std::wstring { |
|||
return format(FMT_STRING(L"{}"), value); |
|||
} |
|||
FMT_MODULE_EXPORT_END |
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_XCHAR_H_ |
@ -1,361 +0,0 @@ |
|||
// Formatting library for C++ - optional OS-specific functionality
|
|||
//
|
|||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
|||
// All rights reserved.
|
|||
//
|
|||
// For the license information refer to format.h.
|
|||
|
|||
// Disable bogus MSVC warnings.
|
|||
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
|
|||
# define _CRT_SECURE_NO_WARNINGS
|
|||
#endif
|
|||
|
|||
#include "fmt/os.h"
|
|||
|
|||
#include <climits>
|
|||
|
|||
#if FMT_USE_FCNTL
|
|||
# include <sys/stat.h>
|
|||
# include <sys/types.h>
|
|||
|
|||
# ifndef _WIN32
|
|||
# include <unistd.h>
|
|||
# else
|
|||
# ifndef WIN32_LEAN_AND_MEAN
|
|||
# define WIN32_LEAN_AND_MEAN
|
|||
# endif
|
|||
# include <io.h>
|
|||
|
|||
# ifndef S_IRUSR
|
|||
# define S_IRUSR _S_IREAD
|
|||
# endif
|
|||
# ifndef S_IWUSR
|
|||
# define S_IWUSR _S_IWRITE
|
|||
# endif
|
|||
# ifndef S_IRGRP
|
|||
# define S_IRGRP 0
|
|||
# endif
|
|||
# ifndef S_IWGRP
|
|||
# define S_IWGRP 0
|
|||
# endif
|
|||
# ifndef S_IROTH
|
|||
# define S_IROTH 0
|
|||
# endif
|
|||
# ifndef S_IWOTH
|
|||
# define S_IWOTH 0
|
|||
# endif
|
|||
# endif // _WIN32
|
|||
#endif // FMT_USE_FCNTL
|
|||
|
|||
#ifdef _WIN32
|
|||
# include <windows.h>
|
|||
#endif
|
|||
|
|||
namespace { |
|||
#ifdef _WIN32
|
|||
// Return type of read and write functions.
|
|||
using rwresult = int; |
|||
|
|||
// On Windows the count argument to read and write is unsigned, so convert
|
|||
// it from size_t preventing integer overflow.
|
|||
inline unsigned convert_rwcount(std::size_t count) { |
|||
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX; |
|||
} |
|||
#elif FMT_USE_FCNTL
|
|||
// Return type of read and write functions.
|
|||
using rwresult = ssize_t; |
|||
|
|||
inline std::size_t convert_rwcount(std::size_t count) { return count; } |
|||
#endif
|
|||
} // namespace
|
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
|
|||
#ifdef _WIN32
|
|||
detail::utf16_to_utf8::utf16_to_utf8(basic_string_view<wchar_t> s) { |
|||
if (int error_code = convert(s)) { |
|||
FMT_THROW(windows_error(error_code, |
|||
"cannot convert string from UTF-16 to UTF-8")); |
|||
} |
|||
} |
|||
|
|||
int detail::utf16_to_utf8::convert(basic_string_view<wchar_t> s) { |
|||
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; |
|||
int s_size = static_cast<int>(s.size()); |
|||
if (s_size == 0) { |
|||
// WideCharToMultiByte does not support zero length, handle separately.
|
|||
buffer_.resize(1); |
|||
buffer_[0] = 0; |
|||
return 0; |
|||
} |
|||
|
|||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0, |
|||
nullptr, nullptr); |
|||
if (length == 0) return GetLastError(); |
|||
buffer_.resize(length + 1); |
|||
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0], |
|||
length, nullptr, nullptr); |
|||
if (length == 0) return GetLastError(); |
|||
buffer_[length] = 0; |
|||
return 0; |
|||
} |
|||
|
|||
namespace detail { |
|||
|
|||
class system_message { |
|||
system_message(const system_message&) = delete; |
|||
void operator=(const system_message&) = delete; |
|||
|
|||
unsigned long result_; |
|||
wchar_t* message_; |
|||
|
|||
static bool is_whitespace(wchar_t c) noexcept { |
|||
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0'; |
|||
} |
|||
|
|||
public: |
|||
explicit system_message(unsigned long error_code) |
|||
: result_(0), message_(nullptr) { |
|||
result_ = FormatMessageW( |
|||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
|||
FORMAT_MESSAGE_IGNORE_INSERTS, |
|||
nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
|||
reinterpret_cast<wchar_t*>(&message_), 0, nullptr); |
|||
if (result_ != 0) { |
|||
while (result_ != 0 && is_whitespace(message_[result_ - 1])) { |
|||
--result_; |
|||
} |
|||
} |
|||
} |
|||
~system_message() { LocalFree(message_); } |
|||
explicit operator bool() const noexcept { return result_ != 0; } |
|||
operator basic_string_view<wchar_t>() const noexcept { |
|||
return basic_string_view<wchar_t>(message_, result_); |
|||
} |
|||
}; |
|||
|
|||
class utf8_system_category final : public std::error_category { |
|||
public: |
|||
const char* name() const noexcept override { return "system"; } |
|||
std::string message(int error_code) const override { |
|||
system_message msg(error_code); |
|||
if (msg) { |
|||
utf16_to_utf8 utf8_message; |
|||
if (utf8_message.convert(msg) == ERROR_SUCCESS) { |
|||
return utf8_message.str(); |
|||
} |
|||
} |
|||
return "unknown error"; |
|||
} |
|||
}; |
|||
|
|||
} // namespace detail
|
|||
|
|||
FMT_API const std::error_category& system_category() noexcept { |
|||
static const detail::utf8_system_category category; |
|||
return category; |
|||
} |
|||
|
|||
std::system_error vwindows_error(int err_code, string_view format_str, |
|||
format_args args) { |
|||
auto ec = std::error_code(err_code, system_category()); |
|||
return std::system_error(ec, vformat(format_str, args)); |
|||
} |
|||
|
|||
void detail::format_windows_error(detail::buffer<char>& out, int error_code, |
|||
const char* message) noexcept { |
|||
FMT_TRY { |
|||
system_message msg(error_code); |
|||
if (msg) { |
|||
utf16_to_utf8 utf8_message; |
|||
if (utf8_message.convert(msg) == ERROR_SUCCESS) { |
|||
fmt::format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message); |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
FMT_CATCH(...) {} |
|||
format_error_code(out, error_code, message); |
|||
} |
|||
|
|||
void report_windows_error(int error_code, const char* message) noexcept { |
|||
report_error(detail::format_windows_error, error_code, message); |
|||
} |
|||
#endif // _WIN32
|
|||
|
|||
buffered_file::~buffered_file() noexcept { |
|||
if (file_ && FMT_SYSTEM(fclose(file_)) != 0) |
|||
report_system_error(errno, "cannot close file"); |
|||
} |
|||
|
|||
buffered_file::buffered_file(cstring_view filename, cstring_view mode) { |
|||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), |
|||
nullptr); |
|||
if (!file_) |
|||
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str())); |
|||
} |
|||
|
|||
void buffered_file::close() { |
|||
if (!file_) return; |
|||
int result = FMT_SYSTEM(fclose(file_)); |
|||
file_ = nullptr; |
|||
if (result != 0) FMT_THROW(system_error(errno, "cannot close file")); |
|||
} |
|||
|
|||
int buffered_file::descriptor() const { |
|||
int fd = FMT_POSIX_CALL(fileno(file_)); |
|||
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor")); |
|||
return fd; |
|||
} |
|||
|
|||
#if FMT_USE_FCNTL
|
|||
file::file(cstring_view path, int oflag) { |
|||
# ifdef _WIN32
|
|||
using mode_t = int; |
|||
# endif
|
|||
constexpr mode_t mode = |
|||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; |
|||
# if defined(_WIN32) && !defined(__MINGW32__)
|
|||
fd_ = -1; |
|||
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); |
|||
# else
|
|||
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); |
|||
# endif
|
|||
if (fd_ == -1) |
|||
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str())); |
|||
} |
|||
|
|||
file::~file() noexcept { |
|||
// Don't retry close in case of EINTR!
|
|||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
|||
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) |
|||
report_system_error(errno, "cannot close file"); |
|||
} |
|||
|
|||
void file::close() { |
|||
if (fd_ == -1) return; |
|||
// Don't retry close in case of EINTR!
|
|||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
|||
int result = FMT_POSIX_CALL(close(fd_)); |
|||
fd_ = -1; |
|||
if (result != 0) FMT_THROW(system_error(errno, "cannot close file")); |
|||
} |
|||
|
|||
long long file::size() const { |
|||
# ifdef _WIN32
|
|||
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
|
|||
// is less than 0x0500 as is the case with some default MinGW builds.
|
|||
// Both functions support large file sizes.
|
|||
DWORD size_upper = 0; |
|||
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_)); |
|||
DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); |
|||
if (size_lower == INVALID_FILE_SIZE) { |
|||
DWORD error = GetLastError(); |
|||
if (error != NO_ERROR) |
|||
FMT_THROW(windows_error(GetLastError(), "cannot get file size")); |
|||
} |
|||
unsigned long long long_size = size_upper; |
|||
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; |
|||
# else
|
|||
using Stat = struct stat; |
|||
Stat file_stat = Stat(); |
|||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) |
|||
FMT_THROW(system_error(errno, "cannot get file attributes")); |
|||
static_assert(sizeof(long long) >= sizeof(file_stat.st_size), |
|||
"return type of file::size is not large enough"); |
|||
return file_stat.st_size; |
|||
# endif
|
|||
} |
|||
|
|||
std::size_t file::read(void* buffer, std::size_t count) { |
|||
rwresult result = 0; |
|||
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); |
|||
if (result < 0) FMT_THROW(system_error(errno, "cannot read from file")); |
|||
return detail::to_unsigned(result); |
|||
} |
|||
|
|||
std::size_t file::write(const void* buffer, std::size_t count) { |
|||
rwresult result = 0; |
|||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); |
|||
if (result < 0) FMT_THROW(system_error(errno, "cannot write to file")); |
|||
return detail::to_unsigned(result); |
|||
} |
|||
|
|||
file file::dup(int fd) { |
|||
// Don't retry as dup doesn't return EINTR.
|
|||
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
|
|||
int new_fd = FMT_POSIX_CALL(dup(fd)); |
|||
if (new_fd == -1) |
|||
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd)); |
|||
return file(new_fd); |
|||
} |
|||
|
|||
void file::dup2(int fd) { |
|||
int result = 0; |
|||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); |
|||
if (result == -1) { |
|||
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}", |
|||
fd_, fd)); |
|||
} |
|||
} |
|||
|
|||
void file::dup2(int fd, std::error_code& ec) noexcept { |
|||
int result = 0; |
|||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); |
|||
if (result == -1) ec = std::error_code(errno, std::generic_category()); |
|||
} |
|||
|
|||
void file::pipe(file& read_end, file& write_end) { |
|||
// Close the descriptors first to make sure that assignments don't throw
|
|||
// and there are no leaks.
|
|||
read_end.close(); |
|||
write_end.close(); |
|||
int fds[2] = {}; |
|||
# ifdef _WIN32
|
|||
// Make the default pipe capacity same as on Linux 2.6.11+.
|
|||
enum { DEFAULT_CAPACITY = 65536 }; |
|||
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); |
|||
# else
|
|||
// Don't retry as the pipe function doesn't return EINTR.
|
|||
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
|||
int result = FMT_POSIX_CALL(pipe(fds)); |
|||
# endif
|
|||
if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe")); |
|||
// The following assignments don't throw because read_fd and write_fd
|
|||
// are closed.
|
|||
read_end = file(fds[0]); |
|||
write_end = file(fds[1]); |
|||
} |
|||
|
|||
buffered_file file::fdopen(const char* mode) { |
|||
// Don't retry as fdopen doesn't return EINTR.
|
|||
# if defined(__MINGW32__) && defined(_POSIX_)
|
|||
FILE* f = ::fdopen(fd_, mode); |
|||
# else
|
|||
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); |
|||
# endif
|
|||
if (!f) |
|||
FMT_THROW( |
|||
system_error(errno, "cannot associate stream with file descriptor")); |
|||
buffered_file bf(f); |
|||
fd_ = -1; |
|||
return bf; |
|||
} |
|||
|
|||
long getpagesize() { |
|||
# ifdef _WIN32
|
|||
SYSTEM_INFO si; |
|||
GetSystemInfo(&si); |
|||
return si.dwPageSize; |
|||
# else
|
|||
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); |
|||
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size")); |
|||
return size; |
|||
# endif
|
|||
} |
|||
|
|||
FMT_API void ostream::grow(size_t) { |
|||
if (this->size() == this->capacity()) flush(); |
|||
} |
|||
#endif // FMT_USE_FCNTL
|
|||
FMT_END_NAMESPACE |
@ -0,0 +1,217 @@ |
|||
#include "pin_threads.hpp"
|
|||
|
|||
#include <syslog.h>
|
|||
|
|||
void |
|||
PinThreads::R1L(const CPU::ThreadIdVec threads_) |
|||
{ |
|||
CPU::CPUVec cpus; |
|||
|
|||
cpus = CPU::cpus(); |
|||
if(cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : threads_) |
|||
CPU::setaffinity(thread_id,cpus.front()); |
|||
} |
|||
|
|||
void |
|||
PinThreads::R1P(const CPU::ThreadIdVec threads_) |
|||
{ |
|||
CPU::Core2CPUsMap core2cpus; |
|||
|
|||
core2cpus = CPU::core2cpus(); |
|||
if(core2cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : threads_) |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
} |
|||
|
|||
void |
|||
PinThreads::RP1L(const CPU::ThreadIdVec read_threads_, |
|||
const CPU::ThreadIdVec process_threads_) |
|||
{ |
|||
CPU::CPUVec cpus; |
|||
|
|||
cpus = CPU::cpus(); |
|||
if(cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : read_threads_) |
|||
CPU::setaffinity(thread_id,cpus.front()); |
|||
for(auto const thread_id : process_threads_) |
|||
CPU::setaffinity(thread_id,cpus.front()); |
|||
} |
|||
|
|||
void |
|||
PinThreads::RP1P(const CPU::ThreadIdVec read_threads_, |
|||
const CPU::ThreadIdVec process_threads_) |
|||
{ |
|||
CPU::Core2CPUsMap core2cpus; |
|||
|
|||
core2cpus = CPU::core2cpus(); |
|||
if(core2cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : read_threads_) |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
for(auto const thread_id : process_threads_) |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
} |
|||
|
|||
|
|||
void |
|||
PinThreads::R1LP1L(const CPU::ThreadIdVec read_threads_, |
|||
const CPU::ThreadIdVec process_threads_) |
|||
{ |
|||
CPU::CPUVec cpus; |
|||
|
|||
cpus = CPU::cpus(); |
|||
if(cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : read_threads_) |
|||
CPU::setaffinity(thread_id,cpus.front()); |
|||
|
|||
for(auto const thread_id : process_threads_) |
|||
CPU::setaffinity(thread_id,cpus.back()); |
|||
} |
|||
|
|||
|
|||
void |
|||
PinThreads::R1PP1P(const CPU::ThreadIdVec read_threads_, |
|||
const CPU::ThreadIdVec process_threads_) |
|||
{ |
|||
CPU::Core2CPUsMap core2cpus; |
|||
|
|||
core2cpus = CPU::core2cpus(); |
|||
if(core2cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : read_threads_) |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
|
|||
if(core2cpus.size() > 1) |
|||
core2cpus.erase(core2cpus.begin()); |
|||
|
|||
for(auto const thread_id : process_threads_) |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
} |
|||
|
|||
|
|||
void |
|||
PinThreads::RPSL(const CPU::ThreadIdVec read_threads_, |
|||
const CPU::ThreadIdVec process_threads_) |
|||
{ |
|||
CPU::CPUVec cpus; |
|||
|
|||
cpus = CPU::cpus(); |
|||
if(cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : read_threads_) |
|||
{ |
|||
if(cpus.empty()) |
|||
cpus = CPU::cpus(); |
|||
CPU::setaffinity(thread_id,cpus.back()); |
|||
cpus.pop_back(); |
|||
} |
|||
|
|||
for(auto const thread_id : process_threads_) |
|||
{ |
|||
if(cpus.empty()) |
|||
cpus = CPU::cpus(); |
|||
CPU::setaffinity(thread_id,cpus.back()); |
|||
cpus.pop_back(); |
|||
} |
|||
} |
|||
|
|||
|
|||
void |
|||
PinThreads::RPSP(const CPU::ThreadIdVec read_threads_, |
|||
const CPU::ThreadIdVec process_threads_) |
|||
{ |
|||
CPU::Core2CPUsMap core2cpus; |
|||
|
|||
core2cpus = CPU::core2cpus(); |
|||
if(core2cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : read_threads_) |
|||
{ |
|||
if(core2cpus.empty()) |
|||
core2cpus = CPU::core2cpus(); |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
core2cpus.erase(core2cpus.begin()); |
|||
} |
|||
|
|||
for(auto const thread_id : process_threads_) |
|||
{ |
|||
if(core2cpus.empty()) |
|||
core2cpus = CPU::core2cpus(); |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
core2cpus.erase(core2cpus.begin()); |
|||
} |
|||
} |
|||
|
|||
|
|||
void |
|||
PinThreads::R1PPSP(const CPU::ThreadIdVec read_threads_, |
|||
const CPU::ThreadIdVec process_threads_) |
|||
{ |
|||
CPU::Core2CPUsMap core2cpus; |
|||
CPU::Core2CPUsMap leftover; |
|||
|
|||
core2cpus = CPU::core2cpus(); |
|||
if(core2cpus.empty()) |
|||
return; |
|||
|
|||
for(auto const thread_id : read_threads_) |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
|
|||
core2cpus.erase(core2cpus.begin()); |
|||
if(core2cpus.empty()) |
|||
core2cpus = CPU::core2cpus(); |
|||
leftover = core2cpus; |
|||
|
|||
for(auto const thread_id : process_threads_) |
|||
{ |
|||
if(core2cpus.empty()) |
|||
core2cpus = leftover; |
|||
CPU::setaffinity(thread_id,core2cpus.begin()->second); |
|||
core2cpus.erase(core2cpus.begin()); |
|||
} |
|||
} |
|||
|
|||
|
|||
void |
|||
PinThreads::pin(const CPU::ThreadIdVec read_threads_, |
|||
const CPU::ThreadIdVec process_threads_, |
|||
const std::string type_) |
|||
{ |
|||
if(type_.empty() || (type_ == "false")) |
|||
return; |
|||
if(type_ == "R1L") |
|||
return PinThreads::R1L(read_threads_); |
|||
if(type_ == "R1P") |
|||
return PinThreads::R1P(read_threads_); |
|||
if(type_ == "RP1L") |
|||
return PinThreads::RP1L(read_threads_,process_threads_); |
|||
if(type_ == "RP1P") |
|||
return PinThreads::RP1P(read_threads_,process_threads_); |
|||
if(type_ == "R1LP1L") |
|||
return PinThreads::R1LP1L(read_threads_,process_threads_); |
|||
if(type_ == "R1PP1P") |
|||
return PinThreads::R1PP1P(read_threads_,process_threads_); |
|||
if(type_ == "RPSL") |
|||
return PinThreads::RPSL(read_threads_,process_threads_); |
|||
if(type_ == "RPSP") |
|||
return PinThreads::RPSP(read_threads_,process_threads_); |
|||
if(type_ == "R1PPSP") |
|||
return PinThreads::R1PPSP(read_threads_,process_threads_); |
|||
|
|||
syslog(LOG_WARNING, |
|||
"Invalid pin-threads type, ignoring: %s", |
|||
type_.c_str()); |
|||
} |
@ -0,0 +1,28 @@ |
|||
#pragma once
|
|||
|
|||
#include "cpu.hpp"
|
|||
|
|||
#include <string>
|
|||
|
|||
namespace PinThreads |
|||
{ |
|||
void R1L(const CPU::ThreadIdVec threads); |
|||
void R1P(const CPU::ThreadIdVec threads); |
|||
void RP1L(const CPU::ThreadIdVec read_threads, |
|||
const CPU::ThreadIdVec process_threads); |
|||
void RP1P(const CPU::ThreadIdVec read_threads, |
|||
const CPU::ThreadIdVec process_threads); |
|||
void R1LP1L(const CPU::ThreadIdVec read_threads, |
|||
const CPU::ThreadIdVec process_threads); |
|||
void R1PP1P(const CPU::ThreadIdVec read_threads, |
|||
const CPU::ThreadIdVec process_threads); |
|||
void RPSL(const CPU::ThreadIdVec read_threads, |
|||
const CPU::ThreadIdVec process_threads); |
|||
void RPSP(const CPU::ThreadIdVec read_threads, |
|||
const CPU::ThreadIdVec process_threads); |
|||
void R1PPSP(const CPU::ThreadIdVec read_threads, |
|||
const CPU::ThreadIdVec process_threads); |
|||
void pin(const CPU::ThreadIdVec read_threads, |
|||
const CPU::ThreadIdVec process_threads, |
|||
const std::string type); |
|||
} |
2969
src/fmt/core.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,245 +0,0 @@ |
|||
// Formatting library for C++ - std::ostream support |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_OSTREAM_H_ |
|||
#define FMT_OSTREAM_H_ |
|||
|
|||
#include <fstream> // std::filebuf |
|||
|
|||
#ifdef _WIN32 |
|||
# ifdef __GLIBCXX__ |
|||
# include <ext/stdio_filebuf.h> |
|||
# include <ext/stdio_sync_filebuf.h> |
|||
# endif |
|||
# include <io.h> |
|||
#endif |
|||
|
|||
#include "format.h" |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
template <typename Streambuf> class formatbuf : public Streambuf { |
|||
private: |
|||
using char_type = typename Streambuf::char_type; |
|||
using streamsize = decltype(std::declval<Streambuf>().sputn(nullptr, 0)); |
|||
using int_type = typename Streambuf::int_type; |
|||
using traits_type = typename Streambuf::traits_type; |
|||
|
|||
buffer<char_type>& buffer_; |
|||
|
|||
public: |
|||
explicit formatbuf(buffer<char_type>& buf) : buffer_(buf) {} |
|||
|
|||
protected: |
|||
// The put area is always empty. This makes the implementation simpler and has |
|||
// the advantage that the streambuf and the buffer are always in sync and |
|||
// sputc never writes into uninitialized memory. A disadvantage is that each |
|||
// call to sputc always results in a (virtual) call to overflow. There is no |
|||
// disadvantage here for sputn since this always results in a call to xsputn. |
|||
|
|||
auto overflow(int_type ch) -> int_type override { |
|||
if (!traits_type::eq_int_type(ch, traits_type::eof())) |
|||
buffer_.push_back(static_cast<char_type>(ch)); |
|||
return ch; |
|||
} |
|||
|
|||
auto xsputn(const char_type* s, streamsize count) -> streamsize override { |
|||
buffer_.append(s, s + count); |
|||
return count; |
|||
} |
|||
}; |
|||
|
|||
// Generate a unique explicit instantion in every translation unit using a tag |
|||
// type in an anonymous namespace. |
|||
namespace { |
|||
struct file_access_tag {}; |
|||
} // namespace |
|||
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr> |
|||
class file_access { |
|||
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } |
|||
}; |
|||
|
|||
#if FMT_MSC_VERSION |
|||
template class file_access<file_access_tag, std::filebuf, |
|||
&std::filebuf::_Myfile>; |
|||
auto get_file(std::filebuf&) -> FILE*; |
|||
#endif |
|||
|
|||
inline auto write_ostream_unicode(std::ostream& os, fmt::string_view data) |
|||
-> bool { |
|||
FILE* f = nullptr; |
|||
#if FMT_MSC_VERSION |
|||
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf())) |
|||
f = get_file(*buf); |
|||
else |
|||
return false; |
|||
#elif defined(_WIN32) && defined(__GLIBCXX__) |
|||
auto* rdbuf = os.rdbuf(); |
|||
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf)) |
|||
f = sfbuf->file(); |
|||
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf)) |
|||
f = fbuf->file(); |
|||
else |
|||
return false; |
|||
#else |
|||
ignore_unused(os, data, f); |
|||
#endif |
|||
#ifdef _WIN32 |
|||
if (f) { |
|||
int fd = _fileno(f); |
|||
if (_isatty(fd)) { |
|||
os.flush(); |
|||
return write_console(fd, data); |
|||
} |
|||
} |
|||
#endif |
|||
return false; |
|||
} |
|||
inline auto write_ostream_unicode(std::wostream&, |
|||
fmt::basic_string_view<wchar_t>) -> bool { |
|||
return false; |
|||
} |
|||
|
|||
// Write the content of buf to os. |
|||
// It is a separate function rather than a part of vprint to simplify testing. |
|||
template <typename Char> |
|||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { |
|||
const Char* buf_data = buf.data(); |
|||
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type; |
|||
unsigned_streamsize size = buf.size(); |
|||
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); |
|||
do { |
|||
unsigned_streamsize n = size <= max_size ? size : max_size; |
|||
os.write(buf_data, static_cast<std::streamsize>(n)); |
|||
buf_data += n; |
|||
size -= n; |
|||
} while (size != 0); |
|||
} |
|||
|
|||
template <typename Char, typename T> |
|||
void format_value(buffer<Char>& buf, const T& value) { |
|||
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf); |
|||
auto&& output = std::basic_ostream<Char>(&format_buf); |
|||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) |
|||
output.imbue(std::locale::classic()); // The default is always unlocalized. |
|||
#endif |
|||
output << value; |
|||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit); |
|||
} |
|||
|
|||
template <typename T> struct streamed_view { |
|||
const T& value; |
|||
}; |
|||
|
|||
} // namespace detail |
|||
|
|||
// Formats an object of type T that has an overloaded ostream operator<<. |
|||
template <typename Char> |
|||
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> { |
|||
void set_debug_format() = delete; |
|||
|
|||
template <typename T, typename OutputIt> |
|||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const |
|||
-> OutputIt { |
|||
auto buffer = basic_memory_buffer<Char>(); |
|||
detail::format_value(buffer, value); |
|||
return formatter<basic_string_view<Char>, Char>::format( |
|||
{buffer.data(), buffer.size()}, ctx); |
|||
} |
|||
}; |
|||
|
|||
using ostream_formatter = basic_ostream_formatter<char>; |
|||
|
|||
template <typename T, typename Char> |
|||
struct formatter<detail::streamed_view<T>, Char> |
|||
: basic_ostream_formatter<Char> { |
|||
template <typename OutputIt> |
|||
auto format(detail::streamed_view<T> view, |
|||
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt { |
|||
return basic_ostream_formatter<Char>::format(view.value, ctx); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
\rst |
|||
Returns a view that formats `value` via an ostream ``operator<<``. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::print("Current thread id: {}\n", |
|||
fmt::streamed(std::this_thread::get_id())); |
|||
\endrst |
|||
*/ |
|||
template <typename T> |
|||
constexpr auto streamed(const T& value) -> detail::streamed_view<T> { |
|||
return {value}; |
|||
} |
|||
|
|||
namespace detail { |
|||
|
|||
inline void vprint_directly(std::ostream& os, string_view format_str, |
|||
format_args args) { |
|||
auto buffer = memory_buffer(); |
|||
detail::vformat_to(buffer, format_str, args); |
|||
detail::write_buffer(os, buffer); |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
FMT_EXPORT template <typename Char> |
|||
void vprint(std::basic_ostream<Char>& os, |
|||
basic_string_view<type_identity_t<Char>> format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) { |
|||
auto buffer = basic_memory_buffer<Char>(); |
|||
detail::vformat_to(buffer, format_str, args); |
|||
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; |
|||
detail::write_buffer(os, buffer); |
|||
} |
|||
|
|||
/** |
|||
\rst |
|||
Prints formatted data to the stream *os*. |
|||
|
|||
**Example**:: |
|||
|
|||
fmt::print(cerr, "Don't {}!", "panic"); |
|||
\endrst |
|||
*/ |
|||
FMT_EXPORT template <typename... T> |
|||
void print(std::ostream& os, format_string<T...> fmt, T&&... args) { |
|||
const auto& vargs = fmt::make_format_args(args...); |
|||
if (detail::is_utf8()) |
|||
vprint(os, fmt, vargs); |
|||
else |
|||
detail::vprint_directly(os, fmt, vargs); |
|||
} |
|||
|
|||
FMT_EXPORT |
|||
template <typename... Args> |
|||
void print(std::wostream& os, |
|||
basic_format_string<wchar_t, type_identity_t<Args>...> fmt, |
|||
Args&&... args) { |
|||
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...)); |
|||
} |
|||
|
|||
FMT_EXPORT template <typename... T> |
|||
void println(std::ostream& os, format_string<T...> fmt, T&&... args) { |
|||
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...)); |
|||
} |
|||
|
|||
FMT_EXPORT |
|||
template <typename... Args> |
|||
void println(std::wostream& os, |
|||
basic_format_string<wchar_t, type_identity_t<Args>...> fmt, |
|||
Args&&... args) { |
|||
print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...)); |
|||
} |
|||
|
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_OSTREAM_H_ |
@ -1,537 +0,0 @@ |
|||
// Formatting library for C++ - formatters for standard library types |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_STD_H_ |
|||
#define FMT_STD_H_ |
|||
|
|||
#include <atomic> |
|||
#include <bitset> |
|||
#include <cstdlib> |
|||
#include <exception> |
|||
#include <memory> |
|||
#include <thread> |
|||
#include <type_traits> |
|||
#include <typeinfo> |
|||
#include <utility> |
|||
#include <vector> |
|||
|
|||
#include "format.h" |
|||
#include "ostream.h" |
|||
|
|||
#if FMT_HAS_INCLUDE(<version>) |
|||
# include <version> |
|||
#endif |
|||
// Checking FMT_CPLUSPLUS for warning suppression in MSVC. |
|||
#if FMT_CPLUSPLUS >= 201703L |
|||
# if FMT_HAS_INCLUDE(<filesystem>) |
|||
# include <filesystem> |
|||
# endif |
|||
# if FMT_HAS_INCLUDE(<variant>) |
|||
# include <variant> |
|||
# endif |
|||
# if FMT_HAS_INCLUDE(<optional>) |
|||
# include <optional> |
|||
# endif |
|||
#endif |
|||
|
|||
#if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>) |
|||
# include <source_location> |
|||
#endif |
|||
|
|||
// GCC 4 does not support FMT_HAS_INCLUDE. |
|||
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__) |
|||
# include <cxxabi.h> |
|||
// Android NDK with gabi++ library on some architectures does not implement |
|||
// abi::__cxa_demangle(). |
|||
# ifndef __GABIXX_CXXABI_H__ |
|||
# define FMT_HAS_ABI_CXA_DEMANGLE |
|||
# endif |
|||
#endif |
|||
|
|||
// Check if typeid is available. |
|||
#ifndef FMT_USE_TYPEID |
|||
// __RTTI is for EDG compilers. In MSVC typeid is available without RTTI. |
|||
# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \ |
|||
defined(__INTEL_RTTI__) || defined(__RTTI) |
|||
# define FMT_USE_TYPEID 1 |
|||
# else |
|||
# define FMT_USE_TYPEID 0 |
|||
# endif |
|||
#endif |
|||
|
|||
// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined. |
|||
#ifndef FMT_CPP_LIB_FILESYSTEM |
|||
# ifdef __cpp_lib_filesystem |
|||
# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem |
|||
# else |
|||
# define FMT_CPP_LIB_FILESYSTEM 0 |
|||
# endif |
|||
#endif |
|||
|
|||
#ifndef FMT_CPP_LIB_VARIANT |
|||
# ifdef __cpp_lib_variant |
|||
# define FMT_CPP_LIB_VARIANT __cpp_lib_variant |
|||
# else |
|||
# define FMT_CPP_LIB_VARIANT 0 |
|||
# endif |
|||
#endif |
|||
|
|||
#if FMT_CPP_LIB_FILESYSTEM |
|||
FMT_BEGIN_NAMESPACE |
|||
|
|||
namespace detail { |
|||
|
|||
template <typename Char, typename PathChar> |
|||
auto get_path_string(const std::filesystem::path& p, |
|||
const std::basic_string<PathChar>& native) { |
|||
if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>) |
|||
return to_utf8<wchar_t>(native, to_utf8_error_policy::replace); |
|||
else |
|||
return p.string<Char>(); |
|||
} |
|||
|
|||
template <typename Char, typename PathChar> |
|||
void write_escaped_path(basic_memory_buffer<Char>& quoted, |
|||
const std::filesystem::path& p, |
|||
const std::basic_string<PathChar>& native) { |
|||
if constexpr (std::is_same_v<Char, char> && |
|||
std::is_same_v<PathChar, wchar_t>) { |
|||
auto buf = basic_memory_buffer<wchar_t>(); |
|||
write_escaped_string<wchar_t>(std::back_inserter(buf), native); |
|||
bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}); |
|||
FMT_ASSERT(valid, "invalid utf16"); |
|||
} else if constexpr (std::is_same_v<Char, PathChar>) { |
|||
write_escaped_string<std::filesystem::path::value_type>( |
|||
std::back_inserter(quoted), native); |
|||
} else { |
|||
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>()); |
|||
} |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
FMT_EXPORT |
|||
template <typename Char> struct formatter<std::filesystem::path, Char> { |
|||
private: |
|||
format_specs<Char> specs_; |
|||
detail::arg_ref<Char> width_ref_; |
|||
bool debug_ = false; |
|||
char path_type_ = 0; |
|||
|
|||
public: |
|||
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } |
|||
|
|||
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { |
|||
auto it = ctx.begin(), end = ctx.end(); |
|||
if (it == end) return it; |
|||
|
|||
it = detail::parse_align(it, end, specs_); |
|||
if (it == end) return it; |
|||
|
|||
it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); |
|||
if (it != end && *it == '?') { |
|||
debug_ = true; |
|||
++it; |
|||
} |
|||
if (it != end && (*it == 'g')) path_type_ = *it++; |
|||
return it; |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::filesystem::path& p, FormatContext& ctx) const { |
|||
auto specs = specs_; |
|||
# ifdef _WIN32 |
|||
auto path_string = !path_type_ ? p.native() : p.generic_wstring(); |
|||
# else |
|||
auto path_string = !path_type_ ? p.native() : p.generic_string(); |
|||
# endif |
|||
|
|||
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_, |
|||
ctx); |
|||
if (!debug_) { |
|||
auto s = detail::get_path_string<Char>(p, path_string); |
|||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs); |
|||
} |
|||
auto quoted = basic_memory_buffer<Char>(); |
|||
detail::write_escaped_path(quoted, p, path_string); |
|||
return detail::write(ctx.out(), |
|||
basic_string_view<Char>(quoted.data(), quoted.size()), |
|||
specs); |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif // FMT_CPP_LIB_FILESYSTEM |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
FMT_EXPORT |
|||
template <std::size_t N, typename Char> |
|||
struct formatter<std::bitset<N>, Char> : nested_formatter<string_view> { |
|||
private: |
|||
// Functor because C++11 doesn't support generic lambdas. |
|||
struct writer { |
|||
const std::bitset<N>& bs; |
|||
|
|||
template <typename OutputIt> |
|||
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { |
|||
for (auto pos = N; pos > 0; --pos) { |
|||
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0')); |
|||
} |
|||
|
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
public: |
|||
template <typename FormatContext> |
|||
auto format(const std::bitset<N>& bs, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return write_padded(ctx, writer{bs}); |
|||
} |
|||
}; |
|||
|
|||
FMT_EXPORT |
|||
template <typename Char> |
|||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {}; |
|||
FMT_END_NAMESPACE |
|||
|
|||
#ifdef __cpp_lib_optional |
|||
FMT_BEGIN_NAMESPACE |
|||
FMT_EXPORT |
|||
template <typename T, typename Char> |
|||
struct formatter<std::optional<T>, Char, |
|||
std::enable_if_t<is_formattable<T, Char>::value>> { |
|||
private: |
|||
formatter<T, Char> underlying_; |
|||
static constexpr basic_string_view<Char> optional = |
|||
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l', |
|||
'('>{}; |
|||
static constexpr basic_string_view<Char> none = |
|||
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{}; |
|||
|
|||
template <class U> |
|||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) |
|||
-> decltype(u.set_debug_format(set)) { |
|||
u.set_debug_format(set); |
|||
} |
|||
|
|||
template <class U> |
|||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} |
|||
|
|||
public: |
|||
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { |
|||
maybe_set_debug_format(underlying_, true); |
|||
return underlying_.parse(ctx); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::optional<T>& opt, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
if (!opt) return detail::write<Char>(ctx.out(), none); |
|||
|
|||
auto out = ctx.out(); |
|||
out = detail::write<Char>(out, optional); |
|||
ctx.advance_to(out); |
|||
out = underlying_.format(*opt, ctx); |
|||
return detail::write(out, ')'); |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif // __cpp_lib_optional |
|||
|
|||
#ifdef __cpp_lib_source_location |
|||
FMT_BEGIN_NAMESPACE |
|||
FMT_EXPORT |
|||
template <> struct formatter<std::source_location> { |
|||
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::source_location& loc, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
out = detail::write(out, loc.file_name()); |
|||
out = detail::write(out, ':'); |
|||
out = detail::write<char>(out, loc.line()); |
|||
out = detail::write(out, ':'); |
|||
out = detail::write<char>(out, loc.column()); |
|||
out = detail::write(out, ": "); |
|||
out = detail::write(out, loc.function_name()); |
|||
return out; |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif |
|||
|
|||
#if FMT_CPP_LIB_VARIANT |
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
template <typename T> |
|||
using variant_index_sequence = |
|||
std::make_index_sequence<std::variant_size<T>::value>; |
|||
|
|||
template <typename> struct is_variant_like_ : std::false_type {}; |
|||
template <typename... Types> |
|||
struct is_variant_like_<std::variant<Types...>> : std::true_type {}; |
|||
|
|||
// formattable element check. |
|||
template <typename T, typename C> class is_variant_formattable_ { |
|||
template <std::size_t... Is> |
|||
static std::conjunction< |
|||
is_formattable<std::variant_alternative_t<Is, T>, C>...> |
|||
check(std::index_sequence<Is...>); |
|||
|
|||
public: |
|||
static constexpr const bool value = |
|||
decltype(check(variant_index_sequence<T>{}))::value; |
|||
}; |
|||
|
|||
template <typename Char, typename OutputIt, typename T> |
|||
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { |
|||
if constexpr (is_string<T>::value) |
|||
return write_escaped_string<Char>(out, detail::to_string_view(v)); |
|||
else if constexpr (std::is_same_v<T, Char>) |
|||
return write_escaped_char(out, v); |
|||
else |
|||
return write<Char>(out, v); |
|||
} |
|||
|
|||
} // namespace detail |
|||
|
|||
template <typename T> struct is_variant_like { |
|||
static constexpr const bool value = detail::is_variant_like_<T>::value; |
|||
}; |
|||
|
|||
template <typename T, typename C> struct is_variant_formattable { |
|||
static constexpr const bool value = |
|||
detail::is_variant_formattable_<T, C>::value; |
|||
}; |
|||
|
|||
FMT_EXPORT |
|||
template <typename Char> struct formatter<std::monostate, Char> { |
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const std::monostate&, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return detail::write<Char>(ctx.out(), "monostate"); |
|||
} |
|||
}; |
|||
|
|||
FMT_EXPORT |
|||
template <typename Variant, typename Char> |
|||
struct formatter< |
|||
Variant, Char, |
|||
std::enable_if_t<std::conjunction_v< |
|||
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> { |
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
auto format(const Variant& value, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
|
|||
out = detail::write<Char>(out, "variant("); |
|||
FMT_TRY { |
|||
std::visit( |
|||
[&](const auto& v) { |
|||
out = detail::write_variant_alternative<Char>(out, v); |
|||
}, |
|||
value); |
|||
} |
|||
FMT_CATCH(const std::bad_variant_access&) { |
|||
detail::write<Char>(out, "valueless by exception"); |
|||
} |
|||
*out++ = ')'; |
|||
return out; |
|||
} |
|||
}; |
|||
FMT_END_NAMESPACE |
|||
#endif // FMT_CPP_LIB_VARIANT |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
FMT_EXPORT |
|||
template <typename Char> struct formatter<std::error_code, Char> { |
|||
template <typename ParseContext> |
|||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { |
|||
return ctx.begin(); |
|||
} |
|||
|
|||
template <typename FormatContext> |
|||
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
auto out = ctx.out(); |
|||
out = detail::write_bytes(out, ec.category().name(), format_specs<Char>()); |
|||
out = detail::write<Char>(out, Char(':')); |
|||
out = detail::write<Char>(out, ec.value()); |
|||
return out; |
|||
} |
|||
}; |
|||
|
|||
FMT_EXPORT |
|||
template <typename T, typename Char> |
|||
struct formatter< |
|||
T, Char, // DEPRECATED! Mixing code unit types. |
|||
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> { |
|||
private: |
|||
bool with_typename_ = false; |
|||
|
|||
public: |
|||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx) |
|||
-> decltype(ctx.begin()) { |
|||
auto it = ctx.begin(); |
|||
auto end = ctx.end(); |
|||
if (it == end || *it == '}') return it; |
|||
if (*it == 't') { |
|||
++it; |
|||
with_typename_ = FMT_USE_TYPEID != 0; |
|||
} |
|||
return it; |
|||
} |
|||
|
|||
template <typename OutputIt> |
|||
auto format(const std::exception& ex, |
|||
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt { |
|||
format_specs<Char> spec; |
|||
auto out = ctx.out(); |
|||
if (!with_typename_) |
|||
return detail::write_bytes(out, string_view(ex.what()), spec); |
|||
|
|||
#if FMT_USE_TYPEID |
|||
const std::type_info& ti = typeid(ex); |
|||
# ifdef FMT_HAS_ABI_CXA_DEMANGLE |
|||
int status = 0; |
|||
std::size_t size = 0; |
|||
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr( |
|||
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); |
|||
|
|||
string_view demangled_name_view; |
|||
if (demangled_name_ptr) { |
|||
demangled_name_view = demangled_name_ptr.get(); |
|||
|
|||
// Normalization of stdlib inline namespace names. |
|||
// libc++ inline namespaces. |
|||
// std::__1::* -> std::* |
|||
// std::__1::__fs::* -> std::* |
|||
// libstdc++ inline namespaces. |
|||
// std::__cxx11::* -> std::* |
|||
// std::filesystem::__cxx11::* -> std::filesystem::* |
|||
if (demangled_name_view.starts_with("std::")) { |
|||
char* begin = demangled_name_ptr.get(); |
|||
char* to = begin + 5; // std:: |
|||
for (char *from = to, *end = begin + demangled_name_view.size(); |
|||
from < end;) { |
|||
// This is safe, because demangled_name is NUL-terminated. |
|||
if (from[0] == '_' && from[1] == '_') { |
|||
char* next = from + 1; |
|||
while (next < end && *next != ':') next++; |
|||
if (next[0] == ':' && next[1] == ':') { |
|||
from = next + 2; |
|||
continue; |
|||
} |
|||
} |
|||
*to++ = *from++; |
|||
} |
|||
demangled_name_view = {begin, detail::to_unsigned(to - begin)}; |
|||
} |
|||
} else { |
|||
demangled_name_view = string_view(ti.name()); |
|||
} |
|||
out = detail::write_bytes(out, demangled_name_view, spec); |
|||
# elif FMT_MSC_VERSION |
|||
string_view demangled_name_view(ti.name()); |
|||
if (demangled_name_view.starts_with("class ")) |
|||
demangled_name_view.remove_prefix(6); |
|||
else if (demangled_name_view.starts_with("struct ")) |
|||
demangled_name_view.remove_prefix(7); |
|||
out = detail::write_bytes(out, demangled_name_view, spec); |
|||
# else |
|||
out = detail::write_bytes(out, string_view(ti.name()), spec); |
|||
# endif |
|||
*out++ = ':'; |
|||
*out++ = ' '; |
|||
return detail::write_bytes(out, string_view(ex.what()), spec); |
|||
#endif |
|||
} |
|||
}; |
|||
|
|||
namespace detail { |
|||
|
|||
template <typename T, typename Enable = void> |
|||
struct has_flip : std::false_type {}; |
|||
|
|||
template <typename T> |
|||
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>> |
|||
: std::true_type {}; |
|||
|
|||
template <typename T> struct is_bit_reference_like { |
|||
static constexpr const bool value = |
|||
std::is_convertible<T, bool>::value && |
|||
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value; |
|||
}; |
|||
|
|||
#ifdef _LIBCPP_VERSION |
|||
|
|||
// Workaround for libc++ incompatibility with C++ standard. |
|||
// According to the Standard, `bitset::operator[] const` returns bool. |
|||
template <typename C> |
|||
struct is_bit_reference_like<std::__bit_const_reference<C>> { |
|||
static constexpr const bool value = true; |
|||
}; |
|||
|
|||
#endif |
|||
|
|||
} // namespace detail |
|||
|
|||
// We can't use std::vector<bool, Allocator>::reference and |
|||
// std::bitset<N>::reference because the compiler can't deduce Allocator and N |
|||
// in partial specialization. |
|||
FMT_EXPORT |
|||
template <typename BitRef, typename Char> |
|||
struct formatter<BitRef, Char, |
|||
enable_if_t<detail::is_bit_reference_like<BitRef>::value>> |
|||
: formatter<bool, Char> { |
|||
template <typename FormatContext> |
|||
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return formatter<bool, Char>::format(v, ctx); |
|||
} |
|||
}; |
|||
|
|||
FMT_EXPORT |
|||
template <typename T, typename Char> |
|||
struct formatter<std::atomic<T>, Char, |
|||
enable_if_t<is_formattable<T, Char>::value>> |
|||
: formatter<T, Char> { |
|||
template <typename FormatContext> |
|||
auto format(const std::atomic<T>& v, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return formatter<T, Char>::format(v.load(), ctx); |
|||
} |
|||
}; |
|||
|
|||
#ifdef __cpp_lib_atomic_flag_test |
|||
FMT_EXPORT |
|||
template <typename Char> |
|||
struct formatter<std::atomic_flag, Char> : formatter<bool, Char> { |
|||
template <typename FormatContext> |
|||
auto format(const std::atomic_flag& v, FormatContext& ctx) const |
|||
-> decltype(ctx.out()) { |
|||
return formatter<bool, Char>::format(v.test(), ctx); |
|||
} |
|||
}; |
|||
#endif // __cpp_lib_atomic_flag_test |
|||
|
|||
FMT_END_NAMESPACE |
|||
#endif // FMT_STD_H_ |
@ -1,259 +0,0 @@ |
|||
// Formatting library for C++ - optional wchar_t and exotic character support |
|||
// |
|||
// Copyright (c) 2012 - present, Victor Zverovich |
|||
// All rights reserved. |
|||
// |
|||
// For the license information refer to format.h. |
|||
|
|||
#ifndef FMT_XCHAR_H_ |
|||
#define FMT_XCHAR_H_ |
|||
|
|||
#include <cwchar> |
|||
|
|||
#include "format.h" |
|||
|
|||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR |
|||
# include <locale> |
|||
#endif |
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
template <typename T> |
|||
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; |
|||
|
|||
inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out, |
|||
loc_value value, const format_specs<wchar_t>& specs, |
|||
locale_ref loc) -> bool { |
|||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR |
|||
auto& numpunct = |
|||
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>()); |
|||
auto separator = std::wstring(); |
|||
auto grouping = numpunct.grouping(); |
|||
if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); |
|||
return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}}); |
|||
#endif |
|||
return false; |
|||
} |
|||
} // namespace detail |
|||
|
|||
FMT_BEGIN_EXPORT |
|||
|
|||
using wstring_view = basic_string_view<wchar_t>; |
|||
using wformat_parse_context = basic_format_parse_context<wchar_t>; |
|||
using wformat_context = buffer_context<wchar_t>; |
|||
using wformat_args = basic_format_args<wformat_context>; |
|||
using wmemory_buffer = basic_memory_buffer<wchar_t>; |
|||
|
|||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 |
|||
// Workaround broken conversion on older gcc. |
|||
template <typename... Args> using wformat_string = wstring_view; |
|||
inline auto runtime(wstring_view s) -> wstring_view { return s; } |
|||
#else |
|||
template <typename... Args> |
|||
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>; |
|||
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> { |
|||
return {{s}}; |
|||
} |
|||
#endif |
|||
|
|||
template <> struct is_char<wchar_t> : std::true_type {}; |
|||
template <> struct is_char<detail::char8_type> : std::true_type {}; |
|||
template <> struct is_char<char16_t> : std::true_type {}; |
|||
template <> struct is_char<char32_t> : std::true_type {}; |
|||
|
|||
template <typename... T> |
|||
constexpr auto make_wformat_args(const T&... args) |
|||
-> format_arg_store<wformat_context, T...> { |
|||
return {args...}; |
|||
} |
|||
|
|||
inline namespace literals { |
|||
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS |
|||
constexpr auto operator""_a(const wchar_t* s, size_t) |
|||
-> detail::udl_arg<wchar_t> { |
|||
return {s}; |
|||
} |
|||
#endif |
|||
} // namespace literals |
|||
|
|||
template <typename It, typename Sentinel> |
|||
auto join(It begin, Sentinel end, wstring_view sep) |
|||
-> join_view<It, Sentinel, wchar_t> { |
|||
return {begin, end, sep}; |
|||
} |
|||
|
|||
template <typename Range> |
|||
auto join(Range&& range, wstring_view sep) |
|||
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>, |
|||
wchar_t> { |
|||
return join(std::begin(range), std::end(range), sep); |
|||
} |
|||
|
|||
template <typename T> |
|||
auto join(std::initializer_list<T> list, wstring_view sep) |
|||
-> join_view<const T*, const T*, wchar_t> { |
|||
return join(std::begin(list), std::end(list), sep); |
|||
} |
|||
|
|||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> |
|||
auto vformat(basic_string_view<Char> format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) |
|||
-> std::basic_string<Char> { |
|||
auto buf = basic_memory_buffer<Char>(); |
|||
detail::vformat_to(buf, format_str, args); |
|||
return to_string(buf); |
|||
} |
|||
|
|||
template <typename... T> |
|||
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring { |
|||
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
// Pass char_t as a default template parameter instead of using |
|||
// std::basic_string<char_t<S>> to reduce the symbol size. |
|||
template <typename S, typename... T, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(!std::is_same<Char, char>::value && |
|||
!std::is_same<Char, wchar_t>::value)> |
|||
auto format(const S& format_str, T&&... args) -> std::basic_string<Char> { |
|||
return vformat(detail::to_string_view(format_str), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename Locale, typename S, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat( |
|||
const Locale& loc, const S& format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) |
|||
-> std::basic_string<Char> { |
|||
return detail::vformat(loc, detail::to_string_view(format_str), args); |
|||
} |
|||
|
|||
template <typename Locale, typename S, typename... T, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto format(const Locale& loc, const S& format_str, T&&... args) |
|||
-> std::basic_string<Char> { |
|||
return detail::vformat(loc, detail::to_string_view(format_str), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
auto vformat_to(OutputIt out, const S& format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) |
|||
-> OutputIt { |
|||
auto&& buf = detail::get_buffer<Char>(out); |
|||
detail::vformat_to(buf, detail::to_string_view(format_str), args); |
|||
return detail::get_iterator(buf, out); |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename... T, |
|||
typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { |
|||
return vformat_to(out, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename Locale, typename S, typename OutputIt, typename... Args, |
|||
typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_locale<Locale>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat_to( |
|||
OutputIt out, const Locale& loc, const S& format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt { |
|||
auto&& buf = detail::get_buffer<Char>(out); |
|||
vformat_to(buf, detail::to_string_view(format_str), args, |
|||
detail::locale_ref(loc)); |
|||
return detail::get_iterator(buf, out); |
|||
} |
|||
|
|||
template <typename OutputIt, typename Locale, typename S, typename... T, |
|||
typename Char = char_t<S>, |
|||
bool enable = detail::is_output_iterator<OutputIt, Char>::value && |
|||
detail::is_locale<Locale>::value && |
|||
detail::is_exotic_char<Char>::value> |
|||
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, |
|||
T&&... args) -> |
|||
typename std::enable_if<enable, OutputIt>::type { |
|||
return vformat_to(out, loc, detail::to_string_view(format_str), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename OutputIt, typename Char, typename... Args, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto vformat_to_n( |
|||
OutputIt out, size_t n, basic_string_view<Char> format_str, |
|||
basic_format_args<buffer_context<type_identity_t<Char>>> args) |
|||
-> format_to_n_result<OutputIt> { |
|||
using traits = detail::fixed_buffer_traits; |
|||
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n); |
|||
detail::vformat_to(buf, format_str, args); |
|||
return {buf.out(), buf.count()}; |
|||
} |
|||
|
|||
template <typename OutputIt, typename S, typename... T, |
|||
typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& |
|||
detail::is_exotic_char<Char>::value)> |
|||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) |
|||
-> format_to_n_result<OutputIt> { |
|||
return vformat_to_n(out, n, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
} |
|||
|
|||
template <typename S, typename... T, typename Char = char_t<S>, |
|||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> |
|||
inline auto formatted_size(const S& fmt, T&&... args) -> size_t { |
|||
auto buf = detail::counting_buffer<Char>(); |
|||
detail::vformat_to(buf, detail::to_string_view(fmt), |
|||
fmt::make_format_args<buffer_context<Char>>(args...)); |
|||
return buf.count(); |
|||
} |
|||
|
|||
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { |
|||
auto buf = wmemory_buffer(); |
|||
detail::vformat_to(buf, fmt, args); |
|||
buf.push_back(L'\0'); |
|||
if (std::fputws(buf.data(), f) == -1) |
|||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); |
|||
} |
|||
|
|||
inline void vprint(wstring_view fmt, wformat_args args) { |
|||
vprint(stdout, fmt, args); |
|||
} |
|||
|
|||
template <typename... T> |
|||
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { |
|||
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { |
|||
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); |
|||
} |
|||
|
|||
template <typename... T> |
|||
void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) { |
|||
return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); |
|||
} |
|||
|
|||
template <typename... T> void println(wformat_string<T...> fmt, T&&... args) { |
|||
return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); |
|||
} |
|||
|
|||
/** |
|||
Converts *value* to ``std::wstring`` using the default format for type *T*. |
|||
*/ |
|||
template <typename T> inline auto to_wstring(const T& value) -> std::wstring { |
|||
return format(FMT_STRING(L"{}"), value); |
|||
} |
|||
FMT_END_EXPORT |
|||
FMT_END_NAMESPACE |
|||
|
|||
#endif // FMT_XCHAR_H_ |
@ -1,43 +0,0 @@ |
|||
// Formatting library for C++
|
|||
//
|
|||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
|||
// All rights reserved.
|
|||
//
|
|||
// For the license information refer to format.h.
|
|||
|
|||
#include "fmt/format-inl.h"
|
|||
|
|||
FMT_BEGIN_NAMESPACE |
|||
namespace detail { |
|||
|
|||
template FMT_API auto dragonbox::to_decimal(float x) noexcept |
|||
-> dragonbox::decimal_fp<float>; |
|||
template FMT_API auto dragonbox::to_decimal(double x) noexcept |
|||
-> dragonbox::decimal_fp<double>; |
|||
|
|||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
|||
template FMT_API locale_ref::locale_ref(const std::locale& loc); |
|||
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale; |
|||
#endif
|
|||
|
|||
// Explicit instantiations for char.
|
|||
|
|||
template FMT_API auto thousands_sep_impl(locale_ref) |
|||
-> thousands_sep_result<char>; |
|||
template FMT_API auto decimal_point_impl(locale_ref) -> char; |
|||
|
|||
template FMT_API void buffer<char>::append(const char*, const char*); |
|||
|
|||
template FMT_API void vformat_to(buffer<char>&, string_view, |
|||
typename vformat_args<>::type, locale_ref); |
|||
|
|||
// Explicit instantiations for wchar_t.
|
|||
|
|||
template FMT_API auto thousands_sep_impl(locale_ref) |
|||
-> thousands_sep_result<wchar_t>; |
|||
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; |
|||
|
|||
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*); |
|||
|
|||
} // namespace detail
|
|||
FMT_END_NAMESPACE |
@ -1,112 +0,0 @@ |
|||
/*
|
|||
ISC License |
|||
|
|||
Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link> |
|||
|
|||
Permission to use, copy, modify, and/or distribute this software for any |
|||
purpose with or without fee is hereby granted, provided that the above |
|||
copyright notice and this permission notice appear in all copies. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
*/ |
|||
|
|||
#include <stdarg.h>
|
|||
#include <syslog.h>
|
|||
|
|||
|
|||
void |
|||
syslog_open() |
|||
{ |
|||
const char *ident = "mergerfs"; |
|||
const int option = (LOG_CONS|LOG_PID); |
|||
const int facility = LOG_USER; |
|||
|
|||
openlog(ident,option,facility); |
|||
} |
|||
|
|||
void |
|||
syslog_close() |
|||
{ |
|||
closelog(); |
|||
} |
|||
|
|||
void |
|||
syslog_log(const int priority_, |
|||
const char *format_, |
|||
va_list valist_) |
|||
{ |
|||
vsyslog(priority_,format_,valist_); |
|||
} |
|||
|
|||
void |
|||
syslog_log(const int priority_, |
|||
const char *format_, |
|||
...) |
|||
{ |
|||
va_list valist; |
|||
|
|||
va_start(valist,format_); |
|||
syslog_log(priority_,format_,valist); |
|||
va_end(valist); |
|||
} |
|||
|
|||
void |
|||
syslog_debug(const char *format_, |
|||
...) |
|||
{ |
|||
va_list valist; |
|||
|
|||
va_start(valist,format_); |
|||
syslog_log(LOG_DEBUG,format_,valist); |
|||
va_end(valist); |
|||
} |
|||
|
|||
void |
|||
syslog_info(const char *format_, |
|||
...) |
|||
{ |
|||
va_list valist; |
|||
|
|||
va_start(valist,format_); |
|||
syslog_log(LOG_INFO,format_,valist); |
|||
va_end(valist); |
|||
} |
|||
|
|||
void |
|||
syslog_notice(const char *format_, |
|||
...) |
|||
{ |
|||
va_list valist; |
|||
|
|||
va_start(valist,format_); |
|||
syslog_log(LOG_NOTICE,format_,valist); |
|||
va_end(valist); |
|||
} |
|||
|
|||
void |
|||
syslog_warning(const char *format_, |
|||
...) |
|||
{ |
|||
va_list valist; |
|||
|
|||
va_start(valist,format_); |
|||
syslog_log(LOG_WARNING,format_,valist); |
|||
va_end(valist); |
|||
} |
|||
|
|||
void |
|||
syslog_error(const char *format_, |
|||
...) |
|||
{ |
|||
va_list valist; |
|||
|
|||
va_start(valist,format_); |
|||
syslog_log(LOG_ERR,format_,valist); |
|||
va_end(valist); |
|||
} |
@ -1,31 +0,0 @@ |
|||
/*
|
|||
ISC License |
|||
|
|||
Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link> |
|||
|
|||
Permission to use, copy, modify, and/or distribute this software for any |
|||
purpose with or without fee is hereby granted, provided that the above |
|||
copyright notice and this permission notice appear in all copies. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
*/ |
|||
|
|||
#pragma once
|
|||
|
|||
#include <syslog.h>
|
|||
|
|||
|
|||
void syslog_open(); |
|||
void syslog_log(const int priority, const char *format, ...); |
|||
void syslog_debug(const char *format, ...); |
|||
void syslog_info(const char *format, ...); |
|||
void syslog_notice(const char *format, ...); |
|||
void syslog_warning(const char *format, ...); |
|||
void syslog_error(const char *format, ...); |
|||
void syslog_close(); |
Write
Preview
Loading…
Cancel
Save
Reference in new issue