13 #include <type_traits>
38 std::shared_ptr<librealsense::device_interface>
device;
50 template<
class T,
bool S>
55 out <<
':' <<
val << (last ?
"" :
", ");
64 static auto test(
const S*
t) -> decltype(std::cout << **
t);
65 static auto test(...)->std::false_type;
79 else out <<
"nullptr";
80 out << (last ?
"" :
", ");
92 else out <<
"nullptr";
93 out << (last ?
"" :
", ");
98 template<
class T>
void stream_args(std::ostream &
out,
const char * names,
const T & last)
102 s.stream_arg(
out, last,
true);
104 template<
class T,
class... U>
void stream_args(std::ostream &
out,
const char * names,
const T &
first,
const U &... rest)
106 while (*names && *names !=
',')
out << *names++;
109 while (*names && (*names ==
',' || isspace(*names))) ++names;
133 static api_objects& instance() {
134 static api_objects instance;
143 std::lock_guard<std::mutex>
lock(_m);
144 return internal_register(
type, address);
155 std::lock_guard<std::mutex>
lock(_m);
160 bool is_value =
false;
161 for (
auto i = 0;
i <
p.size();
i++)
173 auto it = _names.find(acc);
174 if (
it != _names.end()) acc =
it->second;
179 std::stringstream
ss;
ss << (
int*)0;
180 if (acc.size() ==
ss.str().size())
182 acc = internal_register(
param, acc);
185 res +=
param +
":" + acc;
186 if (
i !=
p.size() - 1) res +=
",";
200 std::lock_guard<std::mutex>
lock(_m);
201 auto it = _names.find(
name);
202 if (
it != _names.end())
208 auto it = _counters.find(
type);
209 if (
it == _counters.end()) _counters[
type] = 0;
211 std::stringstream
ss;
213 _names[address] =
ss.str();
214 return _names[address];
218 std::map<std::string, std::string> _names;
219 std::map<std::string, int> _counters;
227 : _function(
std::move(function)), _result(
""), _param_str(
""), _type(
""),
231 LOG_DEBUG(
"/* Begin " << _function <<
" */");
234 std::size_t found = _function.find_last_of(
"_");
235 _type = _function.substr(found + 1);
237 check_if_deleter(
"rs2_delete");
238 check_if_deleter(
"rs2_release");
242 void check_if_deleter(
const char* prefix)
244 auto deleter_pos = _function.find(prefix);
245 if (deleter_pos == 0)
253 _result = std::move(
result);
258 _params = std::move(
params);
261 std::string get_params() {
return _param_str = _params(); }
264 void report_pointer_return_type() { _returns_pointer =
true; }
269 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
d).count();
270 std::stringstream
ss;
272 if (_param_str ==
"") _param_str = _params();
274 auto&& objs = api_objects::instance();
275 if (_returns_pointer)
277 prefix = objs.register_new_object(_type, _result) +
" = ";
280 if (_is_deleter) objs.remove_object(_result);
281 if (_param_str !=
"") _param_str = objs.augment_params(_param_str);
283 ss << prefix << _function <<
"(" << _param_str <<
")";
284 if (_result !=
"")
ss <<
" returned " << _result;
286 if (ms > 0)
ss <<
" /* Took " << ms <<
"ms */";
293 bool _returns_pointer =
false;
294 bool _is_deleter =
false;
296 std::chrono::high_resolution_clock::time_point _start;
302 template<
typename F,
typename R>
303 R fetch_return_type(F&
f, R(F::*mf)()
const);
311 result_printer(api_logger* logger) : _logger(logger) {}
324 std::stringstream
ss;
ss << _res;
325 _logger->set_return_value(
ss.str());
334 class result_printer<T*>
337 result_printer(api_logger* logger) : _logger(logger) {}
350 std::stringstream
ss;
ss << (
int*)_res;
352 _logger->report_pointer_return_type();
353 _logger->set_return_value(
ss.str());
363 class result_printer<
void>
366 result_printer(api_logger* logger) {}
373 #define BEGIN_API_CALL { api_logger __api_logger(__FUNCTION__); {\
379 #define NOEXCEPT_RETURN(R, ...) };\
380 result_printer<decltype(fetch_return_type(func, &decltype(func)::operator()))> __p(&__api_logger);\
381 __api_logger.set_params([&](){ std::ostringstream ss; librealsense::stream_args(ss, #__VA_ARGS__, __VA_ARGS__); return ss.str(); });\
383 return __p.invoke(func);\
385 rs2_error* e; librealsense::translate_exception(__FUNCTION__, __api_logger.get_params(), &e);\
386 LOG_WARNING(rs2_get_error_message(e)); rs2_free_error(e); __api_logger.report_error(); return R; } } }
388 #define HANDLE_EXCEPTIONS_AND_RETURN(R, ...) };\
389 result_printer<decltype(fetch_return_type(func, &decltype(func)::operator()))> __p(&__api_logger);\
390 __api_logger.set_params([&](){ std::ostringstream ss; librealsense::stream_args(ss, #__VA_ARGS__, __VA_ARGS__); return ss.str(); });\
392 return __p.invoke(func);\
394 librealsense::translate_exception(__FUNCTION__, __api_logger.get_params(), error); __api_logger.report_error(); return R; } } }
396 #define NOARGS_HANDLE_EXCEPTIONS_AND_RETURN(R, ...) };\
397 result_printer<decltype(fetch_return_type(func, &decltype(func)::operator()))> __p(&__api_logger);\
399 return __p.invoke(func);\
400 } catch(...) { librealsense::translate_exception(__FUNCTION__, "", error); __api_logger.report_error(); return R; } } }
402 #else // No API tracing:
404 #define BEGIN_API_CALL try
405 #define NOEXCEPT_RETURN(R, ...) catch(...) { std::ostringstream ss; librealsense::stream_args(ss, #__VA_ARGS__, __VA_ARGS__); rs2_error* e; librealsense::translate_exception(__FUNCTION__, ss.str(), &e); LOG_WARNING(rs2_get_error_message(e)); rs2_free_error(e); return R; }
406 #define HANDLE_EXCEPTIONS_AND_RETURN(R, ...) catch(...) { std::ostringstream ss; librealsense::stream_args(ss, #__VA_ARGS__, __VA_ARGS__); librealsense::translate_exception(__FUNCTION__, ss.str(), error); return R; }
407 #define NOARGS_HANDLE_EXCEPTIONS_AND_RETURN(R) catch(...) { librealsense::translate_exception(__FUNCTION__, "", error); return R; }
408 #define NOARGS_HANDLE_EXCEPTIONS_AND_RETURN_VOID() catch(...) { librealsense::translate_exception(__FUNCTION__, "", error); }
412 #define VALIDATE_FIXED_SIZE(ARG, SIZE) if((ARG) != (SIZE)) { std::ostringstream ss; ss << "Unsupported size provided { " << ARG << " }," " expecting { " << SIZE << " }"; throw librealsense::invalid_value_exception(ss.str()); }
413 #define VALIDATE_NOT_NULL(ARG) if(!(ARG)) throw std::runtime_error("null pointer passed for argument \"" #ARG "\"");
414 #define VALIDATE_ENUM(ARG) if(!librealsense::is_valid(ARG)) { std::ostringstream ss; ss << "invalid enum value for argument \"" #ARG "\""; throw librealsense::invalid_value_exception(ss.str()); }
415 #define VALIDATE_OPTION_ENABLED( OBJ, OPT_ID ) \
416 if( ! OBJ->options->supports_option( OPT_ID ) ) \
418 std::ostringstream ss; \
419 ss << "object doesn't support option " << librealsense::get_string( OPT_ID ); \
420 throw librealsense::invalid_value_exception( ss.str() ); \
422 #define VALIDATE_RANGE(ARG, MIN, MAX) if((ARG) < (MIN) || (ARG) > (MAX)) { std::ostringstream ss; ss << "out of range value for argument \"" #ARG "\""; throw librealsense::invalid_value_exception(ss.str()); }
423 #define VALIDATE_LE(ARG, MAX) if((ARG) > (MAX)) { std::ostringstream ss; ss << "out of range value for argument \"" #ARG "\""; throw std::runtime_error(ss.str()); }
424 #define VALIDATE_GT(ARG, MIN) if((ARG) <= (MIN)) { std::ostringstream ss; ss << "value is below allowed min for argument \"" #ARG "\""; throw std::runtime_error(ss.str()); }
425 #define VALIDATE_LT(ARG, MAX) if((ARG) >= (MAX)) { std::ostringstream ss; ss << "value is bigger than allowed max for argument \"" #ARG "\""; throw std::runtime_error(ss.str()); }
426 #define VALIDATE_INTERFACE_NO_THROW(X, T) \
428 T* p = dynamic_cast<T*>(&(*X)); \
431 auto ext = dynamic_cast<librealsense::extendable_interface*>(&(*X)); \
432 if (ext == nullptr) return nullptr; \
435 if(!ext->extend_to(TypeToExtension<T>::value, (void**)&p)) \
443 #define VALIDATE_INTERFACE(X,T) \
445 T* p = VALIDATE_INTERFACE_NO_THROW(X,T); \
447 throw std::runtime_error("Object does not support \"" #T "\" interface! " ); \
458 return (
version % 10000) / 100;
479 <<
"! Make sure correct version of the library is installed (make install)" );
489 if ((runtime_api_version < 10) || (api_version < 10))
492 if (api_version != runtime_api_version)
499 if (api_version != runtime_api_version)