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