source: trunk/GDE/SINA/builddir/include/spdlog/fmt/bin_to_hex.h

Last change on this file was 19170, checked in by westram, 2 years ago
  • sina source
    • unpack + remove tarball
    • no longer ignore sina builddir.
File size: 4.3 KB
Line 
1//
2// Copyright(c) 2015 Gabi Melman.
3// Distributed under the MIT License (http://opensource.org/licenses/MIT)
4//
5
6#pragma once
7
8//
9// Support for logging binary data as hex
10// format flags:
11// {:X} - print in uppercase.
12// {:s} - don't separate each byte with space.
13// {:p} - don't print the position on each line start.
14// {:n} - don't split the output to lines.
15
16//
17// Examples:
18//
19// std::vector<char> v(200, 0x0b);
20// logger->info("Some buffer {}", spdlog::to_hex(v));
21// char buf[128];
22// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
23
24namespace spdlog {
25namespace details {
26
27template<typename It>
28class bytes_range
29{
30public:
31    bytes_range(It range_begin, It range_end)
32        : begin_(range_begin)
33        , end_(range_end)
34    {
35    }
36
37    It begin() const
38    {
39        return begin_;
40    }
41    It end() const
42    {
43        return end_;
44    }
45
46private:
47    It begin_, end_;
48};
49} // namespace details
50
51// create a bytes_range that wraps the given container
52template<typename Container>
53inline details::bytes_range<typename Container::const_iterator> to_hex(const Container &container)
54{
55    static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
56    using Iter = typename Container::const_iterator;
57    return details::bytes_range<Iter>(std::begin(container), std::end(container));
58}
59
60// create bytes_range from ranges
61template<typename It>
62inline details::bytes_range<It> to_hex(const It range_begin, const It range_end)
63{
64    return details::bytes_range<It>(range_begin, range_end);
65}
66
67} // namespace spdlog
68
69namespace fmt {
70
71template<typename T>
72struct formatter<spdlog::details::bytes_range<T>>
73{
74    const std::size_t line_size = 100;
75    const char delimiter = ' ';
76
77    bool put_newlines = true;
78    bool put_delimiters = true;
79    bool use_uppercase = false;
80    bool put_positions = true; // position on start of each line
81
82    // parse the format string flags
83    template<typename ParseContext>
84    auto parse(ParseContext &ctx) -> decltype(ctx.begin())
85    {
86        auto it = ctx.begin();
87        while (*it && *it != '}')
88        {
89            switch (*it)
90            {
91            case 'X':
92                use_uppercase = true;
93                break;
94            case 's':
95                put_delimiters = false;
96                break;
97            case 'p':
98                put_positions = false;
99                break;
100            case 'n':
101                put_newlines = false;
102                break;
103            }
104
105            ++it;
106        }
107        return it;
108    }
109
110    // format the given bytes range as hex
111    template<typename FormatContext, typename Container>
112    auto format(const spdlog::details::bytes_range<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
113    {
114        SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF";
115        SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef";
116        const char *hex_chars = use_uppercase ? hex_upper : hex_lower;
117
118        std::size_t pos = 0;
119        std::size_t column = line_size;
120        auto inserter = ctx.begin();
121
122        for (auto &item : the_range)
123        {
124            auto ch = static_cast<unsigned char>(item);
125            pos++;
126
127            if (put_newlines && column >= line_size)
128            {
129                column = put_newline(inserter, pos);
130
131                // put first byte without delimiter in front of it
132                *inserter++ = hex_chars[(ch >> 4) & 0x0f];
133                *inserter++ = hex_chars[ch & 0x0f];
134                column += 2;
135                continue;
136            }
137
138            if (put_delimiters)
139            {
140                *inserter++ = delimiter;
141                ++column;
142            }
143
144            *inserter++ = hex_chars[(ch >> 4) & 0x0f];
145            *inserter++ = hex_chars[ch & 0x0f];
146            column += 2;
147        }
148        return inserter;
149    }
150
151    // put newline(and position header)
152    // return the next column
153    template<typename It>
154    std::size_t put_newline(It inserter, std::size_t pos)
155    {
156#ifdef _WIN32
157        *inserter++ = '\r';
158#endif
159        *inserter++ = '\n';
160
161        if (put_positions)
162        {
163            fmt::format_to(inserter, "{:<04X}: ", pos - 1);
164            return 7;
165        }
166        else
167        {
168            return 1;
169        }
170    }
171};
172} // namespace fmt
Note: See TracBrowser for help on using the repository browser.