Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:42

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 {
0045 public:
0046     dump_info(It range_begin, It range_end, size_t size_per_line)
0047         : begin_(range_begin)
0048         , end_(range_end)
0049         , size_per_line_(size_per_line)
0050     {}
0051 
0052     // do not use begin() and end() to avoid collision with fmt/ranges
0053     It get_begin() const
0054     {
0055         return begin_;
0056     }
0057     It get_end() const
0058     {
0059         return end_;
0060     }
0061     size_t size_per_line() const
0062     {
0063         return size_per_line_;
0064     }
0065 
0066 private:
0067     It begin_, end_;
0068     size_t size_per_line_;
0069 };
0070 } // namespace details
0071 
0072 // create a dump_info that wraps the given container
0073 template<typename Container>
0074 inline details::dump_info<typename Container::const_iterator> to_hex(const Container &container, size_t size_per_line = 32)
0075 {
0076     static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
0077     using Iter = typename Container::const_iterator;
0078     return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
0079 }
0080 
0081 #if __cpp_lib_span >= 202002L
0082 
0083 template<typename Value, size_t Extent>
0084 inline details::dump_info<typename std::span<Value, Extent>::iterator> to_hex(
0085     const std::span<Value, Extent> &container, size_t size_per_line = 32)
0086 {
0087     using Container = std::span<Value, Extent>;
0088     static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
0089     using Iter = typename Container::iterator;
0090     return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
0091 }
0092 
0093 #endif
0094 
0095 // create dump_info from ranges
0096 template<typename It>
0097 inline details::dump_info<It> to_hex(const It range_begin, const It range_end, size_t size_per_line = 32)
0098 {
0099     return details::dump_info<It>(range_begin, range_end, size_per_line);
0100 }
0101 
0102 } // namespace spdlog
0103 
0104 namespace
0105 #ifdef SPDLOG_USE_STD_FORMAT
0106     std
0107 #else
0108     fmt
0109 #endif
0110 {
0111 
0112 template<typename T>
0113 struct formatter<spdlog::details::dump_info<T>, char>
0114 {
0115     const char delimiter = ' ';
0116     bool put_newlines = true;
0117     bool put_delimiters = true;
0118     bool use_uppercase = false;
0119     bool put_positions = true; // position on start of each line
0120     bool show_ascii = false;
0121 
0122     // parse the format string flags
0123     template<typename ParseContext>
0124     SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext &ctx) -> decltype(ctx.begin())
0125     {
0126         auto it = ctx.begin();
0127         while (it != ctx.end() && *it != '}')
0128         {
0129             switch (*it)
0130             {
0131             case 'X':
0132                 use_uppercase = true;
0133                 break;
0134             case 's':
0135                 put_delimiters = false;
0136                 break;
0137             case 'p':
0138                 put_positions = false;
0139                 break;
0140             case 'n':
0141                 put_newlines = false;
0142                 show_ascii = false;
0143                 break;
0144             case 'a':
0145                 if (put_newlines)
0146                 {
0147                     show_ascii = true;
0148                 }
0149                 break;
0150             }
0151 
0152             ++it;
0153         }
0154         return it;
0155     }
0156 
0157     // format the given bytes range as hex
0158     template<typename FormatContext, typename Container>
0159     auto format(const spdlog::details::dump_info<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
0160     {
0161         SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF";
0162         SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef";
0163         const char *hex_chars = use_uppercase ? hex_upper : hex_lower;
0164 
0165 #if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION < 60000
0166         auto inserter = ctx.begin();
0167 #else
0168         auto inserter = ctx.out();
0169 #endif
0170 
0171         int size_per_line = static_cast<int>(the_range.size_per_line());
0172         auto start_of_line = the_range.get_begin();
0173         for (auto i = the_range.get_begin(); i != the_range.get_end(); i++)
0174         {
0175             auto ch = static_cast<unsigned char>(*i);
0176 
0177             if (put_newlines && (i == the_range.get_begin() || i - start_of_line >= size_per_line))
0178             {
0179                 if (show_ascii && i != the_range.get_begin())
0180                 {
0181                     *inserter++ = delimiter;
0182                     *inserter++ = delimiter;
0183                     for (auto j = start_of_line; j < i; j++)
0184                     {
0185                         auto pc = static_cast<unsigned char>(*j);
0186                         *inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
0187                     }
0188                 }
0189 
0190                 put_newline(inserter, static_cast<size_t>(i - the_range.get_begin()));
0191 
0192                 // put first byte without delimiter in front of it
0193                 *inserter++ = hex_chars[(ch >> 4) & 0x0f];
0194                 *inserter++ = hex_chars[ch & 0x0f];
0195                 start_of_line = i;
0196                 continue;
0197             }
0198 
0199             if (put_delimiters)
0200             {
0201                 *inserter++ = delimiter;
0202             }
0203 
0204             *inserter++ = hex_chars[(ch >> 4) & 0x0f];
0205             *inserter++ = hex_chars[ch & 0x0f];
0206         }
0207         if (show_ascii) // add ascii to last line
0208         {
0209             if (the_range.get_end() - the_range.get_begin() > size_per_line)
0210             {
0211                 auto blank_num = size_per_line - (the_range.get_end() - start_of_line);
0212                 while (blank_num-- > 0)
0213                 {
0214                     *inserter++ = delimiter;
0215                     *inserter++ = delimiter;
0216                     if (put_delimiters)
0217                     {
0218                         *inserter++ = delimiter;
0219                     }
0220                 }
0221             }
0222             *inserter++ = delimiter;
0223             *inserter++ = delimiter;
0224             for (auto j = start_of_line; j != the_range.get_end(); j++)
0225             {
0226                 auto pc = static_cast<unsigned char>(*j);
0227                 *inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
0228             }
0229         }
0230         return inserter;
0231     }
0232 
0233     // put newline(and position header)
0234     template<typename It>
0235     void put_newline(It inserter, std::size_t pos)
0236     {
0237 #ifdef _WIN32
0238         *inserter++ = '\r';
0239 #endif
0240         *inserter++ = '\n';
0241 
0242         if (put_positions)
0243         {
0244             spdlog::fmt_lib::format_to(inserter, SPDLOG_FMT_STRING("{:04X}: "), pos);
0245         }
0246     }
0247 };
0248 } // namespace std