General Utility Library for C++17 26.5.0
hexdump.h
Go to the documentation of this file.
1
26#ifndef GUL17_HEXDUMP_H_
27#define GUL17_HEXDUMP_H_
28
29#include <iomanip>
30#include <sstream>
31#include <string_view>
32#include <type_traits>
33#include <utility>
34
35#include "gul17/internal.h"
36
38//
39// std::string hexdump(IteratorT begin, IteratorT end, std::string_view prompt = "")
40// std::string hexdump(const ContainerT& cont, std::string_view prompt = "")
41//
42// struct HexdumpParameterForward
43//
44// HexdumpParameterForward<...> hexdump_stream(IteratorT begin, IteratorT end, std::string prompt = "")
45// HexdumpParameterForward<...> hexdump_stream(const ContainerT& cont, std::string prompt = "")
46// HexdumpParameterForward<...> hexdump_stream(ContainerT&& cont, std::string prompt = "")
47//
48// std::ostream& operator<< (std::ostream& os, const HexdumpParameterForward<...>& hdp)
49//
51
52namespace gul17 {
53
60namespace detail {
61
63//
64// Until we have concepts ;-)
65//
66
67// Helper to identify types that have cbegin() and cend() and have integral data
68template <typename T, typename = int>
69struct IsHexDumpContainer : std::false_type { };
70
71template <typename T>
72struct IsHexDumpContainer <T,
74 std::is_integral<typename std::iterator_traits<decltype(
75 std::declval<T>().cbegin())>::value_type>::value,
76 decltype(std::declval<T>().cbegin(),
77 std::declval<T>().cend(),
78 0)
79 >>
80 : std::true_type { };
81
82// Helper to identify types that are ForwardIterators or Pointers
83//
84// We enforce that the data pointed to is integer.
85// We assume that every iterator that is not an input_iterator is at least
86// a forward_iterator.
87// We also check the existence of dereference and increment operators (this might be superfluous).
88// (Type int is used as a dummy.)
89template <typename T, typename = int>
90struct IsHexDumpIterator : std::false_type { };
91
92template <typename T>
93struct IsHexDumpIterator <T,
95 std::is_integral<typename std::iterator_traits<T>::value_type>::value
96 and not std::is_same<typename std::iterator_traits<T>::iterator_category,
97 std::input_iterator_tag>::value,
98 decltype(std::declval<T>().operator*(),
99 std::declval<T>().operator++(),
100 0)
101 >>
102 : std::true_type { };
103
104template <typename T>
105struct IsHexDumpIterator <T,
107 std::is_pointer<T>::value
108 and std::is_integral<typename std::remove_pointer<T>::type>::value,
109 int
110 >>
111 : std::true_type { };
112
113// Helper to identify stream types that we can use for output
114template <typename StreamT,
115 typename = std::enable_if_t<std::is_convertible<
116 StreamT*,
117 std::basic_ostream<typename StreamT::char_type,
118 typename StreamT::traits_type>*>::value>>
119struct IsHexDumpStream : std::true_type { };
120
122
123// Here is the template actually doing the hexdump
124// It is called by the different hexdump*() versions
125template<typename StreamT, typename IteratorT,
126 typename = std::enable_if_t<detail::IsHexDumpStream<StreamT>::value>,
127 typename = std::enable_if_t<detail::IsHexDumpIterator<IteratorT>::value>>
128StreamT& hexdump_stream(StreamT& dest, const IteratorT& begin, const IteratorT& end,
129 std::string_view prompt = "")
130{
131 constexpr auto maxelem = 1000ul * 16; // 1000 lines with 16 elements each
132
133 // Get the number of hex digits to represent any value of the given integral type
134 constexpr auto nod = sizeof(*begin) * 2;
135 constexpr bool is_char = (nod == 2);
136
137 const std::string indent(prompt.length(), ' ');
138 const std::string empty(nod + 1, ' ');
139
140 dest << std::hex << std::setfill('0');
141
142 auto it = IteratorT{ begin };
143
144 // Inspired by epatel @ stack overflow, https://stackoverflow.com/a/29865
145 for (size_t i = 0; (it != end and i < maxelem) or (i == 0); i += 16) {
146 dest << (i ? indent : prompt) << std::setw(6) << i << ": ";
147 auto line = it;
148 for (size_t j = 0; j < 16; ++j) {
149 if (it != end) {
150 const unsigned long long ch = static_cast<
151 typename std::make_unsigned<
152 typename std::decay<decltype(*it)>::type
153 >::type
154 >(*it++);
155 dest << std::setw(nod) << ch << ' ';
156 } else {
157 if (!is_char) {
158 break;
159 }
160 dest << empty;
161 }
162 }
163 if (is_char) {
164 // Here we re-visit the iterator from the beginning of the line, thus
165 // requiring ForwardIterators over InputOperators
166 dest << ' ';
167 for (size_t j = 0; j < 16 and line != end; ++j, ++line) {
168 const auto c = static_cast<unsigned char>(*line);
169 dest << static_cast<char>(isprint(c) ? c : '.'); // isprint() is only defined for unsigned char, but only char creates character output
170 }
171 }
172 dest << "\n";
173 }
174 if (it != end) {
175 dest << indent << "[output truncated...]\n";
176 }
177 return dest;
178}
180
181} // namespace detail
182
184// Functions returning a string
185//
186
221template<typename IteratorT,
222 typename = std::enable_if_t<detail::IsHexDumpIterator<IteratorT>::value>>
223std::string hexdump(IteratorT begin, IteratorT end, std::string_view prompt = "")
224{
225 std::stringstream o{ };
226 return detail::hexdump_stream(o, begin, end, prompt).str();
227}
228
238template<typename ContainerT,
239 typename = std::enable_if_t<detail::IsHexDumpContainer<ContainerT>::value>>
240std::string hexdump(const ContainerT& cont, std::string_view prompt = "")
241{
242 std::stringstream o{ };
243 return detail::hexdump_stream(o, cont.cbegin(), cont.cend(), prompt).str();
244}
245
247// Functions returning a forwarder object
248// (Support for 'stream << hexdump' without intermediate data image)
249//
250
259template<typename IteratorT, typename ContainerT = void*>
261public:
267 std::string prompt_;
270
271 HexdumpParameterForward() = default;
272 ~HexdumpParameterForward() = default;
273
291
297
303 {
304 *this = std::move(other);
305 }
306
312 {
313 if (this == &other)
314 return *this;
315
317 end_ = other.end_;
318 prompt_ = other.prompt_;
319 cont_ = other.cont_;
320
322
323 return *this;
324 }
325
331 {
332 if (this == &other)
333 return *this;
334
335 begin_ = std::move(other.begin_);
336 end_ = std::move(other.end_);
337 prompt_ = std::move(other.prompt_);
338 cont_ = std::move(other.cont_);
339
341
342 return *this;
343 }
344
354 friend std::ostream& operator<<(
356 {
357 return detail::hexdump_stream(os, hdp.begin_, hdp.end_, hdp.prompt_);
358 }
359
360private:
361 template <typename ContType,
362 std::enable_if_t<!detail::IsHexDumpContainer<ContType>::value, int> = 0
363 >
364 void regenerate_iterators() noexcept
365 {
366 // This is empty, but we need this member function template so that we can
367 // regenerate the iterators if need be for the other enable_if case, see
368 // below...
369 }
370
371 template <typename ContType,
372 std::enable_if_t<detail::IsHexDumpContainer<ContType>::value, int> = 0
373 >
374 void regenerate_iterators() noexcept
375 {
376 begin_ = cont_.begin();
377 end_ = cont_.end();
378 }
379};
380
423template<typename IteratorT,
424 typename = std::enable_if_t<detail::IsHexDumpIterator<IteratorT>::value>>
426hexdump_stream(const IteratorT& begin, const IteratorT& end, std::string prompt = "")
427{
428 return { begin, end, std::move(prompt), nullptr };
429}
430
439template<typename ContainerT,
440 typename = std::enable_if_t<detail::IsHexDumpContainer<ContainerT>::value>>
442hexdump_stream(const ContainerT& cont, std::string prompt = "")
443{
444 return { cont.cbegin(), cont.cend(), std::move(prompt), nullptr };
445}
446
455template<typename ContainerT,
456 typename = std::enable_if_t<detail::IsHexDumpContainer<ContainerT>::value,
458 ContainerT> {}, 0)>>
459HexdumpParameterForward<decltype(std::declval<ContainerT>().cbegin()), ContainerT>
461{
462 // The temporary container must be moved to retain the values until we need them
463 // after operator<<.
464 return { cont.cbegin(), cont.cbegin(), std::move(prompt),
465 std::forward<ContainerT>(cont) };
466}
467
469
470} // namespace gul17
471
472#endif
473
474// vi:ts=4:sw=4:et
Helper object used to enable a convenient syntax to dump things to a stream.
Definition hexdump.h:260
IteratorT begin_
Iterator to begin of elements to be dumped (in iterator mode)
Definition hexdump.h:263
HexdumpParameterForward & operator=(const HexdumpParameterForward &other)
Copy assignment (automatically updates the begin_ and end_ interator members if the copied object hol...
Definition hexdump.h:311
HexdumpParameterForward(IteratorT begin_it, IteratorT end_it, std::string prompt, ContainerT &&cont)
Construct a hexdump parameter forwarder object.
Definition hexdump.h:282
IteratorT end_
Iterator past end of elements to be dumped (in iterator mode)
Definition hexdump.h:265
std::string prompt_
Possible prompt to prepend to the dump.
Definition hexdump.h:267
HexdumpParameterForward & operator=(HexdumpParameterForward &&other) noexcept
Move assignment (automatically updates the begin_ and end_ interator members if the moved-from object...
Definition hexdump.h:330
ContainerT cont_
A container with the elements to be dumped (in container/temporary mode)
Definition hexdump.h:269
HexdumpParameterForward(HexdumpParameterForward &&other) noexcept
Move constructor (automatically updates the begin_ and end_ interator members if the moved-from objec...
Definition hexdump.h:302
HexdumpParameterForward(const HexdumpParameterForward &other)
Copy constructor (automatically updates the begin_ and end_ interator members if the copied object ho...
Definition hexdump.h:296
friend std::ostream & operator<<(std::ostream &os, const HexdumpParameterForward< IteratorT, ContainerT > &hdp)
Overload of std::ostream's operator<< to enable a convenient syntax to dump things to a stream.
Definition hexdump.h:354
auto constexpr bit_set(unsigned bit) noexcept -> ReturnT
Set a bit in an integral type.
Definition bit_manip.h:124
HexdumpParameterForward< const IteratorT > hexdump_stream(const IteratorT &begin, const IteratorT &end, std::string prompt="")
Generate a hexdump of a data range that can be efficiently written to a stream using operator<<.
Definition hexdump.h:426
std::string hexdump(IteratorT begin, IteratorT end, std::string_view prompt="")
Generate a hexdump of a data range and return it as a string.
Definition hexdump.h:223
Definition of macros used internally by GUL.
Namespace gul17 contains all functions and classes of the General Utility Library.
Definition doxygen.h:29