1 /*
2 * Copyright (c) 2022-2023, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file     media_debug_serializer.h
24 //!
25 
26 #pragma once
27 
28 #if USE_MEDIA_DEBUG_TOOL
29 
30 #include <cstring>
31 #include <iomanip>
32 #include <ostream>
33 #include <sstream>
34 #include <string>
35 #include <typeinfo>
36 #include <type_traits>
37 #include <stdint.h>
38 #include "media_class_trace.h"
39 
40 template <typename T, typename = void>
41 class MediaDebugSerializer
42 {
43 public:
operator()44     void operator()(std::ostream &os, const void *data, size_t size)
45     {
46         const size_t num = size / sizeof(T);
47         size_t       idx = 0;
48 
49         if (num > 1)
50         {
51             os << "Total Num: " << num << std::endl;
52             os << std::endl;
53         }
54 
55         while (idx < num)
56         {
57             if (num > 1)
58             {
59                 os << "---------"
60                    << "Index = " << idx << "---------" << std::endl;
61             }
62 
63             os << reinterpret_cast<const T *>(data)[idx++] << std::endl;
64         }
65 
66         size_t numTrailingBytes = size - num * sizeof(T);
67         if (numTrailingBytes)
68         {
69             os << numTrailingBytes << " trailing bytes cannot be reinterpreted as "
70                << typeid(T).name() << " whose size is " << sizeof(T) << ":"
71                << std::endl;
72             for (size_t i = size - numTrailingBytes; i < size; ++i)
73             {
74                 os << std::setfill('0') << std::setw(2) << std::hex << std::nouppercase
75                    << static_cast<uint32_t>(reinterpret_cast<const uint8_t *>(data)[i])
76                    << std::endl;
77             }
78         }
79     }
80 
81     MEDIA_CLASS_DEFINE_END(MediaDebugSerializer)
82 };
83 
84 template <typename T>
85 class MediaDebugSerializer<
86     T,
87 #if __cplusplus < 201703L
88     typename std::enable_if<std::is_fundamental<T>::value && !std::is_unsigned<T>::value>::type>
89 #else
90     std::enable_if_t<std::is_fundamental_v<T> && !std::is_unsigned_v<T> > >
91 #endif
92 {
93 public:
operator()94     void operator()(std::ostream &os, const void *data, size_t size)
95     {
96         const size_t num = size / sizeof(T);
97         size_t       idx = 0;
98 
99         while (idx < num)
100         {
101             os << reinterpret_cast<const T *>(data)[idx++] << std::endl;
102         }
103 
104         size_t numTrailingBytes = size - num * sizeof(T);
105         if (numTrailingBytes)
106         {
107             os << numTrailingBytes << " trailing bytes cannot be reinterpreted as "
108                << typeid(T).name() << " whose size is " << sizeof(T) << ":"
109                << std::endl;
110             for (size_t i = size - numTrailingBytes; i < size; ++i)
111             {
112                 os << std::setfill('0') << std::setw(2) << std::hex << std::nouppercase
113                    << static_cast<uint32_t>(reinterpret_cast<const uint8_t *>(data)[i])
114                    << std::endl;
115             }
116         }
117     }
118 
119     MEDIA_CLASS_DEFINE_END(MediaDebugSerializer)
120 };
121 
122 template <typename T>
123 class MediaDebugSerializer<
124     T,
125 #if __cplusplus < 201703L
126     typename std::enable_if<std::is_unsigned<T>::value>::type>
127 #else
128     std::enable_if_t<std::is_unsigned_v<T> > >
129 #endif
130 {
131 public:
operator()132     void operator()(std::ostream &os, const void *data, size_t size)
133     {
134         constexpr size_t LINE_WIDTH = 16 / sizeof(T);
135         constexpr size_t ELEM_WIDTH = sizeof(T) << 1;
136 
137         const size_t num = size / sizeof(T);
138         size_t       idx = 0;
139         while (idx < num)
140         {
141             os << std::setfill('0') << std::setw(ELEM_WIDTH) << std::hex
142                << std::nouppercase << reinterpret_cast<const T *>(data)[idx]
143                << ((idx + 1) % LINE_WIDTH == 0 ? "\n" : " ");
144             ++idx;
145         }
146 
147         size_t numTrailingBytes = size - num * sizeof(T);
148         if (numTrailingBytes)
149         {
150             T last = 0;
151             std::memcpy(
152                 &last,
153                 static_cast<const char *>(data) + size - numTrailingBytes,
154                 numTrailingBytes);
155 
156             std::stringstream ss;
157             ss << std::setfill('?') << std::setw(ELEM_WIDTH) << std::hex
158                << std::nouppercase << last;
159 
160             std::string str(ss.str());
161             if (str[0] == '?')  // little endian
162             {
163                 for (auto it = str.rbegin(); it != str.rbegin() + numTrailingBytes * 2; ++it)
164                 {
165                     *it = *it == '?' ? '0' : *it;
166                 }
167             }
168             else  // big endian
169             {
170                 for (auto it = str.begin(); it != str.begin() + numTrailingBytes * 2; ++it)
171                 {
172                     *it = *it == '?' ? '0' : *it;
173                 }
174             }
175 
176             os << str << ((idx + 1) % LINE_WIDTH == 0 ? "\n" : " ");
177         }
178     }
179 
180     MEDIA_CLASS_DEFINE_END(MediaDebugSerializer)
181 };
182 
183 template <>
184 class MediaDebugSerializer<uint8_t>
185 {
186 public:
operator()187     void operator()(std::ostream &os, const void *data, size_t size)
188     {
189         size_t idx = 0;
190         while (idx < size)
191         {
192             os << std::setfill('0') << std::setw(2) << std::hex << std::nouppercase
193                << static_cast<uint32_t>(reinterpret_cast<const uint8_t *>(data)[idx])
194                << ((idx + 1) % 32 == 0 ? "\n" : " ");
195             ++idx;
196         }
197     }
198 
199     MEDIA_CLASS_DEFINE_END(MediaDebugSerializer)
200 };
201 
202 template <>
203 class MediaDebugSerializer<int8_t>
204 {
205 public:
operator()206     void operator()(std::ostream &os, const void *data, size_t size)
207     {
208         size_t idx = 0;
209         while (idx < size)
210         {
211             os << static_cast<int32_t>(reinterpret_cast<const int8_t *>(data)[idx++])
212                << std::endl;
213         }
214     }
215 
216     MEDIA_CLASS_DEFINE_END(MediaDebugSerializer)
217 };
218 
219 template <>
220 class MediaDebugSerializer<void>
221 {
222 public:
operator()223     void operator()(std::ostream &os, const void *data, size_t size)
224     {
225         size_t idx = 0;
226         while (idx < size)
227         {
228             os << std::setfill('0') << std::setw(2) << std::hex << std::nouppercase
229                << static_cast<uint32_t>(reinterpret_cast<const uint8_t *>(data)[idx])
230                << ((idx + 1) % 32 == 0 ? "\n" : " ");
231             ++idx;
232         }
233     }
234 
235     MEDIA_CLASS_DEFINE_END(MediaDebugSerializer)
236 };
237 
238 #endif  // USE_MEDIA_DEBUG_TOOL
239