WireCellToolkit
Wire Cell Simulation, Signal Process and Reconstruction Toolki for Liquid Argon Detectors
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 //
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 
24 namespace spdlog {
25 namespace details {
26 
27 template<typename It>
29 {
30 public:
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 
46 private:
47  It begin_, end_;
48 };
49 } // namespace details
50 
51 // create a bytes_range that wraps the given container
52 template<typename 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
61 template<typename It>
62 inline 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 
69 namespace fmt {
70 
71 template<typename T>
72 struct 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
details::bytes_range< typename Container::const_iterator > to_hex(const Container &container)
Definition: bin_to_hex.h:53
FMT_CONSTEXPR auto begin(const C &c) -> decltype(c.begin())
Definition: format.h:251
bytes_range(It range_begin, It range_end)
Definition: bin_to_hex.h:31
Definition: async.h:27
FMT_CONSTEXPR auto end(const C &c) -> decltype(c.end())
Definition: format.h:257
auto parse(ParseContext &ctx) -> decltype(ctx.begin())
Definition: bin_to_hex.h:84
std::enable_if< is_contiguous< Container >::value &&internal::is_string< S >::value, std::back_insert_iterator< Container > >::type format_to(std::back_insert_iterator< Container > out, const S &format_str, const Args &... args)
Definition: core.h:1430
std::size_t put_newline(It inserter, std::size_t pos)
Definition: bin_to_hex.h:154
auto format(const spdlog::details::bytes_range< Container > &the_range, FormatContext &ctx) -> decltype(ctx.out())
Definition: bin_to_hex.h:112
Definition: bin_to_hex.h:69
#define SPDLOG_CONSTEXPR
Definition: common.h:36