Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-02 08:50:50

0001 //
0002 // Copyright(c) 2015 Gabi Melman.
0003 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
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 // Support for logging binary data as hex
0023 // format flags, any combination of the following:
0024 // {:X} - print in uppercase.
0025 // {:s} - don't separate each byte with space.
0026 // {:p} - don't print the position on each line start.
0027 // {:n} - don't split the output to lines.
0028 // {:a} - show ASCII if :n is not set
0029 
0030 //
0031 // Examples:
0032 //
0033 // std::vector<char> v(200, 0x0b);
0034 // logger->info("Some buffer {}", spdlog::to_hex(v));
0035 // char buf[128];
0036 // logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
0037 // logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16));
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     // do not use begin() and end() to avoid collision with fmt/ranges
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 }  // namespace details
0060 
0061 // create a dump_info that wraps the given container
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 // create dump_info from ranges
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 }  // namespace spdlog
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;  // position on start of each line
0110     bool show_ascii = false;
0111 
0112     // parse the format string flags
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     // format the given bytes range as hex
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                 // put first byte without delimiter in front of it
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)  // add ascii to last line
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     // put newline(and position header)
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 }  // namespace std