Photon 1.0.0
Loading...
Searching...
No Matches
bin_to_hex.h
Go to the documentation of this file.
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#include <cctype>
9#include <spdlog/common.h>
10
11#if defined(__has_include)
12#if __has_include(<version>)
13#include <version>
14#endif
15#endif
16
17#if __cpp_lib_span >= 202002L
18#include <span>
19#endif
20
21//
22// Support for logging binary data as hex
23// format flags, any combination of the following:
24// {:X} - print in uppercase.
25// {:s} - don't separate each byte with space.
26// {:p} - don't print the position on each line start.
27// {:n} - don't split the output to lines.
28// {:a} - show ASCII if :n is not set
29
30//
31// Examples:
32//
33// std::vector<char> v(200, 0x0b);
34// logger->info("Some buffer {}", spdlog::to_hex(v));
35// char buf[128];
36// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
37// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16));
38
39namespace spdlog
40{
41 namespace details
42 {
43
44 template <typename It>
46 {
47 public:
48 dump_info(It range_begin, It range_end, size_t size_per_line)
49 : begin_(range_begin), end_(range_end), size_per_line_(size_per_line)
50 {
51 }
52
53 // do not use begin() and end() to avoid collision with fmt/ranges
54 It get_begin() const
55 {
56 return begin_;
57 }
58 It get_end() const
59 {
60 return end_;
61 }
62 size_t size_per_line() const
63 {
64 return size_per_line_;
65 }
66
67 private:
70 };
71 } // namespace details
72
73 // create a dump_info that wraps the given container
74 template <typename Container>
75 inline details::dump_info<typename Container::const_iterator> to_hex(const Container& container, size_t size_per_line = 32)
76 {
77 static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
78 using Iter = typename Container::const_iterator;
79 return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
80 }
81
82#if __cpp_lib_span >= 202002L
83
84 template <typename Value, size_t Extent>
85 inline details::dump_info<typename std::span<Value, Extent>::iterator> to_hex(
86 const std::span<Value, Extent>& container, size_t size_per_line = 32)
87 {
88 using Container = std::span<Value, Extent>;
89 static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
90 using Iter = typename Container::iterator;
91 return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
92 }
93
94#endif
95
96 // create dump_info from ranges
97 template <typename It>
98 inline details::dump_info<It> to_hex(const It range_begin, const It range_end, size_t size_per_line = 32)
99 {
100 return details::dump_info<It>(range_begin, range_end, size_per_line);
101 }
102
103} // namespace spdlog
104
105namespace
106#ifdef SPDLOG_USE_STD_FORMAT
107 std
108#else
109 fmt
110#endif
111{
112
113 template <typename T>
114 struct formatter<spdlog::details::dump_info<T>, char>
115 {
116 const char delimiter = ' ';
117 bool put_newlines = true;
118 bool put_delimiters = true;
119 bool use_uppercase = false;
120 bool put_positions = true; // position on start of each line
121 bool show_ascii = false;
122
123 // parse the format string flags
124 template <typename ParseContext>
125 SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext& ctx) -> decltype(ctx.begin())
126 {
127 auto it = ctx.begin();
128 while (it != ctx.end() && *it != '}')
129 {
130 switch (*it)
131 {
132 case 'X':
133 use_uppercase = true;
134 break;
135 case 's':
136 put_delimiters = false;
137 break;
138 case 'p':
139 put_positions = false;
140 break;
141 case 'n':
142 put_newlines = false;
143 show_ascii = false;
144 break;
145 case 'a':
146 if (put_newlines)
147 {
148 show_ascii = true;
149 }
150 break;
151 }
152
153 ++it;
154 }
155 return it;
156 }
157
158 // format the given bytes range as hex
159 template <typename FormatContext, typename Container>
160 auto format(const spdlog::details::dump_info<Container>& the_range, FormatContext& ctx) -> decltype(ctx.out())
161 {
162 SPDLOG_CONSTEXPR const char* hex_upper = "0123456789ABCDEF";
163 SPDLOG_CONSTEXPR const char* hex_lower = "0123456789abcdef";
164 const char* hex_chars = use_uppercase ? hex_upper : hex_lower;
165
166#if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION < 60000
167 auto inserter = ctx.begin();
168#else
169 auto inserter = ctx.out();
170#endif
171
172 int size_per_line = static_cast<int>(the_range.size_per_line());
173 auto start_of_line = the_range.get_begin();
174 for (auto i = the_range.get_begin(); i != the_range.get_end(); i++)
175 {
176 auto ch = static_cast<unsigned char>(*i);
177
178 if (put_newlines && (i == the_range.get_begin() || i - start_of_line >= size_per_line))
179 {
180 if (show_ascii && i != the_range.get_begin())
181 {
182 *inserter++ = delimiter;
183 *inserter++ = delimiter;
184 for (auto j = start_of_line; j < i; j++)
185 {
186 auto pc = static_cast<unsigned char>(*j);
187 *inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
188 }
189 }
190
191 put_newline(inserter, static_cast<size_t>(i - the_range.get_begin()));
192
193 // put first byte without delimiter in front of it
194 *inserter++ = hex_chars[(ch >> 4) & 0x0f];
195 *inserter++ = hex_chars[ch & 0x0f];
196 start_of_line = i;
197 continue;
198 }
199
200 if (put_delimiters && i != the_range.get_begin())
201 {
202 *inserter++ = delimiter;
203 }
204
205 *inserter++ = hex_chars[(ch >> 4) & 0x0f];
206 *inserter++ = hex_chars[ch & 0x0f];
207 }
208 if (show_ascii) // add ascii to last line
209 {
210 if (the_range.get_end() - the_range.get_begin() > size_per_line)
211 {
212 auto blank_num = size_per_line - (the_range.get_end() - start_of_line);
213 while (blank_num-- > 0)
214 {
215 *inserter++ = delimiter;
216 *inserter++ = delimiter;
217 if (put_delimiters)
218 {
219 *inserter++ = delimiter;
220 }
221 }
222 }
223 *inserter++ = delimiter;
224 *inserter++ = delimiter;
225 for (auto j = start_of_line; j != the_range.get_end(); j++)
226 {
227 auto pc = static_cast<unsigned char>(*j);
228 *inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
229 }
230 }
231 return inserter;
232 }
233
234 // put newline(and position header)
235 template <typename It>
236 void put_newline(It inserter, std::size_t pos)
237 {
238#ifdef _WIN32
239 *inserter++ = '\r';
240#endif
241 *inserter++ = '\n';
242
243 if (put_positions)
244 {
245 spdlog::fmt_lib::format_to(inserter, SPDLOG_FMT_STRING("{:04X}: "), pos);
246 }
247 }
248 };
249} // namespace std
Definition bin_to_hex.h:46
dump_info(It range_begin, It range_end, size_t size_per_line)
Definition bin_to_hex.h:48
size_t size_per_line_
Definition bin_to_hex.h:69
It get_end() const
Definition bin_to_hex.h:58
size_t size_per_line() const
Definition bin_to_hex.h:62
It begin_
Definition bin_to_hex.h:68
It end_
Definition bin_to_hex.h:68
It get_begin() const
Definition bin_to_hex.h:54
#define SPDLOG_CONSTEXPR_FUNC
Definition common.h:74
#define SPDLOG_FMT_STRING(format_string)
Definition common.h:60
#define SPDLOG_CONSTEXPR
Definition common.h:70
Definition bin_to_hex.h:111
Definition async.h:26
details::dump_info< typename Container::const_iterator > to_hex(const Container &container, size_t size_per_line=32)
Definition bin_to_hex.h:75
Definition uuid.h:926
SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext &ctx) -> decltype(ctx.begin())
Definition bin_to_hex.h:125
void put_newline(It inserter, std::size_t pos)
Definition bin_to_hex.h:236
auto format(const spdlog::details::dump_info< Container > &the_range, FormatContext &ctx) -> decltype(ctx.out())
Definition bin_to_hex.h:160
Definition core.h:944
annotation details
Definition tag_strings.h:125
i
Definition tag_strings.h:60