File indexing completed on 2025-07-02 08:50:50
0001
0002
0003
0004
0005
0006 #pragma once
0007
0008 #include <cctype>
0009 #include <spdlog/common.h>
0010
0011 #if defined(__has_include)
0012 #if __has_include(<version>)
0013 #include <version>
0014 #endif
0015 #endif
0016
0017 #if __cpp_lib_span >= 202002L
0018 #include <span>
0019 #endif
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 namespace spdlog {
0040 namespace details {
0041
0042 template <typename It>
0043 class dump_info {
0044 public:
0045 dump_info(It range_begin, It range_end, size_t size_per_line)
0046 : begin_(range_begin),
0047 end_(range_end),
0048 size_per_line_(size_per_line) {}
0049
0050
0051 It get_begin() const { return begin_; }
0052 It get_end() const { return end_; }
0053 size_t size_per_line() const { return size_per_line_; }
0054
0055 private:
0056 It begin_, end_;
0057 size_t size_per_line_;
0058 };
0059 }
0060
0061
0062 template <typename Container>
0063 inline details::dump_info<typename Container::const_iterator> to_hex(const Container &container,
0064 size_t size_per_line = 32) {
0065 static_assert(sizeof(typename Container::value_type) == 1,
0066 "sizeof(Container::value_type) != 1");
0067 using Iter = typename Container::const_iterator;
0068 return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
0069 }
0070
0071 #if __cpp_lib_span >= 202002L
0072
0073 template <typename Value, size_t Extent>
0074 inline details::dump_info<typename std::span<Value, Extent>::iterator> to_hex(
0075 const std::span<Value, Extent> &container, size_t size_per_line = 32) {
0076 using Container = std::span<Value, Extent>;
0077 static_assert(sizeof(typename Container::value_type) == 1,
0078 "sizeof(Container::value_type) != 1");
0079 using Iter = typename Container::iterator;
0080 return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
0081 }
0082
0083 #endif
0084
0085
0086 template <typename It>
0087 inline details::dump_info<It> to_hex(const It range_begin,
0088 const It range_end,
0089 size_t size_per_line = 32) {
0090 return details::dump_info<It>(range_begin, range_end, size_per_line);
0091 }
0092
0093 }
0094
0095 namespace
0096 #ifdef SPDLOG_USE_STD_FORMAT
0097 std
0098 #else
0099 fmt
0100 #endif
0101 {
0102
0103 template <typename T>
0104 struct formatter<spdlog::details::dump_info<T>, char> {
0105 const char delimiter = ' ';
0106 bool put_newlines = true;
0107 bool put_delimiters = true;
0108 bool use_uppercase = false;
0109 bool put_positions = true;
0110 bool show_ascii = false;
0111
0112
0113 template <typename ParseContext>
0114 SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
0115 auto it = ctx.begin();
0116 while (it != ctx.end() && *it != '}') {
0117 switch (*it) {
0118 case 'X':
0119 use_uppercase = true;
0120 break;
0121 case 's':
0122 put_delimiters = false;
0123 break;
0124 case 'p':
0125 put_positions = false;
0126 break;
0127 case 'n':
0128 put_newlines = false;
0129 show_ascii = false;
0130 break;
0131 case 'a':
0132 if (put_newlines) {
0133 show_ascii = true;
0134 }
0135 break;
0136 }
0137
0138 ++it;
0139 }
0140 return it;
0141 }
0142
0143
0144 template <typename FormatContext, typename Container>
0145 auto format(const spdlog::details::dump_info<Container> &the_range, FormatContext &ctx) const
0146 -> decltype(ctx.out()) {
0147 SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF";
0148 SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef";
0149 const char *hex_chars = use_uppercase ? hex_upper : hex_lower;
0150
0151 #if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION < 60000
0152 auto inserter = ctx.begin();
0153 #else
0154 auto inserter = ctx.out();
0155 #endif
0156
0157 int size_per_line = static_cast<int>(the_range.size_per_line());
0158 auto start_of_line = the_range.get_begin();
0159 for (auto i = the_range.get_begin(); i != the_range.get_end(); i++) {
0160 auto ch = static_cast<unsigned char>(*i);
0161
0162 if (put_newlines &&
0163 (i == the_range.get_begin() || i - start_of_line >= size_per_line)) {
0164 if (show_ascii && i != the_range.get_begin()) {
0165 *inserter++ = delimiter;
0166 *inserter++ = delimiter;
0167 for (auto j = start_of_line; j < i; j++) {
0168 auto pc = static_cast<unsigned char>(*j);
0169 *inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
0170 }
0171 }
0172
0173 put_newline(inserter, static_cast<size_t>(i - the_range.get_begin()));
0174
0175
0176 *inserter++ = hex_chars[(ch >> 4) & 0x0f];
0177 *inserter++ = hex_chars[ch & 0x0f];
0178 start_of_line = i;
0179 continue;
0180 }
0181
0182 if (put_delimiters && i != the_range.get_begin()) {
0183 *inserter++ = delimiter;
0184 }
0185
0186 *inserter++ = hex_chars[(ch >> 4) & 0x0f];
0187 *inserter++ = hex_chars[ch & 0x0f];
0188 }
0189 if (show_ascii)
0190 {
0191 if (the_range.get_end() - the_range.get_begin() > size_per_line) {
0192 auto blank_num = size_per_line - (the_range.get_end() - start_of_line);
0193 while (blank_num-- > 0) {
0194 *inserter++ = delimiter;
0195 *inserter++ = delimiter;
0196 if (put_delimiters) {
0197 *inserter++ = delimiter;
0198 }
0199 }
0200 }
0201 *inserter++ = delimiter;
0202 *inserter++ = delimiter;
0203 for (auto j = start_of_line; j != the_range.get_end(); j++) {
0204 auto pc = static_cast<unsigned char>(*j);
0205 *inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
0206 }
0207 }
0208 return inserter;
0209 }
0210
0211
0212 template <typename It>
0213 void put_newline(It inserter, std::size_t pos) const {
0214 #ifdef _WIN32
0215 *inserter++ = '\r';
0216 #endif
0217 *inserter++ = '\n';
0218
0219 if (put_positions) {
0220 spdlog::fmt_lib::format_to(inserter, SPDLOG_FMT_STRING("{:04X}: "), pos);
0221 }
0222 }
0223 };
0224 }