master
h 154 lines 3.68 KB
Raw
1 //
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //
4
5 /*++
6
7 Module Name:
8
9 prettyprintshared.h
10
11 Abstract:
12
13 This is the header file for message pretty printing.
14
15 --*/
16
17 #pragma once
18
19 #include <sstream>
20 #include <cstring>
21 #include <string_view>
22
23 #include "defs.h"
24 #include "stringshared.h"
25
26 #ifdef WIN32
27 #include <guiddef.h>
28 #else
29 #include "lxdef.h"
30 #endif
31
32 #define FIELD(Name) #Name, Name
33
34 #define STRING_FIELD(Name) #Name, (Name <= 0 ? "<empty>" : ((char*)(this)) + Name)
35
36 #define STRING_ARRAY_FIELD(Name) #Name, (StringArray((char*)(this), Name, Header.MessageSize))
37
38 // Safe pretty-print for flexible array members (char Buffer[]). Bounds the read
39 // using the struct's Header.MessageSize so it never reads past the received data.
40 #define BUFFER_FIELD(Name) #Name, PrettyPrintSafeBufferView(this, Header.MessageSize, Name)
41
42 inline std::string_view PrettyPrintSafeBufferView(const void* structBase, unsigned int messageSize, const char* buffer)
43 {
44 const auto offset = static_cast<size_t>(buffer - reinterpret_cast<const char*>(structBase));
45 if (offset >= messageSize)
46 {
47 return "<out-of-bounds>";
48 }
49
50 const size_t maxLen = messageSize - offset;
51 return std::string_view(buffer, strnlen(buffer, maxLen));
52 }
53
54 #define PRETTY_PRINT(...) \
55 void PrettyPrintImpl(std::stringstream& Out) const \
56 { \
57 PrettyPrintField(Out, __VA_ARGS__); \
58 } \
59 \
60 std::string PrettyPrint() const \
61 { \
62 std::stringstream Out; \
63 PrettyPrintImpl(Out); \
64 return Out.str(); \
65 }
66
67 struct StringArray
68 {
69 const char* MessageHead = nullptr;
70 unsigned int Index = 0;
71 unsigned int MessageSize = 0;
72 };
73
74 template <typename T>
75 inline void PrettyPrint(std::stringstream& Out, const T& Value)
76 {
77 if constexpr (std::is_same_v<T, std::string_view>)
78 {
79 Out << Value;
80 }
81 else if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, char[]>)
82 {
83 if (Value == nullptr)
84 {
85 Out << "<null>";
86 }
87 else
88 {
89 Out << Value;
90 }
91 }
92 else if constexpr (std::is_same_v<T, GUID>)
93 {
94 Out << wsl::shared::string::GuidToString<char>(Value);
95 }
96 else if constexpr (std::is_same_v<T, char>)
97 {
98 Out << Value;
99 }
100 else if constexpr (std::is_fundamental_v<T> || std::is_enum_v<T>)
101 {
102 // N.B. Enum can be specialized by creating an overload for this method.
103 Out << std::to_string(Value);
104 }
105 else if constexpr (std::is_same_v<T, StringArray>)
106 {
107 if (Value.Index <= 0)
108 {
109 Out << "<empty>";
110 return;
111 }
112
113 gsl::span<const char> span(Value.MessageHead + Value.Index, Value.MessageHead + Value.MessageSize);
114 Out << wsl::shared::string::Join(wsl::shared::string::ArrayFromSpan(gsl::as_bytes(span)), ',');
115 }
116 else
117 {
118 Out << "{";
119 Value.PrettyPrintImpl(Out);
120 Out << "}";
121 }
122 }
123
124 template <typename T, int Size>
125 inline void PrettyPrint(std::stringstream& Out, const T (&Value)[Size])
126 {
127 Out << "[";
128 for (auto i = 0; i < Size; i++)
129 {
130 if (i > 0 && i < Size)
131 {
132 Out << ",";
133 }
134
135 PrettyPrint(Out, Value[i]);
136 }
137
138 Out << "]";
139 }
140
141 template <typename TArg>
142 inline void PrettyPrintField(std::stringstream& Out, const char* FieldName, const TArg& FieldValue)
143 {
144 Out << FieldName << " = ";
145 PrettyPrint(Out, FieldValue);
146 Out << "\n";
147 }
148
149 template <typename TFirst, typename... TArgs>
150 inline void PrettyPrintField(std::stringstream& Out, const char* FieldName, const TFirst& FieldValue, TArgs&&... Args)
151 {
152 PrettyPrintField(Out, FieldName, FieldValue);
153 PrettyPrintField(Out, std::forward<TArgs>(Args)...);
154 }