nx_server_plugin_sdk  1.0
Server Plugin SDK
debug.h
Go to the documentation of this file.
1 // Copyright 2018-present Network Optix, Inc. Licensed under MPL 2.0: www.mozilla.org/MPL/2.0/
2 
3 #pragma once
4 
12 #include <iostream>
13 #include <stdint.h>
14 #include <functional>
15 #include <sstream>
16 #include <memory>
17 
18 #include <nx/kit/utils.h>
19 
20 #if !defined(NX_KIT_API)
21  #define NX_KIT_API /*empty*/
22 #endif
23 
24 namespace nx {
25 namespace kit {
26 namespace debug {
27 
28 //-------------------------------------------------------------------------------------------------
29 // Tools
30 
34 NX_KIT_API std::string srcFileRelativePath(const std::string& file);
35 
39 NX_KIT_API std::string srcFileBaseNameWithoutExt(const std::string& file);
40 
41 //-------------------------------------------------------------------------------------------------
42 // Output
43 
45 #if defined(NX_PRINT_TO_QDEBUG)
46  #define NX_DEBUG_STREAM qDebug().nospace().noquote()
47  #define NX_DEBUG_ENDL ""
48  static inline QDebug operator<<(QDebug d, const std::string& s)
49  {
50  return d << QString::fromStdString(s);
51  }
52 #endif
53 
54 #if !defined(NX_DEBUG_INI)
55 
56  #define NX_DEBUG_INI ini().
57 #endif
58 
59 #if !defined(NX_DEBUG_ENABLE_OUTPUT)
60 
61  #define NX_DEBUG_ENABLE_OUTPUT NX_DEBUG_INI enableOutput
62 #endif
63 
64 #if !defined(NX_PRINT_PREFIX)
65 
66  #define NX_PRINT_PREFIX ::nx::kit::debug::detail::printPrefix(__FILE__)
67 #endif
68 
69 #if !defined(NX_DEBUG_STREAM)
70 
71  #define NX_DEBUG_STREAM *::nx::kit::debug::stream()
72 #endif
73 
74 #if !defined(NX_DEBUG_ENDL)
75 
76  #define NX_DEBUG_ENDL "\n"
77 #endif
78 
83 NX_KIT_API std::ostream*& stream();
84 
85 #if !defined(NX_PRINT)
86 
90  #define NX_PRINT /* << args... */ \
91  nx::kit::debug::detail::Print(&(NX_DEBUG_STREAM), NX_DEBUG_ENDL) << NX_PRINT_PREFIX
92 #endif
93 
97 #define NX_OUTPUT /* << args... */ \
98  for (/* Executed either once or never; `for` instead of `if` gives no warnings. */ \
99  int NX_KIT_DEBUG_DETAIL_CONCAT(nxOutput_, __line__) = 0; \
100  NX_KIT_DEBUG_DETAIL_CONCAT(nxOutput_, __line__) != 1 && (NX_DEBUG_ENABLE_OUTPUT); \
101  ++NX_KIT_DEBUG_DETAIL_CONCAT(nxOutput_, __line__) \
102  ) NX_PRINT
103 
104 //-------------------------------------------------------------------------------------------------
105 // Assertions
106 
122 #define NX_KIT_ASSERT(/* CONDITION, MESSAGE = "" */ ...) \
123  NX_KIT_DEBUG_DETAIL_MSVC_EXPAND(NX_KIT_DEBUG_DETAIL_GET_3RD_ARG( \
124  __VA_ARGS__, NX_KIT_DEBUG_DETAIL_ASSERT2, NX_KIT_DEBUG_DETAIL_ASSERT1, \
125  /* Helps to generate a reasonable compiler error. */ args_required)(__VA_ARGS__))
126 
131 NX_KIT_API void intentionallyCrash(const char* message);
132 
133 //-------------------------------------------------------------------------------------------------
134 // Print info
135 
139 #define LL \
140  NX_PRINT << "####### LL line " + ::nx::kit::utils::toString(__LINE__) \
141  + NX_KIT_DEBUG_DETAIL_THREAD_ID \
142  + ", " + ::nx::kit::debug::srcFileRelativePath(__FILE__) \
143  /* The final semicolon allows to use this macro as a line prefix. */;
144 
148 #define NX_PRINT_VALUE(VALUE) \
149  NX_PRINT << "####### " #VALUE ": " + ::nx::kit::utils::toString(VALUE)
150 
154 #define NX_PRINT_HEX_DUMP(CAPTION, BYTES, SIZE) \
155  ::nx::kit::debug::detail::printHexDump( \
156  NX_KIT_DEBUG_DETAIL_PRINT_FUNC, (CAPTION), (const char*) (BYTES), (int) (SIZE))
157 
161 NX_KIT_API std::string hexDumpLine(const char* bytes, int size, int bytesPerLine = 0);
162 
163 #if !defined(NX_DEBUG_SAVE_DIR)
164 
165  #define NX_DEBUG_SAVE_DIR ::nx::kit::IniConfig::iniFilesDir()
166 #endif
167 
173 #define NX_SAVE_STR(FILENAME, STR) \
174  ::nx::kit::debug::detail::saveStr( \
175  NX_KIT_DEBUG_DETAIL_PRINT_FUNC, (NX_DEBUG_SAVE_DIR), (FILENAME), #STR, (STR))
176 
180 #define NX_SAVE_BIN(FILENAME, BYTES, SIZE) \
181  ::nx::kit::debug::detail::saveBin( \
182  NX_KIT_DEBUG_DETAIL_PRINT_FUNC, (NX_DEBUG_SAVE_DIR), (FILENAME), (BYTES), (SIZE))
183 
184 //-------------------------------------------------------------------------------------------------
185 // Time
186 
187 #if !defined(NX_DEBUG_ENABLE_TIME)
188 
189  #define NX_DEBUG_ENABLE_TIME NX_DEBUG_INI enableTime
190 #endif
191 
195 #define NX_TIME_BEGIN(TAG) \
196  ::nx::kit::debug::detail::Timer nxTimer_##TAG( \
197  (NX_DEBUG_ENABLE_TIME), NX_KIT_DEBUG_DETAIL_PRINT_FUNC, #TAG)
198 
203 #define NX_TIME_MARK(TAG, MARK) do \
204 { \
205  if (NX_DEBUG_ENABLE_TIME) \
206  nxTimer_##TAG.mark((MARK)); \
207 } while (0)
208 
212 #define NX_TIME_END(TAG) do \
213 { \
214  if (NX_DEBUG_ENABLE_TIME) \
215  nxTimer_##TAG.finish(); \
216 } while (0)
217 
218 //-------------------------------------------------------------------------------------------------
219 // Fps
220 
221 #if !defined(NX_DEBUG_ENABLE_FPS)
222 
223  #define NX_DEBUG_ENABLE_FPS NX_DEBUG_INI enableFps
224 #endif
225 
230 #define NX_FPS(TAG, /*OPTIONAL_MARK*/...) do \
231 { \
232  if (NX_KIT_DEBUG_DETAIL_CONCAT(NX_DEBUG_ENABLE_FPS, TAG)) \
233  { \
234  static ::nx::kit::debug::detail::Fps fps( \
235  NX_KIT_DEBUG_DETAIL_PRINT_FUNC, #TAG); \
236  fps.mark(__VA_ARGS__); \
237  } \
238 } while (0)
239 
240 //-------------------------------------------------------------------------------------------------
241 // Implementation
242 
243 namespace detail {
244 
246 class Print: public std::ostringstream
247 {
248 public:
249  Print(std::ostream* outputStream, const char* const newline):
250  m_outputStream(outputStream), m_newline(newline)
251  {
252  }
253 
254  ~Print()
255  {
256  (*this) << m_newline;
257  *m_outputStream << (*this).str(); //< Perform the actual output.
258  }
259 
260 private:
261  std::ostream* m_outputStream;
262  const char* const m_newline;
263 };
264 
265 typedef std::function<void(const char*)> PrintFunc;
266 
267 #define NX_KIT_DEBUG_DETAIL_PRINT_FUNC ([&](const char* message) { NX_PRINT << message; })
268 
273 #define NX_KIT_DEBUG_DETAIL_MSVC_EXPAND(ARG) ARG
274 
276 #define NX_KIT_DEBUG_DETAIL_GET_3RD_ARG(ARG1, ARG2, ARG3, ...) ARG3
277 
278 #define NX_KIT_DEBUG_DETAIL_ASSERT1(CONDITION) \
279  ::nx::kit::debug::detail::doAssert( \
280  !!(CONDITION), NX_KIT_DEBUG_DETAIL_PRINT_FUNC, #CONDITION, "", __FILE__, __LINE__)
281 
282 #define NX_KIT_DEBUG_DETAIL_ASSERT2(CONDITION, MESSAGE) \
283  ::nx::kit::debug::detail::doAssert( \
284  !!(CONDITION), NX_KIT_DEBUG_DETAIL_PRINT_FUNC, #CONDITION, MESSAGE, __FILE__, __LINE__)
285 
286 NX_KIT_API void assertionFailed(
287  PrintFunc printFunc, const char* conditionStr, const std::string& message,
288  const char* file, int line);
289 
290 inline bool doAssert(
291  bool condition, PrintFunc printFunc, const char* conditionStr, const std::string& message,
292  const char* file, int line)
293 {
294  if (!condition)
295  assertionFailed(printFunc, conditionStr, message, file, line);
296  return condition;
297 }
298 
299 #define NX_KIT_DEBUG_DETAIL_CONCAT(X, Y) NX_KIT_DEBUG_DETAIL_CONCAT2(X, Y)
300 #define NX_KIT_DEBUG_DETAIL_CONCAT2(X, Y) X##Y
301 
303 NX_KIT_API std::string printPrefix(const char* file);
304 
305 class NX_KIT_API Timer
306 {
307 public:
308  Timer(bool enabled, PrintFunc printFunc, const char* tag);
309  ~Timer();
310  void mark(const char* markStr);
311  void finish();
312 
313 private:
314  struct Impl;
315  Impl* const d;
316 };
317 
318 class NX_KIT_API Fps
319 {
320 public:
321  Fps(PrintFunc printFunc, const char* tag);
322  ~Fps();
323  void mark(const char* markStr = nullptr);
324 
325 private:
326  struct Impl;
327  Impl* const d;
328 };
329 
330 NX_KIT_API void printHexDump(
331  PrintFunc printFunc, const char* caption, const char* bytes, int size);
332 
333 NX_KIT_API void saveStr(
334  PrintFunc printFunc,
335  const char* originDir,
336  const char* filename,
337  const char* strCaption,
338  const std::string& str);
339 
340 NX_KIT_API void saveBin(
341  PrintFunc printFunc,
342  const char* originDir,
343  const char* filename,
344  const char* bytes,
345  int size);
346 
347 } // namespace detail
348 
349 } // namespace debug
350 } // namespace kit
351 } // namespace nx
352 
353 // Define NX_KIT_DEBUG_DETAIL_THREAD_ID.
354 #if defined(__linux__)
355  #if defined(__has_include) //< This C++17 feature was available in GCC/Clang long before.
356  #if __has_include(<pthread.h>)
357  #include <pthread.h>
358  #define NX_KIT_DEBUG_DETAIL_THREAD_ID \
359  ::nx::kit::utils::format(", thread %llx", (long long) pthread_self())
360  #endif
361  #endif
362 #elif defined(QT_CORE_LIB)
363  #include <QtCore/QThread>
364  #define NX_KIT_DEBUG_DETAIL_THREAD_ID \
365  ::nx::kit::utils::format(", thread %llx", (long long) QThread::currentThreadId())
366 #endif
367 #if !defined(NX_KIT_DEBUG_DETAIL_THREAD_ID)
368  // No threading libs available - do not print thread id.
369  #define NX_KIT_DEBUG_DETAIL_THREAD_ID ""
370 #endif
Definition: debug.h:318
Definition: debug.cpp:309
Definition: debug.cpp:234
Definition: apple_utils.h:6
Definition: debug.h:246
Definition: debug.h:305