Debug.h 15.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
// Copyright (C) : 2009-2011
// European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// FRANCE
//
// This is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
//###########################################################################
22
// This code was taken from the Debug.h file (Generic debug in C++)
23 24 25 26 27
// in: /segfs/dserver/classes++/extdevice/

#ifndef DEBUG_H
#define DEBUG_H

28 29 30
#include "lima/LimaCompatibility.h"
#include "lima/StreamUtils.h"
#include "lima/ThreadUtils.h"
31

32 33
#include <string>
#include <map>
34
#ifndef __unix
35
#pragma warning(disable:4251)
36
#endif
37 38 39 40 41 42 43
namespace lima
{

// Do not forget to update the corresponding Type/Format/Module name in
// DebParams::checkInit (Debug.cpp) when you change these enums

enum DebType {
44 45 46 47 48 49 50 51
	DebTypeFatal		= 1 << 0,
	DebTypeError		= 1 << 1,
	DebTypeWarning		= 1 << 2,
	DebTypeTrace		= 1 << 3,
	DebTypeFunct		= 1 << 4,
	DebTypeParam		= 1 << 5,
	DebTypeReturn		= 1 << 6,
	DebTypeAlways		= 1 << 7,
52 53
};

54

55
enum DebFormat {
56
	DebFmtDateTime		= 1 << 0,
57 58 59 60 61 62 63 64
	DebFmtThread		= 1 << 1,
	DebFmtModule		= 1 << 2,
	DebFmtObj		= 1 << 3,
	DebFmtFunct		= 1 << 4,	
	DebFmtFileLine		= 1 << 5,
	DebFmtType		= 1 << 6,
	DebFmtIndent		= 1 << 7,
	DebFmtColor		= 1 << 8,
65 66 67
};

enum DebModule {
68 69 70
	DebModNone		= 1 << 0,
	DebModCommon		= 1 << 1,
	DebModHardware		= 1 << 2,
71 72 73 74 75 76 77 78
	DebModHardwareSerial	= 1 << 3,
	DebModControl		= 1 << 4,
	DebModEspia		= 1 << 5,
	DebModEspiaSerial	= 1 << 6,
	DebModFocla		= 1 << 7,
	DebModCamera		= 1 << 8,
	DebModCameraCom		= 1 << 9,
	DebModTest		= 1 << 10,
79
	DebModApplication	= 1 << 11,
80 81 82 83 84 85 86 87
};

typedef const char *ConstStr;

/*------------------------------------------------------------------
 *  class DebStream
 *------------------------------------------------------------------*/

88
class LIMACORE_API DebStream : public std::ostream
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
{
 public:
	typedef OCopyStream::StreamList StreamList;
	typedef StreamList::iterator ListIterator;
	enum Selector {
		None, Output, Error, Both
	};

	DebStream();
	
	DebStream& SetStream(Selector new_selector);
	
	bool FindStream(std::ostream *os, Selector buffer);
	void AddOutput(std::ostream *os);
	void RemoveOutput(std::ostream *os);
	void AddError(std::ostream *os);
	void RemoveError(std::ostream *os);

 protected:
	bool Find(std::ostream *os, StreamList& slist, ListIterator& it);

 private:
	StreamList m_out_list;
	StreamList m_err_list;
	StreamList m_all_list;
	
	NullStreamBuf m_null_buf;
	OCopyStream m_out_streams;
	OCopyStream m_err_streams;
	CopyStreamBuf m_all_buf;
	
	Selector m_current;
	std::streambuf *m_buffers[4];
};

inline DebStream& DebStream::SetStream(Selector new_selector)
{
	m_current = new_selector;
	rdbuf(m_buffers[m_current]);
	return *this;
}

/*------------------------------------------------------------------
 *  class DebParams 
 *------------------------------------------------------------------*/

class DebObj;
class DebProxy;

138
class LIMACORE_API DebParams
139 140 141
{
 public:
	typedef long long Flags;
142 143 144
	typedef std::vector<std::string> NameList;

	static const Flags AllFlags;
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

	DebParams(DebModule mod = DebModNone, 
		  ConstStr class_name = NULL, ConstStr name_space = NULL);

	void setModule(DebModule mod);
	DebModule getModule() const;

	void setClassName(ConstStr class_name);
	ConstStr getClassName() const;

	void setNameSpace(ConstStr name_space);
	ConstStr getNameSpace() const;

	bool checkModule() const;
	bool checkType(DebType type) const;

161 162 163 164 165
	static void setTypeFlags(Flags type_flags);
	static Flags getTypeFlags();

	static void enableTypeFlags(Flags type_flags);
	static void disableTypeFlags(Flags type_flags);
166 167 168 169

	static void setFormatFlags(Flags fmt_flags);
	static Flags getFormatFlags();

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
	static void enableFormatFlags(Flags fmt_flags);
	static void disableFormatFlags(Flags fmt_flags);

	static void setModuleFlags(Flags mod_flags);
	static Flags getModuleFlags();

	static void enableModuleFlags(Flags mod_flags);
	static void disableModuleFlags(Flags mod_flags);

	static void setTypeFlagsNameList(const NameList& type_name_list);
	static NameList getTypeFlagsNameList();

	static void setFormatFlagsNameList(const NameList& fmt_name_list);
	static NameList getFormatFlagsNameList();

	static void setModuleFlagsNameList(const NameList& mod_name_list);
	static NameList getModuleFlagsNameList();
187 188 189 190 191 192 193 194

	static DebStream& getDebStream();
	static AutoMutex lock();

	static ConstStr getTypeName(DebType type);
	static ConstStr getFormatName(DebFormat fmt);
	static ConstStr getModuleName(DebModule mod);

195 196
	static void checkInit();

197 198 199 200
private:
	friend class DebProxy;
	friend class DebObj;

201
	static void doInit();
202

203 204 205 206 207 208 209 210 211
	template <class T>
	static void setFlagsNameList(Flags& flags, 
				     const std::map<T, std::string>& name_map,
				     const NameList& name_list);
	template <class T>
	static void getFlagsNameList(Flags flags, 
				     const std::map<T, std::string>& name_map,
				     NameList& name_list);

212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
	static Flags s_type_flags;
	static Flags s_fmt_flags;
	static Flags s_mod_flags;

	static DebStream *s_deb_stream;

	static std::map<DebType,   std::string> *s_type_name_map;
	static std::map<DebFormat, std::string> *s_fmt_name_map;
	static std::map<DebModule, std::string> *s_mod_name_map;

	static Mutex *s_mutex;

	DebModule m_mod;
	ConstStr m_class_name;
	ConstStr m_name_space;
};

229 230 231
std::ostream& operator <<(std::ostream& os, 
			  const DebParams::NameList& name_list);

232 233 234 235 236

/*------------------------------------------------------------------
 *  class DebProxy
 *------------------------------------------------------------------*/

237
class LIMACORE_API DebProxy
238 239 240 241 242
{
 public:
	DebProxy();
	DebProxy(DebObj *deb_obj, DebType type, ConstStr file_name, 
		 int line_nr);
243
	DebProxy(const DebProxy& p);
244 245 246 247 248 249 250 251
	~DebProxy();

	template <class T> 
        const DebProxy& operator <<(const T& o) const;

	bool isActive() const;

 private:
252
	mutable AutoMutex *m_lock;
253 254
};

255 256 257 258 259 260 261 262 263 264 265 266 267
/*------------------------------------------------------------------
 *  class DebSink
 *------------------------------------------------------------------*/

class LIMACORE_API DebSink
{
 public:
  	DebSink() {};

