├── README.md ├── hello.cc ├── .gitignore ├── Makefile ├── LICENSE └── ext └── fmt-10.1.1 ├── src ├── format.cc └── os.cc └── include └── fmt ├── ostream.h ├── args.h ├── xchar.h ├── os.h ├── std.h ├── compile.h ├── printf.h ├── color.h └── ranges.h /README.md: -------------------------------------------------------------------------------- 1 | # code-tour 2 | a tour of the components of a software project 3 | -------------------------------------------------------------------------------- /hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // (C) 2023 AHU Holding BV 5 | 6 | int main() { 7 | std::vector v = {1, 2, 3}; 8 | 9 | // print contents 10 | fmt::print("{}\n", v); 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | FMTPATH=ext/fmt-10.1.1 2 | CXXFLAGS?=-Wall -ggdb -std=c++17 -O2 -MMD -I ${FMTPATH}/include 3 | CFLAGS?= ${CXXFLAGS} 4 | LDFLAGS = -pthread 5 | LIBS= 6 | 7 | PROGRAMS= hello 8 | 9 | all: $(PROGRAMS) 10 | 11 | -include *.d 12 | 13 | hello: hello.o ${FMTPATH}/src/format.o ${FMTPATH}/src/os.o 14 | g++ ${LDFLAGS} $^ -o $@ 15 | 16 | clean: 17 | rm -f *~ $(PROGRAMS) *.o *.d 18 | rm ${FMTPATH}/src/format.o ${FMTPATH}/src/os.o 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 bert hubert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/src/format.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #include "fmt/format-inl.h" 9 | 10 | FMT_BEGIN_NAMESPACE 11 | namespace detail { 12 | 13 | template FMT_API auto dragonbox::to_decimal(float x) noexcept 14 | -> dragonbox::decimal_fp; 15 | template FMT_API auto dragonbox::to_decimal(double x) noexcept 16 | -> dragonbox::decimal_fp; 17 | 18 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 19 | template FMT_API locale_ref::locale_ref(const std::locale& loc); 20 | template FMT_API auto locale_ref::get() const -> std::locale; 21 | #endif 22 | 23 | // Explicit instantiations for char. 24 | 25 | template FMT_API auto thousands_sep_impl(locale_ref) 26 | -> thousands_sep_result; 27 | template FMT_API auto decimal_point_impl(locale_ref) -> char; 28 | 29 | template FMT_API void buffer::append(const char*, const char*); 30 | 31 | template FMT_API void vformat_to(buffer&, string_view, 32 | typename vformat_args<>::type, locale_ref); 33 | 34 | // Explicit instantiations for wchar_t. 35 | 36 | template FMT_API auto thousands_sep_impl(locale_ref) 37 | -> thousands_sep_result; 38 | template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; 39 | 40 | template FMT_API void buffer::append(const wchar_t*, const wchar_t*); 41 | 42 | } // namespace detail 43 | FMT_END_NAMESPACE 44 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #include // std::filebuf 12 | 13 | #if defined(_WIN32) && defined(__GLIBCXX__) 14 | # include 15 | # include 16 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 17 | # include <__std_stream> 18 | #endif 19 | 20 | #include "format.h" 21 | 22 | FMT_BEGIN_NAMESPACE 23 | 24 | namespace detail { 25 | 26 | // Generate a unique explicit instantion in every translation unit using a tag 27 | // type in an anonymous namespace. 28 | namespace { 29 | struct file_access_tag {}; 30 | } // namespace 31 | template 32 | class file_access { 33 | friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } 34 | }; 35 | 36 | #if FMT_MSC_VERSION 37 | template class file_access; 39 | auto get_file(std::filebuf&) -> FILE*; 40 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 41 | template class file_access, 42 | &std::__stdoutbuf::__file_>; 43 | auto get_file(std::__stdoutbuf&) -> FILE*; 44 | #endif 45 | 46 | inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) { 47 | #if FMT_MSC_VERSION 48 | if (auto* buf = dynamic_cast(os.rdbuf())) 49 | if (FILE* f = get_file(*buf)) return write_console(f, data); 50 | #elif defined(_WIN32) && defined(__GLIBCXX__) 51 | auto* rdbuf = os.rdbuf(); 52 | FILE* c_file; 53 | if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) 54 | c_file = sfbuf->file(); 55 | else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) 56 | c_file = fbuf->file(); 57 | else 58 | return false; 59 | if (c_file) return write_console(c_file, data); 60 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 61 | if (auto* buf = dynamic_cast*>(os.rdbuf())) 62 | if (FILE* f = get_file(*buf)) return write_console(f, data); 63 | #else 64 | ignore_unused(os, data); 65 | #endif 66 | return false; 67 | } 68 | inline bool write_ostream_unicode(std::wostream&, 69 | fmt::basic_string_view) { 70 | return false; 71 | } 72 | 73 | // Write the content of buf to os. 74 | // It is a separate function rather than a part of vprint to simplify testing. 75 | template 76 | void write_buffer(std::basic_ostream& os, buffer& buf) { 77 | const Char* buf_data = buf.data(); 78 | using unsigned_streamsize = std::make_unsigned::type; 79 | unsigned_streamsize size = buf.size(); 80 | unsigned_streamsize max_size = to_unsigned(max_value()); 81 | do { 82 | unsigned_streamsize n = size <= max_size ? size : max_size; 83 | os.write(buf_data, static_cast(n)); 84 | buf_data += n; 85 | size -= n; 86 | } while (size != 0); 87 | } 88 | 89 | template 90 | void format_value(buffer& buf, const T& value, 91 | locale_ref loc = locale_ref()) { 92 | auto&& format_buf = formatbuf>(buf); 93 | auto&& output = std::basic_ostream(&format_buf); 94 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 95 | if (loc) output.imbue(loc.get()); 96 | #endif 97 | output << value; 98 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 99 | } 100 | 101 | template struct streamed_view { const T& value; }; 102 | 103 | } // namespace detail 104 | 105 | // Formats an object of type T that has an overloaded ostream operator<<. 106 | template 107 | struct basic_ostream_formatter : formatter, Char> { 108 | void set_debug_format() = delete; 109 | 110 | template 111 | auto format(const T& value, basic_format_context& ctx) const 112 | -> OutputIt { 113 | auto buffer = basic_memory_buffer(); 114 | detail::format_value(buffer, value, ctx.locale()); 115 | return formatter, Char>::format( 116 | {buffer.data(), buffer.size()}, ctx); 117 | } 118 | }; 119 | 120 | using ostream_formatter = basic_ostream_formatter; 121 | 122 | template 123 | struct formatter, Char> 124 | : basic_ostream_formatter { 125 | template 126 | auto format(detail::streamed_view view, 127 | basic_format_context& ctx) const -> OutputIt { 128 | return basic_ostream_formatter::format(view.value, ctx); 129 | } 130 | }; 131 | 132 | /** 133 | \rst 134 | Returns a view that formats `value` via an ostream ``operator<<``. 135 | 136 | **Example**:: 137 | 138 | fmt::print("Current thread id: {}\n", 139 | fmt::streamed(std::this_thread::get_id())); 140 | \endrst 141 | */ 142 | template 143 | auto streamed(const T& value) -> detail::streamed_view { 144 | return {value}; 145 | } 146 | 147 | namespace detail { 148 | 149 | inline void vprint_directly(std::ostream& os, string_view format_str, 150 | format_args args) { 151 | auto buffer = memory_buffer(); 152 | detail::vformat_to(buffer, format_str, args); 153 | detail::write_buffer(os, buffer); 154 | } 155 | 156 | } // namespace detail 157 | 158 | FMT_EXPORT template 159 | void vprint(std::basic_ostream& os, 160 | basic_string_view> format_str, 161 | basic_format_args>> args) { 162 | auto buffer = basic_memory_buffer(); 163 | detail::vformat_to(buffer, format_str, args); 164 | if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; 165 | detail::write_buffer(os, buffer); 166 | } 167 | 168 | /** 169 | \rst 170 | Prints formatted data to the stream *os*. 171 | 172 | **Example**:: 173 | 174 | fmt::print(cerr, "Don't {}!", "panic"); 175 | \endrst 176 | */ 177 | FMT_EXPORT template 178 | void print(std::ostream& os, format_string fmt, T&&... args) { 179 | const auto& vargs = fmt::make_format_args(args...); 180 | if (detail::is_utf8()) 181 | vprint(os, fmt, vargs); 182 | else 183 | detail::vprint_directly(os, fmt, vargs); 184 | } 185 | 186 | FMT_EXPORT 187 | template 188 | void print(std::wostream& os, 189 | basic_format_string...> fmt, 190 | Args&&... args) { 191 | vprint(os, fmt, fmt::make_format_args>(args...)); 192 | } 193 | 194 | FMT_EXPORT template 195 | void println(std::ostream& os, format_string fmt, T&&... args) { 196 | fmt::print(os, "{}\n", fmt::format(fmt, std::forward(args)...)); 197 | } 198 | 199 | FMT_EXPORT 200 | template 201 | void println(std::wostream& os, 202 | basic_format_string...> fmt, 203 | Args&&... args) { 204 | print(os, L"{}\n", fmt::format(fmt, std::forward(args)...)); 205 | } 206 | 207 | FMT_END_NAMESPACE 208 | 209 | #endif // FMT_OSTREAM_H_ 210 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/args.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - dynamic argument lists 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_ARGS_H_ 9 | #define FMT_ARGS_H_ 10 | 11 | #include // std::reference_wrapper 12 | #include // std::unique_ptr 13 | #include 14 | 15 | #include "core.h" 16 | 17 | FMT_BEGIN_NAMESPACE 18 | 19 | namespace detail { 20 | 21 | template struct is_reference_wrapper : std::false_type {}; 22 | template 23 | struct is_reference_wrapper> : std::true_type {}; 24 | 25 | template const T& unwrap(const T& v) { return v; } 26 | template const T& unwrap(const std::reference_wrapper& v) { 27 | return static_cast(v); 28 | } 29 | 30 | class dynamic_arg_list { 31 | // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for 32 | // templates it doesn't complain about inability to deduce single translation 33 | // unit for placing vtable. So storage_node_base is made a fake template. 34 | template struct node { 35 | virtual ~node() = default; 36 | std::unique_ptr> next; 37 | }; 38 | 39 | template struct typed_node : node<> { 40 | T value; 41 | 42 | template 43 | FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} 44 | 45 | template 46 | FMT_CONSTEXPR typed_node(const basic_string_view& arg) 47 | : value(arg.data(), arg.size()) {} 48 | }; 49 | 50 | std::unique_ptr> head_; 51 | 52 | public: 53 | template const T& push(const Arg& arg) { 54 | auto new_node = std::unique_ptr>(new typed_node(arg)); 55 | auto& value = new_node->value; 56 | new_node->next = std::move(head_); 57 | head_ = std::move(new_node); 58 | return value; 59 | } 60 | }; 61 | } // namespace detail 62 | 63 | /** 64 | \rst 65 | A dynamic version of `fmt::format_arg_store`. 66 | It's equipped with a storage to potentially temporary objects which lifetimes 67 | could be shorter than the format arguments object. 68 | 69 | It can be implicitly converted into `~fmt::basic_format_args` for passing 70 | into type-erased formatting functions such as `~fmt::vformat`. 71 | \endrst 72 | */ 73 | template 74 | class dynamic_format_arg_store 75 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 76 | // Workaround a GCC template argument substitution bug. 77 | : public basic_format_args 78 | #endif 79 | { 80 | private: 81 | using char_type = typename Context::char_type; 82 | 83 | template struct need_copy { 84 | static constexpr detail::type mapped_type = 85 | detail::mapped_type_constant::value; 86 | 87 | enum { 88 | value = !(detail::is_reference_wrapper::value || 89 | std::is_same>::value || 90 | std::is_same>::value || 91 | (mapped_type != detail::type::cstring_type && 92 | mapped_type != detail::type::string_type && 93 | mapped_type != detail::type::custom_type)) 94 | }; 95 | }; 96 | 97 | template 98 | using stored_type = conditional_t< 99 | std::is_convertible>::value && 100 | !detail::is_reference_wrapper::value, 101 | std::basic_string, T>; 102 | 103 | // Storage of basic_format_arg must be contiguous. 104 | std::vector> data_; 105 | std::vector> named_info_; 106 | 107 | // Storage of arguments not fitting into basic_format_arg must grow 108 | // without relocation because items in data_ refer to it. 109 | detail::dynamic_arg_list dynamic_args_; 110 | 111 | friend class basic_format_args; 112 | 113 | unsigned long long get_types() const { 114 | return detail::is_unpacked_bit | data_.size() | 115 | (named_info_.empty() 116 | ? 0ULL 117 | : static_cast(detail::has_named_args_bit)); 118 | } 119 | 120 | const basic_format_arg* data() const { 121 | return named_info_.empty() ? data_.data() : data_.data() + 1; 122 | } 123 | 124 | template void emplace_arg(const T& arg) { 125 | data_.emplace_back(detail::make_arg(arg)); 126 | } 127 | 128 | template 129 | void emplace_arg(const detail::named_arg& arg) { 130 | if (named_info_.empty()) { 131 | constexpr const detail::named_arg_info* zero_ptr{nullptr}; 132 | data_.insert(data_.begin(), {zero_ptr, 0}); 133 | } 134 | data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); 135 | auto pop_one = [](std::vector>* data) { 136 | data->pop_back(); 137 | }; 138 | std::unique_ptr>, decltype(pop_one)> 139 | guard{&data_, pop_one}; 140 | named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); 141 | data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; 142 | guard.release(); 143 | } 144 | 145 | public: 146 | constexpr dynamic_format_arg_store() = default; 147 | 148 | /** 149 | \rst 150 | Adds an argument into the dynamic store for later passing to a formatting 151 | function. 152 | 153 | Note that custom types and string types (but not string views) are copied 154 | into the store dynamically allocating memory if necessary. 155 | 156 | **Example**:: 157 | 158 | fmt::dynamic_format_arg_store store; 159 | store.push_back(42); 160 | store.push_back("abc"); 161 | store.push_back(1.5f); 162 | std::string result = fmt::vformat("{} and {} and {}", store); 163 | \endrst 164 | */ 165 | template void push_back(const T& arg) { 166 | if (detail::const_check(need_copy::value)) 167 | emplace_arg(dynamic_args_.push>(arg)); 168 | else 169 | emplace_arg(detail::unwrap(arg)); 170 | } 171 | 172 | /** 173 | \rst 174 | Adds a reference to the argument into the dynamic store for later passing to 175 | a formatting function. 176 | 177 | **Example**:: 178 | 179 | fmt::dynamic_format_arg_store store; 180 | char band[] = "Rolling Stones"; 181 | store.push_back(std::cref(band)); 182 | band[9] = 'c'; // Changing str affects the output. 183 | std::string result = fmt::vformat("{}", store); 184 | // result == "Rolling Scones" 185 | \endrst 186 | */ 187 | template void push_back(std::reference_wrapper arg) { 188 | static_assert( 189 | need_copy::value, 190 | "objects of built-in types and string views are always copied"); 191 | emplace_arg(arg.get()); 192 | } 193 | 194 | /** 195 | Adds named argument into the dynamic store for later passing to a formatting 196 | function. ``std::reference_wrapper`` is supported to avoid copying of the 197 | argument. The name is always copied into the store. 198 | */ 199 | template 200 | void push_back(const detail::named_arg& arg) { 201 | const char_type* arg_name = 202 | dynamic_args_.push>(arg.name).c_str(); 203 | if (detail::const_check(need_copy::value)) { 204 | emplace_arg( 205 | fmt::arg(arg_name, dynamic_args_.push>(arg.value))); 206 | } else { 207 | emplace_arg(fmt::arg(arg_name, arg.value)); 208 | } 209 | } 210 | 211 | /** Erase all elements from the store */ 212 | void clear() { 213 | data_.clear(); 214 | named_info_.clear(); 215 | dynamic_args_ = detail::dynamic_arg_list(); 216 | } 217 | 218 | /** 219 | \rst 220 | Reserves space to store at least *new_cap* arguments including 221 | *new_cap_named* named arguments. 222 | \endrst 223 | */ 224 | void reserve(size_t new_cap, size_t new_cap_named) { 225 | FMT_ASSERT(new_cap >= new_cap_named, 226 | "Set of arguments includes set of named arguments"); 227 | data_.reserve(new_cap); 228 | named_info_.reserve(new_cap_named); 229 | } 230 | }; 231 | 232 | FMT_END_NAMESPACE 233 | 234 | #endif // FMT_ARGS_H_ 235 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/xchar.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional wchar_t and exotic character support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_XCHAR_H_ 9 | #define FMT_XCHAR_H_ 10 | 11 | #include 12 | 13 | #include "format.h" 14 | 15 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 16 | # include 17 | #endif 18 | 19 | FMT_BEGIN_NAMESPACE 20 | namespace detail { 21 | 22 | template 23 | using is_exotic_char = bool_constant::value>; 24 | 25 | inline auto write_loc(std::back_insert_iterator> out, 26 | loc_value value, const format_specs& specs, 27 | locale_ref loc) -> bool { 28 | #ifndef FMT_STATIC_THOUSANDS_SEPARATOR 29 | auto& numpunct = 30 | std::use_facet>(loc.get()); 31 | auto separator = std::wstring(); 32 | auto grouping = numpunct.grouping(); 33 | if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); 34 | return value.visit(loc_writer{out, specs, separator, grouping, {}}); 35 | #endif 36 | return false; 37 | } 38 | } // namespace detail 39 | 40 | FMT_BEGIN_EXPORT 41 | 42 | using wstring_view = basic_string_view; 43 | using wformat_parse_context = basic_format_parse_context; 44 | using wformat_context = buffer_context; 45 | using wformat_args = basic_format_args; 46 | using wmemory_buffer = basic_memory_buffer; 47 | 48 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 49 | // Workaround broken conversion on older gcc. 50 | template using wformat_string = wstring_view; 51 | inline auto runtime(wstring_view s) -> wstring_view { return s; } 52 | #else 53 | template 54 | using wformat_string = basic_format_string...>; 55 | inline auto runtime(wstring_view s) -> runtime_format_string { 56 | return {{s}}; 57 | } 58 | #endif 59 | 60 | template <> struct is_char : std::true_type {}; 61 | template <> struct is_char : std::true_type {}; 62 | template <> struct is_char : std::true_type {}; 63 | template <> struct is_char : std::true_type {}; 64 | 65 | template 66 | constexpr format_arg_store make_wformat_args( 67 | const T&... args) { 68 | return {args...}; 69 | } 70 | 71 | inline namespace literals { 72 | #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS 73 | constexpr detail::udl_arg operator"" _a(const wchar_t* s, size_t) { 74 | return {s}; 75 | } 76 | #endif 77 | } // namespace literals 78 | 79 | template 80 | auto join(It begin, Sentinel end, wstring_view sep) 81 | -> join_view { 82 | return {begin, end, sep}; 83 | } 84 | 85 | template 86 | auto join(Range&& range, wstring_view sep) 87 | -> join_view, detail::sentinel_t, 88 | wchar_t> { 89 | return join(std::begin(range), std::end(range), sep); 90 | } 91 | 92 | template 93 | auto join(std::initializer_list list, wstring_view sep) 94 | -> join_view { 95 | return join(std::begin(list), std::end(list), sep); 96 | } 97 | 98 | template ::value)> 99 | auto vformat(basic_string_view format_str, 100 | basic_format_args>> args) 101 | -> std::basic_string { 102 | auto buf = basic_memory_buffer(); 103 | detail::vformat_to(buf, format_str, args); 104 | return to_string(buf); 105 | } 106 | 107 | template 108 | auto format(wformat_string fmt, T&&... args) -> std::wstring { 109 | return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); 110 | } 111 | 112 | // Pass char_t as a default template parameter instead of using 113 | // std::basic_string> to reduce the symbol size. 114 | template , 115 | FMT_ENABLE_IF(!std::is_same::value && 116 | !std::is_same::value)> 117 | auto format(const S& format_str, T&&... args) -> std::basic_string { 118 | return vformat(detail::to_string_view(format_str), 119 | fmt::make_format_args>(args...)); 120 | } 121 | 122 | template , 123 | FMT_ENABLE_IF(detail::is_locale::value&& 124 | detail::is_exotic_char::value)> 125 | inline auto vformat( 126 | const Locale& loc, const S& format_str, 127 | basic_format_args>> args) 128 | -> std::basic_string { 129 | return detail::vformat(loc, detail::to_string_view(format_str), args); 130 | } 131 | 132 | template , 133 | FMT_ENABLE_IF(detail::is_locale::value&& 134 | detail::is_exotic_char::value)> 135 | inline auto format(const Locale& loc, const S& format_str, T&&... args) 136 | -> std::basic_string { 137 | return detail::vformat(loc, detail::to_string_view(format_str), 138 | fmt::make_format_args>(args...)); 139 | } 140 | 141 | template , 142 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 143 | detail::is_exotic_char::value)> 144 | auto vformat_to(OutputIt out, const S& format_str, 145 | basic_format_args>> args) 146 | -> OutputIt { 147 | auto&& buf = detail::get_buffer(out); 148 | detail::vformat_to(buf, detail::to_string_view(format_str), args); 149 | return detail::get_iterator(buf, out); 150 | } 151 | 152 | template , 154 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 155 | detail::is_exotic_char::value)> 156 | inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { 157 | return vformat_to(out, detail::to_string_view(fmt), 158 | fmt::make_format_args>(args...)); 159 | } 160 | 161 | template , 163 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 164 | detail::is_locale::value&& 165 | detail::is_exotic_char::value)> 166 | inline auto vformat_to( 167 | OutputIt out, const Locale& loc, const S& format_str, 168 | basic_format_args>> args) -> OutputIt { 169 | auto&& buf = detail::get_buffer(out); 170 | vformat_to(buf, detail::to_string_view(format_str), args, 171 | detail::locale_ref(loc)); 172 | return detail::get_iterator(buf, out); 173 | } 174 | 175 | template < 176 | typename OutputIt, typename Locale, typename S, typename... T, 177 | typename Char = char_t, 178 | bool enable = detail::is_output_iterator::value&& 179 | detail::is_locale::value&& detail::is_exotic_char::value> 180 | inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, 181 | T&&... args) -> 182 | typename std::enable_if::type { 183 | return vformat_to(out, loc, detail::to_string_view(format_str), 184 | fmt::make_format_args>(args...)); 185 | } 186 | 187 | template ::value&& 189 | detail::is_exotic_char::value)> 190 | inline auto vformat_to_n( 191 | OutputIt out, size_t n, basic_string_view format_str, 192 | basic_format_args>> args) 193 | -> format_to_n_result { 194 | using traits = detail::fixed_buffer_traits; 195 | auto buf = detail::iterator_buffer(out, n); 196 | detail::vformat_to(buf, format_str, args); 197 | return {buf.out(), buf.count()}; 198 | } 199 | 200 | template , 202 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 203 | detail::is_exotic_char::value)> 204 | inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) 205 | -> format_to_n_result { 206 | return vformat_to_n(out, n, detail::to_string_view(fmt), 207 | fmt::make_format_args>(args...)); 208 | } 209 | 210 | template , 211 | FMT_ENABLE_IF(detail::is_exotic_char::value)> 212 | inline auto formatted_size(const S& fmt, T&&... args) -> size_t { 213 | auto buf = detail::counting_buffer(); 214 | detail::vformat_to(buf, detail::to_string_view(fmt), 215 | fmt::make_format_args>(args...)); 216 | return buf.count(); 217 | } 218 | 219 | inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { 220 | auto buf = wmemory_buffer(); 221 | detail::vformat_to(buf, fmt, args); 222 | buf.push_back(L'\0'); 223 | if (std::fputws(buf.data(), f) == -1) 224 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 225 | } 226 | 227 | inline void vprint(wstring_view fmt, wformat_args args) { 228 | vprint(stdout, fmt, args); 229 | } 230 | 231 | template 232 | void print(std::FILE* f, wformat_string fmt, T&&... args) { 233 | return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); 234 | } 235 | 236 | template void print(wformat_string fmt, T&&... args) { 237 | return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); 238 | } 239 | 240 | template 241 | void println(std::FILE* f, wformat_string fmt, T&&... args) { 242 | return print(f, L"{}\n", fmt::format(fmt, std::forward(args)...)); 243 | } 244 | 245 | template void println(wformat_string fmt, T&&... args) { 246 | return print(L"{}\n", fmt::format(fmt, std::forward(args)...)); 247 | } 248 | 249 | /** 250 | Converts *value* to ``std::wstring`` using the default format for type *T*. 251 | */ 252 | template inline auto to_wstring(const T& value) -> std::wstring { 253 | return format(FMT_STRING(L"{}"), value); 254 | } 255 | FMT_END_EXPORT 256 | FMT_END_NAMESPACE 257 | 258 | #endif // FMT_XCHAR_H_ 259 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/src/os.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional OS-specific functionality 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | // Disable bogus MSVC warnings. 9 | #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) 10 | # define _CRT_SECURE_NO_WARNINGS 11 | #endif 12 | 13 | #include "fmt/os.h" 14 | 15 | #include 16 | 17 | #if FMT_USE_FCNTL 18 | # include 19 | # include 20 | 21 | # ifdef _WRS_KERNEL // VxWorks7 kernel 22 | # include // getpagesize 23 | # endif 24 | 25 | # ifndef _WIN32 26 | # include 27 | # else 28 | # ifndef WIN32_LEAN_AND_MEAN 29 | # define WIN32_LEAN_AND_MEAN 30 | # endif 31 | # include 32 | 33 | # ifndef S_IRUSR 34 | # define S_IRUSR _S_IREAD 35 | # endif 36 | # ifndef S_IWUSR 37 | # define S_IWUSR _S_IWRITE 38 | # endif 39 | # ifndef S_IRGRP 40 | # define S_IRGRP 0 41 | # endif 42 | # ifndef S_IWGRP 43 | # define S_IWGRP 0 44 | # endif 45 | # ifndef S_IROTH 46 | # define S_IROTH 0 47 | # endif 48 | # ifndef S_IWOTH 49 | # define S_IWOTH 0 50 | # endif 51 | # endif // _WIN32 52 | #endif // FMT_USE_FCNTL 53 | 54 | #ifdef _WIN32 55 | # include 56 | #endif 57 | 58 | namespace { 59 | #ifdef _WIN32 60 | // Return type of read and write functions. 61 | using rwresult = int; 62 | 63 | // On Windows the count argument to read and write is unsigned, so convert 64 | // it from size_t preventing integer overflow. 65 | inline unsigned convert_rwcount(std::size_t count) { 66 | return count <= UINT_MAX ? static_cast(count) : UINT_MAX; 67 | } 68 | #elif FMT_USE_FCNTL 69 | // Return type of read and write functions. 70 | using rwresult = ssize_t; 71 | 72 | inline std::size_t convert_rwcount(std::size_t count) { return count; } 73 | #endif 74 | } // namespace 75 | 76 | FMT_BEGIN_NAMESPACE 77 | 78 | #ifdef _WIN32 79 | namespace detail { 80 | 81 | class system_message { 82 | system_message(const system_message&) = delete; 83 | void operator=(const system_message&) = delete; 84 | 85 | unsigned long result_; 86 | wchar_t* message_; 87 | 88 | static bool is_whitespace(wchar_t c) noexcept { 89 | return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0'; 90 | } 91 | 92 | public: 93 | explicit system_message(unsigned long error_code) 94 | : result_(0), message_(nullptr) { 95 | result_ = FormatMessageW( 96 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 97 | FORMAT_MESSAGE_IGNORE_INSERTS, 98 | nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 99 | reinterpret_cast(&message_), 0, nullptr); 100 | if (result_ != 0) { 101 | while (result_ != 0 && is_whitespace(message_[result_ - 1])) { 102 | --result_; 103 | } 104 | } 105 | } 106 | ~system_message() { LocalFree(message_); } 107 | explicit operator bool() const noexcept { return result_ != 0; } 108 | operator basic_string_view() const noexcept { 109 | return basic_string_view(message_, result_); 110 | } 111 | }; 112 | 113 | class utf8_system_category final : public std::error_category { 114 | public: 115 | const char* name() const noexcept override { return "system"; } 116 | std::string message(int error_code) const override { 117 | auto&& msg = system_message(error_code); 118 | if (msg) { 119 | auto utf8_message = to_utf8(); 120 | if (utf8_message.convert(msg)) { 121 | return utf8_message.str(); 122 | } 123 | } 124 | return "unknown error"; 125 | } 126 | }; 127 | 128 | } // namespace detail 129 | 130 | FMT_API const std::error_category& system_category() noexcept { 131 | static const detail::utf8_system_category category; 132 | return category; 133 | } 134 | 135 | std::system_error vwindows_error(int err_code, string_view format_str, 136 | format_args args) { 137 | auto ec = std::error_code(err_code, system_category()); 138 | return std::system_error(ec, vformat(format_str, args)); 139 | } 140 | 141 | void detail::format_windows_error(detail::buffer& out, int error_code, 142 | const char* message) noexcept { 143 | FMT_TRY { 144 | auto&& msg = system_message(error_code); 145 | if (msg) { 146 | auto utf8_message = to_utf8(); 147 | if (utf8_message.convert(msg)) { 148 | fmt::format_to(appender(out), FMT_STRING("{}: {}"), message, 149 | string_view(utf8_message)); 150 | return; 151 | } 152 | } 153 | } 154 | FMT_CATCH(...) {} 155 | format_error_code(out, error_code, message); 156 | } 157 | 158 | void report_windows_error(int error_code, const char* message) noexcept { 159 | report_error(detail::format_windows_error, error_code, message); 160 | } 161 | #endif // _WIN32 162 | 163 | buffered_file::~buffered_file() noexcept { 164 | if (file_ && FMT_SYSTEM(fclose(file_)) != 0) 165 | report_system_error(errno, "cannot close file"); 166 | } 167 | 168 | buffered_file::buffered_file(cstring_view filename, cstring_view mode) { 169 | FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 170 | nullptr); 171 | if (!file_) 172 | FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"), 173 | filename.c_str())); 174 | } 175 | 176 | void buffered_file::close() { 177 | if (!file_) return; 178 | int result = FMT_SYSTEM(fclose(file_)); 179 | file_ = nullptr; 180 | if (result != 0) 181 | FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); 182 | } 183 | 184 | int buffered_file::descriptor() const { 185 | #ifdef fileno // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL. 186 | int fd = fileno(file_); 187 | #else 188 | int fd = FMT_POSIX_CALL(fileno(file_)); 189 | #endif 190 | if (fd == -1) 191 | FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor"))); 192 | return fd; 193 | } 194 | 195 | #if FMT_USE_FCNTL 196 | # ifdef _WIN32 197 | using mode_t = int; 198 | # endif 199 | constexpr mode_t default_open_mode = 200 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 201 | 202 | file::file(cstring_view path, int oflag) { 203 | # if defined(_WIN32) && !defined(__MINGW32__) 204 | fd_ = -1; 205 | auto converted = detail::utf8_to_utf16(string_view(path.c_str())); 206 | *this = file::open_windows_file(converted.c_str(), oflag); 207 | # else 208 | FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode))); 209 | if (fd_ == -1) 210 | FMT_THROW( 211 | system_error(errno, FMT_STRING("cannot open file {}"), path.c_str())); 212 | # endif 213 | } 214 | 215 | file::~file() noexcept { 216 | // Don't retry close in case of EINTR! 217 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 218 | if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) 219 | report_system_error(errno, "cannot close file"); 220 | } 221 | 222 | void file::close() { 223 | if (fd_ == -1) return; 224 | // Don't retry close in case of EINTR! 225 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 226 | int result = FMT_POSIX_CALL(close(fd_)); 227 | fd_ = -1; 228 | if (result != 0) 229 | FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); 230 | } 231 | 232 | long long file::size() const { 233 | # ifdef _WIN32 234 | // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT 235 | // is less than 0x0500 as is the case with some default MinGW builds. 236 | // Both functions support large file sizes. 237 | DWORD size_upper = 0; 238 | HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); 239 | DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); 240 | if (size_lower == INVALID_FILE_SIZE) { 241 | DWORD error = GetLastError(); 242 | if (error != NO_ERROR) 243 | FMT_THROW(windows_error(GetLastError(), "cannot get file size")); 244 | } 245 | unsigned long long long_size = size_upper; 246 | return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; 247 | # else 248 | using Stat = struct stat; 249 | Stat file_stat = Stat(); 250 | if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) 251 | FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes"))); 252 | static_assert(sizeof(long long) >= sizeof(file_stat.st_size), 253 | "return type of file::size is not large enough"); 254 | return file_stat.st_size; 255 | # endif 256 | } 257 | 258 | std::size_t file::read(void* buffer, std::size_t count) { 259 | rwresult result = 0; 260 | FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); 261 | if (result < 0) 262 | FMT_THROW(system_error(errno, FMT_STRING("cannot read from file"))); 263 | return detail::to_unsigned(result); 264 | } 265 | 266 | std::size_t file::write(const void* buffer, std::size_t count) { 267 | rwresult result = 0; 268 | FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); 269 | if (result < 0) 270 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 271 | return detail::to_unsigned(result); 272 | } 273 | 274 | file file::dup(int fd) { 275 | // Don't retry as dup doesn't return EINTR. 276 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html 277 | int new_fd = FMT_POSIX_CALL(dup(fd)); 278 | if (new_fd == -1) 279 | FMT_THROW(system_error( 280 | errno, FMT_STRING("cannot duplicate file descriptor {}"), fd)); 281 | return file(new_fd); 282 | } 283 | 284 | void file::dup2(int fd) { 285 | int result = 0; 286 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 287 | if (result == -1) { 288 | FMT_THROW(system_error( 289 | errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_, 290 | fd)); 291 | } 292 | } 293 | 294 | void file::dup2(int fd, std::error_code& ec) noexcept { 295 | int result = 0; 296 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 297 | if (result == -1) ec = std::error_code(errno, std::generic_category()); 298 | } 299 | 300 | void file::pipe(file& read_end, file& write_end) { 301 | // Close the descriptors first to make sure that assignments don't throw 302 | // and there are no leaks. 303 | read_end.close(); 304 | write_end.close(); 305 | int fds[2] = {}; 306 | # ifdef _WIN32 307 | // Make the default pipe capacity same as on Linux 2.6.11+. 308 | enum { DEFAULT_CAPACITY = 65536 }; 309 | int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); 310 | # else 311 | // Don't retry as the pipe function doesn't return EINTR. 312 | // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html 313 | int result = FMT_POSIX_CALL(pipe(fds)); 314 | # endif 315 | if (result != 0) 316 | FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe"))); 317 | // The following assignments don't throw because read_fd and write_fd 318 | // are closed. 319 | read_end = file(fds[0]); 320 | write_end = file(fds[1]); 321 | } 322 | 323 | buffered_file file::fdopen(const char* mode) { 324 | // Don't retry as fdopen doesn't return EINTR. 325 | # if defined(__MINGW32__) && defined(_POSIX_) 326 | FILE* f = ::fdopen(fd_, mode); 327 | # else 328 | FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); 329 | # endif 330 | if (!f) { 331 | FMT_THROW(system_error( 332 | errno, FMT_STRING("cannot associate stream with file descriptor"))); 333 | } 334 | buffered_file bf(f); 335 | fd_ = -1; 336 | return bf; 337 | } 338 | 339 | # if defined(_WIN32) && !defined(__MINGW32__) 340 | file file::open_windows_file(wcstring_view path, int oflag) { 341 | int fd = -1; 342 | auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode); 343 | if (fd == -1) { 344 | FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"), 345 | detail::to_utf8(path.c_str()).c_str())); 346 | } 347 | return file(fd); 348 | } 349 | # endif 350 | 351 | # if !defined(__MSDOS__) 352 | long getpagesize() { 353 | # ifdef _WIN32 354 | SYSTEM_INFO si; 355 | GetSystemInfo(&si); 356 | return si.dwPageSize; 357 | # else 358 | # ifdef _WRS_KERNEL 359 | long size = FMT_POSIX_CALL(getpagesize()); 360 | # else 361 | long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); 362 | # endif 363 | 364 | if (size < 0) 365 | FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size"))); 366 | return size; 367 | # endif 368 | } 369 | # endif 370 | 371 | namespace detail { 372 | 373 | void file_buffer::grow(size_t) { 374 | if (this->size() == this->capacity()) flush(); 375 | } 376 | 377 | file_buffer::file_buffer(cstring_view path, 378 | const detail::ostream_params& params) 379 | : file_(path, params.oflag) { 380 | set(new char[params.buffer_size], params.buffer_size); 381 | } 382 | 383 | file_buffer::file_buffer(file_buffer&& other) 384 | : detail::buffer(other.data(), other.size(), other.capacity()), 385 | file_(std::move(other.file_)) { 386 | other.clear(); 387 | other.set(nullptr, 0); 388 | } 389 | 390 | file_buffer::~file_buffer() { 391 | flush(); 392 | delete[] data(); 393 | } 394 | } // namespace detail 395 | 396 | ostream::~ostream() = default; 397 | #endif // FMT_USE_FCNTL 398 | FMT_END_NAMESPACE 399 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/os.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional OS-specific functionality 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OS_H_ 9 | #define FMT_OS_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include // std::system_error 15 | 16 | #if defined __APPLE__ || defined(__FreeBSD__) 17 | # include // for LC_NUMERIC_MASK on OS X 18 | #endif 19 | 20 | #include "format.h" 21 | 22 | #ifndef FMT_USE_FCNTL 23 | // UWP doesn't provide _pipe. 24 | # if FMT_HAS_INCLUDE("winapifamily.h") 25 | # include 26 | # endif 27 | # if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ 28 | defined(__linux__)) && \ 29 | (!defined(WINAPI_FAMILY) || \ 30 | (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) 31 | # include // for O_RDONLY 32 | # define FMT_USE_FCNTL 1 33 | # else 34 | # define FMT_USE_FCNTL 0 35 | # endif 36 | #endif 37 | 38 | #ifndef FMT_POSIX 39 | # if defined(_WIN32) && !defined(__MINGW32__) 40 | // Fix warnings about deprecated symbols. 41 | # define FMT_POSIX(call) _##call 42 | # else 43 | # define FMT_POSIX(call) call 44 | # endif 45 | #endif 46 | 47 | // Calls to system functions are wrapped in FMT_SYSTEM for testability. 48 | #ifdef FMT_SYSTEM 49 | # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) 50 | #else 51 | # define FMT_SYSTEM(call) ::call 52 | # ifdef _WIN32 53 | // Fix warnings about deprecated symbols. 54 | # define FMT_POSIX_CALL(call) ::_##call 55 | # else 56 | # define FMT_POSIX_CALL(call) ::call 57 | # endif 58 | #endif 59 | 60 | // Retries the expression while it evaluates to error_result and errno 61 | // equals to EINTR. 62 | #ifndef _WIN32 63 | # define FMT_RETRY_VAL(result, expression, error_result) \ 64 | do { \ 65 | (result) = (expression); \ 66 | } while ((result) == (error_result) && errno == EINTR) 67 | #else 68 | # define FMT_RETRY_VAL(result, expression, error_result) result = (expression) 69 | #endif 70 | 71 | #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) 72 | 73 | FMT_BEGIN_NAMESPACE 74 | FMT_BEGIN_EXPORT 75 | 76 | /** 77 | \rst 78 | A reference to a null-terminated string. It can be constructed from a C 79 | string or ``std::string``. 80 | 81 | You can use one of the following type aliases for common character types: 82 | 83 | +---------------+-----------------------------+ 84 | | Type | Definition | 85 | +===============+=============================+ 86 | | cstring_view | basic_cstring_view | 87 | +---------------+-----------------------------+ 88 | | wcstring_view | basic_cstring_view | 89 | +---------------+-----------------------------+ 90 | 91 | This class is most useful as a parameter type to allow passing 92 | different types of strings to a function, for example:: 93 | 94 | template 95 | std::string format(cstring_view format_str, const Args & ... args); 96 | 97 | format("{}", 42); 98 | format(std::string("{}"), 42); 99 | \endrst 100 | */ 101 | template class basic_cstring_view { 102 | private: 103 | const Char* data_; 104 | 105 | public: 106 | /** Constructs a string reference object from a C string. */ 107 | basic_cstring_view(const Char* s) : data_(s) {} 108 | 109 | /** 110 | \rst 111 | Constructs a string reference from an ``std::string`` object. 112 | \endrst 113 | */ 114 | basic_cstring_view(const std::basic_string& s) : data_(s.c_str()) {} 115 | 116 | /** Returns the pointer to a C string. */ 117 | const Char* c_str() const { return data_; } 118 | }; 119 | 120 | using cstring_view = basic_cstring_view; 121 | using wcstring_view = basic_cstring_view; 122 | 123 | #ifdef _WIN32 124 | FMT_API const std::error_category& system_category() noexcept; 125 | 126 | namespace detail { 127 | FMT_API void format_windows_error(buffer& out, int error_code, 128 | const char* message) noexcept; 129 | } 130 | 131 | FMT_API std::system_error vwindows_error(int error_code, string_view format_str, 132 | format_args args); 133 | 134 | /** 135 | \rst 136 | Constructs a :class:`std::system_error` object with the description 137 | of the form 138 | 139 | .. parsed-literal:: 140 | **: ** 141 | 142 | where ** is the formatted message and ** is the 143 | system message corresponding to the error code. 144 | *error_code* is a Windows error code as given by ``GetLastError``. 145 | If *error_code* is not a valid error code such as -1, the system message 146 | will look like "error -1". 147 | 148 | **Example**:: 149 | 150 | // This throws a system_error with the description 151 | // cannot open file 'madeup': The system cannot find the file specified. 152 | // or similar (system message may vary). 153 | const char *filename = "madeup"; 154 | LPOFSTRUCT of = LPOFSTRUCT(); 155 | HFILE file = OpenFile(filename, &of, OF_READ); 156 | if (file == HFILE_ERROR) { 157 | throw fmt::windows_error(GetLastError(), 158 | "cannot open file '{}'", filename); 159 | } 160 | \endrst 161 | */ 162 | template 163 | std::system_error windows_error(int error_code, string_view message, 164 | const Args&... args) { 165 | return vwindows_error(error_code, message, fmt::make_format_args(args...)); 166 | } 167 | 168 | // Reports a Windows error without throwing an exception. 169 | // Can be used to report errors from destructors. 170 | FMT_API void report_windows_error(int error_code, const char* message) noexcept; 171 | #else 172 | inline const std::error_category& system_category() noexcept { 173 | return std::system_category(); 174 | } 175 | #endif // _WIN32 176 | 177 | // std::system is not available on some platforms such as iOS (#2248). 178 | #ifdef __OSX__ 179 | template > 180 | void say(const S& format_str, Args&&... args) { 181 | std::system(format("say \"{}\"", format(format_str, args...)).c_str()); 182 | } 183 | #endif 184 | 185 | // A buffered file. 186 | class buffered_file { 187 | private: 188 | FILE* file_; 189 | 190 | friend class file; 191 | 192 | explicit buffered_file(FILE* f) : file_(f) {} 193 | 194 | public: 195 | buffered_file(const buffered_file&) = delete; 196 | void operator=(const buffered_file&) = delete; 197 | 198 | // Constructs a buffered_file object which doesn't represent any file. 199 | buffered_file() noexcept : file_(nullptr) {} 200 | 201 | // Destroys the object closing the file it represents if any. 202 | FMT_API ~buffered_file() noexcept; 203 | 204 | public: 205 | buffered_file(buffered_file&& other) noexcept : file_(other.file_) { 206 | other.file_ = nullptr; 207 | } 208 | 209 | buffered_file& operator=(buffered_file&& other) { 210 | close(); 211 | file_ = other.file_; 212 | other.file_ = nullptr; 213 | return *this; 214 | } 215 | 216 | // Opens a file. 217 | FMT_API buffered_file(cstring_view filename, cstring_view mode); 218 | 219 | // Closes the file. 220 | FMT_API void close(); 221 | 222 | // Returns the pointer to a FILE object representing this file. 223 | FILE* get() const noexcept { return file_; } 224 | 225 | FMT_API int descriptor() const; 226 | 227 | void vprint(string_view format_str, format_args args) { 228 | fmt::vprint(file_, format_str, args); 229 | } 230 | 231 | template 232 | inline void print(string_view format_str, const Args&... args) { 233 | vprint(format_str, fmt::make_format_args(args...)); 234 | } 235 | }; 236 | 237 | #if FMT_USE_FCNTL 238 | // A file. Closed file is represented by a file object with descriptor -1. 239 | // Methods that are not declared with noexcept may throw 240 | // fmt::system_error in case of failure. Note that some errors such as 241 | // closing the file multiple times will cause a crash on Windows rather 242 | // than an exception. You can get standard behavior by overriding the 243 | // invalid parameter handler with _set_invalid_parameter_handler. 244 | class FMT_API file { 245 | private: 246 | int fd_; // File descriptor. 247 | 248 | // Constructs a file object with a given descriptor. 249 | explicit file(int fd) : fd_(fd) {} 250 | 251 | public: 252 | // Possible values for the oflag argument to the constructor. 253 | enum { 254 | RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. 255 | WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. 256 | RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. 257 | CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. 258 | APPEND = FMT_POSIX(O_APPEND), // Open in append mode. 259 | TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. 260 | }; 261 | 262 | // Constructs a file object which doesn't represent any file. 263 | file() noexcept : fd_(-1) {} 264 | 265 | // Opens a file and constructs a file object representing this file. 266 | file(cstring_view path, int oflag); 267 | 268 | public: 269 | file(const file&) = delete; 270 | void operator=(const file&) = delete; 271 | 272 | file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } 273 | 274 | // Move assignment is not noexcept because close may throw. 275 | file& operator=(file&& other) { 276 | close(); 277 | fd_ = other.fd_; 278 | other.fd_ = -1; 279 | return *this; 280 | } 281 | 282 | // Destroys the object closing the file it represents if any. 283 | ~file() noexcept; 284 | 285 | // Returns the file descriptor. 286 | int descriptor() const noexcept { return fd_; } 287 | 288 | // Closes the file. 289 | void close(); 290 | 291 | // Returns the file size. The size has signed type for consistency with 292 | // stat::st_size. 293 | long long size() const; 294 | 295 | // Attempts to read count bytes from the file into the specified buffer. 296 | size_t read(void* buffer, size_t count); 297 | 298 | // Attempts to write count bytes from the specified buffer to the file. 299 | size_t write(const void* buffer, size_t count); 300 | 301 | // Duplicates a file descriptor with the dup function and returns 302 | // the duplicate as a file object. 303 | static file dup(int fd); 304 | 305 | // Makes fd be the copy of this file descriptor, closing fd first if 306 | // necessary. 307 | void dup2(int fd); 308 | 309 | // Makes fd be the copy of this file descriptor, closing fd first if 310 | // necessary. 311 | void dup2(int fd, std::error_code& ec) noexcept; 312 | 313 | // Creates a pipe setting up read_end and write_end file objects for reading 314 | // and writing respectively. 315 | static void pipe(file& read_end, file& write_end); 316 | 317 | // Creates a buffered_file object associated with this file and detaches 318 | // this file object from the file. 319 | buffered_file fdopen(const char* mode); 320 | 321 | # if defined(_WIN32) && !defined(__MINGW32__) 322 | // Opens a file and constructs a file object representing this file by 323 | // wcstring_view filename. Windows only. 324 | static file open_windows_file(wcstring_view path, int oflag); 325 | # endif 326 | }; 327 | 328 | // Returns the memory page size. 329 | long getpagesize(); 330 | 331 | namespace detail { 332 | 333 | struct buffer_size { 334 | buffer_size() = default; 335 | size_t value = 0; 336 | buffer_size operator=(size_t val) const { 337 | auto bs = buffer_size(); 338 | bs.value = val; 339 | return bs; 340 | } 341 | }; 342 | 343 | struct ostream_params { 344 | int oflag = file::WRONLY | file::CREATE | file::TRUNC; 345 | size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; 346 | 347 | ostream_params() {} 348 | 349 | template 350 | ostream_params(T... params, int new_oflag) : ostream_params(params...) { 351 | oflag = new_oflag; 352 | } 353 | 354 | template 355 | ostream_params(T... params, detail::buffer_size bs) 356 | : ostream_params(params...) { 357 | this->buffer_size = bs.value; 358 | } 359 | 360 | // Intel has a bug that results in failure to deduce a constructor 361 | // for empty parameter packs. 362 | # if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 363 | ostream_params(int new_oflag) : oflag(new_oflag) {} 364 | ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} 365 | # endif 366 | }; 367 | 368 | class file_buffer final : public buffer { 369 | file file_; 370 | 371 | FMT_API void grow(size_t) override; 372 | 373 | public: 374 | FMT_API file_buffer(cstring_view path, const ostream_params& params); 375 | FMT_API file_buffer(file_buffer&& other); 376 | FMT_API ~file_buffer(); 377 | 378 | void flush() { 379 | if (size() == 0) return; 380 | file_.write(data(), size() * sizeof(data()[0])); 381 | clear(); 382 | } 383 | 384 | void close() { 385 | flush(); 386 | file_.close(); 387 | } 388 | }; 389 | 390 | } // namespace detail 391 | 392 | // Added {} below to work around default constructor error known to 393 | // occur in Xcode versions 7.2.1 and 8.2.1. 394 | constexpr detail::buffer_size buffer_size{}; 395 | 396 | /** A fast output stream which is not thread-safe. */ 397 | class FMT_API ostream { 398 | private: 399 | FMT_MSC_WARNING(suppress : 4251) 400 | detail::file_buffer buffer_; 401 | 402 | ostream(cstring_view path, const detail::ostream_params& params) 403 | : buffer_(path, params) {} 404 | 405 | public: 406 | ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {} 407 | 408 | ~ostream(); 409 | 410 | void flush() { buffer_.flush(); } 411 | 412 | template 413 | friend ostream output_file(cstring_view path, T... params); 414 | 415 | void close() { buffer_.close(); } 416 | 417 | /** 418 | Formats ``args`` according to specifications in ``fmt`` and writes the 419 | output to the file. 420 | */ 421 | template void print(format_string fmt, T&&... args) { 422 | vformat_to(detail::buffer_appender(buffer_), fmt, 423 | fmt::make_format_args(args...)); 424 | } 425 | }; 426 | 427 | /** 428 | \rst 429 | Opens a file for writing. Supported parameters passed in *params*: 430 | 431 | * ````: Flags passed to `open 432 | `_ 433 | (``file::WRONLY | file::CREATE | file::TRUNC`` by default) 434 | * ``buffer_size=``: Output buffer size 435 | 436 | **Example**:: 437 | 438 | auto out = fmt::output_file("guide.txt"); 439 | out.print("Don't {}", "Panic"); 440 | \endrst 441 | */ 442 | template 443 | inline ostream output_file(cstring_view path, T... params) { 444 | return {path, detail::ostream_params(params...)}; 445 | } 446 | #endif // FMT_USE_FCNTL 447 | 448 | FMT_END_EXPORT 449 | FMT_END_NAMESPACE 450 | 451 | #endif // FMT_OS_H_ 452 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/std.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - formatters for standard library types 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_STD_H_ 9 | #define FMT_STD_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "format.h" 23 | #include "ostream.h" 24 | 25 | #if FMT_HAS_INCLUDE() 26 | # include 27 | #endif 28 | // Checking FMT_CPLUSPLUS for warning suppression in MSVC. 29 | #if FMT_CPLUSPLUS >= 201703L 30 | # if FMT_HAS_INCLUDE() 31 | # include 32 | # endif 33 | # if FMT_HAS_INCLUDE() 34 | # include 35 | # endif 36 | # if FMT_HAS_INCLUDE() 37 | # include 38 | # endif 39 | #endif 40 | 41 | // GCC 4 does not support FMT_HAS_INCLUDE. 42 | #if FMT_HAS_INCLUDE() || defined(__GLIBCXX__) 43 | # include 44 | // Android NDK with gabi++ library on some architectures does not implement 45 | // abi::__cxa_demangle(). 46 | # ifndef __GABIXX_CXXABI_H__ 47 | # define FMT_HAS_ABI_CXA_DEMANGLE 48 | # endif 49 | #endif 50 | 51 | // Check if typeid is available. 52 | #ifndef FMT_USE_TYPEID 53 | // __RTTI is for EDG compilers. In MSVC typeid is available without RTTI. 54 | # if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \ 55 | defined(__INTEL_RTTI__) || defined(__RTTI) 56 | # define FMT_USE_TYPEID 1 57 | # else 58 | # define FMT_USE_TYPEID 0 59 | # endif 60 | #endif 61 | 62 | #ifdef __cpp_lib_filesystem 63 | FMT_BEGIN_NAMESPACE 64 | 65 | namespace detail { 66 | 67 | template auto get_path_string(const std::filesystem::path& p) { 68 | return p.string(); 69 | } 70 | 71 | template 72 | void write_escaped_path(basic_memory_buffer& quoted, 73 | const std::filesystem::path& p) { 74 | write_escaped_string(std::back_inserter(quoted), p.string()); 75 | } 76 | 77 | # ifdef _WIN32 78 | template <> 79 | inline auto get_path_string(const std::filesystem::path& p) { 80 | return to_utf8(p.native(), to_utf8_error_policy::replace); 81 | } 82 | 83 | template <> 84 | inline void write_escaped_path(memory_buffer& quoted, 85 | const std::filesystem::path& p) { 86 | auto buf = basic_memory_buffer(); 87 | write_escaped_string(std::back_inserter(buf), p.native()); 88 | bool valid = to_utf8::convert(quoted, {buf.data(), buf.size()}); 89 | FMT_ASSERT(valid, "invalid utf16"); 90 | } 91 | # endif // _WIN32 92 | 93 | template <> 94 | inline void write_escaped_path( 95 | basic_memory_buffer& quoted, 96 | const std::filesystem::path& p) { 97 | write_escaped_string( 98 | std::back_inserter(quoted), p.native()); 99 | } 100 | 101 | } // namespace detail 102 | 103 | FMT_EXPORT 104 | template struct formatter { 105 | private: 106 | format_specs specs_; 107 | detail::arg_ref width_ref_; 108 | bool debug_ = false; 109 | 110 | public: 111 | FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } 112 | 113 | template FMT_CONSTEXPR auto parse(ParseContext& ctx) { 114 | auto it = ctx.begin(), end = ctx.end(); 115 | if (it == end) return it; 116 | 117 | it = detail::parse_align(it, end, specs_); 118 | if (it == end) return it; 119 | 120 | it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); 121 | if (it != end && *it == '?') { 122 | debug_ = true; 123 | ++it; 124 | } 125 | return it; 126 | } 127 | 128 | template 129 | auto format(const std::filesystem::path& p, FormatContext& ctx) const { 130 | auto specs = specs_; 131 | detail::handle_dynamic_spec(specs.width, width_ref_, 132 | ctx); 133 | if (!debug_) { 134 | auto s = detail::get_path_string(p); 135 | return detail::write(ctx.out(), basic_string_view(s), specs); 136 | } 137 | auto quoted = basic_memory_buffer(); 138 | detail::write_escaped_path(quoted, p); 139 | return detail::write(ctx.out(), 140 | basic_string_view(quoted.data(), quoted.size()), 141 | specs); 142 | } 143 | }; 144 | FMT_END_NAMESPACE 145 | #endif 146 | 147 | FMT_BEGIN_NAMESPACE 148 | FMT_EXPORT 149 | template 150 | struct formatter : basic_ostream_formatter {}; 151 | FMT_END_NAMESPACE 152 | 153 | #ifdef __cpp_lib_optional 154 | FMT_BEGIN_NAMESPACE 155 | FMT_EXPORT 156 | template 157 | struct formatter, Char, 158 | std::enable_if_t::value>> { 159 | private: 160 | formatter underlying_; 161 | static constexpr basic_string_view optional = 162 | detail::string_literal{}; 164 | static constexpr basic_string_view none = 165 | detail::string_literal{}; 166 | 167 | template 168 | FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) 169 | -> decltype(u.set_debug_format(set)) { 170 | u.set_debug_format(set); 171 | } 172 | 173 | template 174 | FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} 175 | 176 | public: 177 | template FMT_CONSTEXPR auto parse(ParseContext& ctx) { 178 | maybe_set_debug_format(underlying_, true); 179 | return underlying_.parse(ctx); 180 | } 181 | 182 | template 183 | auto format(std::optional const& opt, FormatContext& ctx) const 184 | -> decltype(ctx.out()) { 185 | if (!opt) return detail::write(ctx.out(), none); 186 | 187 | auto out = ctx.out(); 188 | out = detail::write(out, optional); 189 | ctx.advance_to(out); 190 | out = underlying_.format(*opt, ctx); 191 | return detail::write(out, ')'); 192 | } 193 | }; 194 | FMT_END_NAMESPACE 195 | #endif // __cpp_lib_optional 196 | 197 | #ifdef __cpp_lib_variant 198 | FMT_BEGIN_NAMESPACE 199 | namespace detail { 200 | 201 | template 202 | using variant_index_sequence = 203 | std::make_index_sequence::value>; 204 | 205 | template struct is_variant_like_ : std::false_type {}; 206 | template 207 | struct is_variant_like_> : std::true_type {}; 208 | 209 | // formattable element check. 210 | template class is_variant_formattable_ { 211 | template 212 | static std::conjunction< 213 | is_formattable, C>...> 214 | check(std::index_sequence); 215 | 216 | public: 217 | static constexpr const bool value = 218 | decltype(check(variant_index_sequence{}))::value; 219 | }; 220 | 221 | template 222 | auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { 223 | if constexpr (is_string::value) 224 | return write_escaped_string(out, detail::to_string_view(v)); 225 | else if constexpr (std::is_same_v) 226 | return write_escaped_char(out, v); 227 | else 228 | return write(out, v); 229 | } 230 | 231 | } // namespace detail 232 | 233 | template struct is_variant_like { 234 | static constexpr const bool value = detail::is_variant_like_::value; 235 | }; 236 | 237 | template struct is_variant_formattable { 238 | static constexpr const bool value = 239 | detail::is_variant_formattable_::value; 240 | }; 241 | 242 | FMT_EXPORT 243 | template struct formatter { 244 | template 245 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 246 | return ctx.begin(); 247 | } 248 | 249 | template 250 | auto format(const std::monostate&, FormatContext& ctx) const 251 | -> decltype(ctx.out()) { 252 | return detail::write(ctx.out(), "monostate"); 253 | } 254 | }; 255 | 256 | FMT_EXPORT 257 | template 258 | struct formatter< 259 | Variant, Char, 260 | std::enable_if_t, is_variant_formattable>>> { 262 | template 263 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 264 | return ctx.begin(); 265 | } 266 | 267 | template 268 | auto format(const Variant& value, FormatContext& ctx) const 269 | -> decltype(ctx.out()) { 270 | auto out = ctx.out(); 271 | 272 | out = detail::write(out, "variant("); 273 | FMT_TRY { 274 | std::visit( 275 | [&](const auto& v) { 276 | out = detail::write_variant_alternative(out, v); 277 | }, 278 | value); 279 | } 280 | FMT_CATCH(const std::bad_variant_access&) { 281 | detail::write(out, "valueless by exception"); 282 | } 283 | *out++ = ')'; 284 | return out; 285 | } 286 | }; 287 | FMT_END_NAMESPACE 288 | #endif // __cpp_lib_variant 289 | 290 | FMT_BEGIN_NAMESPACE 291 | FMT_EXPORT 292 | template struct formatter { 293 | template 294 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 295 | return ctx.begin(); 296 | } 297 | 298 | template 299 | FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const 300 | -> decltype(ctx.out()) { 301 | auto out = ctx.out(); 302 | out = detail::write_bytes(out, ec.category().name(), format_specs()); 303 | out = detail::write(out, Char(':')); 304 | out = detail::write(out, ec.value()); 305 | return out; 306 | } 307 | }; 308 | 309 | FMT_EXPORT 310 | template 311 | struct formatter< 312 | T, Char, 313 | typename std::enable_if::value>::type> { 314 | private: 315 | bool with_typename_ = false; 316 | 317 | public: 318 | FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) 319 | -> decltype(ctx.begin()) { 320 | auto it = ctx.begin(); 321 | auto end = ctx.end(); 322 | if (it == end || *it == '}') return it; 323 | if (*it == 't') { 324 | ++it; 325 | with_typename_ = FMT_USE_TYPEID != 0; 326 | } 327 | return it; 328 | } 329 | 330 | template 331 | auto format(const std::exception& ex, 332 | basic_format_context& ctx) const -> OutputIt { 333 | format_specs spec; 334 | auto out = ctx.out(); 335 | if (!with_typename_) 336 | return detail::write_bytes(out, string_view(ex.what()), spec); 337 | 338 | #if FMT_USE_TYPEID 339 | const std::type_info& ti = typeid(ex); 340 | # ifdef FMT_HAS_ABI_CXA_DEMANGLE 341 | int status = 0; 342 | std::size_t size = 0; 343 | std::unique_ptr demangled_name_ptr( 344 | abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); 345 | 346 | string_view demangled_name_view; 347 | if (demangled_name_ptr) { 348 | demangled_name_view = demangled_name_ptr.get(); 349 | 350 | // Normalization of stdlib inline namespace names. 351 | // libc++ inline namespaces. 352 | // std::__1::* -> std::* 353 | // std::__1::__fs::* -> std::* 354 | // libstdc++ inline namespaces. 355 | // std::__cxx11::* -> std::* 356 | // std::filesystem::__cxx11::* -> std::filesystem::* 357 | if (demangled_name_view.starts_with("std::")) { 358 | char* begin = demangled_name_ptr.get(); 359 | char* to = begin + 5; // std:: 360 | for (char *from = to, *end = begin + demangled_name_view.size(); 361 | from < end;) { 362 | // This is safe, because demangled_name is NUL-terminated. 363 | if (from[0] == '_' && from[1] == '_') { 364 | char* next = from + 1; 365 | while (next < end && *next != ':') next++; 366 | if (next[0] == ':' && next[1] == ':') { 367 | from = next + 2; 368 | continue; 369 | } 370 | } 371 | *to++ = *from++; 372 | } 373 | demangled_name_view = {begin, detail::to_unsigned(to - begin)}; 374 | } 375 | } else { 376 | demangled_name_view = string_view(ti.name()); 377 | } 378 | out = detail::write_bytes(out, demangled_name_view, spec); 379 | # elif FMT_MSC_VERSION 380 | string_view demangled_name_view(ti.name()); 381 | if (demangled_name_view.starts_with("class ")) 382 | demangled_name_view.remove_prefix(6); 383 | else if (demangled_name_view.starts_with("struct ")) 384 | demangled_name_view.remove_prefix(7); 385 | out = detail::write_bytes(out, demangled_name_view, spec); 386 | # else 387 | out = detail::write_bytes(out, string_view(ti.name()), spec); 388 | # endif 389 | *out++ = ':'; 390 | *out++ = ' '; 391 | return detail::write_bytes(out, string_view(ex.what()), spec); 392 | #endif 393 | } 394 | }; 395 | 396 | namespace detail { 397 | 398 | template 399 | struct has_flip : std::false_type {}; 400 | 401 | template 402 | struct has_flip().flip())>> 403 | : std::true_type {}; 404 | 405 | template struct is_bit_reference_like { 406 | static constexpr const bool value = 407 | std::is_convertible::value && 408 | std::is_nothrow_assignable::value && has_flip::value; 409 | }; 410 | 411 | #ifdef _LIBCPP_VERSION 412 | 413 | // Workaround for libc++ incompatibility with C++ standard. 414 | // According to the Standard, `bitset::operator[] const` returns bool. 415 | template 416 | struct is_bit_reference_like> { 417 | static constexpr const bool value = true; 418 | }; 419 | 420 | #endif 421 | 422 | } // namespace detail 423 | 424 | // We can't use std::vector::reference and 425 | // std::bitset::reference because the compiler can't deduce Allocator and N 426 | // in partial specialization. 427 | FMT_EXPORT 428 | template 429 | struct formatter::value>> 431 | : formatter { 432 | template 433 | FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const 434 | -> decltype(ctx.out()) { 435 | return formatter::format(v, ctx); 436 | } 437 | }; 438 | 439 | FMT_EXPORT 440 | template 441 | struct formatter, Char, 442 | enable_if_t::value>> 443 | : formatter { 444 | template 445 | auto format(const std::atomic& v, FormatContext& ctx) const 446 | -> decltype(ctx.out()) { 447 | return formatter::format(v.load(), ctx); 448 | } 449 | }; 450 | 451 | #ifdef __cpp_lib_atomic_flag_test 452 | FMT_EXPORT 453 | template 454 | struct formatter 455 | : formatter { 456 | template 457 | auto format(const std::atomic_flag& v, FormatContext& ctx) const 458 | -> decltype(ctx.out()) { 459 | return formatter::format(v.test(), ctx); 460 | } 461 | }; 462 | #endif // __cpp_lib_atomic_flag_test 463 | 464 | FMT_END_NAMESPACE 465 | #endif // FMT_STD_H_ 466 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/compile.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - experimental format string compilation 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich and fmt contributors 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_COMPILE_H_ 9 | #define FMT_COMPILE_H_ 10 | 11 | #include "format.h" 12 | 13 | FMT_BEGIN_NAMESPACE 14 | namespace detail { 15 | 16 | template 17 | FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end, 18 | counting_iterator it) { 19 | return it + (end - begin); 20 | } 21 | 22 | // A compile-time string which is compiled into fast formatting code. 23 | class compiled_string {}; 24 | 25 | template 26 | struct is_compiled_string : std::is_base_of {}; 27 | 28 | /** 29 | \rst 30 | Converts a string literal *s* into a format string that will be parsed at 31 | compile time and converted into efficient formatting code. Requires C++17 32 | ``constexpr if`` compiler support. 33 | 34 | **Example**:: 35 | 36 | // Converts 42 into std::string using the most efficient method and no 37 | // runtime format string processing. 38 | std::string s = fmt::format(FMT_COMPILE("{}"), 42); 39 | \endrst 40 | */ 41 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 42 | # define FMT_COMPILE(s) \ 43 | FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) 44 | #else 45 | # define FMT_COMPILE(s) FMT_STRING(s) 46 | #endif 47 | 48 | #if FMT_USE_NONTYPE_TEMPLATE_ARGS 49 | template Str> 51 | struct udl_compiled_string : compiled_string { 52 | using char_type = Char; 53 | explicit constexpr operator basic_string_view() const { 54 | return {Str.data, N - 1}; 55 | } 56 | }; 57 | #endif 58 | 59 | template 60 | const T& first(const T& value, const Tail&...) { 61 | return value; 62 | } 63 | 64 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 65 | template struct type_list {}; 66 | 67 | // Returns a reference to the argument at index N from [first, rest...]. 68 | template 69 | constexpr const auto& get([[maybe_unused]] const T& first, 70 | [[maybe_unused]] const Args&... rest) { 71 | static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); 72 | if constexpr (N == 0) 73 | return first; 74 | else 75 | return detail::get(rest...); 76 | } 77 | 78 | template 79 | constexpr int get_arg_index_by_name(basic_string_view name, 80 | type_list) { 81 | return get_arg_index_by_name(name); 82 | } 83 | 84 | template struct get_type_impl; 85 | 86 | template struct get_type_impl> { 87 | using type = 88 | remove_cvref_t(std::declval()...))>; 89 | }; 90 | 91 | template 92 | using get_type = typename get_type_impl::type; 93 | 94 | template struct is_compiled_format : std::false_type {}; 95 | 96 | template struct text { 97 | basic_string_view data; 98 | using char_type = Char; 99 | 100 | template 101 | constexpr OutputIt format(OutputIt out, const Args&...) const { 102 | return write(out, data); 103 | } 104 | }; 105 | 106 | template 107 | struct is_compiled_format> : std::true_type {}; 108 | 109 | template 110 | constexpr text make_text(basic_string_view s, size_t pos, 111 | size_t size) { 112 | return {{&s[pos], size}}; 113 | } 114 | 115 | template struct code_unit { 116 | Char value; 117 | using char_type = Char; 118 | 119 | template 120 | constexpr OutputIt format(OutputIt out, const Args&...) const { 121 | *out++ = value; 122 | return out; 123 | } 124 | }; 125 | 126 | // This ensures that the argument type is convertible to `const T&`. 127 | template 128 | constexpr const T& get_arg_checked(const Args&... args) { 129 | const auto& arg = detail::get(args...); 130 | if constexpr (detail::is_named_arg>()) { 131 | return arg.value; 132 | } else { 133 | return arg; 134 | } 135 | } 136 | 137 | template 138 | struct is_compiled_format> : std::true_type {}; 139 | 140 | // A replacement field that refers to argument N. 141 | template struct field { 142 | using char_type = Char; 143 | 144 | template 145 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 146 | const T& arg = get_arg_checked(args...); 147 | if constexpr (std::is_convertible_v>) { 148 | auto s = basic_string_view(arg); 149 | return copy_str(s.begin(), s.end(), out); 150 | } 151 | return write(out, arg); 152 | } 153 | }; 154 | 155 | template 156 | struct is_compiled_format> : std::true_type {}; 157 | 158 | // A replacement field that refers to argument with name. 159 | template struct runtime_named_field { 160 | using char_type = Char; 161 | basic_string_view name; 162 | 163 | template 164 | constexpr static bool try_format_argument( 165 | OutputIt& out, 166 | // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 167 | [[maybe_unused]] basic_string_view arg_name, const T& arg) { 168 | if constexpr (is_named_arg::type>::value) { 169 | if (arg_name == arg.name) { 170 | out = write(out, arg.value); 171 | return true; 172 | } 173 | } 174 | return false; 175 | } 176 | 177 | template 178 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 179 | bool found = (try_format_argument(out, name, args) || ...); 180 | if (!found) { 181 | FMT_THROW(format_error("argument with specified name is not found")); 182 | } 183 | return out; 184 | } 185 | }; 186 | 187 | template 188 | struct is_compiled_format> : std::true_type {}; 189 | 190 | // A replacement field that refers to argument N and has format specifiers. 191 | template struct spec_field { 192 | using char_type = Char; 193 | formatter fmt; 194 | 195 | template 196 | constexpr FMT_INLINE OutputIt format(OutputIt out, 197 | const Args&... args) const { 198 | const auto& vargs = 199 | fmt::make_format_args>(args...); 200 | basic_format_context ctx(out, vargs); 201 | return fmt.format(get_arg_checked(args...), ctx); 202 | } 203 | }; 204 | 205 | template 206 | struct is_compiled_format> : std::true_type {}; 207 | 208 | template struct concat { 209 | L lhs; 210 | R rhs; 211 | using char_type = typename L::char_type; 212 | 213 | template 214 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 215 | out = lhs.format(out, args...); 216 | return rhs.format(out, args...); 217 | } 218 | }; 219 | 220 | template 221 | struct is_compiled_format> : std::true_type {}; 222 | 223 | template 224 | constexpr concat make_concat(L lhs, R rhs) { 225 | return {lhs, rhs}; 226 | } 227 | 228 | struct unknown_format {}; 229 | 230 | template 231 | constexpr size_t parse_text(basic_string_view str, size_t pos) { 232 | for (size_t size = str.size(); pos != size; ++pos) { 233 | if (str[pos] == '{' || str[pos] == '}') break; 234 | } 235 | return pos; 236 | } 237 | 238 | template 239 | constexpr auto compile_format_string(S format_str); 240 | 241 | template 242 | constexpr auto parse_tail(T head, S format_str) { 243 | if constexpr (POS != 244 | basic_string_view(format_str).size()) { 245 | constexpr auto tail = compile_format_string(format_str); 246 | if constexpr (std::is_same, 247 | unknown_format>()) 248 | return tail; 249 | else 250 | return make_concat(head, tail); 251 | } else { 252 | return head; 253 | } 254 | } 255 | 256 | template struct parse_specs_result { 257 | formatter fmt; 258 | size_t end; 259 | int next_arg_id; 260 | }; 261 | 262 | enum { manual_indexing_id = -1 }; 263 | 264 | template 265 | constexpr parse_specs_result parse_specs(basic_string_view str, 266 | size_t pos, int next_arg_id) { 267 | str.remove_prefix(pos); 268 | auto ctx = 269 | compile_parse_context(str, max_value(), nullptr, next_arg_id); 270 | auto f = formatter(); 271 | auto end = f.parse(ctx); 272 | return {f, pos + fmt::detail::to_unsigned(end - str.data()), 273 | next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; 274 | } 275 | 276 | template struct arg_id_handler { 277 | arg_ref arg_id; 278 | 279 | constexpr int on_auto() { 280 | FMT_ASSERT(false, "handler cannot be used with automatic indexing"); 281 | return 0; 282 | } 283 | constexpr int on_index(int id) { 284 | arg_id = arg_ref(id); 285 | return 0; 286 | } 287 | constexpr int on_name(basic_string_view id) { 288 | arg_id = arg_ref(id); 289 | return 0; 290 | } 291 | }; 292 | 293 | template struct parse_arg_id_result { 294 | arg_ref arg_id; 295 | const Char* arg_id_end; 296 | }; 297 | 298 | template 299 | constexpr auto parse_arg_id(const Char* begin, const Char* end) { 300 | auto handler = arg_id_handler{arg_ref{}}; 301 | auto arg_id_end = parse_arg_id(begin, end, handler); 302 | return parse_arg_id_result{handler.arg_id, arg_id_end}; 303 | } 304 | 305 | template struct field_type { 306 | using type = remove_cvref_t; 307 | }; 308 | 309 | template 310 | struct field_type::value>> { 311 | using type = remove_cvref_t; 312 | }; 313 | 314 | template 316 | constexpr auto parse_replacement_field_then_tail(S format_str) { 317 | using char_type = typename S::char_type; 318 | constexpr auto str = basic_string_view(format_str); 319 | constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); 320 | if constexpr (c == '}') { 321 | return parse_tail( 322 | field::type, ARG_INDEX>(), 323 | format_str); 324 | } else if constexpr (c != ':') { 325 | FMT_THROW(format_error("expected ':'")); 326 | } else { 327 | constexpr auto result = parse_specs::type>( 328 | str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); 329 | if constexpr (result.end >= str.size() || str[result.end] != '}') { 330 | FMT_THROW(format_error("expected '}'")); 331 | return 0; 332 | } else { 333 | return parse_tail( 334 | spec_field::type, ARG_INDEX>{ 335 | result.fmt}, 336 | format_str); 337 | } 338 | } 339 | } 340 | 341 | // Compiles a non-empty format string and returns the compiled representation 342 | // or unknown_format() on unrecognized input. 343 | template 344 | constexpr auto compile_format_string(S format_str) { 345 | using char_type = typename S::char_type; 346 | constexpr auto str = basic_string_view(format_str); 347 | if constexpr (str[POS] == '{') { 348 | if constexpr (POS + 1 == str.size()) 349 | FMT_THROW(format_error("unmatched '{' in format string")); 350 | if constexpr (str[POS + 1] == '{') { 351 | return parse_tail(make_text(str, POS, 1), format_str); 352 | } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { 353 | static_assert(ID != manual_indexing_id, 354 | "cannot switch from manual to automatic argument indexing"); 355 | constexpr auto next_id = 356 | ID != manual_indexing_id ? ID + 1 : manual_indexing_id; 357 | return parse_replacement_field_then_tail, Args, 358 | POS + 1, ID, next_id>( 359 | format_str); 360 | } else { 361 | constexpr auto arg_id_result = 362 | parse_arg_id(str.data() + POS + 1, str.data() + str.size()); 363 | constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); 364 | constexpr char_type c = 365 | arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); 366 | static_assert(c == '}' || c == ':', "missing '}' in format string"); 367 | if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { 368 | static_assert( 369 | ID == manual_indexing_id || ID == 0, 370 | "cannot switch from automatic to manual argument indexing"); 371 | constexpr auto arg_index = arg_id_result.arg_id.val.index; 372 | return parse_replacement_field_then_tail, 373 | Args, arg_id_end_pos, 374 | arg_index, manual_indexing_id>( 375 | format_str); 376 | } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { 377 | constexpr auto arg_index = 378 | get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); 379 | if constexpr (arg_index >= 0) { 380 | constexpr auto next_id = 381 | ID != manual_indexing_id ? ID + 1 : manual_indexing_id; 382 | return parse_replacement_field_then_tail< 383 | decltype(get_type::value), Args, arg_id_end_pos, 384 | arg_index, next_id>(format_str); 385 | } else if constexpr (c == '}') { 386 | return parse_tail( 387 | runtime_named_field{arg_id_result.arg_id.val.name}, 388 | format_str); 389 | } else if constexpr (c == ':') { 390 | return unknown_format(); // no type info for specs parsing 391 | } 392 | } 393 | } 394 | } else if constexpr (str[POS] == '}') { 395 | if constexpr (POS + 1 == str.size()) 396 | FMT_THROW(format_error("unmatched '}' in format string")); 397 | return parse_tail(make_text(str, POS, 1), format_str); 398 | } else { 399 | constexpr auto end = parse_text(str, POS + 1); 400 | if constexpr (end - POS > 1) { 401 | return parse_tail(make_text(str, POS, end - POS), 402 | format_str); 403 | } else { 404 | return parse_tail(code_unit{str[POS]}, 405 | format_str); 406 | } 407 | } 408 | } 409 | 410 | template ::value)> 412 | constexpr auto compile(S format_str) { 413 | constexpr auto str = basic_string_view(format_str); 414 | if constexpr (str.size() == 0) { 415 | return detail::make_text(str, 0, 0); 416 | } else { 417 | constexpr auto result = 418 | detail::compile_format_string, 0, 0>( 419 | format_str); 420 | return result; 421 | } 422 | } 423 | #endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 424 | } // namespace detail 425 | 426 | FMT_BEGIN_EXPORT 427 | 428 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 429 | 430 | template ::value)> 433 | FMT_INLINE std::basic_string format(const CompiledFormat& cf, 434 | const Args&... args) { 435 | auto s = std::basic_string(); 436 | cf.format(std::back_inserter(s), args...); 437 | return s; 438 | } 439 | 440 | template ::value)> 442 | constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, 443 | const Args&... args) { 444 | return cf.format(out, args...); 445 | } 446 | 447 | template ::value)> 449 | FMT_INLINE std::basic_string format(const S&, 450 | Args&&... args) { 451 | if constexpr (std::is_same::value) { 452 | constexpr auto str = basic_string_view(S()); 453 | if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { 454 | const auto& first = detail::first(args...); 455 | if constexpr (detail::is_named_arg< 456 | remove_cvref_t>::value) { 457 | return fmt::to_string(first.value); 458 | } else { 459 | return fmt::to_string(first); 460 | } 461 | } 462 | } 463 | constexpr auto compiled = detail::compile(S()); 464 | if constexpr (std::is_same, 465 | detail::unknown_format>()) { 466 | return fmt::format( 467 | static_cast>(S()), 468 | std::forward(args)...); 469 | } else { 470 | return fmt::format(compiled, std::forward(args)...); 471 | } 472 | } 473 | 474 | template ::value)> 476 | FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { 477 | constexpr auto compiled = detail::compile(S()); 478 | if constexpr (std::is_same, 479 | detail::unknown_format>()) { 480 | return fmt::format_to( 481 | out, static_cast>(S()), 482 | std::forward(args)...); 483 | } else { 484 | return fmt::format_to(out, compiled, std::forward(args)...); 485 | } 486 | } 487 | #endif 488 | 489 | template ::value)> 491 | format_to_n_result format_to_n(OutputIt out, size_t n, 492 | const S& format_str, Args&&... args) { 493 | using traits = detail::fixed_buffer_traits; 494 | auto buf = detail::iterator_buffer(out, n); 495 | format_to(std::back_inserter(buf), format_str, std::forward(args)...); 496 | return {buf.out(), buf.count()}; 497 | } 498 | 499 | template ::value)> 501 | FMT_CONSTEXPR20 size_t formatted_size(const S& format_str, 502 | const Args&... args) { 503 | return fmt::format_to(detail::counting_iterator(), format_str, args...) 504 | .count(); 505 | } 506 | 507 | template ::value)> 509 | void print(std::FILE* f, const S& format_str, const Args&... args) { 510 | memory_buffer buffer; 511 | fmt::format_to(std::back_inserter(buffer), format_str, args...); 512 | detail::print(f, {buffer.data(), buffer.size()}); 513 | } 514 | 515 | template ::value)> 517 | void print(const S& format_str, const Args&... args) { 518 | print(stdout, format_str, args...); 519 | } 520 | 521 | #if FMT_USE_NONTYPE_TEMPLATE_ARGS 522 | inline namespace literals { 523 | template constexpr auto operator""_cf() { 524 | using char_t = remove_cvref_t; 525 | return detail::udl_compiled_string(); 527 | } 528 | } // namespace literals 529 | #endif 530 | 531 | FMT_END_EXPORT 532 | FMT_END_NAMESPACE 533 | 534 | #endif // FMT_COMPILE_H_ 535 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/printf.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - legacy printf implementation 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_PRINTF_H_ 9 | #define FMT_PRINTF_H_ 10 | 11 | #include // std::max 12 | #include // std::numeric_limits 13 | 14 | #include "format.h" 15 | 16 | FMT_BEGIN_NAMESPACE 17 | FMT_BEGIN_EXPORT 18 | 19 | template struct printf_formatter { printf_formatter() = delete; }; 20 | 21 | template class basic_printf_context { 22 | private: 23 | detail::buffer_appender out_; 24 | basic_format_args args_; 25 | 26 | public: 27 | using char_type = Char; 28 | using parse_context_type = basic_format_parse_context; 29 | template using formatter_type = printf_formatter; 30 | 31 | /** 32 | \rst 33 | Constructs a ``printf_context`` object. References to the arguments are 34 | stored in the context object so make sure they have appropriate lifetimes. 35 | \endrst 36 | */ 37 | basic_printf_context(detail::buffer_appender out, 38 | basic_format_args args) 39 | : out_(out), args_(args) {} 40 | 41 | auto out() -> detail::buffer_appender { return out_; } 42 | void advance_to(detail::buffer_appender) {} 43 | 44 | auto locale() -> detail::locale_ref { return {}; } 45 | 46 | auto arg(int id) const -> basic_format_arg { 47 | return args_.get(id); 48 | } 49 | 50 | FMT_CONSTEXPR void on_error(const char* message) { 51 | detail::error_handler().on_error(message); 52 | } 53 | }; 54 | 55 | namespace detail { 56 | 57 | // Checks if a value fits in int - used to avoid warnings about comparing 58 | // signed and unsigned integers. 59 | template struct int_checker { 60 | template static auto fits_in_int(T value) -> bool { 61 | unsigned max = max_value(); 62 | return value <= max; 63 | } 64 | static auto fits_in_int(bool) -> bool { return true; } 65 | }; 66 | 67 | template <> struct int_checker { 68 | template static auto fits_in_int(T value) -> bool { 69 | return value >= (std::numeric_limits::min)() && 70 | value <= max_value(); 71 | } 72 | static auto fits_in_int(int) -> bool { return true; } 73 | }; 74 | 75 | struct printf_precision_handler { 76 | template ::value)> 77 | auto operator()(T value) -> int { 78 | if (!int_checker::is_signed>::fits_in_int(value)) 79 | throw_format_error("number is too big"); 80 | return (std::max)(static_cast(value), 0); 81 | } 82 | 83 | template ::value)> 84 | auto operator()(T) -> int { 85 | throw_format_error("precision is not integer"); 86 | return 0; 87 | } 88 | }; 89 | 90 | // An argument visitor that returns true iff arg is a zero integer. 91 | struct is_zero_int { 92 | template ::value)> 93 | auto operator()(T value) -> bool { 94 | return value == 0; 95 | } 96 | 97 | template ::value)> 98 | auto operator()(T) -> bool { 99 | return false; 100 | } 101 | }; 102 | 103 | template struct make_unsigned_or_bool : std::make_unsigned {}; 104 | 105 | template <> struct make_unsigned_or_bool { using type = bool; }; 106 | 107 | template class arg_converter { 108 | private: 109 | using char_type = typename Context::char_type; 110 | 111 | basic_format_arg& arg_; 112 | char_type type_; 113 | 114 | public: 115 | arg_converter(basic_format_arg& arg, char_type type) 116 | : arg_(arg), type_(type) {} 117 | 118 | void operator()(bool value) { 119 | if (type_ != 's') operator()(value); 120 | } 121 | 122 | template ::value)> 123 | void operator()(U value) { 124 | bool is_signed = type_ == 'd' || type_ == 'i'; 125 | using target_type = conditional_t::value, U, T>; 126 | if (const_check(sizeof(target_type) <= sizeof(int))) { 127 | // Extra casts are used to silence warnings. 128 | if (is_signed) { 129 | auto n = static_cast(static_cast(value)); 130 | arg_ = detail::make_arg(n); 131 | } else { 132 | using unsigned_type = typename make_unsigned_or_bool::type; 133 | auto n = static_cast(static_cast(value)); 134 | arg_ = detail::make_arg(n); 135 | } 136 | } else { 137 | if (is_signed) { 138 | // glibc's printf doesn't sign extend arguments of smaller types: 139 | // std::printf("%lld", -42); // prints "4294967254" 140 | // but we don't have to do the same because it's a UB. 141 | auto n = static_cast(value); 142 | arg_ = detail::make_arg(n); 143 | } else { 144 | auto n = static_cast::type>(value); 145 | arg_ = detail::make_arg(n); 146 | } 147 | } 148 | } 149 | 150 | template ::value)> 151 | void operator()(U) {} // No conversion needed for non-integral types. 152 | }; 153 | 154 | // Converts an integer argument to T for printf, if T is an integral type. 155 | // If T is void, the argument is converted to corresponding signed or unsigned 156 | // type depending on the type specifier: 'd' and 'i' - signed, other - 157 | // unsigned). 158 | template 159 | void convert_arg(basic_format_arg& arg, Char type) { 160 | visit_format_arg(arg_converter(arg, type), arg); 161 | } 162 | 163 | // Converts an integer argument to char for printf. 164 | template class char_converter { 165 | private: 166 | basic_format_arg& arg_; 167 | 168 | public: 169 | explicit char_converter(basic_format_arg& arg) : arg_(arg) {} 170 | 171 | template ::value)> 172 | void operator()(T value) { 173 | auto c = static_cast(value); 174 | arg_ = detail::make_arg(c); 175 | } 176 | 177 | template ::value)> 178 | void operator()(T) {} // No conversion needed for non-integral types. 179 | }; 180 | 181 | // An argument visitor that return a pointer to a C string if argument is a 182 | // string or null otherwise. 183 | template struct get_cstring { 184 | template auto operator()(T) -> const Char* { return nullptr; } 185 | auto operator()(const Char* s) -> const Char* { return s; } 186 | }; 187 | 188 | // Checks if an argument is a valid printf width specifier and sets 189 | // left alignment if it is negative. 190 | template class printf_width_handler { 191 | private: 192 | format_specs& specs_; 193 | 194 | public: 195 | explicit printf_width_handler(format_specs& specs) : specs_(specs) {} 196 | 197 | template ::value)> 198 | auto operator()(T value) -> unsigned { 199 | auto width = static_cast>(value); 200 | if (detail::is_negative(value)) { 201 | specs_.align = align::left; 202 | width = 0 - width; 203 | } 204 | unsigned int_max = max_value(); 205 | if (width > int_max) throw_format_error("number is too big"); 206 | return static_cast(width); 207 | } 208 | 209 | template ::value)> 210 | auto operator()(T) -> unsigned { 211 | throw_format_error("width is not integer"); 212 | return 0; 213 | } 214 | }; 215 | 216 | // Workaround for a bug with the XL compiler when initializing 217 | // printf_arg_formatter's base class. 218 | template 219 | auto make_arg_formatter(buffer_appender iter, format_specs& s) 220 | -> arg_formatter { 221 | return {iter, s, locale_ref()}; 222 | } 223 | 224 | // The ``printf`` argument formatter. 225 | template 226 | class printf_arg_formatter : public arg_formatter { 227 | private: 228 | using base = arg_formatter; 229 | using context_type = basic_printf_context; 230 | 231 | context_type& context_; 232 | 233 | void write_null_pointer(bool is_string = false) { 234 | auto s = this->specs; 235 | s.type = presentation_type::none; 236 | write_bytes(this->out, is_string ? "(null)" : "(nil)", s); 237 | } 238 | 239 | public: 240 | printf_arg_formatter(buffer_appender iter, format_specs& s, 241 | context_type& ctx) 242 | : base(make_arg_formatter(iter, s)), context_(ctx) {} 243 | 244 | void operator()(monostate value) { base::operator()(value); } 245 | 246 | template ::value)> 247 | void operator()(T value) { 248 | // MSVC2013 fails to compile separate overloads for bool and Char so use 249 | // std::is_same instead. 250 | if (!std::is_same::value) { 251 | base::operator()(value); 252 | return; 253 | } 254 | format_specs fmt_specs = this->specs; 255 | if (fmt_specs.type != presentation_type::none && 256 | fmt_specs.type != presentation_type::chr) { 257 | return (*this)(static_cast(value)); 258 | } 259 | fmt_specs.sign = sign::none; 260 | fmt_specs.alt = false; 261 | fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types. 262 | // align::numeric needs to be overwritten here since the '0' flag is 263 | // ignored for non-numeric types 264 | if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) 265 | fmt_specs.align = align::right; 266 | write(this->out, static_cast(value), fmt_specs); 267 | } 268 | 269 | template ::value)> 270 | void operator()(T value) { 271 | base::operator()(value); 272 | } 273 | 274 | /** Formats a null-terminated C string. */ 275 | void operator()(const char* value) { 276 | if (value) 277 | base::operator()(value); 278 | else 279 | write_null_pointer(this->specs.type != presentation_type::pointer); 280 | } 281 | 282 | /** Formats a null-terminated wide C string. */ 283 | void operator()(const wchar_t* value) { 284 | if (value) 285 | base::operator()(value); 286 | else 287 | write_null_pointer(this->specs.type != presentation_type::pointer); 288 | } 289 | 290 | void operator()(basic_string_view value) { base::operator()(value); } 291 | 292 | /** Formats a pointer. */ 293 | void operator()(const void* value) { 294 | if (value) 295 | base::operator()(value); 296 | else 297 | write_null_pointer(); 298 | } 299 | 300 | /** Formats an argument of a custom (user-defined) type. */ 301 | void operator()(typename basic_format_arg::handle handle) { 302 | auto parse_ctx = basic_format_parse_context({}); 303 | handle.format(parse_ctx, context_); 304 | } 305 | }; 306 | 307 | template 308 | void parse_flags(format_specs& specs, const Char*& it, const Char* end) { 309 | for (; it != end; ++it) { 310 | switch (*it) { 311 | case '-': 312 | specs.align = align::left; 313 | break; 314 | case '+': 315 | specs.sign = sign::plus; 316 | break; 317 | case '0': 318 | specs.fill[0] = '0'; 319 | break; 320 | case ' ': 321 | if (specs.sign != sign::plus) specs.sign = sign::space; 322 | break; 323 | case '#': 324 | specs.alt = true; 325 | break; 326 | default: 327 | return; 328 | } 329 | } 330 | } 331 | 332 | template 333 | auto parse_header(const Char*& it, const Char* end, format_specs& specs, 334 | GetArg get_arg) -> int { 335 | int arg_index = -1; 336 | Char c = *it; 337 | if (c >= '0' && c <= '9') { 338 | // Parse an argument index (if followed by '$') or a width possibly 339 | // preceded with '0' flag(s). 340 | int value = parse_nonnegative_int(it, end, -1); 341 | if (it != end && *it == '$') { // value is an argument index 342 | ++it; 343 | arg_index = value != -1 ? value : max_value(); 344 | } else { 345 | if (c == '0') specs.fill[0] = '0'; 346 | if (value != 0) { 347 | // Nonzero value means that we parsed width and don't need to 348 | // parse it or flags again, so return now. 349 | if (value == -1) throw_format_error("number is too big"); 350 | specs.width = value; 351 | return arg_index; 352 | } 353 | } 354 | } 355 | parse_flags(specs, it, end); 356 | // Parse width. 357 | if (it != end) { 358 | if (*it >= '0' && *it <= '9') { 359 | specs.width = parse_nonnegative_int(it, end, -1); 360 | if (specs.width == -1) throw_format_error("number is too big"); 361 | } else if (*it == '*') { 362 | ++it; 363 | specs.width = static_cast(visit_format_arg( 364 | detail::printf_width_handler(specs), get_arg(-1))); 365 | } 366 | } 367 | return arg_index; 368 | } 369 | 370 | inline auto parse_printf_presentation_type(char c, type t) 371 | -> presentation_type { 372 | using pt = presentation_type; 373 | constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; 374 | switch (c) { 375 | case 'd': 376 | return in(t, integral_set) ? pt::dec : pt::none; 377 | case 'o': 378 | return in(t, integral_set) ? pt::oct : pt::none; 379 | case 'x': 380 | return in(t, integral_set) ? pt::hex_lower : pt::none; 381 | case 'X': 382 | return in(t, integral_set) ? pt::hex_upper : pt::none; 383 | case 'a': 384 | return in(t, float_set) ? pt::hexfloat_lower : pt::none; 385 | case 'A': 386 | return in(t, float_set) ? pt::hexfloat_upper : pt::none; 387 | case 'e': 388 | return in(t, float_set) ? pt::exp_lower : pt::none; 389 | case 'E': 390 | return in(t, float_set) ? pt::exp_upper : pt::none; 391 | case 'f': 392 | return in(t, float_set) ? pt::fixed_lower : pt::none; 393 | case 'F': 394 | return in(t, float_set) ? pt::fixed_upper : pt::none; 395 | case 'g': 396 | return in(t, float_set) ? pt::general_lower : pt::none; 397 | case 'G': 398 | return in(t, float_set) ? pt::general_upper : pt::none; 399 | case 'c': 400 | return in(t, integral_set) ? pt::chr : pt::none; 401 | case 's': 402 | return in(t, string_set | cstring_set) ? pt::string : pt::none; 403 | case 'p': 404 | return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; 405 | default: 406 | return pt::none; 407 | } 408 | } 409 | 410 | template 411 | void vprintf(buffer& buf, basic_string_view format, 412 | basic_format_args args) { 413 | using iterator = buffer_appender; 414 | auto out = iterator(buf); 415 | auto context = basic_printf_context(out, args); 416 | auto parse_ctx = basic_format_parse_context(format); 417 | 418 | // Returns the argument with specified index or, if arg_index is -1, the next 419 | // argument. 420 | auto get_arg = [&](int arg_index) { 421 | if (arg_index < 0) 422 | arg_index = parse_ctx.next_arg_id(); 423 | else 424 | parse_ctx.check_arg_id(--arg_index); 425 | return detail::get_arg(context, arg_index); 426 | }; 427 | 428 | const Char* start = parse_ctx.begin(); 429 | const Char* end = parse_ctx.end(); 430 | auto it = start; 431 | while (it != end) { 432 | if (!find(it, end, '%', it)) { 433 | it = end; // find leaves it == nullptr if it doesn't find '%'. 434 | break; 435 | } 436 | Char c = *it++; 437 | if (it != end && *it == c) { 438 | write(out, basic_string_view(start, to_unsigned(it - start))); 439 | start = ++it; 440 | continue; 441 | } 442 | write(out, basic_string_view(start, to_unsigned(it - 1 - start))); 443 | 444 | auto specs = format_specs(); 445 | specs.align = align::right; 446 | 447 | // Parse argument index, flags and width. 448 | int arg_index = parse_header(it, end, specs, get_arg); 449 | if (arg_index == 0) throw_format_error("argument not found"); 450 | 451 | // Parse precision. 452 | if (it != end && *it == '.') { 453 | ++it; 454 | c = it != end ? *it : 0; 455 | if ('0' <= c && c <= '9') { 456 | specs.precision = parse_nonnegative_int(it, end, 0); 457 | } else if (c == '*') { 458 | ++it; 459 | specs.precision = static_cast( 460 | visit_format_arg(printf_precision_handler(), get_arg(-1))); 461 | } else { 462 | specs.precision = 0; 463 | } 464 | } 465 | 466 | auto arg = get_arg(arg_index); 467 | // For d, i, o, u, x, and X conversion specifiers, if a precision is 468 | // specified, the '0' flag is ignored 469 | if (specs.precision >= 0 && arg.is_integral()) { 470 | // Ignore '0' for non-numeric types or if '-' present. 471 | specs.fill[0] = ' '; 472 | } 473 | if (specs.precision >= 0 && arg.type() == type::cstring_type) { 474 | auto str = visit_format_arg(get_cstring(), arg); 475 | auto str_end = str + specs.precision; 476 | auto nul = std::find(str, str_end, Char()); 477 | auto sv = basic_string_view( 478 | str, to_unsigned(nul != str_end ? nul - str : specs.precision)); 479 | arg = make_arg>(sv); 480 | } 481 | if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false; 482 | if (specs.fill[0] == '0') { 483 | if (arg.is_arithmetic() && specs.align != align::left) 484 | specs.align = align::numeric; 485 | else 486 | specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-' 487 | // flag is also present. 488 | } 489 | 490 | // Parse length and convert the argument to the required type. 491 | c = it != end ? *it++ : 0; 492 | Char t = it != end ? *it : 0; 493 | switch (c) { 494 | case 'h': 495 | if (t == 'h') { 496 | ++it; 497 | t = it != end ? *it : 0; 498 | convert_arg(arg, t); 499 | } else { 500 | convert_arg(arg, t); 501 | } 502 | break; 503 | case 'l': 504 | if (t == 'l') { 505 | ++it; 506 | t = it != end ? *it : 0; 507 | convert_arg(arg, t); 508 | } else { 509 | convert_arg(arg, t); 510 | } 511 | break; 512 | case 'j': 513 | convert_arg(arg, t); 514 | break; 515 | case 'z': 516 | convert_arg(arg, t); 517 | break; 518 | case 't': 519 | convert_arg(arg, t); 520 | break; 521 | case 'L': 522 | // printf produces garbage when 'L' is omitted for long double, no 523 | // need to do the same. 524 | break; 525 | default: 526 | --it; 527 | convert_arg(arg, c); 528 | } 529 | 530 | // Parse type. 531 | if (it == end) throw_format_error("invalid format string"); 532 | char type = static_cast(*it++); 533 | if (arg.is_integral()) { 534 | // Normalize type. 535 | switch (type) { 536 | case 'i': 537 | case 'u': 538 | type = 'd'; 539 | break; 540 | case 'c': 541 | visit_format_arg(char_converter>(arg), arg); 542 | break; 543 | } 544 | } 545 | specs.type = parse_printf_presentation_type(type, arg.type()); 546 | if (specs.type == presentation_type::none) 547 | throw_format_error("invalid format specifier"); 548 | 549 | start = it; 550 | 551 | // Format argument. 552 | visit_format_arg(printf_arg_formatter(out, specs, context), arg); 553 | } 554 | write(out, basic_string_view(start, to_unsigned(it - start))); 555 | } 556 | } // namespace detail 557 | 558 | using printf_context = basic_printf_context; 559 | using wprintf_context = basic_printf_context; 560 | 561 | using printf_args = basic_format_args; 562 | using wprintf_args = basic_format_args; 563 | 564 | /** 565 | \rst 566 | Constructs an `~fmt::format_arg_store` object that contains references to 567 | arguments and can be implicitly converted to `~fmt::printf_args`. 568 | \endrst 569 | */ 570 | template 571 | inline auto make_printf_args(const T&... args) 572 | -> format_arg_store { 573 | return {args...}; 574 | } 575 | 576 | // DEPRECATED! 577 | template 578 | inline auto make_wprintf_args(const T&... args) 579 | -> format_arg_store { 580 | return {args...}; 581 | } 582 | 583 | template 584 | inline auto vsprintf( 585 | basic_string_view fmt, 586 | basic_format_args>> args) 587 | -> std::basic_string { 588 | auto buf = basic_memory_buffer(); 589 | detail::vprintf(buf, fmt, args); 590 | return to_string(buf); 591 | } 592 | 593 | /** 594 | \rst 595 | Formats arguments and returns the result as a string. 596 | 597 | **Example**:: 598 | 599 | std::string message = fmt::sprintf("The answer is %d", 42); 600 | \endrst 601 | */ 602 | template ::value, char_t>> 604 | inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string { 605 | return vsprintf(detail::to_string_view(fmt), 606 | fmt::make_format_args>(args...)); 607 | } 608 | 609 | template 610 | inline auto vfprintf( 611 | std::FILE* f, basic_string_view fmt, 612 | basic_format_args>> args) 613 | -> int { 614 | auto buf = basic_memory_buffer(); 615 | detail::vprintf(buf, fmt, args); 616 | size_t size = buf.size(); 617 | return std::fwrite(buf.data(), sizeof(Char), size, f) < size 618 | ? -1 619 | : static_cast(size); 620 | } 621 | 622 | /** 623 | \rst 624 | Prints formatted data to the file *f*. 625 | 626 | **Example**:: 627 | 628 | fmt::fprintf(stderr, "Don't %s!", "panic"); 629 | \endrst 630 | */ 631 | template > 632 | inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { 633 | return vfprintf(f, detail::to_string_view(fmt), 634 | fmt::make_format_args>(args...)); 635 | } 636 | 637 | template 638 | FMT_DEPRECATED inline auto vprintf( 639 | basic_string_view fmt, 640 | basic_format_args>> args) 641 | -> int { 642 | return vfprintf(stdout, fmt, args); 643 | } 644 | 645 | /** 646 | \rst 647 | Prints formatted data to ``stdout``. 648 | 649 | **Example**:: 650 | 651 | fmt::printf("Elapsed time: %.2f seconds", 1.23); 652 | \endrst 653 | */ 654 | template 655 | inline auto printf(string_view fmt, const T&... args) -> int { 656 | return vfprintf(stdout, fmt, make_printf_args(args...)); 657 | } 658 | template 659 | FMT_DEPRECATED inline auto printf(basic_string_view fmt, 660 | const T&... args) -> int { 661 | return vfprintf(stdout, fmt, make_wprintf_args(args...)); 662 | } 663 | 664 | FMT_END_EXPORT 665 | FMT_END_NAMESPACE 666 | 667 | #endif // FMT_PRINTF_H_ 668 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/color.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - color support 2 | // 3 | // Copyright (c) 2018 - present, Victor Zverovich and fmt contributors 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_COLOR_H_ 9 | #define FMT_COLOR_H_ 10 | 11 | #include "format.h" 12 | 13 | FMT_BEGIN_NAMESPACE 14 | FMT_BEGIN_EXPORT 15 | 16 | enum class color : uint32_t { 17 | alice_blue = 0xF0F8FF, // rgb(240,248,255) 18 | antique_white = 0xFAEBD7, // rgb(250,235,215) 19 | aqua = 0x00FFFF, // rgb(0,255,255) 20 | aquamarine = 0x7FFFD4, // rgb(127,255,212) 21 | azure = 0xF0FFFF, // rgb(240,255,255) 22 | beige = 0xF5F5DC, // rgb(245,245,220) 23 | bisque = 0xFFE4C4, // rgb(255,228,196) 24 | black = 0x000000, // rgb(0,0,0) 25 | blanched_almond = 0xFFEBCD, // rgb(255,235,205) 26 | blue = 0x0000FF, // rgb(0,0,255) 27 | blue_violet = 0x8A2BE2, // rgb(138,43,226) 28 | brown = 0xA52A2A, // rgb(165,42,42) 29 | burly_wood = 0xDEB887, // rgb(222,184,135) 30 | cadet_blue = 0x5F9EA0, // rgb(95,158,160) 31 | chartreuse = 0x7FFF00, // rgb(127,255,0) 32 | chocolate = 0xD2691E, // rgb(210,105,30) 33 | coral = 0xFF7F50, // rgb(255,127,80) 34 | cornflower_blue = 0x6495ED, // rgb(100,149,237) 35 | cornsilk = 0xFFF8DC, // rgb(255,248,220) 36 | crimson = 0xDC143C, // rgb(220,20,60) 37 | cyan = 0x00FFFF, // rgb(0,255,255) 38 | dark_blue = 0x00008B, // rgb(0,0,139) 39 | dark_cyan = 0x008B8B, // rgb(0,139,139) 40 | dark_golden_rod = 0xB8860B, // rgb(184,134,11) 41 | dark_gray = 0xA9A9A9, // rgb(169,169,169) 42 | dark_green = 0x006400, // rgb(0,100,0) 43 | dark_khaki = 0xBDB76B, // rgb(189,183,107) 44 | dark_magenta = 0x8B008B, // rgb(139,0,139) 45 | dark_olive_green = 0x556B2F, // rgb(85,107,47) 46 | dark_orange = 0xFF8C00, // rgb(255,140,0) 47 | dark_orchid = 0x9932CC, // rgb(153,50,204) 48 | dark_red = 0x8B0000, // rgb(139,0,0) 49 | dark_salmon = 0xE9967A, // rgb(233,150,122) 50 | dark_sea_green = 0x8FBC8F, // rgb(143,188,143) 51 | dark_slate_blue = 0x483D8B, // rgb(72,61,139) 52 | dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) 53 | dark_turquoise = 0x00CED1, // rgb(0,206,209) 54 | dark_violet = 0x9400D3, // rgb(148,0,211) 55 | deep_pink = 0xFF1493, // rgb(255,20,147) 56 | deep_sky_blue = 0x00BFFF, // rgb(0,191,255) 57 | dim_gray = 0x696969, // rgb(105,105,105) 58 | dodger_blue = 0x1E90FF, // rgb(30,144,255) 59 | fire_brick = 0xB22222, // rgb(178,34,34) 60 | floral_white = 0xFFFAF0, // rgb(255,250,240) 61 | forest_green = 0x228B22, // rgb(34,139,34) 62 | fuchsia = 0xFF00FF, // rgb(255,0,255) 63 | gainsboro = 0xDCDCDC, // rgb(220,220,220) 64 | ghost_white = 0xF8F8FF, // rgb(248,248,255) 65 | gold = 0xFFD700, // rgb(255,215,0) 66 | golden_rod = 0xDAA520, // rgb(218,165,32) 67 | gray = 0x808080, // rgb(128,128,128) 68 | green = 0x008000, // rgb(0,128,0) 69 | green_yellow = 0xADFF2F, // rgb(173,255,47) 70 | honey_dew = 0xF0FFF0, // rgb(240,255,240) 71 | hot_pink = 0xFF69B4, // rgb(255,105,180) 72 | indian_red = 0xCD5C5C, // rgb(205,92,92) 73 | indigo = 0x4B0082, // rgb(75,0,130) 74 | ivory = 0xFFFFF0, // rgb(255,255,240) 75 | khaki = 0xF0E68C, // rgb(240,230,140) 76 | lavender = 0xE6E6FA, // rgb(230,230,250) 77 | lavender_blush = 0xFFF0F5, // rgb(255,240,245) 78 | lawn_green = 0x7CFC00, // rgb(124,252,0) 79 | lemon_chiffon = 0xFFFACD, // rgb(255,250,205) 80 | light_blue = 0xADD8E6, // rgb(173,216,230) 81 | light_coral = 0xF08080, // rgb(240,128,128) 82 | light_cyan = 0xE0FFFF, // rgb(224,255,255) 83 | light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) 84 | light_gray = 0xD3D3D3, // rgb(211,211,211) 85 | light_green = 0x90EE90, // rgb(144,238,144) 86 | light_pink = 0xFFB6C1, // rgb(255,182,193) 87 | light_salmon = 0xFFA07A, // rgb(255,160,122) 88 | light_sea_green = 0x20B2AA, // rgb(32,178,170) 89 | light_sky_blue = 0x87CEFA, // rgb(135,206,250) 90 | light_slate_gray = 0x778899, // rgb(119,136,153) 91 | light_steel_blue = 0xB0C4DE, // rgb(176,196,222) 92 | light_yellow = 0xFFFFE0, // rgb(255,255,224) 93 | lime = 0x00FF00, // rgb(0,255,0) 94 | lime_green = 0x32CD32, // rgb(50,205,50) 95 | linen = 0xFAF0E6, // rgb(250,240,230) 96 | magenta = 0xFF00FF, // rgb(255,0,255) 97 | maroon = 0x800000, // rgb(128,0,0) 98 | medium_aquamarine = 0x66CDAA, // rgb(102,205,170) 99 | medium_blue = 0x0000CD, // rgb(0,0,205) 100 | medium_orchid = 0xBA55D3, // rgb(186,85,211) 101 | medium_purple = 0x9370DB, // rgb(147,112,219) 102 | medium_sea_green = 0x3CB371, // rgb(60,179,113) 103 | medium_slate_blue = 0x7B68EE, // rgb(123,104,238) 104 | medium_spring_green = 0x00FA9A, // rgb(0,250,154) 105 | medium_turquoise = 0x48D1CC, // rgb(72,209,204) 106 | medium_violet_red = 0xC71585, // rgb(199,21,133) 107 | midnight_blue = 0x191970, // rgb(25,25,112) 108 | mint_cream = 0xF5FFFA, // rgb(245,255,250) 109 | misty_rose = 0xFFE4E1, // rgb(255,228,225) 110 | moccasin = 0xFFE4B5, // rgb(255,228,181) 111 | navajo_white = 0xFFDEAD, // rgb(255,222,173) 112 | navy = 0x000080, // rgb(0,0,128) 113 | old_lace = 0xFDF5E6, // rgb(253,245,230) 114 | olive = 0x808000, // rgb(128,128,0) 115 | olive_drab = 0x6B8E23, // rgb(107,142,35) 116 | orange = 0xFFA500, // rgb(255,165,0) 117 | orange_red = 0xFF4500, // rgb(255,69,0) 118 | orchid = 0xDA70D6, // rgb(218,112,214) 119 | pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) 120 | pale_green = 0x98FB98, // rgb(152,251,152) 121 | pale_turquoise = 0xAFEEEE, // rgb(175,238,238) 122 | pale_violet_red = 0xDB7093, // rgb(219,112,147) 123 | papaya_whip = 0xFFEFD5, // rgb(255,239,213) 124 | peach_puff = 0xFFDAB9, // rgb(255,218,185) 125 | peru = 0xCD853F, // rgb(205,133,63) 126 | pink = 0xFFC0CB, // rgb(255,192,203) 127 | plum = 0xDDA0DD, // rgb(221,160,221) 128 | powder_blue = 0xB0E0E6, // rgb(176,224,230) 129 | purple = 0x800080, // rgb(128,0,128) 130 | rebecca_purple = 0x663399, // rgb(102,51,153) 131 | red = 0xFF0000, // rgb(255,0,0) 132 | rosy_brown = 0xBC8F8F, // rgb(188,143,143) 133 | royal_blue = 0x4169E1, // rgb(65,105,225) 134 | saddle_brown = 0x8B4513, // rgb(139,69,19) 135 | salmon = 0xFA8072, // rgb(250,128,114) 136 | sandy_brown = 0xF4A460, // rgb(244,164,96) 137 | sea_green = 0x2E8B57, // rgb(46,139,87) 138 | sea_shell = 0xFFF5EE, // rgb(255,245,238) 139 | sienna = 0xA0522D, // rgb(160,82,45) 140 | silver = 0xC0C0C0, // rgb(192,192,192) 141 | sky_blue = 0x87CEEB, // rgb(135,206,235) 142 | slate_blue = 0x6A5ACD, // rgb(106,90,205) 143 | slate_gray = 0x708090, // rgb(112,128,144) 144 | snow = 0xFFFAFA, // rgb(255,250,250) 145 | spring_green = 0x00FF7F, // rgb(0,255,127) 146 | steel_blue = 0x4682B4, // rgb(70,130,180) 147 | tan = 0xD2B48C, // rgb(210,180,140) 148 | teal = 0x008080, // rgb(0,128,128) 149 | thistle = 0xD8BFD8, // rgb(216,191,216) 150 | tomato = 0xFF6347, // rgb(255,99,71) 151 | turquoise = 0x40E0D0, // rgb(64,224,208) 152 | violet = 0xEE82EE, // rgb(238,130,238) 153 | wheat = 0xF5DEB3, // rgb(245,222,179) 154 | white = 0xFFFFFF, // rgb(255,255,255) 155 | white_smoke = 0xF5F5F5, // rgb(245,245,245) 156 | yellow = 0xFFFF00, // rgb(255,255,0) 157 | yellow_green = 0x9ACD32 // rgb(154,205,50) 158 | }; // enum class color 159 | 160 | enum class terminal_color : uint8_t { 161 | black = 30, 162 | red, 163 | green, 164 | yellow, 165 | blue, 166 | magenta, 167 | cyan, 168 | white, 169 | bright_black = 90, 170 | bright_red, 171 | bright_green, 172 | bright_yellow, 173 | bright_blue, 174 | bright_magenta, 175 | bright_cyan, 176 | bright_white 177 | }; 178 | 179 | enum class emphasis : uint8_t { 180 | bold = 1, 181 | faint = 1 << 1, 182 | italic = 1 << 2, 183 | underline = 1 << 3, 184 | blink = 1 << 4, 185 | reverse = 1 << 5, 186 | conceal = 1 << 6, 187 | strikethrough = 1 << 7, 188 | }; 189 | 190 | // rgb is a struct for red, green and blue colors. 191 | // Using the name "rgb" makes some editors show the color in a tooltip. 192 | struct rgb { 193 | FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} 194 | FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} 195 | FMT_CONSTEXPR rgb(uint32_t hex) 196 | : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} 197 | FMT_CONSTEXPR rgb(color hex) 198 | : r((uint32_t(hex) >> 16) & 0xFF), 199 | g((uint32_t(hex) >> 8) & 0xFF), 200 | b(uint32_t(hex) & 0xFF) {} 201 | uint8_t r; 202 | uint8_t g; 203 | uint8_t b; 204 | }; 205 | 206 | namespace detail { 207 | 208 | // color is a struct of either a rgb color or a terminal color. 209 | struct color_type { 210 | FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} 211 | FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { 212 | value.rgb_color = static_cast(rgb_color); 213 | } 214 | FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} { 215 | value.rgb_color = (static_cast(rgb_color.r) << 16) | 216 | (static_cast(rgb_color.g) << 8) | rgb_color.b; 217 | } 218 | FMT_CONSTEXPR color_type(terminal_color term_color) noexcept 219 | : is_rgb(), value{} { 220 | value.term_color = static_cast(term_color); 221 | } 222 | bool is_rgb; 223 | union color_union { 224 | uint8_t term_color; 225 | uint32_t rgb_color; 226 | } value; 227 | }; 228 | } // namespace detail 229 | 230 | /** A text style consisting of foreground and background colors and emphasis. */ 231 | class text_style { 232 | public: 233 | FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept 234 | : set_foreground_color(), set_background_color(), ems(em) {} 235 | 236 | FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { 237 | if (!set_foreground_color) { 238 | set_foreground_color = rhs.set_foreground_color; 239 | foreground_color = rhs.foreground_color; 240 | } else if (rhs.set_foreground_color) { 241 | if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) 242 | FMT_THROW(format_error("can't OR a terminal color")); 243 | foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; 244 | } 245 | 246 | if (!set_background_color) { 247 | set_background_color = rhs.set_background_color; 248 | background_color = rhs.background_color; 249 | } else if (rhs.set_background_color) { 250 | if (!background_color.is_rgb || !rhs.background_color.is_rgb) 251 | FMT_THROW(format_error("can't OR a terminal color")); 252 | background_color.value.rgb_color |= rhs.background_color.value.rgb_color; 253 | } 254 | 255 | ems = static_cast(static_cast(ems) | 256 | static_cast(rhs.ems)); 257 | return *this; 258 | } 259 | 260 | friend FMT_CONSTEXPR text_style operator|(text_style lhs, 261 | const text_style& rhs) { 262 | return lhs |= rhs; 263 | } 264 | 265 | FMT_CONSTEXPR bool has_foreground() const noexcept { 266 | return set_foreground_color; 267 | } 268 | FMT_CONSTEXPR bool has_background() const noexcept { 269 | return set_background_color; 270 | } 271 | FMT_CONSTEXPR bool has_emphasis() const noexcept { 272 | return static_cast(ems) != 0; 273 | } 274 | FMT_CONSTEXPR detail::color_type get_foreground() const noexcept { 275 | FMT_ASSERT(has_foreground(), "no foreground specified for this style"); 276 | return foreground_color; 277 | } 278 | FMT_CONSTEXPR detail::color_type get_background() const noexcept { 279 | FMT_ASSERT(has_background(), "no background specified for this style"); 280 | return background_color; 281 | } 282 | FMT_CONSTEXPR emphasis get_emphasis() const noexcept { 283 | FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); 284 | return ems; 285 | } 286 | 287 | private: 288 | FMT_CONSTEXPR text_style(bool is_foreground, 289 | detail::color_type text_color) noexcept 290 | : set_foreground_color(), set_background_color(), ems() { 291 | if (is_foreground) { 292 | foreground_color = text_color; 293 | set_foreground_color = true; 294 | } else { 295 | background_color = text_color; 296 | set_background_color = true; 297 | } 298 | } 299 | 300 | friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept; 301 | 302 | friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept; 303 | 304 | detail::color_type foreground_color; 305 | detail::color_type background_color; 306 | bool set_foreground_color; 307 | bool set_background_color; 308 | emphasis ems; 309 | }; 310 | 311 | /** Creates a text style from the foreground (text) color. */ 312 | FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept { 313 | return text_style(true, foreground); 314 | } 315 | 316 | /** Creates a text style from the background color. */ 317 | FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept { 318 | return text_style(false, background); 319 | } 320 | 321 | FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept { 322 | return text_style(lhs) | rhs; 323 | } 324 | 325 | namespace detail { 326 | 327 | template struct ansi_color_escape { 328 | FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, 329 | const char* esc) noexcept { 330 | // If we have a terminal color, we need to output another escape code 331 | // sequence. 332 | if (!text_color.is_rgb) { 333 | bool is_background = esc == string_view("\x1b[48;2;"); 334 | uint32_t value = text_color.value.term_color; 335 | // Background ASCII codes are the same as the foreground ones but with 336 | // 10 more. 337 | if (is_background) value += 10u; 338 | 339 | size_t index = 0; 340 | buffer[index++] = static_cast('\x1b'); 341 | buffer[index++] = static_cast('['); 342 | 343 | if (value >= 100u) { 344 | buffer[index++] = static_cast('1'); 345 | value %= 100u; 346 | } 347 | buffer[index++] = static_cast('0' + value / 10u); 348 | buffer[index++] = static_cast('0' + value % 10u); 349 | 350 | buffer[index++] = static_cast('m'); 351 | buffer[index++] = static_cast('\0'); 352 | return; 353 | } 354 | 355 | for (int i = 0; i < 7; i++) { 356 | buffer[i] = static_cast(esc[i]); 357 | } 358 | rgb color(text_color.value.rgb_color); 359 | to_esc(color.r, buffer + 7, ';'); 360 | to_esc(color.g, buffer + 11, ';'); 361 | to_esc(color.b, buffer + 15, 'm'); 362 | buffer[19] = static_cast(0); 363 | } 364 | FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept { 365 | uint8_t em_codes[num_emphases] = {}; 366 | if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; 367 | if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; 368 | if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; 369 | if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; 370 | if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; 371 | if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; 372 | if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; 373 | if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; 374 | 375 | size_t index = 0; 376 | for (size_t i = 0; i < num_emphases; ++i) { 377 | if (!em_codes[i]) continue; 378 | buffer[index++] = static_cast('\x1b'); 379 | buffer[index++] = static_cast('['); 380 | buffer[index++] = static_cast('0' + em_codes[i]); 381 | buffer[index++] = static_cast('m'); 382 | } 383 | buffer[index++] = static_cast(0); 384 | } 385 | FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } 386 | 387 | FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; } 388 | FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept { 389 | return buffer + std::char_traits::length(buffer); 390 | } 391 | 392 | private: 393 | static constexpr size_t num_emphases = 8; 394 | Char buffer[7u + 3u * num_emphases + 1u]; 395 | 396 | static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, 397 | char delimiter) noexcept { 398 | out[0] = static_cast('0' + c / 100); 399 | out[1] = static_cast('0' + c / 10 % 10); 400 | out[2] = static_cast('0' + c % 10); 401 | out[3] = static_cast(delimiter); 402 | } 403 | static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept { 404 | return static_cast(em) & static_cast(mask); 405 | } 406 | }; 407 | 408 | template 409 | FMT_CONSTEXPR ansi_color_escape make_foreground_color( 410 | detail::color_type foreground) noexcept { 411 | return ansi_color_escape(foreground, "\x1b[38;2;"); 412 | } 413 | 414 | template 415 | FMT_CONSTEXPR ansi_color_escape make_background_color( 416 | detail::color_type background) noexcept { 417 | return ansi_color_escape(background, "\x1b[48;2;"); 418 | } 419 | 420 | template 421 | FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) noexcept { 422 | return ansi_color_escape(em); 423 | } 424 | 425 | template inline void reset_color(buffer& buffer) { 426 | auto reset_color = string_view("\x1b[0m"); 427 | buffer.append(reset_color.begin(), reset_color.end()); 428 | } 429 | 430 | template struct styled_arg { 431 | const T& value; 432 | text_style style; 433 | }; 434 | 435 | template 436 | void vformat_to(buffer& buf, const text_style& ts, 437 | basic_string_view format_str, 438 | basic_format_args>> args) { 439 | bool has_style = false; 440 | if (ts.has_emphasis()) { 441 | has_style = true; 442 | auto emphasis = detail::make_emphasis(ts.get_emphasis()); 443 | buf.append(emphasis.begin(), emphasis.end()); 444 | } 445 | if (ts.has_foreground()) { 446 | has_style = true; 447 | auto foreground = detail::make_foreground_color(ts.get_foreground()); 448 | buf.append(foreground.begin(), foreground.end()); 449 | } 450 | if (ts.has_background()) { 451 | has_style = true; 452 | auto background = detail::make_background_color(ts.get_background()); 453 | buf.append(background.begin(), background.end()); 454 | } 455 | detail::vformat_to(buf, format_str, args, {}); 456 | if (has_style) detail::reset_color(buf); 457 | } 458 | 459 | } // namespace detail 460 | 461 | inline void vprint(std::FILE* f, const text_style& ts, string_view fmt, 462 | format_args args) { 463 | // Legacy wide streams are not supported. 464 | auto buf = memory_buffer(); 465 | detail::vformat_to(buf, ts, fmt, args); 466 | if (detail::is_utf8()) { 467 | detail::print(f, string_view(buf.begin(), buf.size())); 468 | return; 469 | } 470 | buf.push_back('\0'); 471 | int result = std::fputs(buf.data(), f); 472 | if (result < 0) 473 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 474 | } 475 | 476 | /** 477 | \rst 478 | Formats a string and prints it to the specified file stream using ANSI 479 | escape sequences to specify text formatting. 480 | 481 | **Example**:: 482 | 483 | fmt::print(fmt::emphasis::bold | fg(fmt::color::red), 484 | "Elapsed time: {0:.2f} seconds", 1.23); 485 | \endrst 486 | */ 487 | template ::value)> 489 | void print(std::FILE* f, const text_style& ts, const S& format_str, 490 | const Args&... args) { 491 | vprint(f, ts, format_str, 492 | fmt::make_format_args>>(args...)); 493 | } 494 | 495 | /** 496 | \rst 497 | Formats a string and prints it to stdout using ANSI escape sequences to 498 | specify text formatting. 499 | 500 | **Example**:: 501 | 502 | fmt::print(fmt::emphasis::bold | fg(fmt::color::red), 503 | "Elapsed time: {0:.2f} seconds", 1.23); 504 | \endrst 505 | */ 506 | template ::value)> 508 | void print(const text_style& ts, const S& format_str, const Args&... args) { 509 | return print(stdout, ts, format_str, args...); 510 | } 511 | 512 | template > 513 | inline std::basic_string vformat( 514 | const text_style& ts, const S& format_str, 515 | basic_format_args>> args) { 516 | basic_memory_buffer buf; 517 | detail::vformat_to(buf, ts, detail::to_string_view(format_str), args); 518 | return fmt::to_string(buf); 519 | } 520 | 521 | /** 522 | \rst 523 | Formats arguments and returns the result as a string using ANSI 524 | escape sequences to specify text formatting. 525 | 526 | **Example**:: 527 | 528 | #include 529 | std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), 530 | "The answer is {}", 42); 531 | \endrst 532 | */ 533 | template > 534 | inline std::basic_string format(const text_style& ts, const S& format_str, 535 | const Args&... args) { 536 | return fmt::vformat(ts, detail::to_string_view(format_str), 537 | fmt::make_format_args>(args...)); 538 | } 539 | 540 | /** 541 | Formats a string with the given text_style and writes the output to ``out``. 542 | */ 543 | template ::value)> 545 | OutputIt vformat_to( 546 | OutputIt out, const text_style& ts, basic_string_view format_str, 547 | basic_format_args>> args) { 548 | auto&& buf = detail::get_buffer(out); 549 | detail::vformat_to(buf, ts, format_str, args); 550 | return detail::get_iterator(buf, out); 551 | } 552 | 553 | /** 554 | \rst 555 | Formats arguments with the given text_style, writes the result to the output 556 | iterator ``out`` and returns the iterator past the end of the output range. 557 | 558 | **Example**:: 559 | 560 | std::vector out; 561 | fmt::format_to(std::back_inserter(out), 562 | fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); 563 | \endrst 564 | */ 565 | template >::value&& 567 | detail::is_string::value> 568 | inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, 569 | Args&&... args) -> 570 | typename std::enable_if::type { 571 | return vformat_to(out, ts, detail::to_string_view(format_str), 572 | fmt::make_format_args>>(args...)); 573 | } 574 | 575 | template 576 | struct formatter, Char> : formatter { 577 | template 578 | auto format(const detail::styled_arg& arg, FormatContext& ctx) const 579 | -> decltype(ctx.out()) { 580 | const auto& ts = arg.style; 581 | const auto& value = arg.value; 582 | auto out = ctx.out(); 583 | 584 | bool has_style = false; 585 | if (ts.has_emphasis()) { 586 | has_style = true; 587 | auto emphasis = detail::make_emphasis(ts.get_emphasis()); 588 | out = std::copy(emphasis.begin(), emphasis.end(), out); 589 | } 590 | if (ts.has_foreground()) { 591 | has_style = true; 592 | auto foreground = 593 | detail::make_foreground_color(ts.get_foreground()); 594 | out = std::copy(foreground.begin(), foreground.end(), out); 595 | } 596 | if (ts.has_background()) { 597 | has_style = true; 598 | auto background = 599 | detail::make_background_color(ts.get_background()); 600 | out = std::copy(background.begin(), background.end(), out); 601 | } 602 | out = formatter::format(value, ctx); 603 | if (has_style) { 604 | auto reset_color = string_view("\x1b[0m"); 605 | out = std::copy(reset_color.begin(), reset_color.end(), out); 606 | } 607 | return out; 608 | } 609 | }; 610 | 611 | /** 612 | \rst 613 | Returns an argument that will be formatted using ANSI escape sequences, 614 | to be used in a formatting function. 615 | 616 | **Example**:: 617 | 618 | fmt::print("Elapsed time: {0:.2f} seconds", 619 | fmt::styled(1.23, fmt::fg(fmt::color::green) | 620 | fmt::bg(fmt::color::blue))); 621 | \endrst 622 | */ 623 | template 624 | FMT_CONSTEXPR auto styled(const T& value, text_style ts) 625 | -> detail::styled_arg> { 626 | return detail::styled_arg>{value, ts}; 627 | } 628 | 629 | FMT_END_EXPORT 630 | FMT_END_NAMESPACE 631 | 632 | #endif // FMT_COLOR_H_ 633 | -------------------------------------------------------------------------------- /ext/fmt-10.1.1/include/fmt/ranges.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - experimental range support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | // 8 | // Copyright (c) 2018 - present, Remotion (Igor Schulz) 9 | // All Rights Reserved 10 | // {fmt} support for ranges, containers and types tuple interface. 11 | 12 | #ifndef FMT_RANGES_H_ 13 | #define FMT_RANGES_H_ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "format.h" 20 | 21 | FMT_BEGIN_NAMESPACE 22 | 23 | namespace detail { 24 | 25 | template 26 | auto copy(const Range& range, OutputIt out) -> OutputIt { 27 | for (auto it = range.begin(), end = range.end(); it != end; ++it) 28 | *out++ = *it; 29 | return out; 30 | } 31 | 32 | template 33 | auto copy(const char* str, OutputIt out) -> OutputIt { 34 | while (*str) *out++ = *str++; 35 | return out; 36 | } 37 | 38 | template auto copy(char ch, OutputIt out) -> OutputIt { 39 | *out++ = ch; 40 | return out; 41 | } 42 | 43 | template auto copy(wchar_t ch, OutputIt out) -> OutputIt { 44 | *out++ = ch; 45 | return out; 46 | } 47 | 48 | // Returns true if T has a std::string-like interface, like std::string_view. 49 | template class is_std_string_like { 50 | template 51 | static auto check(U* p) 52 | -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); 53 | template static void check(...); 54 | 55 | public: 56 | static constexpr const bool value = 57 | is_string::value || 58 | std::is_convertible>::value || 59 | !std::is_void(nullptr))>::value; 60 | }; 61 | 62 | template 63 | struct is_std_string_like> : std::true_type {}; 64 | 65 | template class is_map { 66 | template static auto check(U*) -> typename U::mapped_type; 67 | template static void check(...); 68 | 69 | public: 70 | #ifdef FMT_FORMAT_MAP_AS_LIST // DEPRECATED! 71 | static constexpr const bool value = false; 72 | #else 73 | static constexpr const bool value = 74 | !std::is_void(nullptr))>::value; 75 | #endif 76 | }; 77 | 78 | template class is_set { 79 | template static auto check(U*) -> typename U::key_type; 80 | template static void check(...); 81 | 82 | public: 83 | #ifdef FMT_FORMAT_SET_AS_LIST // DEPRECATED! 84 | static constexpr const bool value = false; 85 | #else 86 | static constexpr const bool value = 87 | !std::is_void(nullptr))>::value && !is_map::value; 88 | #endif 89 | }; 90 | 91 | template struct conditional_helper {}; 92 | 93 | template struct is_range_ : std::false_type {}; 94 | 95 | #if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800 96 | 97 | # define FMT_DECLTYPE_RETURN(val) \ 98 | ->decltype(val) { return val; } \ 99 | static_assert( \ 100 | true, "") // This makes it so that a semicolon is required after the 101 | // macro, which helps clang-format handle the formatting. 102 | 103 | // C array overload 104 | template 105 | auto range_begin(const T (&arr)[N]) -> const T* { 106 | return arr; 107 | } 108 | template 109 | auto range_end(const T (&arr)[N]) -> const T* { 110 | return arr + N; 111 | } 112 | 113 | template 114 | struct has_member_fn_begin_end_t : std::false_type {}; 115 | 116 | template 117 | struct has_member_fn_begin_end_t().begin()), 118 | decltype(std::declval().end())>> 119 | : std::true_type {}; 120 | 121 | // Member function overload 122 | template 123 | auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast(rng).begin()); 124 | template 125 | auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast(rng).end()); 126 | 127 | // ADL overload. Only participates in overload resolution if member functions 128 | // are not found. 129 | template 130 | auto range_begin(T&& rng) 131 | -> enable_if_t::value, 132 | decltype(begin(static_cast(rng)))> { 133 | return begin(static_cast(rng)); 134 | } 135 | template 136 | auto range_end(T&& rng) -> enable_if_t::value, 137 | decltype(end(static_cast(rng)))> { 138 | return end(static_cast(rng)); 139 | } 140 | 141 | template 142 | struct has_const_begin_end : std::false_type {}; 143 | template 144 | struct has_mutable_begin_end : std::false_type {}; 145 | 146 | template 147 | struct has_const_begin_end< 148 | T, 149 | void_t< 150 | decltype(detail::range_begin(std::declval&>())), 151 | decltype(detail::range_end(std::declval&>()))>> 152 | : std::true_type {}; 153 | 154 | template 155 | struct has_mutable_begin_end< 156 | T, void_t())), 157 | decltype(detail::range_end(std::declval())), 158 | // the extra int here is because older versions of MSVC don't 159 | // SFINAE properly unless there are distinct types 160 | int>> : std::true_type {}; 161 | 162 | template 163 | struct is_range_ 164 | : std::integral_constant::value || 165 | has_mutable_begin_end::value)> {}; 166 | # undef FMT_DECLTYPE_RETURN 167 | #endif 168 | 169 | // tuple_size and tuple_element check. 170 | template class is_tuple_like_ { 171 | template 172 | static auto check(U* p) -> decltype(std::tuple_size::value, int()); 173 | template static void check(...); 174 | 175 | public: 176 | static constexpr const bool value = 177 | !std::is_void(nullptr))>::value; 178 | }; 179 | 180 | // Check for integer_sequence 181 | #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 182 | template 183 | using integer_sequence = std::integer_sequence; 184 | template using index_sequence = std::index_sequence; 185 | template using make_index_sequence = std::make_index_sequence; 186 | #else 187 | template struct integer_sequence { 188 | using value_type = T; 189 | 190 | static FMT_CONSTEXPR size_t size() { return sizeof...(N); } 191 | }; 192 | 193 | template using index_sequence = integer_sequence; 194 | 195 | template 196 | struct make_integer_sequence : make_integer_sequence {}; 197 | template 198 | struct make_integer_sequence : integer_sequence {}; 199 | 200 | template 201 | using make_index_sequence = make_integer_sequence; 202 | #endif 203 | 204 | template 205 | using tuple_index_sequence = make_index_sequence::value>; 206 | 207 | template ::value> 208 | class is_tuple_formattable_ { 209 | public: 210 | static constexpr const bool value = false; 211 | }; 212 | template class is_tuple_formattable_ { 213 | template 214 | static std::true_type check2(index_sequence, 215 | integer_sequence); 216 | static std::false_type check2(...); 217 | template 218 | static decltype(check2( 219 | index_sequence{}, 220 | integer_sequence< 221 | bool, (is_formattable::type, 222 | C>::value)...>{})) check(index_sequence); 223 | 224 | public: 225 | static constexpr const bool value = 226 | decltype(check(tuple_index_sequence{}))::value; 227 | }; 228 | 229 | template 230 | FMT_CONSTEXPR void for_each(index_sequence, Tuple&& t, F&& f) { 231 | using std::get; 232 | // Using a free function get(Tuple) now. 233 | const int unused[] = {0, ((void)f(get(t)), 0)...}; 234 | ignore_unused(unused); 235 | } 236 | 237 | template 238 | FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) { 239 | for_each(tuple_index_sequence>(), 240 | std::forward(t), std::forward(f)); 241 | } 242 | 243 | template 244 | void for_each2(index_sequence, Tuple1&& t1, Tuple2&& t2, F&& f) { 245 | using std::get; 246 | const int unused[] = {0, ((void)f(get(t1), get(t2)), 0)...}; 247 | ignore_unused(unused); 248 | } 249 | 250 | template 251 | void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) { 252 | for_each2(tuple_index_sequence>(), 253 | std::forward(t1), std::forward(t2), 254 | std::forward(f)); 255 | } 256 | 257 | namespace tuple { 258 | // Workaround a bug in MSVC 2019 (v140). 259 | template 260 | using result_t = std::tuple, Char>...>; 261 | 262 | using std::get; 263 | template 264 | auto get_formatters(index_sequence) 265 | -> result_t(std::declval()))...>; 266 | } // namespace tuple 267 | 268 | #if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920 269 | // Older MSVC doesn't get the reference type correctly for arrays. 270 | template struct range_reference_type_impl { 271 | using type = decltype(*detail::range_begin(std::declval())); 272 | }; 273 | 274 | template struct range_reference_type_impl { 275 | using type = T&; 276 | }; 277 | 278 | template 279 | using range_reference_type = typename range_reference_type_impl::type; 280 | #else 281 | template 282 | using range_reference_type = 283 | decltype(*detail::range_begin(std::declval())); 284 | #endif 285 | 286 | // We don't use the Range's value_type for anything, but we do need the Range's 287 | // reference type, with cv-ref stripped. 288 | template 289 | using uncvref_type = remove_cvref_t>; 290 | 291 | template 292 | FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) 293 | -> decltype(f.set_debug_format(set)) { 294 | f.set_debug_format(set); 295 | } 296 | template 297 | FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} 298 | 299 | // These are not generic lambdas for compatibility with C++11. 300 | template struct parse_empty_specs { 301 | template FMT_CONSTEXPR void operator()(Formatter& f) { 302 | f.parse(ctx); 303 | detail::maybe_set_debug_format(f, true); 304 | } 305 | ParseContext& ctx; 306 | }; 307 | template struct format_tuple_element { 308 | using char_type = typename FormatContext::char_type; 309 | 310 | template 311 | void operator()(const formatter& f, const T& v) { 312 | if (i > 0) 313 | ctx.advance_to(detail::copy_str(separator, ctx.out())); 314 | ctx.advance_to(f.format(v, ctx)); 315 | ++i; 316 | } 317 | 318 | int i; 319 | FormatContext& ctx; 320 | basic_string_view separator; 321 | }; 322 | 323 | } // namespace detail 324 | 325 | template struct is_tuple_like { 326 | static constexpr const bool value = 327 | detail::is_tuple_like_::value && !detail::is_range_::value; 328 | }; 329 | 330 | template struct is_tuple_formattable { 331 | static constexpr const bool value = 332 | detail::is_tuple_formattable_::value; 333 | }; 334 | 335 | template 336 | struct formatter::value && 338 | fmt::is_tuple_formattable::value>> { 339 | private: 340 | decltype(detail::tuple::get_formatters( 341 | detail::tuple_index_sequence())) formatters_; 342 | 343 | basic_string_view separator_ = detail::string_literal{}; 344 | basic_string_view opening_bracket_ = 345 | detail::string_literal{}; 346 | basic_string_view closing_bracket_ = 347 | detail::string_literal{}; 348 | 349 | public: 350 | FMT_CONSTEXPR formatter() {} 351 | 352 | FMT_CONSTEXPR void set_separator(basic_string_view sep) { 353 | separator_ = sep; 354 | } 355 | 356 | FMT_CONSTEXPR void set_brackets(basic_string_view open, 357 | basic_string_view close) { 358 | opening_bracket_ = open; 359 | closing_bracket_ = close; 360 | } 361 | 362 | template 363 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 364 | auto it = ctx.begin(); 365 | if (it != ctx.end() && *it != '}') 366 | FMT_THROW(format_error("invalid format specifier")); 367 | detail::for_each(formatters_, detail::parse_empty_specs{ctx}); 368 | return it; 369 | } 370 | 371 | template 372 | auto format(const Tuple& value, FormatContext& ctx) const 373 | -> decltype(ctx.out()) { 374 | ctx.advance_to(detail::copy_str(opening_bracket_, ctx.out())); 375 | detail::for_each2( 376 | formatters_, value, 377 | detail::format_tuple_element{0, ctx, separator_}); 378 | return detail::copy_str(closing_bracket_, ctx.out()); 379 | } 380 | }; 381 | 382 | template struct is_range { 383 | static constexpr const bool value = 384 | detail::is_range_::value && !detail::is_std_string_like::value && 385 | !std::is_convertible>::value && 386 | !std::is_convertible>::value; 387 | }; 388 | 389 | namespace detail { 390 | template struct range_mapper { 391 | using mapper = arg_mapper; 392 | 393 | template , Context>::value)> 395 | static auto map(T&& value) -> T&& { 396 | return static_cast(value); 397 | } 398 | template , Context>::value)> 400 | static auto map(T&& value) 401 | -> decltype(mapper().map(static_cast(value))) { 402 | return mapper().map(static_cast(value)); 403 | } 404 | }; 405 | 406 | template 407 | using range_formatter_type = 408 | formatter>{}.map( 409 | std::declval()))>, 410 | Char>; 411 | 412 | template 413 | using maybe_const_range = 414 | conditional_t::value, const R, R>; 415 | 416 | // Workaround a bug in MSVC 2015 and earlier. 417 | #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 418 | template 419 | struct is_formattable_delayed 420 | : is_formattable>, Char> {}; 421 | #endif 422 | } // namespace detail 423 | 424 | template 425 | struct range_formatter; 426 | 427 | template 428 | struct range_formatter< 429 | T, Char, 430 | enable_if_t>, 431 | is_formattable>::value>> { 432 | private: 433 | detail::range_formatter_type underlying_; 434 | basic_string_view separator_ = detail::string_literal{}; 435 | basic_string_view opening_bracket_ = 436 | detail::string_literal{}; 437 | basic_string_view closing_bracket_ = 438 | detail::string_literal{}; 439 | 440 | public: 441 | FMT_CONSTEXPR range_formatter() {} 442 | 443 | FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type& { 444 | return underlying_; 445 | } 446 | 447 | FMT_CONSTEXPR void set_separator(basic_string_view sep) { 448 | separator_ = sep; 449 | } 450 | 451 | FMT_CONSTEXPR void set_brackets(basic_string_view open, 452 | basic_string_view close) { 453 | opening_bracket_ = open; 454 | closing_bracket_ = close; 455 | } 456 | 457 | template 458 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 459 | auto it = ctx.begin(); 460 | auto end = ctx.end(); 461 | 462 | if (it != end && *it == 'n') { 463 | set_brackets({}, {}); 464 | ++it; 465 | } 466 | 467 | if (it != end && *it != '}') { 468 | if (*it != ':') FMT_THROW(format_error("invalid format specifier")); 469 | ++it; 470 | } else { 471 | detail::maybe_set_debug_format(underlying_, true); 472 | } 473 | 474 | ctx.advance_to(it); 475 | return underlying_.parse(ctx); 476 | } 477 | 478 | template 479 | auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { 480 | detail::range_mapper> mapper; 481 | auto out = ctx.out(); 482 | out = detail::copy_str(opening_bracket_, out); 483 | int i = 0; 484 | auto it = detail::range_begin(range); 485 | auto end = detail::range_end(range); 486 | for (; it != end; ++it) { 487 | if (i > 0) out = detail::copy_str(separator_, out); 488 | ctx.advance_to(out); 489 | out = underlying_.format(mapper.map(*it), ctx); 490 | ++i; 491 | } 492 | out = detail::copy_str(closing_bracket_, out); 493 | return out; 494 | } 495 | }; 496 | 497 | enum class range_format { disabled, map, set, sequence, string, debug_string }; 498 | 499 | namespace detail { 500 | template 501 | struct range_format_kind_ 502 | : std::integral_constant, T>::value 504 | ? range_format::disabled 505 | : is_map::value ? range_format::map 506 | : is_set::value ? range_format::set 507 | : range_format::sequence> {}; 508 | 509 | template 510 | struct range_default_formatter; 511 | 512 | template 513 | using range_format_constant = std::integral_constant; 514 | 515 | template 516 | struct range_default_formatter< 517 | K, R, Char, 518 | enable_if_t<(K == range_format::sequence || K == range_format::map || 519 | K == range_format::set)>> { 520 | using range_type = detail::maybe_const_range; 521 | range_formatter, Char> underlying_; 522 | 523 | FMT_CONSTEXPR range_default_formatter() { init(range_format_constant()); } 524 | 525 | FMT_CONSTEXPR void init(range_format_constant) { 526 | underlying_.set_brackets(detail::string_literal{}, 527 | detail::string_literal{}); 528 | } 529 | 530 | FMT_CONSTEXPR void init(range_format_constant) { 531 | underlying_.set_brackets(detail::string_literal{}, 532 | detail::string_literal{}); 533 | underlying_.underlying().set_brackets({}, {}); 534 | underlying_.underlying().set_separator( 535 | detail::string_literal{}); 536 | } 537 | 538 | FMT_CONSTEXPR void init(range_format_constant) {} 539 | 540 | template 541 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 542 | return underlying_.parse(ctx); 543 | } 544 | 545 | template 546 | auto format(range_type& range, FormatContext& ctx) const 547 | -> decltype(ctx.out()) { 548 | return underlying_.format(range, ctx); 549 | } 550 | }; 551 | } // namespace detail 552 | 553 | template 554 | struct range_format_kind 555 | : conditional_t< 556 | is_range::value, detail::range_format_kind_, 557 | std::integral_constant> {}; 558 | 559 | template 560 | struct formatter< 561 | R, Char, 562 | enable_if_t::value != 563 | range_format::disabled> 564 | // Workaround a bug in MSVC 2015 and earlier. 565 | #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 566 | , 567 | detail::is_formattable_delayed 568 | #endif 569 | >::value>> 570 | : detail::range_default_formatter::value, R, 571 | Char> { 572 | }; 573 | 574 | template struct tuple_join_view : detail::view { 575 | const std::tuple& tuple; 576 | basic_string_view sep; 577 | 578 | tuple_join_view(const std::tuple& t, basic_string_view s) 579 | : tuple(t), sep{s} {} 580 | }; 581 | 582 | // Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers 583 | // support in tuple_join. It is disabled by default because of issues with 584 | // the dynamic width and precision. 585 | #ifndef FMT_TUPLE_JOIN_SPECIFIERS 586 | # define FMT_TUPLE_JOIN_SPECIFIERS 0 587 | #endif 588 | 589 | template 590 | struct formatter, Char> { 591 | template 592 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 593 | return do_parse(ctx, std::integral_constant()); 594 | } 595 | 596 | template 597 | auto format(const tuple_join_view& value, 598 | FormatContext& ctx) const -> typename FormatContext::iterator { 599 | return do_format(value, ctx, 600 | std::integral_constant()); 601 | } 602 | 603 | private: 604 | std::tuple::type, Char>...> formatters_; 605 | 606 | template 607 | FMT_CONSTEXPR auto do_parse(ParseContext& ctx, 608 | std::integral_constant) 609 | -> decltype(ctx.begin()) { 610 | return ctx.begin(); 611 | } 612 | 613 | template 614 | FMT_CONSTEXPR auto do_parse(ParseContext& ctx, 615 | std::integral_constant) 616 | -> decltype(ctx.begin()) { 617 | auto end = ctx.begin(); 618 | #if FMT_TUPLE_JOIN_SPECIFIERS 619 | end = std::get(formatters_).parse(ctx); 620 | if (N > 1) { 621 | auto end1 = do_parse(ctx, std::integral_constant()); 622 | if (end != end1) 623 | FMT_THROW(format_error("incompatible format specs for tuple elements")); 624 | } 625 | #endif 626 | return end; 627 | } 628 | 629 | template 630 | auto do_format(const tuple_join_view&, FormatContext& ctx, 631 | std::integral_constant) const -> 632 | typename FormatContext::iterator { 633 | return ctx.out(); 634 | } 635 | 636 | template 637 | auto do_format(const tuple_join_view& value, FormatContext& ctx, 638 | std::integral_constant) const -> 639 | typename FormatContext::iterator { 640 | auto out = std::get(formatters_) 641 | .format(std::get(value.tuple), ctx); 642 | if (N > 1) { 643 | out = std::copy(value.sep.begin(), value.sep.end(), out); 644 | ctx.advance_to(out); 645 | return do_format(value, ctx, std::integral_constant()); 646 | } 647 | return out; 648 | } 649 | }; 650 | 651 | namespace detail { 652 | // Check if T has an interface like a container adaptor (e.g. std::stack, 653 | // std::queue, std::priority_queue). 654 | template class is_container_adaptor_like { 655 | template static auto check(U* p) -> typename U::container_type; 656 | template static void check(...); 657 | 658 | public: 659 | static constexpr const bool value = 660 | !std::is_void(nullptr))>::value; 661 | }; 662 | 663 | template struct all { 664 | const Container& c; 665 | auto begin() const -> typename Container::const_iterator { return c.begin(); } 666 | auto end() const -> typename Container::const_iterator { return c.end(); } 667 | }; 668 | } // namespace detail 669 | 670 | template 671 | struct formatter< 672 | T, Char, 673 | enable_if_t, 674 | bool_constant::value == 675 | range_format::disabled>>::value>> 676 | : formatter, Char> { 677 | using all = detail::all; 678 | template 679 | auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) { 680 | struct getter : T { 681 | static auto get(const T& t) -> all { 682 | return {t.*(&getter::c)}; // Access c through the derived class. 683 | } 684 | }; 685 | return formatter::format(getter::get(t), ctx); 686 | } 687 | }; 688 | 689 | FMT_BEGIN_EXPORT 690 | 691 | /** 692 | \rst 693 | Returns an object that formats `tuple` with elements separated by `sep`. 694 | 695 | **Example**:: 696 | 697 | std::tuple t = {1, 'a'}; 698 | fmt::print("{}", fmt::join(t, ", ")); 699 | // Output: "1, a" 700 | \endrst 701 | */ 702 | template 703 | FMT_CONSTEXPR auto join(const std::tuple& tuple, string_view sep) 704 | -> tuple_join_view { 705 | return {tuple, sep}; 706 | } 707 | 708 | template 709 | FMT_CONSTEXPR auto join(const std::tuple& tuple, 710 | basic_string_view sep) 711 | -> tuple_join_view { 712 | return {tuple, sep}; 713 | } 714 | 715 | /** 716 | \rst 717 | Returns an object that formats `initializer_list` with elements separated by 718 | `sep`. 719 | 720 | **Example**:: 721 | 722 | fmt::print("{}", fmt::join({1, 2, 3}, ", ")); 723 | // Output: "1, 2, 3" 724 | \endrst 725 | */ 726 | template 727 | auto join(std::initializer_list list, string_view sep) 728 | -> join_view { 729 | return join(std::begin(list), std::end(list), sep); 730 | } 731 | 732 | FMT_END_EXPORT 733 | FMT_END_NAMESPACE 734 | 735 | #endif // FMT_RANGES_H_ 736 | --------------------------------------------------------------------------------