PageRenderTime 79ms CodeModel.GetById 16ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 0ms

/include/oglplus/error.hpp

https://github.com/MaikKlein/oglplus
C++ Header | 1297 lines | 831 code | 120 blank | 346 comment | 37 complexity | 496e580ece398b458fcbf378d3798d8b MD5 | raw file
   1/**
   2 *  @file oglplus/error.hpp
   3 *  @brief Declaration of OGLplus' exceptions
   4 *
   5 *  @author Matus Chochlik
   6 *
   7 *  Copyright 2010-2013 Matus Chochlik. Distributed under the Boost
   8 *  Software License, Version 1.0. (See accompanying file
   9 *  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10 */
  11
  12#pragma once
  13#ifndef OGLPLUS_ERROR_1107121317_HPP
  14#define OGLPLUS_ERROR_1107121317_HPP
  15
  16#include <oglplus/auxiliary/strings.hpp>
  17#include <oglplus/config.hpp>
  18#include <stdexcept>
  19#include <cassert>
  20#include <list>
  21#include <map>
  22
  23#if OGLPLUS_CUSTOM_ERROR_HANDLING
  24#include <stack>
  25#include <functional>
  26#endif
  27
  28#define OGLPLUS_ERROR_INFO_CONTEXT(CONTEXT, CLASS) \
  29	static const char* _errinf_ctxt(void) \
  30	{ \
  31		return #CONTEXT; \
  32	} \
  33	static const char* _errinf_cls(void) \
  34	{ \
  35		return #CLASS; \
  36	}
  37
  38#define OGLPLUS_ERROR_INFO_REUSE_CONTEXT(SOURCE) \
  39	using SOURCE::_errinf_ctxt; \
  40	using SOURCE::_errinf_cls;
  41
  42
  43// Define a macro that initializes the _glsym member of ErrorInfo
  44#if OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
  45#define OGLPLUS_ERROR_INFO_INIT_GLSYM(SYMBOL)
  46#else
  47#define OGLPLUS_ERROR_INFO_INIT_GLSYM(SYMBOL) , SYMBOL
  48#endif
  49
  50// Define a macro that initializes the _file member of ErrorInfo
  51#if OGLPLUS_ERROR_INFO_NO_FILE
  52#define OGLPLUS_ERROR_INFO_INIT_FILE(FILEPATH)
  53#else
  54#define OGLPLUS_ERROR_INFO_INIT_FILE(FILEPATH) , FILEPATH
  55#endif
  56
  57// Define a macro that initializes the _func member of ErrorInfo
  58#if OGLPLUS_ERROR_INFO_NO_FUNC
  59#define OGLPLUS_ERROR_INFO_INIT_FUNC(FUNC)
  60#else
  61#define OGLPLUS_ERROR_INFO_INIT_FUNC(FUNC) , FUNC
  62#endif
  63
  64// Define a macro that initializes the _line member of ErrorInfo
  65#if OGLPLUS_ERROR_INFO_NO_LINE
  66#define OGLPLUS_ERROR_INFO_INIT_LINE(LINE)
  67#else
  68#define OGLPLUS_ERROR_INFO_INIT_LINE(LINE) , LINE
  69#endif
  70
  71// Define a macro that initializes the _cls_name member of ErrorInfo
  72#if OGLPLUS_ERROR_INFO_NO_CLASS_NAME
  73#define OGLPLUS_ERROR_INFO_INIT_CLS_NAME(NAME)
  74#else
  75#define OGLPLUS_ERROR_INFO_INIT_CLS_NAME(NAME) , NAME
  76#endif
  77
  78// Define a macro that initializes the _bind_tgt member of ErrorInfo
  79#if OGLPLUS_ERROR_INFO_NO_BIND_TARGET
  80#define OGLPLUS_ERROR_INFO_INIT_BIND_TGT(NAME)
  81#else
  82#define OGLPLUS_ERROR_INFO_INIT_BIND_TGT(NAME) , NAME
  83#endif
  84
  85// Define a macro that initializes the description-related members of ErrorInfo
  86#if OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
  87#define OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(GET, PURGE, NAME)
  88#else
  89#define OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(GET, PURGE, NAME) \
  90	, GET, PURGE, GLuint(NAME)
  91#endif
  92
  93
  94#define OGLPLUS_ERROR_INFO(CONTEXT) \
  95oglplus::ErrorInfo(\
  96	sizeof(decltype(&gl ## CONTEXT)) \
  97	OGLPLUS_ERROR_INFO_INIT_GLSYM(#CONTEXT) \
  98	OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
  99	OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
 100	OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
 101	OGLPLUS_ERROR_INFO_INIT_CLS_NAME("") \
 102	OGLPLUS_ERROR_INFO_INIT_BIND_TGT(StrLit()) \
 103	OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(nullptr, nullptr, 0) \
 104)
 105
 106#define OGLPLUS_LIMIT_ERROR_INFO(CONTEXT) \
 107oglplus::ErrorInfo(\
 108	sizeof(decltype(GL_ ## CONTEXT)) \
 109	OGLPLUS_ERROR_INFO_INIT_GLSYM(#CONTEXT) \
 110	OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
 111	OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
 112	OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
 113	OGLPLUS_ERROR_INFO_INIT_CLS_NAME("") \
 114	OGLPLUS_ERROR_INFO_INIT_BIND_TGT(StrLit()) \
 115	OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(nullptr, nullptr, 0) \
 116)
 117
 118#define OGLPLUS_ERROR_INFO_AUTO_CTXT() \
 119oglplus::ErrorInfo(\
 120	0 \
 121	OGLPLUS_ERROR_INFO_INIT_GLSYM(_errinf_ctxt()) \
 122	OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
 123	OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
 124	OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
 125	OGLPLUS_ERROR_INFO_INIT_CLS_NAME(_errinf_cls())  \
 126	OGLPLUS_ERROR_INFO_INIT_BIND_TGT(StrLit()) \
 127	OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(nullptr, nullptr, 0) \
 128)
 129
 130#define OGLPLUS_ERROR_INFO_STR(CONTEXT_STR) \
 131oglplus::ErrorInfo(\
 132	0 \
 133	OGLPLUS_ERROR_INFO_INIT_GLSYM(CONTEXT_STR) \
 134	OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
 135	OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
 136	OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
 137	OGLPLUS_ERROR_INFO_INIT_CLS_NAME("") \
 138	OGLPLUS_ERROR_INFO_INIT_BIND_TGT(StrLit()) \
 139	OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS(nullptr, nullptr, 0) \
 140)
 141
 142#define OGLPLUS_OBJECT_ERROR_INFO(CONTEXT, CLASS, TARGET_NAME, NAME) \
 143oglplus::ErrorInfo(\
 144	sizeof(decltype(&gl ## CONTEXT)) \
 145	OGLPLUS_ERROR_INFO_INIT_GLSYM(#CONTEXT) \
 146	OGLPLUS_ERROR_INFO_INIT_FILE(__FILE__) \
 147	OGLPLUS_ERROR_INFO_INIT_FUNC(__FUNCTION__) \
 148	OGLPLUS_ERROR_INFO_INIT_LINE(__LINE__) \
 149	OGLPLUS_ERROR_INFO_INIT_CLS_NAME(#CLASS) \
 150	OGLPLUS_ERROR_INFO_INIT_BIND_TGT(TARGET_NAME) \
 151	OGLPLUS_ERROR_INFO_INIT_OBJ_DECS_FUNCS( \
 152		&oglplus::aux::ObjectDescRegistry<CLASS##Ops>::_get_desc, \
 153		&oglplus::aux::ObjectDescRegistry<CLASS##Ops>::_purge_archive,\
 154		NAME \
 155	) \
 156)
 157
 158namespace oglplus {
 159
 160/** @defgroup error_handling Error handling
 161 *
 162 *  The exception classes listed below provide information about errors
 163 *  that occur during the excecution of the OpenGL function calls in the
 164 *  @OGLplus wrappers.
 165 */
 166
 167/// Basic information about exception's throw site and propagation trace points
 168/**
 169 *  @see ErrorGLSymbol
 170 *  @see ErrorFunc
 171 *  @see ErrorFile
 172 *  @see ErrorLine
 173 *  @see ErrorObjectDescription
 174 *
 175 *  @ingroup error_handling
 176 */
 177struct ErrorInfo
 178{
 179	// the data members of this structure are internal
 180	// implementation details which are subject to change
 181	// without any prior notice. Do not use directly.
 182
 183	const size_t _dummy;
 184
 185#if !OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
 186	const char* _glsym;
 187#endif
 188
 189#if !OGLPLUS_ERROR_INFO_NO_FILE
 190	const char* _file;
 191#endif
 192
 193#if !OGLPLUS_ERROR_INFO_NO_FUNC
 194	const char* _func;
 195#endif
 196
 197#if !OGLPLUS_ERROR_INFO_NO_LINE
 198	const unsigned _line;
 199#endif
 200
 201#if !OGLPLUS_ERROR_INFO_NO_CLASS_NAME
 202	const char* _cls_name;
 203#endif
 204
 205#if !OGLPLUS_ERROR_INFO_NO_BIND_TARGET
 206	const StrLit _bind_tgt;
 207#endif
 208
 209#if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
 210	const String& (*_get_obj_desc)(GLuint);
 211	void (*_purge_archive)(void);
 212	GLuint _obj_name;
 213#endif
 214
 215	inline ErrorInfo(
 216		const size_t dummy
 217#if !OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
 218		, const char* glsym
 219#endif
 220
 221#if !OGLPLUS_ERROR_INFO_NO_FILE
 222		, const char* file
 223#endif
 224
 225#if !OGLPLUS_ERROR_INFO_NO_FUNC
 226		, const char* func
 227#endif
 228
 229#if !OGLPLUS_ERROR_INFO_NO_LINE
 230		, const unsigned line
 231#endif
 232
 233#if !OGLPLUS_ERROR_INFO_NO_CLASS_NAME
 234		, const char* cls_name
 235#endif
 236
 237#if !OGLPLUS_ERROR_INFO_NO_BIND_TARGET
 238		, const StrLit& bind_tgt
 239#endif
 240
 241#if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
 242		, const String& (*get_obj_desc)(GLuint)
 243		, void (*purge_archive)(void)
 244		, GLuint obj_name
 245#endif
 246	): _dummy(dummy)
 247
 248#if !OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
 249	 , _glsym(glsym)
 250#endif
 251
 252#if !OGLPLUS_ERROR_INFO_NO_FILE
 253	 , _file(file)
 254#endif
 255
 256#if !OGLPLUS_ERROR_INFO_NO_FUNC
 257	 , _func(func)
 258#endif
 259
 260#if !OGLPLUS_ERROR_INFO_NO_LINE
 261	 , _line(line)
 262#endif
 263
 264#if !OGLPLUS_ERROR_INFO_NO_CLASS_NAME
 265	 , _cls_name(cls_name)
 266#endif
 267
 268#if !OGLPLUS_ERROR_INFO_NO_BIND_TARGET
 269	 , _bind_tgt(bind_tgt)
 270#endif
 271
 272#if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
 273	 , _get_obj_desc(get_obj_desc)
 274	 , _purge_archive(purge_archive)
 275	 , _obj_name(obj_name)
 276#endif
 277	{ }
 278};
 279
 280/// Returns the name of the symbol or constant related to the error
 281/** This function returns the name of the failed OpenGL function
 282 *  without the gl prefix in case of a function error or the name
 283 *  of the OpenGL constant (usually a implementation-dependent) limit
 284 *  which are related to the error.
 285 *
 286 *  The result of this function is also influenced by the
 287 *  #OGLPLUS_ERROR_INFO_NO_GL_SYMBOL preprocessor configuration option.
 288 *  If set to zero this function behaves as described above, otherwise it
 289 *  returns an empty C string.
 290 *
 291 *  @see ErrorInfo
 292 *  @see ErrorFunc()
 293 *  @see ErrorFile()
 294 *  @see ErrorLine()
 295 *  @see ErrorClassName()
 296 *  @see ErrorBindTarget()
 297 *  @see ErrorObjectDescription()
 298 *
 299 *  @ingroup error_handling
 300 */
 301inline const char* ErrorGLSymbol(const ErrorInfo& info)
 302{
 303#if !OGLPLUS_ERROR_INFO_NO_GL_SYMBOL
 304	return info._glsym;
 305#else
 306	return "";
 307#endif
 308}
 309
 310/// Returns the path of the source file where the exception originated
 311/**
 312 *  The result of this function is also influenced by the
 313 *  #OGLPLUS_ERROR_INFO_NO_FILE preprocessor configuration option.
 314 *  If set to zero this function behaves as described above, otherwise it
 315 *  returns an empty C string.
 316 *
 317 *  @see ErrorInfo
 318 *  @see ErrorGLSymbol()
 319 *  @see ErrorFunc()
 320 *  @see ErrorLine()
 321 *  @see ErrorClassName()
 322 *  @see ErrorBindTarget()
 323 *  @see ErrorObjectDescription()
 324 *
 325 *  @ingroup error_handling
 326 */
 327inline const char* ErrorFile(const ErrorInfo& info)
 328{
 329#if !OGLPLUS_ERROR_INFO_NO_FILE
 330	return info._file;
 331#else
 332	OGLPLUS_FAKE_USE(info);
 333	return "";
 334#endif
 335}
 336
 337/// Returns the name of the function where the exception originated
 338/**
 339 *  The result of this function is also influenced by the
 340 *  #OGLPLUS_ERROR_INFO_NO_FUNC preprocessor configuration option.
 341 *  If set to zero this function behaves as described above, otherwise it
 342 *  returns an empty C string.
 343 *
 344 *  @see ErrorInfo
 345 *  @see ErrorGLSymbol()
 346 *  @see ErrorFile()
 347 *  @see ErrorLine()
 348 *  @see ErrorClassName()
 349 *  @see ErrorBindTarget()
 350 *  @see ErrorObjectDescription()
 351 *
 352 *  @ingroup error_handling
 353 */
 354inline const char* ErrorFunc(const ErrorInfo& info)
 355{
 356#if !OGLPLUS_ERROR_INFO_NO_FUNC
 357	return info._func;
 358#else
 359	OGLPLUS_FAKE_USE(info);
 360	return "";
 361#endif
 362}
 363
 364/// Returns the line in the source file where the exception originated
 365/**
 366 *  The result of this function is also influenced by the
 367 *  #OGLPLUS_ERROR_INFO_NO_LINE preprocessor configuration option.
 368 *  If set to zero this function behaves as described above, otherwise it
 369 *  returns zero.
 370 *
 371 *  @see ErrorInfo
 372 *  @see ErrorGLSymbol()
 373 *  @see ErrorFile()
 374 *  @see ErrorFunc()
 375 *  @see ErrorClassName()
 376 *  @see ErrorBindTarget()
 377 *  @see ErrorObjectDescription()
 378 *
 379 *  @ingroup error_handling
 380 */
 381inline unsigned ErrorLine(const ErrorInfo& info)
 382{
 383#if !OGLPLUS_ERROR_INFO_NO_LINE
 384	return info._line;
 385#else
 386	OGLPLUS_FAKE_USE(info);
 387	return 0;
 388#endif
 389}
 390
 391/// Returns the name of the class of the object where the exception originated
 392/**
 393 *  The result of this function is also influenced by the
 394 *  #OGLPLUS_ERROR_INFO_NO_CLASS_NAME preprocessor configuration option.
 395 *  If set to zero this function behaves as described above, otherwise it
 396 *  returns the string "UnknownClass".
 397 *
 398 *  @see ErrorInfo
 399 *  @see ErrorGLSymbol()
 400 *  @see ErrorFile()
 401 *  @see ErrorFunc()
 402 *  @see ErrorLine()
 403 *  @see ErrorBindTarget()
 404 *  @see ErrorObjectDescription()
 405 *
 406 *  @ingroup error_handling
 407 */
 408inline const char* ErrorClassName(const ErrorInfo& info)
 409{
 410#if !OGLPLUS_ERROR_INFO_NO_CLASS_NAME
 411	return (info._cls_name && *info._cls_name) ?
 412		info._cls_name :
 413		"UnknownClass";
 414#else
 415	OGLPLUS_FAKE_USE(info);
 416	return "UnknownClass";
 417#endif
 418}
 419
 420/// Returns the name of the binding point the object where the exception originated
 421/**
 422 *  The result of this function is also influenced by the
 423 *  #OGLPLUS_ERROR_INFO_NO_BIND_TARGET preprocessor configuration option.
 424 *  If set to zero this function behaves as described above, otherwise it
 425 *  returns the string "UnknownTarget".
 426 *
 427 *  @see ErrorInfo
 428 *  @see ErrorGLSymbol()
 429 *  @see ErrorFile()
 430 *  @see ErrorFunc()
 431 *  @see ErrorLine()
 432 *  @see ErrorClassName()
 433 *  @see ErrorObjectDescription()
 434 *
 435 *  @ingroup error_handling
 436 */
 437inline const char* ErrorBindTarget(const ErrorInfo& info)
 438{
 439	OGLPLUS_FAKE_USE(info);
 440	return
 441#if !OGLPLUS_ERROR_INFO_NO_BIND_TARGET
 442	(info._bind_tgt) ?
 443		info._bind_tgt.c_str() :
 444#endif
 445		"UnknownTarget";
 446}
 447
 448/// Returns the optional description of the object related to the error
 449/**
 450 *  The result of this function is also influenced by the
 451 *  #OGLPLUS_ERROR_INFO_NO_OBJECT_DESC preprocessor configuration option.
 452 *  If set to zero this function behaves as described above, otherwise it
 453 *  returns an empty string.
 454 *
 455 *  @see ErrorInfo
 456 *  @see ErrorGLSymbol()
 457 *  @see ErrorFile()
 458 *  @see ErrorFunc()
 459 *  @see ErrorLine()
 460 *  @see ErrorClassName()
 461 *  @see ErrorBindTarget()
 462 *
 463 *  @ingroup error_handling
 464 */
 465inline const String& ErrorObjectDescription(const ErrorInfo& info)
 466{
 467	OGLPLUS_FAKE_USE(info);
 468#if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
 469	if((info._get_obj_desc != 0) && (info._obj_name != 0))
 470		return info._get_obj_desc(info._obj_name);
 471#endif
 472	return aux::EmptyString();
 473}
 474
 475/// Exception class for general OpenGL errors
 476/** Instances of this exception class are throws whenever an error is detected
 477 *  during the execution of OpenGL API calls in the @OGLplus code. There are several
 478 *  other classes derived for more specific error types, like GL shading language
 479 *  compilation and linking errors, out-of-memory errors, etc.
 480 *  This class is derived from the standard runtime_error exception and thus
 481 *  the basic error message can be obtained by calling its @c what() member function.
 482 *
 483 *  @ingroup error_handling
 484 */
 485class Error
 486 : public std::runtime_error
 487{
 488public:
 489	/// A map of properties attached to the exception
 490	typedef std::map<String, String> PropertyMap;
 491
 492#if !OGLPLUS_ERROR_NO_PROPERTIES
 493	typedef PropertyMap PropertyMapInit;
 494#else
 495	struct PropertyMapInit { };
 496#endif
 497
 498	/// List of ErrorInfo objects marking exception trace points
 499	typedef std::list<ErrorInfo> PropagationInfoList;
 500private:
 501	GLenum _code;
 502	ErrorInfo _info;
 503#if !OGLPLUS_ERROR_NO_PROPERTIES
 504	PropertyMap _properties;
 505#endif
 506
 507#if !OGLPLUS_ERROR_NO_PROPAGATION_INFO
 508	PropagationInfoList  _propagation;
 509#endif
 510	bool _assertion;
 511public:
 512	Error(
 513		GLenum code,
 514		const char* desc,
 515		const ErrorInfo& info,
 516		bool assertion = false
 517	): std::runtime_error(desc)
 518	 , _code(code)
 519	 , _info(info)
 520	 , _assertion(assertion)
 521	{ }
 522
 523	Error(
 524		GLenum code,
 525		const char* desc,
 526		const ErrorInfo& info,
 527		PropertyMapInit&& properties
 528	): std::runtime_error(desc)
 529	 , _code(code)
 530	 , _info(info)
 531#if !OGLPLUS_ERROR_NO_PROPERTIES
 532	 , _properties(std::move(properties))
 533#endif
 534	 , _assertion(false)
 535	{
 536#if OGLPLUS_ERROR_NO_PROPERTIES
 537		OGLPLUS_FAKE_USE(properties);
 538#endif
 539	}
 540
 541	inline ~Error(void) throw()
 542	{ }
 543
 544	/// Returns the OpenGL error code
 545	/** This is basically the value of error code returned by the glGetError
 546	 *  functions.
 547	 *
 548	 *  @see ThrowInfo
 549	 *  @see File
 550	 *  @see Func
 551	 *  @see Line
 552	 *  @see ClassName
 553	 *  @see ObjectDescription
 554	 */
 555	GLenum Code(void) const
 556	{
 557		return _code;
 558	}
 559
 560	/// Returns information about the throw site of the exception
 561	/**
 562	 *  @see GLSymbol
 563	 *  @see Code
 564	 *  @see File
 565	 *  @see Func
 566	 *  @see Line
 567	 *  @see ClassName
 568	 *  @see ObjectDescription
 569	 */
 570	const ErrorInfo& ThrowInfo(void) const
 571	{
 572		return _info;
 573	}
 574
 575	/// Returns the name of the symbol or constant related to the error
 576	/** This function returns the name of the failed OpenGL function
 577	 *  without the gl prefix in case of a function error or the name
 578	 *  of the OpenGL constant (usually a implementation-dependent) limit
 579	 *  which are related to the error.
 580	 *
 581	 *  @see ThrowInfo
 582	 *  @see Code
 583	 *  @see Func
 584	 *  @see File
 585	 *  @see Line
 586	 *  @see ClassName
 587	 *  @see ObjectDescription
 588	 */
 589	const char* GLSymbol(void) const
 590	{
 591		return ::oglplus::ErrorGLSymbol(_info);
 592	}
 593
 594	/// Returns the path of the source file where the exception originated
 595	/**
 596	 *  @see ThrowInfo
 597	 *  @see GLSymbol
 598	 *  @see Code
 599	 *  @see Func
 600	 *  @see Line
 601	 *  @see ClassName
 602	 *  @see ObjectDescription
 603	 */
 604	const char* File(void) const
 605	{
 606		return ::oglplus::ErrorFile(_info);
 607	}
 608
 609	/// Returns the name of the function where the exception originated
 610	/**
 611	 *  @see ThrowInfo
 612	 *  @see GLSymbol
 613	 *  @see Code
 614	 *  @see File
 615	 *  @see Line
 616	 *  @see ClassName
 617	 *  @see ObjectDescription
 618	 */
 619	const char* Func(void) const
 620	{
 621		return ::oglplus::ErrorFunc(_info);
 622	}
 623
 624	/// Returns the line in the source file where the exception originated
 625	/**
 626	 *  @see ThrowInfo
 627	 *  @see GLSymbol
 628	 *  @see Code
 629	 *  @see File
 630	 *  @see Func
 631	 *  @see ClassName
 632	 *  @see ObjectDescription
 633	 */
 634	unsigned Line(void) const
 635	{
 636		return ::oglplus::ErrorLine(_info);
 637	}
 638
 639	/// Returns the class name of the object that caused the exception
 640	const char* ClassName(void) const
 641	{
 642		return ::oglplus::ErrorClassName(_info);
 643	}
 644
 645	/// Returns the name of the binding point that caused the exception
 646	const char* BindTarget(void) const
 647	{
 648		return ::oglplus::ErrorBindTarget(_info);
 649	}
 650
 651	/// Returns the description of the object that caused the exception
 652	const String& ObjectDescription(void) const
 653	{
 654		return ::oglplus::ErrorObjectDescription(_info);
 655	}
 656
 657#if OGLPLUS_DOCUMENTATION_ONLY || OGLPLUS_ERROR_NO_PROPERTIES
 658	/// Returns the properties of the exception
 659	/**
 660	 *  @see #OGLPLUS_ERROR_NO_PROPERTIES
 661	 */
 662	PropertyMap Properties(void) const
 663	{
 664		return PropertyMap();
 665	}
 666#else
 667	const PropertyMap& Properties(void) const
 668	{
 669		return _properties;
 670	}
 671#endif
 672
 673#if OGLPLUS_DOCUMENTATION_ONLY || !OGLPLUS_ERROR_NO_PROPERTIES
 674	/// Set a property key/value to the property map
 675	template <typename Key, typename Value>
 676	static void AddPropertyValue(
 677		PropertyMapInit& properties,
 678		Key&& key,
 679		Value&& value
 680	)
 681	{
 682		properties[key] = value;
 683	}
 684#else
 685	template <typename Key, typename Value>
 686	static void AddPropertyValue(PropertyMapInit&, Key&&, Value&&) { }
 687#endif
 688
 689	/// Set a property key/value to the exception
 690	void SetPropertyValue(const String& key, const String& value)
 691	{
 692#if !OGLPLUS_ERROR_NO_PROPERTIES
 693		_properties[key] = value;
 694#else
 695		OGLPLUS_FAKE_USE(key);
 696		OGLPLUS_FAKE_USE(value);
 697#endif
 698	}
 699
 700#if OGLPLUS_DOCUMENTATION_ONLY || OGLPLUS_ERROR_NO_PROPAGATION_INFO
 701	/// Returns a list of ErrorInfo objects marking exception trace points
 702	/**
 703	 *  @see #OGLPLUS_ERROR_NO_PROPAGATION_INFO
 704	 */
 705	PropagationInfoList PropagationInfo(void) const
 706	{
 707		return PropagationInfoList();
 708	}
 709#else
 710	const PropagationInfoList& PropagationInfo(void) const
 711	{
 712		return _propagation;
 713	}
 714#endif
 715
 716	void Trace(const ErrorInfo& info)
 717	{
 718#if !OGLPLUS_ERROR_NO_PROPAGATION_INFO
 719		_propagation.push_back(info);
 720#else
 721		OGLPLUS_FAKE_USE(info);
 722#endif
 723		throw;
 724	}
 725
 726	void Cleanup(void) const
 727	{
 728#if !OGLPLUS_ERROR_INFO_NO_OBJECT_DESC
 729		if(_info._purge_archive != 0)
 730			_info._purge_archive();
 731		for(auto i=_propagation.begin(),e=_propagation.end();i!=e;++i)
 732		{
 733			if(i->_purge_archive != 0)
 734				i->_purge_archive();
 735		}
 736#endif
 737	}
 738};
 739
 740/// Exception class for out-of-memory OpenGL errors
 741/** Out-of-memory is a very serious error and applications generally should not
 742 *  try to recover from such errors, but terminate gracefully if possible.
 743 *
 744 *  @ingroup error_handling
 745 */
 746class OutOfMemory
 747 : public Error
 748{
 749public:
 750	OutOfMemory(GLenum code, const char* desc, const ErrorInfo& info)
 751	 : Error(code, desc, info, true)
 752	{ }
 753};
 754
 755#if OGLPLUS_DOCUMENTATION_ONLY
 756/// Exception class for situations when a pointer to a GL function is invalid.
 757/** @OGLplus optionally (based on the value of the #OGLPLUS_NO_GLFUNC_CHECKS
 758 *  compile-time switch) checks, if pointers to OpenGL functions are valid
 759 *  (i.e. not @c nullptr). OpenGL functions are usually called through pointers,
 760 *  when using a library such as GLEW, which tries to find and get the addresses
 761 *  of GL functions from the GL library dynamically at run-time. Sometimes
 762 *  the pointers to several of the functions remain uninitialized and usually
 763 *  result in a memory violation and program termination if called.
 764 *
 765 *  The MissingFunction exception class indicates that the usage
 766 *  of such uninitialized function pointer was detected at run-time
 767 *  and allows the application to terminate more gracefully.
 768 *
 769 *  @see #OGLPLUS_NO_GLFUNC_CHECKS
 770 *
 771 *  @ingroup error_handling
 772 */
 773class MissingFunction
 774 : public Error
 775{ };
 776#else
 777class MissingFunction
 778 : public Error
 779{
 780public:
 781	MissingFunction(GLenum code, const char* msg, const ErrorInfo& info)
 782	 : Error(code, msg, info, true)
 783	{ }
 784};
 785#endif
 786
 787/// Exception indicating exceeded implementation-defined limits
 788/** Instances of this class are thrown if an instance of a (usually unsigned
 789 *  integer) type is assigned a value that it is outside of an implementation
 790 *  dependent range. This includes things like limits on the number of texture
 791 *  units of the GPU, the maximum texture dimensions, maximum number of draw
 792 *  buffers, vertex attributes, etc.
 793 *
 794 *  @ingroup error_handling
 795 */
 796class LimitError
 797 : public Error
 798{
 799private:
 800	GLuint _value;
 801	GLuint _limit;
 802public:
 803	LimitError(
 804		GLuint value,
 805		GLuint limit,
 806		const GLchar* msg,
 807		const ErrorInfo& info
 808	): Error(GL_INVALID_VALUE, msg, info)
 809	 , _value(value)
 810	 , _limit(limit)
 811	{ }
 812
 813	/// The value assigned to the limited-type variable
 814	GLuint Value(void) const
 815	{
 816		return _value;
 817	}
 818
 819	/// The allowed limit of the limited-type
 820	GLuint Limit(void) const
 821	{
 822		return _limit;
 823	}
 824};
 825
 826/// Exception indicating shader variable-related error
 827/** Instances of this class are thrown when an invalid shader variable-related
 828 *  operation is performed, for example when a value of a invalid type is
 829 *  assigned to a shader uniform variable or vertex attribute.
 830 *
 831 *  @ingroup error_handling
 832 */
 833class ShaderVariableError
 834 : public Error
 835{
 836private:
 837	GLint _location;
 838public:
 839	ShaderVariableError(
 840		GLenum code,
 841		GLint location,
 842		const GLchar* msg,
 843		const ErrorInfo& info,
 844		Error::PropertyMapInit&& properties
 845	): Error(code, msg, info, std::move(properties))
 846	 , _location(location)
 847	{ }
 848
 849	/// The location of the shader variable (uniform, vertex attribute)
 850	/** This is the value either assigned by the GL or explicitly specified
 851	 *  by the GLSL layout location specifier or bound by BindAttribLocation
 852	 */
 853	GLint Location(void) const
 854	{
 855		return _location;
 856	}
 857};
 858
 859#if OGLPLUS_DOCUMENTATION_ONLY || OGLPLUS_CUSTOM_ERROR_HANDLING
 860
 861/// Structure containing all error-related data; Used in custom error handlers
 862/**
 863 *  Available only if the #OGLPLUS_CUSTOM_ERROR_HANDLING compile-time switch
 864 *  is set to a nonzero value.
 865 *
 866 *  @ingroup error_handling
 867 */
 868struct ErrorData
 869{
 870private:
 871	GLenum _error_code;
 872	GLuint _value;
 873	GLuint _limit;
 874	const char* _message;
 875	ErrorInfo _info;
 876	Error::PropertyMap _properties;
 877	bool _assertion;
 878	bool _fatal_error;
 879	bool _build_error;
 880	bool _limit_error;
 881public:
 882	/// The OpenGL error code
 883	inline GLenum ErrorCode(void) const
 884	{
 885		return _error_code;
 886	}
 887
 888	/// The invalid value that caused a limit error
 889	inline GLuint Value(void) const
 890	{
 891		return _value;
 892	}
 893
 894	/// The limited value limit
 895	inline GLuint Limit(void) const
 896	{
 897		return _limit;
 898	}
 899
 900	/// The error message
 901	/** The returned pointer should not be used when its ErrorData instance
 902	 *  goes out of scope. If this is necessary the string should be copied.
 903	 */
 904	inline const char* Message(void) const
 905	{
 906		return _message;
 907	}
 908
 909	/// Additional error info
 910	inline const ErrorInfo& Info(void) const
 911	{
 912		return _info;
 913	}
 914
 915	/// Additional error property (key/values)
 916	inline const Error::PropertyMap& Properties(void) const
 917	{
 918		return _properties;
 919	}
 920
 921	/// Indicates that an assertion has failed
 922	inline bool Assertion(void) const
 923	{
 924		return _assertion;
 925	}
 926
 927	/// Indicates a fatal (very severe) error like (out of memory)
 928	inline bool FatalError(void) const
 929	{
 930		return _fatal_error;
 931	}
 932
 933	/// Indicates a build error
 934	inline bool BuildError(void) const
 935	{
 936		return _build_error;
 937	}
 938
 939	/// Indicates a limited value error
 940	inline bool LimitError(void) const
 941	{
 942		return _limit_error;
 943	}
 944
 945	inline ErrorData(
 946		GLenum error_code,
 947		GLuint value,
 948		GLuint limit,
 949		const char* message,
 950		const ErrorInfo& info,
 951		Error::PropertyMapInit&& properties,
 952		bool assertion,
 953		bool fatal_error,
 954		bool build_error,
 955		bool limit_error
 956	): _error_code(error_code)
 957	 , _value(value)
 958	 , _limit(limit)
 959	 , _message(message)
 960	 , _info(info)
 961	 , _properties(std::move(properties))
 962	 , _assertion(assertion)
 963	 , _fatal_error(fatal_error)
 964	 , _build_error(build_error)
 965	 , _limit_error(limit_error)
 966	{ }
 967};
 968
 969/// Type of installable custom error handler functor
 970/**
 971 *  Available only if the #OGLPLUS_CUSTOM_ERROR_HANDLING compile-time switch
 972 *  is set to a nonzero value.
 973 *
 974 *  @ingroup error_handling
 975 */
 976typedef std::function<bool (const ErrorData&)> ErrorHandlerFunc;
 977
 978namespace aux {
 979
 980inline std::stack<ErrorHandlerFunc>& _error_handlers(void)
 981{
 982	static std::stack<ErrorHandlerFunc> _handlers;
 983	return _handlers;
 984}
 985
 986inline bool _has_error_handler(void)
 987{
 988	return !_error_handlers().empty();
 989}
 990
 991inline ErrorHandlerFunc& _get_error_handler(void)
 992{
 993	assert(!_error_handlers().empty());
 994	return _error_handlers().top();
 995}
 996
 997} // namespace aux
 998
 999/// A RAII class installing a temporary custom error handler
1000/**
1001 *  Available only if the #OGLPLUS_CUSTOM_ERROR_HANDLING compile-time switch
1002 *  is set to a nonzero value.
1003 *
1004 *  @ingroup error_handling
1005 */
1006class LocalErrorHandler
1007{
1008private:
1009	size_t _installed;
1010public:
1011	/// Installs the specified error @p handler
1012	LocalErrorHandler(ErrorHandlerFunc handler)
1013	{
1014		aux::_error_handlers().push(handler);
1015		_installed = aux::_error_handlers().size();
1016	}
1017
1018	/// This class is non-copyable
1019	LocalErrorHandler(const LocalErrorHandler&) = delete;
1020
1021	/// Uninstalls the previously installed handler
1022	~LocalErrorHandler(void)
1023	{
1024		if(_installed)
1025		{
1026			assert(aux::_error_handlers().size() == _installed);
1027			aux::_error_handlers().pop();
1028		}
1029	}
1030};
1031
1032#endif // OGLPLUS_CUSTOM_ERROR_HANDLING
1033
1034template <class Exception>
1035inline void HandleBuildError(const String& msg, const ErrorInfo& info)
1036{
1037#if OGLPLUS_CUSTOM_ERROR_HANDLING
1038	if(aux::_has_error_handler() && aux::_get_error_handler()(
1039		ErrorData(
1040			GL_INVALID_OPERATION,
1041			0u, 0u,
1042			msg.c_str(),
1043			info,
1044			Error::PropertyMapInit(),
1045			false,
1046			false,
1047			true,
1048			false
1049		)
1050	)) return;
1051#endif // OGLPLUS_CUSTOM_ERROR_HANDLING
1052	throw Exception(msg, info);
1053}
1054
1055inline void HandleShaderVariableError(
1056	GLenum code,
1057	GLint location,
1058	const GLchar* msg,
1059	const ErrorInfo& info,
1060	Error::PropertyMapInit&& properties
1061)
1062{
1063#if OGLPLUS_CUSTOM_ERROR_HANDLING
1064	if(aux::_has_error_handler() && aux::_get_error_handler()(
1065		ErrorData(
1066			code,
1067			0u, 0u,
1068			msg,
1069			info,
1070			Error::PropertyMapInit(),
1071			false,
1072			false,
1073			false,
1074			false
1075		)
1076	)) return;
1077#endif // OGLPLUS_CUSTOM_ERROR_HANDLING
1078	throw ShaderVariableError(
1079		code,
1080		location,
1081		msg,
1082		info,
1083		std::move(properties)
1084	);
1085}
1086
1087inline void HandleLimitError(GLuint value, GLuint limit, const ErrorInfo& info)
1088{
1089	const GLchar* msg = "OpenGL limited value out of range";
1090#if OGLPLUS_CUSTOM_ERROR_HANDLING
1091	if(aux::_has_error_handler() && aux::_get_error_handler()(
1092		ErrorData(
1093			GL_INVALID_VALUE,
1094			value, limit,
1095			msg,
1096			info,
1097			Error::PropertyMapInit(),
1098			false,
1099			false,
1100			false,
1101			true
1102		)
1103	)) return;
1104#endif // OGLPLUS_CUSTOM_ERROR_HANDLING
1105	throw LimitError(value, limit, msg, info);
1106}
1107
1108template <class Exception, typename FBStatus>
1109inline void HandleIncompleteFramebuffer(
1110	FBStatus status,
1111	const ErrorInfo& info
1112)
1113{
1114	const GLchar* msg = "Framebuffer is incomplete";
1115#if OGLPLUS_CUSTOM_ERROR_HANDLING
1116	if(aux::_has_error_handler() && aux::_get_error_handler()(
1117		ErrorData(
1118			GL_INVALID_FRAMEBUFFER_OPERATION,
1119			0u, 0u,
1120			msg,
1121			info,
1122			Error::PropertyMapInit(),
1123			false,
1124			false,
1125			false,
1126			true
1127		)
1128	)) return;
1129#endif // OGLPLUS_CUSTOM_ERROR_HANDLING
1130	throw Exception(status, msg, info);
1131}
1132
1133#if !OGLPLUS_NO_VARIADIC_TEMPLATES && !OGLPLUS_NO_GLFUNC_CHECKS
1134inline void HandleMissingFunction(const ErrorInfo& info)
1135{
1136	const GLenum code = GL_INVALID_VALUE;
1137	const char* msg = "Function called through an invalid pointer";
1138#if OGLPLUS_CUSTOM_ERROR_HANDLING
1139	if(aux::_has_error_handler() && aux::_get_error_handler()(
1140		ErrorData(
1141			code,
1142			0u, 0u,
1143			msg,
1144			info,
1145			Error::PropertyMapInit(),
1146			true,
1147			true,
1148			false,
1149			false
1150		)
1151	)) return;
1152#endif // OGLPLUS_CUSTOM_ERROR_HANDLING
1153	throw MissingFunction(code, msg, info);
1154}
1155#endif // OGLPLUS_NO_VARIADIC_TEMPLATES || OGLPLUS_NO_GLFUNC_CHECKS
1156
1157inline void HandleError(
1158	GLenum code,
1159	const GLchar* msg,
1160	const ErrorInfo& info,
1161	Error::PropertyMapInit&& properties
1162)
1163{
1164#if OGLPLUS_CUSTOM_ERROR_HANDLING
1165	if(aux::_has_error_handler() && aux::_get_error_handler()(
1166		ErrorData(
1167			code,
1168			0, 0,
1169			msg,
1170			info,
1171			std::move(properties),
1172			false,
1173			code == GL_OUT_OF_MEMORY,
1174			false,
1175			false
1176		)
1177	)) return;
1178#endif // OGLPLUS_CUSTOM_ERROR_HANDLING
1179	throw Error(
1180		code,
1181		msg,
1182		info,
1183		std::move(properties)
1184	);
1185}
1186
1187inline void HandleError(GLenum code, const ErrorInfo& info, bool assertion)
1188{
1189	const GLchar* msg = "Unknown error";
1190	switch(code)
1191	{
1192		case GL_OUT_OF_MEMORY:
1193			msg = "OpenGL out of memory";
1194			break;
1195		case GL_INVALID_ENUM:
1196			msg = "Invalid OpenGL enum argument";
1197			break;
1198		case GL_INVALID_VALUE:
1199			msg = "OpenGL numeric argument out of range";
1200			break;
1201		case GL_INVALID_OPERATION:
1202			msg = "Invalid OpenGL operation";
1203			break;
1204		case GL_INVALID_FRAMEBUFFER_OPERATION:
1205			msg = "Invalid OpenGL framebuffer operation";
1206			break;
1207
1208#ifdef GL_STACK_OVERFLOW
1209		case GL_STACK_OVERFLOW:
1210			msg = "Stack overflow";
1211			break;
1212#endif
1213
1214#ifdef GL_STACK_UNDERFLOW
1215		case GL_STACK_UNDERFLOW:
1216			msg = "Stack underflow";
1217			break;
1218#endif
1219
1220#ifdef GL_TABLE_TOO_LARGE
1221		case GL_TABLE_TOO_LARGE:
1222			msg = "Table too large";
1223			break;
1224#endif
1225	}
1226#if OGLPLUS_CUSTOM_ERROR_HANDLING
1227	if(aux::_has_error_handler() && aux::_get_error_handler()(
1228		ErrorData(
1229			code,
1230			0, 0,
1231			msg,
1232			info,
1233			Error::PropertyMapInit(),
1234			assertion,
1235			code == GL_OUT_OF_MEMORY,
1236			false,
1237			false
1238		)
1239	)) return;
1240#endif // OGLPLUS_CUSTOM_ERROR_HANDLING
1241	throw Error(code, msg, info, assertion);
1242}
1243
1244#if OGLPLUS_DOCUMENTATION_ONLY
1245/// This macro decides if error handling should be done
1246/** The @p EXPRESSION parameter is a boolean expression
1247 *  and true values indicate an error condition. If this
1248 *  macro returns a false expression any error handling
1249 *  is skipped.
1250 */
1251#define OGLPLUS_IS_ERROR(EXPRESSION)
1252#endif
1253
1254#ifndef OGLPLUS_IS_ERROR
1255#define OGLPLUS_IS_ERROR(EXPRESSION) (EXPRESSION)
1256#endif
1257
1258#if OGLPLUS_DOCUMENTATION_ONLY
1259/// Macro checking and possibly handling run-time errors in previous call to GL
1260/** This macro is called immediatelly after calls to GL functions
1261 *  that may fail due to invalid values of run-time parameters.
1262 */
1263#define OGLPLUS_CHECK(PARAM)
1264#endif
1265
1266#ifndef OGLPLUS_CHECK
1267#define OGLPLUS_CHECK(PARAM) { \
1268	GLenum error_code = ::glGetError(); \
1269	if(error_code != GL_NO_ERROR) HandleError(error_code, PARAM, false); \
1270}
1271#endif
1272
1273#if OGLPLUS_DOCUMENTATION_ONLY
1274/// Macro asserting that no errors occured in prevous call to GL
1275/** This macro is called immediatelly after calls to GL functions
1276 *  that "should not" fail and if they do fail it indicates
1277 *  a program logic error that is not dependent on run-time parameters.
1278 */
1279#define OGLPLUS_VERIFY(PARAM)
1280#endif
1281
1282#ifndef OGLPLUS_VERIFY
1283#if !OGPLUS_LOW_PROFILE
1284#define OGLPLUS_VERIFY(PARAM) { \
1285	GLenum error_code = ::glGetError(); \
1286	if(error_code != GL_NO_ERROR) HandleError(error_code, PARAM, true); \
1287}
1288#else
1289#define OGLPLUS_VERIFY(PARAM)
1290#endif
1291#endif
1292
1293#define OGLPLUS_IGNORE(PARAM) ::glGetError();
1294
1295} // namespace oglplus
1296
1297#endif // include guard