	template <class T> 
	  const DebSink& operator <<(const T&) const {return *this;}
};

268 269 270 271 272

/*------------------------------------------------------------------
 *  class DebObj
 *------------------------------------------------------------------*/

273
class LIMACORE_API DebObj
274 275
{
 public:
276 277 278 279
	enum {
		IndentSize = 4,
	};

280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
	DebObj(DebParams& deb_params, bool destructor = false,
	       ConstStr funct_name = NULL, ConstStr obj_name = NULL, 
	       ConstStr file_name = NULL, int line_nr = 0);
	~DebObj();

	bool checkOut(DebType type);
	bool checkErr(DebType type);
	bool checkAny(DebType type);

	DebParams& getDebParams();

	DebProxy write(DebType type, 
		       ConstStr file_name = NULL, int line_nr = 0);

 private:
	friend class DebProxy;

297 298
	typedef struct ThreadData {
		int indent;
299
		ThreadData() : indent(-1) {}
300 301 302
	} ThreadData;
	
	void heading(DebType type, ConstStr file_name, int line_nr);
303 304
	static ThreadData *getThreadData();
	static void deleteThreadData(void *thread_data);
305 306 307 308 309 310 311 312 313 314

	DebParams *m_deb_params;
	bool m_destructor;
	ConstStr m_funct_name;
	ConstStr m_obj_name;
	ConstStr m_file_name;
	int m_line_nr;
};


315 316 317 318
/*------------------------------------------------------------------
 *  class DebHex
 *------------------------------------------------------------------*/

319
class LIMACORE_API DebHex
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
{
 public:
	DebHex(unsigned long val) : m_val(val) 
	{}

	unsigned long getVal() const
	{ return m_val; }

 private:
	unsigned long m_val;
};

inline std::ostream& operator <<(std::ostream& os, const DebHex& deb_hex)
{
	return os << std::hex << std::showbase << deb_hex.getVal()
		  << std::dec << std::noshowbase;
}


339 340 341 342 343 344
/*------------------------------------------------------------------
 *  global inline functions
 *------------------------------------------------------------------*/

inline bool DebHasFlag(DebParams::Flags flags, int val)
{
345
	return ((flags & val) != 0);
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
}

/*------------------------------------------------------------------
 *  class DebParams inline functions
 *------------------------------------------------------------------*/

inline DebParams::DebParams(DebModule mod, ConstStr class_name, 
			    ConstStr name_space)
{
	checkInit();
	m_mod = mod;
	m_class_name = class_name;
	m_name_space = name_space;
}

inline void DebParams::setModule(DebModule mod)
{
	m_mod = mod; 
}

inline DebModule DebParams::getModule() const
{ 
	return m_mod; 
}

inline void DebParams::setClassName(ConstStr class_name)
{ 
	m_class_name = class_name; 
}

inline ConstStr DebParams::getClassName() const
{ 
	return m_class_name; 
}

inline void DebParams::setNameSpace(ConstStr name_space)
{ 
	m_name_space = name_space; 
}

inline ConstStr DebParams::getNameSpace() const
{ 
	return m_name_space; 
}
390

391 392 393 394 395 396 397 398 399
inline bool DebParams::checkModule() const
{ 
	return DebHasFlag(s_mod_flags, m_mod); 
}

inline bool DebParams::checkType(DebType type) const
{ 
	return DebHasFlag(s_type_flags, type); 
}
400

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420

/*------------------------------------------------------------------
 *  class DebProxy inline functions
 *------------------------------------------------------------------*/

inline DebProxy::DebProxy()
	: m_lock(NULL)
{
}

inline DebProxy::DebProxy(DebObj *deb_obj, DebType type, ConstStr file_name, 
			  int line_nr)
{
	AutoMutex lock(*DebParams::s_mutex);

	deb_obj->heading(type, file_name, line_nr);

	m_lock = new AutoMutex(lock);
}

421 422 423 424 425 426
inline DebProxy::DebProxy(const DebProxy& p)
	: m_lock(p.m_lock)
{
	p.m_lock = NULL;
}

427 428 429 430 431 432 433 434 435 436 437
inline DebProxy::~DebProxy()
{
	if (!m_lock)
		return;

	*DebParams::s_deb_stream << std::endl;
	delete m_lock;
}

inline bool DebProxy::isActive() const
{
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
438
	return !!m_lock;
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
}

template <class T>
inline const DebProxy& DebProxy::operator <<(const T& o) const
{
	if (isActive()) 
		*DebParams::s_deb_stream << o;
	return *this;
}


/*------------------------------------------------------------------
 *  class DebObj inline functions
 *------------------------------------------------------------------*/

inline DebObj::DebObj(DebParams& deb_params, bool destructor, 
		      ConstStr funct_name, ConstStr obj_name, 
		      ConstStr file_name, int line_nr)
	: m_deb_params(&deb_params), m_destructor(destructor), 
	  m_funct_name(funct_name), m_obj_name(obj_name), 
	  m_file_name(file_name), m_line_nr(line_nr)
{
461 462
	getThreadData()->indent++;
	write(DebTypeFunct, m_file_name, m_line_nr) << "Enter";
463 464 465 466
}

inline DebObj::~DebObj()
{
467 468
	write(DebTypeFunct, m_file_name, m_line_nr) << "Exit";
	getThreadData()->indent--;
469 470 471 472
}

inline bool DebObj::checkOut(DebType type)
{
473 474 475
	return ((type == DebTypeAlways) || (type == DebTypeFatal) || 
		((type == DebTypeError) && 
		 m_deb_params->checkType(DebTypeError)) ||
476 477 478 479 480 481
		(m_deb_params->checkModule() && 
		 m_deb_params->checkType(type)));
}

inline bool DebObj::checkErr(DebType type)
{
482
	return ((type == DebTypeFatal) || (type == DebTypeError));
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
}

inline bool DebObj::checkAny(DebType type)
{
	return checkOut(type) || checkErr(type);
}

inline DebParams& DebObj::getDebParams()
{
	return *m_deb_params;
}

inline DebProxy DebObj::write(DebType type, ConstStr file_name, int line_nr)
{
	if (checkAny(type))
		return DebProxy(this, type, file_name, line_nr);
	else
		return DebProxy();
}

503

504 505 506 507
/*------------------------------------------------------------------
 *  debug macros
 *------------------------------------------------------------------*/

508
#define DEB_GLOBAL_NAMESPC(mod, name_space)				\
509
	inline DebParams& getDebParams()				\
510 511
	{								\
		static DebParams *deb_params = NULL;			\
512 513
		EXEC_ONCE(deb_params = new DebParams(mod, NULL,		\
						     name_space));	\
514 515 516 517 518 519
		return *deb_params;					\
	}

#define DEB_GLOBAL(mod)							\
	DEB_GLOBAL_NAMESPC(mod, NULL)

520 521 522 523 524
#define DEB_CLASS_NAMESPC(mod, class_name, name_space)			\
  private:								\
	static DebParams& getDebParams()				\
	{								\
		static DebParams *deb_params = NULL;			\
525 526
		EXEC_ONCE(deb_params = new DebParams(mod, class_name,	\
						     name_space));	\
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
		return *deb_params;					\
	}								\
									\
	void setDebObjName(const std::string& obj_name)			\
	{								\
		m_deb_obj_name = obj_name;				\
	}								\
									\
	ConstStr getDebObjName() const					\
	{								\
		if (m_deb_obj_name.empty())				\
			return NULL;					\
		return m_deb_obj_name.c_str();				\
	}								\
									\
	std::string m_deb_obj_name

544 545
#define DEB_CLASS(mod, class_name)					\
	DEB_CLASS_NAMESPC(mod, class_name, NULL)
546

547 548 549 550 551 552
#ifndef NO_LIMA_DEBUG

#define DEB_GLOBAL_FUNCT()						\
	DebObj deb(getDebParams(), false, __FUNCTION__,			\
		   NULL, __FILE__, __LINE__)

553 554 555 556 557 558 559
#define DEB_CONSTRUCTOR()						\
	DEB_MEMBER_FUNCT()

#define DEB_DESTRUCTOR()						\
	DebObj deb(getDebParams(), true, __FUNCTION__,			\
		   getDebObjName(), __FILE__, __LINE__)

560 561 562 563
#define DEB_MEMBER_FUNCT()						\
	DebObj deb(getDebParams(), false, __FUNCTION__,			\
		   getDebObjName(), __FILE__, __LINE__)

564 565 566
#define DEB_FROM_PTR(deb_ptr)						\
	DebObj& deb = *(deb_ptr)

567 568 569
#define DEB_STATIC_FUNCT()						\
	DEB_GLOBAL_FUNCT()

570 571 572
#define DEB_SET_OBJ_NAME(n) \
	setDebObjName(n)

573

574 575
#define DEB_MSG(type)	deb.write(type, __FILE__, __LINE__)

576 577 578 579 580 581 582
#define DEB_FATAL()	DEB_MSG(DebTypeFatal)
#define DEB_ERROR()	DEB_MSG(DebTypeError)
#define DEB_WARNING()	DEB_MSG(DebTypeWarning)
#define DEB_TRACE()	DEB_MSG(DebTypeTrace)
#define DEB_PARAM()	DEB_MSG(DebTypeParam)
#define DEB_RETURN()	DEB_MSG(DebTypeReturn)
#define DEB_ALWAYS()	DEB_MSG(DebTypeAlways)
583

584 585 586 587 588 589 590 591 592 593 594 595 596 597
#define DEB_HEX(x)	DebHex(x)

#define DEB_VAR1(v1)	\
	#v1 << "=" << v1
#define DEB_VAR2(v1, v2)	\
	DEB_VAR1(v1) << ", " << #v2 << "=" << v2
#define DEB_VAR3(v1, v2, v3)	\
	DEB_VAR2(v1, v2) << ", " << #v3 << "=" << v3
#define DEB_VAR4(v1, v2, v3, v4)	\
	DEB_VAR3(v1, v2, v3) << ", " << #v4 << "=" << v4
#define DEB_VAR5(v1, v2, v3, v4, v5)	\
	DEB_VAR4(v1, v2, v3, v4) << ", " << #v5 << "=" << v5
#define DEB_VAR6(v1, v2, v3, v4, v5, v6)	\
	DEB_VAR5(v1, v2, v3, v4, v5) << ", " << #v6 << "=" << v6
598 599
#define DEB_VAR7(v1, v2, v3, v4, v5, v6, v7)	\
	DEB_VAR6(v1, v2, v3, v4, v5, v6) << ", " << #v7 << "=" << v7
600 601 602

#define DEB_OBJ_NAME(o) \
	((o)->getDebObjName())
603

604 605
#define DEB_CHECK_ANY(type)	deb.checkAny(type)

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
#else //NO_LIMA_DEBUG

#define DEB_GLOBAL_FUNCT() DebSink deb
#define DEB_CONSTRUCTOR() DebSink deb
#define DEB_DESTRUCTOR()  DebSink deb
#define DEB_MEMBER_FUNCT() DebSink deb

#define DEB_FROM_PTR(deb_ptr) DebSink deb
#define DEB_STATIC_FUNCT() DEB_GLOBAL_FUNCT()
#define DEB_SET_OBJ_NAME(n)

#define DEB_MSG(type) 	deb
#define DEB_FATAL()	deb
#define DEB_ERROR()	deb
#define DEB_WARNING()	deb
#define DEB_TRACE()	deb
#define DEB_PARAM()	deb
#define DEB_RETURN()	deb
#define DEB_ALWAYS()	deb
#define DEB_HEX(x)				""
#define DEB_VAR1(v1)				""
#define DEB_VAR2(v1, v2)			""
#define DEB_VAR3(v1, v2, v3)			""
#define DEB_VAR4(v1, v2, v3, v4)		""
#define DEB_VAR5(v1, v2, v3, v4, v5)		""
#define DEB_VAR6(v1, v2, v3, v4, v5, v6)	""
#define DEB_VAR7(v1, v2, v3, v4, v5, v6, v7)	""

#define DEB_OBJ_NAME(o)

636 637
#define DEB_CHECK_ANY(type)	0

638
#endif //NO_LIMA_DEBUG
639 640 641
} // namespace lima

#endif // DEBUG_H