1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 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 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 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 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
|
/*
igraph library.
Copyright (C) 2003-2025 The igraph development team <igraph@igraph.org>
This program 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 2 of the License, or
(at your option) any later version.
This program 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 <https://www.gnu.org/licenses/>.
*/
#ifndef IGRAPH_ERROR_H
#define IGRAPH_ERROR_H
#include "igraph_decls.h"
#include "igraph_config.h"
#include <stdarg.h>
IGRAPH_BEGIN_C_DECLS
/* This file contains the igraph error handling.
* Most bits are taken literally from the GSL library (with the GSL_
* prefix renamed to IGRAPH_), as I couldn't find a better way to do
* them. */
/* With some compilers, we use function attributes to help diagnostics
* and optimizations. These are not part of the public API, do not use
* them outside of igraph itself.
*
* IGRAPH_FUNCATTR_NORETURN indicates to the compiler that a function does not return.
* There are standard facilities for this, namely _Noreturn in C11 and [[noreturn]] in C++11.
* However, since igraph is currently compiled with older standards, and since
* the standard 'noreturn' specification would need to be diferent between C and C++,
* we do not use these facilities.
*
* IGRAPH_FUNCATTR_PRINTFLIKE(string, first) marks a function as having a printf-like syntax,
* allowing the compiler to check that the format specifiers match argument types.
* 'string' is the index of the string-argument and 'first' is the index of the
* first argument to check against format specifiers.
*/
#if defined(__GNUC__)
/* Compilers that support the GNU C syntax. Use __noreturn__ instead of 'noreturn' as the latter is a macro in C11. */
#define IGRAPH_FUNCATTR_NORETURN __attribute__((__noreturn__))
#define IGRAPH_FUNCATTR_PRINTFLIKE(string, first) __attribute__((__format__(printf, string, first)))
#elif defined(_MSC_VER)
/* Compilers that support the MSVC syntax. */
#define IGRAPH_FUNCATTR_NORETURN __declspec(noreturn)
#define IGRAPH_FUNCATTR_PRINTFLIKE(string, first)
#else
#define IGRAPH_FUNCATTR_NORETURN
#define IGRAPH_FUNCATTR_PRINTFLIKE(string, first)
#endif
/* IGRAPH_PREPROCESSOR_WARNING(reason) is a macro that evaluates to nothing
* but triggers a preprocessor warning with the given message, if the compiler
* supports this functionality.
*/
#if defined(__GNUC__)
#define IGRAPH_PREPROCESSOR_WARNING(reason) _Pragma(IGRAPH_I_STRINGIFY(GCC warning reason))
#else
#define IGRAPH_PREPROCESSOR_WARNING(reason) /* empty */
#endif
/**
* \section error_handling_basics Error handling basics
*
* <para>\a igraph functions can run into various problems preventing them
* from normal operation. The user might have supplied invalid arguments,
* e.g. a non-square matrix when a square-matrix was expected, or the program
* has run out of memory while some more memory allocation is required, etc.
* </para>
*
* <para>By default \a igraph aborts the program when it runs into an
* error. While this behavior might be good enough for smaller programs,
* it is without doubt avoidable in larger projects. Please read further
* if your project requires more sophisticated error handling. You can
* safely skip the rest of this chapter otherwise.
* </para>
*/
/**
* \section error_handlers Error handlers
*
* <para>
* If \a igraph runs into an error - an invalid argument was supplied
* to a function, or we've ran out of memory - the control is
* transferred to the \emb error handler \eme function.
* </para><para>
* The default error handler is \ref igraph_error_handler_abort which
* prints an error message and aborts the program.
* </para>
* <para>
* The \ref igraph_set_error_handler() function can be used to set a new
* error handler function of type \ref igraph_error_handler_t; see the
* documentation of this type for details.
* </para>
* <para>
* There are two other predefined error handler functions,
* \ref igraph_error_handler_ignore and \ref igraph_error_handler_printignore.
* These deallocate the temporarily allocated memory (more about this
* later) and return with the error code. The latter also prints an
* error message. If you use these error handlers you need to take
* care about possible errors yourself by checking the return value of
* (almost) every non-void \a igraph function.
* </para><para>
* Independently of the error handler installed, all functions in the
* library do their best to leave their arguments
* \em semantically unchanged if an error
* happens. By semantically we mean that the implementation of an
* object supplied as an argument might change, but its
* \quote meaning \endquote in most cases does not. The rare occasions
* when this rule is violated are documented in this manual.
* </para>
*/
/**
* \section error_codes Error codes
*
* <para>Every \a igraph function which can fail return a
* single integer error code. Some functions are very simple and
* cannot run into any error, these may return other types, or
* \type void as well. The error codes are defined by the
* \ref igraph_error_type_t enumeration.
* </para>
*/
/**
* \section writing_error_handlers Writing error handlers
*
* <para>
* The contents of the rest of this chapter might be useful only
* for those who want to create an interface to \a igraph from another
* language, or use igraph from a GUI application. Most readers can
* safely skip to the next chapter.
* </para>
*
* <para>
* You can write and install error handlers simply by defining a
* function of type \ref igraph_error_handler_t and calling
* \ref igraph_set_error_handler(). This feature is useful for interface
* writers, as \a igraph will have the chance to
* signal errors the appropriate way. For example, the R interface uses
* R's native printing facilities to communicate errors, while the Python
* interface converts them into Python exceptions.
* </para>
*
* <para>
* The two main tasks of the error handler are to report the error
* (i.e. print the error message) and ensure proper resource cleanup.
* This is ensured by calling \ref IGRAPH_FINALLY_FREE(), which deallocates
* some of the temporary memory to avoid memory leaks. Note that this may
* invalidate the error message buffer \p reason passed to the error handler.
* Do not access it after having called \ref IGRAPH_FINALLY_FREE().
* </para>
*
* <para>
* As of \a igraph 0.10, temporary memory is dellocated in stages, through
* multiple calls to the error handler (and indirectly to \ref IGRAPH_FINALLY_FREE()).
* Therefore, error handlers that do not abort the program
* immediately are expected to return. The error handler should not perform
* a <code>longjmp</code>, as this may lead to some of the memory not
* getting freed.
* </para>
*/
/**
* \section error_handling_internals Error handling internals
*
* <para>
* If an error happens, the functions in the library call the
* \ref IGRAPH_ERROR() macro with a textual description of the error and an
* \a igraph error code. This macro calls (through the \ref
* igraph_error() function) the installed error handler. Another useful
* macro is \ref IGRAPH_CHECK(). This checks the return value of its
* argument, which is normally a function call, and calls \ref
* IGRAPH_ERROR() if it is not \c IGRAPH_SUCCESS.
* </para>
*/
/**
* \section deallocating_memory Deallocating memory
*
* <para>
* If a function runs into an error (and the program is not aborted)
* the error handler should deallocate all temporary memory. This is
* done by storing the address and the destroy function of all temporary
* objects in a stack. The \ref IGRAPH_FINALLY function declares an object as
* temporary by placing its address in the stack. If an \a igraph function returns
* with success it calls \ref IGRAPH_FINALLY_CLEAN() with the
* number of objects to remove from the stack. If an error happens
* however, the error handler should call \ref IGRAPH_FINALLY_FREE() to
* deallocate each object added to the stack. This means that the
* temporary objects allocated in the calling function (and etc.) will
* be freed as well.
* </para>
*/
/**
* \section writing_functions_error_handling Writing \a igraph functions with
* proper error handling
*
* <para>
* There are some simple rules to keep in order to have functions
* behaving well in erroneous situations. First, check the arguments
* of the functions and call \ref IGRAPH_ERROR() if they are invalid. Second,
* call \ref IGRAPH_FINALLY on each dynamically allocated object and call
* \ref IGRAPH_FINALLY_CLEAN() with the proper argument before returning. Third, use
* \ref IGRAPH_CHECK on all \a igraph function calls which can generate errors.
* </para>
* <para>
* The size of the stack used for this bookkeeping is fixed, and
* small. If you want to allocate several objects, write a destroy
* function which can deallocate all of these. See the
* <filename>adjlist.c</filename> file in the
* \a igraph source for an example.
* </para>
* <para>
* For some functions these mechanisms are simply not flexible
* enough. These functions should define their own error handlers and
* restore the error handler before they return.
* </para>
*
* \example examples/simple/igraph_contract_vertices.c
*/
/**
* \typedef igraph_error_type_t
* \brief Error code type.
* These are the possible values returned by \a igraph functions.
* Note that these are interesting only if you defined an error handler
* with \ref igraph_set_error_handler(). Otherwise the program is aborted
* and the function causing the error never returns.
*
* \enumval IGRAPH_SUCCESS The function successfully completed its task.
* \enumval IGRAPH_FAILURE Something went wrong. You'll almost never
* meet this error as normally more specific error codes are used.
* \enumval IGRAPH_ENOMEM There wasn't enough memory to allocate
* on the heap.
* \enumval IGRAPH_PARSEERROR A parse error was found in a file.
* \enumval IGRAPH_EINVAL A parameter's value is invalid. E.g. negative
* number was specified as the number of vertices.
* \enumval IGRAPH_EXISTS A graph/vertex/edge attribute is already
* installed with the given name.
* \enumval IGRAPH_EINVVID Invalid vertex ID, negative or too big.
* \enumval IGRAPH_EINVEID Invalid edge ID, negative or too big.
* \enumval IGRAPH_EINVMODE Invalid mode parameter.
* \enumval IGRAPH_EFILE A file operation failed. E.g. a file doesn't exist,
* or the user has no rights to open it.
* \enumval IGRAPH_UNIMPLEMENTED Attempted to call an unimplemented or
* disabled (at compile-time) function.
* \enumval IGRAPH_DIVERGED A numeric algorithm failed to converge.
* \enumval IGRAPH_ARPACK An error happened inside a calculation implemented
* in ARPACK. The calculation involved is most likely an eigenvector-related
* calculation.
* \enumval IGRAPH_ENEGCYCLE Negative cycle detected while calculating shortest paths.
* \enumval IGRAPH_EINTERNAL Internal error, likely a bug in igraph.
* \enumval IGRAPH_EATTRCOMBINE Unimplemented attribute combination
* method for the given attribute type.
* \enumval IGRAPH_EOVERFLOW Integer or double overflow.
* \enumval IGRAPH_EUNDERFLOW Integer or double underflow.
* \enumval IGRAPH_ERWSTUCK Random walk got stuck.
* \enumval IGRAPH_ERANGE Maximum vertex or edge count exceeded.
* \enumval IGRAPH_ENOSOL Input problem has no solution.
*/
typedef enum {
IGRAPH_SUCCESS = 0,
IGRAPH_FAILURE = 1,
IGRAPH_ENOMEM = 2,
IGRAPH_PARSEERROR = 3,
IGRAPH_EINVAL = 4,
IGRAPH_EXISTS = 5,
/* IGRAPH_EINVEVECTOR = 6, */ /* removed in 1.0 */
IGRAPH_EINVVID = 7,
IGRAPH_EINVEID = 8, /* used to be IGRAPH_NONSQUARE before 1.0 */
IGRAPH_EINVMODE = 9,
IGRAPH_EFILE = 10,
IGRAPH_UNIMPLEMENTED = 12,
IGRAPH_INTERRUPTED = 13,
IGRAPH_DIVERGED = 14,
IGRAPH_EARPACK = 15,
/* ARPACK error codes from 15 to 36 were moved to igraph_arpack_error_t in 1.0 */
IGRAPH_ENEGCYCLE = 37,
IGRAPH_EINTERNAL = 38,
/* ARPACK error codes from 39 to 41 were moved to igraph_arpack_error_t in 1.0 */
/* IGRAPH_EDIVZERO = 42, */ /* removed in 1.0 */
/* IGRAPH_GLP_EBOUND = 43, */ /* removed in 1.0 */
/* IGRAPH_GLP_EROOT = 44, */ /* removed in 1.0 */
/* IGRAPH_GLP_ENOPFS = 45, */ /* removed in 1.0 */
/* IGRAPH_GLP_ENODFS = 46, */ /* removed in 1.0 */
/* IGRAPH_GLP_EFAIL = 47, */ /* removed in 1.0 */
/* IGRAPH_GLP_EMIPGAP = 48, */ /* removed in 1.0 */
/* IGRAPH_GLP_ETMLIM = 49, */ /* removed in 1.0 */
/* IGRAPH_GLP_ESTOP = 50, */ /* removed in 1.0 */
/* IGRAPH_EATTRIBUTES = 51, */ /* removed in 1.0 */
IGRAPH_EATTRCOMBINE = 52,
/* IGRAPH_ELAPACK = 53, */ /* removed in 1.0 */
/* IGRAPH_EDRL = 54, */ /* deprecated in 0.10.2, removed in 1.0 */
IGRAPH_EOVERFLOW = 55,
/* IGRAPH_EGLP = 56, */ /* removed in 1.0 */
/* IGRAPH_CPUTIME = 57, */ /* removed in 1.0 */
IGRAPH_EUNDERFLOW = 58,
IGRAPH_ERWSTUCK = 59,
IGRAPH_STOP = 60,
IGRAPH_ERANGE = 61,
IGRAPH_ENOSOL = 62
} igraph_error_type_t;
/* Each enum value above must have a corresponding error string in
* igraph_i_error_strings[] in core/error.c
*
* Information on undocumented codes:
* - IGRAPH_STOP signals a request to stop in functions like igraph_i_maximal_cliques_bk()
*/
/**
* \section error_handling_threads Error handling and threads
*
* <para>
* It is likely that the \a igraph error handling
* method is \em not thread-safe, mainly because of
* the static global stack which is used to store the address of the
* temporarily allocated objects. This issue might be addressed in a
* later version of \a igraph.
* </para>
*/
/**
* \typedef igraph_error_t
* \brief Return type for functions returning an error code.
*
* This type is used as the return type of igraph functions that return an
* error code. It is a type alias because \type igraph_error_t used to be
* an \c int, and was used slightly differenly than \type igraph_error_type_t.
*/
typedef igraph_error_type_t igraph_error_t;
/**
* \typedef igraph_error_handler_t
* \brief The type of error handler functions.
*
* This is the type of the error handler functions.
*
* \param reason Textual description of the error.
* \param file The source file in which the error is noticed.
* \param line The number of the line in the source file which triggered
* the error
* \param igraph_errno The \a igraph error code.
*/
typedef void igraph_error_handler_t(const char *reason, const char *file,
int line, igraph_error_t igraph_errno);
/**
* \var igraph_error_handler_abort
* \brief Abort program in case of error.
*
* The default error handler, prints an error message and aborts the
* program.
*/
IGRAPH_EXPORT IGRAPH_FUNCATTR_NORETURN igraph_error_handler_t igraph_error_handler_abort;
/**
* \var igraph_error_handler_ignore
* \brief Ignore errors.
*
* This error handler frees the temporarily allocated memory and returns
* with the error code.
*/
IGRAPH_EXPORT igraph_error_handler_t igraph_error_handler_ignore;
/**
* \var igraph_error_handler_printignore
* \brief Print and ignore errors.
*
* Frees temporarily allocated memory, prints an error message to the
* standard error and returns with the error code.
*/
IGRAPH_EXPORT igraph_error_handler_t igraph_error_handler_printignore;
IGRAPH_EXPORT igraph_error_handler_t *igraph_set_error_handler(igraph_error_handler_t* new_handler);
/* We use IGRAPH_FILE_BASENAME instead of __FILE__ to ensure that full
* paths don't leak into the library code. IGRAPH_FILE_BASENAME is set up
* by the build system when compiling the individual files. However, when
* including igraph_error.h in user code, this macro is not defined so we
* fall back to __FILE__ here
*/
#ifndef IGRAPH_FILE_BASENAME
# define IGRAPH_FILE_BASENAME __FILE__
#endif
/**
* \define IGRAPH_ERROR
* \brief Triggers an error.
*
* \a igraph functions usually use this macro when they notice an error.
* It calls
* \ref igraph_error() with the proper parameters and if that returns
* the macro returns the "calling" function as well, with the error
* code. If for some (suspicious) reason you want to call the error
* handler without returning from the current function, call
* \ref igraph_error() directly.
*
* \param reason Textual description of the error. This should be
* something more descriptive than the text associated with the error
* code. E.g. if the error code is \c IGRAPH_EINVAL,
* its associated text (see \ref igraph_strerror()) is "Invalid
* value" and this string should explain which parameter was invalid
* and maybe why.
* \param igraph_errno The \a igraph error code.
*/
#define IGRAPH_ERROR(reason, igraph_errno) \
do { \
igraph_error (reason, IGRAPH_FILE_BASENAME, __LINE__, igraph_errno) ; \
return igraph_errno ; \
} while (0)
#define IGRAPH_ERROR_NO_RETURN(reason, igraph_errno) \
do { \
igraph_error (reason, IGRAPH_FILE_BASENAME, __LINE__, igraph_errno) ; \
} while (0)
IGRAPH_EXPORT igraph_error_t igraph_error(const char *reason, const char *file,
int line, igraph_error_t igraph_errno);
/**
* \define IGRAPH_ERRORF
* \brief Triggers an error, with printf-like syntax.
*
* \a igraph functions can use this macro when they notice an error and
* want to pass on extra information to the user about what went wrong.
* It calls \ref igraph_errorf() with the proper parameters and if that
* returns the macro returns the "calling" function as well, with the
* error code. If for some (suspicious) reason you want to call the
* error handler without returning from the current function, call
* \ref igraph_errorf() directly.
*
* \param reason Textual description of the error, a template string
* with the same syntax as the standard printf C library function.
* This should be something more descriptive than the text associated
* with the error code. E.g. if the error code is \c IGRAPH_EINVAL,
* its associated text (see \ref igraph_strerror()) is "Invalid
* value" and this string should explain which parameter was invalid
* and maybe what was expected and what was recieved.
* \param igraph_errno The \a igraph error code.
* \param ... The additional arguments to be substituted into the
* template string.
*/
#define IGRAPH_ERRORF(reason, igraph_errno, ...) \
do { \
igraph_errorf(reason, IGRAPH_FILE_BASENAME, __LINE__, \
igraph_errno, __VA_ARGS__) ; \
return igraph_errno; \
} while (0)
IGRAPH_FUNCATTR_PRINTFLIKE(1,5)
IGRAPH_EXPORT igraph_error_t igraph_errorf(const char *reason, const char *file,
int line, igraph_error_t igraph_errno,
...);
IGRAPH_EXPORT igraph_error_t igraph_errorvf(const char *reason, const char *file,
int line, igraph_error_t igraph_errno,
va_list ap);
IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE const char *igraph_strerror(igraph_error_t igraph_errno);
#define IGRAPH_ERROR_SELECT_2(a,b) ((a) != IGRAPH_SUCCESS ? (a) : ((b) != IGRAPH_SUCCESS ? (b) : IGRAPH_SUCCESS))
#define IGRAPH_ERROR_SELECT_3(a,b,c) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_2(b,c))
#define IGRAPH_ERROR_SELECT_4(a,b,c,d) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_3(b,c,d))
#define IGRAPH_ERROR_SELECT_5(a,b,c,d,e) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_4(b,c,d,e))
/* Now comes the more convenient error handling macro arsenal.
* Ideas taken from exception.{h,c} by Laurent Deniau see
* http://cern.ch/Laurent.Deniau/html/oopc/oopc.html#Exceptions for more
* information. We don't use the exception handling code though. */
struct igraph_i_protectedPtr {
int level;
void *ptr;
void (*func)(void*);
};
typedef void igraph_finally_func_t(void *);
IGRAPH_EXPORT void IGRAPH_FINALLY_REAL(igraph_finally_func_t *func, void *ptr);
/**
* \function IGRAPH_FINALLY_CLEAN
* \brief Signals clean deallocation of objects.
*
* Removes the specified number of objects from the stack of
* temporarily allocated objects. It is typically called
* immediately after manually destroying the objects:
*
* <programlisting>
* igraph_vector_t vector;
* igraph_vector_init(&vector, 10);
* IGRAPH_FINALLY(igraph_vector_destroy, &vector);
* // use vector
* igraph_vector_destroy(&vector);
* IGRAPH_FINALLY_CLEAN(1);
* </programlisting>
*
* \param num The number of objects to remove from the bookkeeping
* stack.
*/
IGRAPH_EXPORT void IGRAPH_FINALLY_CLEAN(int num);
/**
* \function IGRAPH_FINALLY_FREE
* \brief Deallocates objects registered at the current level.
*
* Calls the destroy function for all objects in the current level
* of the stack of temporarily allocated objects, i.e. up to the
* nearest mark set by <code>IGRAPH_FINALLY_ENTER()</code>.
* This function must only be called from an error handler.
* It is \em not appropriate to use it
* instead of destroying each unneeded object of a function, as it
* destroys the temporary objects of the caller function (and so on)
* as well.
*/
IGRAPH_EXPORT void IGRAPH_FINALLY_FREE(void);
IGRAPH_EXPORT void IGRAPH_FINALLY_ENTER(void);
IGRAPH_EXPORT void IGRAPH_FINALLY_EXIT(void);
/**
* \function IGRAPH_FINALLY_STACK_SIZE
* \brief The number of registered objects.
*
* Returns the number of objects in the stack of temporarily allocated
* objects. This function is handy if you write an own igraph routine and
* you want to make sure it handles errors properly. A properly written
* igraph routine should not leave pointers to temporarily allocated objects
* in the finally stack, because otherwise an \ref IGRAPH_FINALLY_FREE call
* in another igraph function would result in freeing these objects as well
* (and this is really hard to debug, since the error will be not in that
* function that shows erroneous behaviour). Therefore, it is advised to
* write your own test cases and examine \ref IGRAPH_FINALLY_STACK_SIZE
* before and after your test cases - the numbers should be equal.
*/
IGRAPH_EXPORT int IGRAPH_FINALLY_STACK_SIZE(void);
/**
* \define IGRAPH_FINALLY_STACK_EMPTY
* \brief Returns true if there are no registered objects, false otherwise.
*
* This is just a shorthand notation for checking that
* \ref IGRAPH_FINALLY_STACK_SIZE() is zero.
*/
#define IGRAPH_FINALLY_STACK_EMPTY (IGRAPH_FINALLY_STACK_SIZE() == 0)
/**
* \define IGRAPH_FINALLY
* \brief Registers an object for deallocation.
*
* This macro places the address of an object, together with the
* address of its destructor on a stack. This stack is used if an
* error happens to deallocate temporarily allocated objects to
* prevent memory leaks. After manual deallocation, objects are removed
* from the stack using \ref IGRAPH_FINALLY_CLEAN().
*
* </para><para>
* The typical usage is just after an initialization:
*
* <programlisting>
* IGRAPH_CHECK(igraph_vector_init(&vector, 0));
* IGRAPH_FINALLY(igraph_vector_destroy, &vector);
* </programlisting>
*
* The most commonly used data structures, such as \ref igraph_vector_t,
* have associated convenience macros that initialize the object and register
* it on this stack in one step. Thus the pattern above can be replaced with a
* single line:
*
* <programlisting>
* IGRAPH_VECTOR_INIT_FINALLY(&vector, 0);
* </programlisting>
*
* \param func The function which is normally called to
* destroy the object.
* \param ptr Pointer to the object itself.
*/
#define IGRAPH_FINALLY(func, ptr) \
do { \
/* the following branch makes the compiler check the compatibility of \
* func and ptr to detect cases when we are accidentally invoking an \
* incorrect destructor function with the pointer */ \
if (0) { func(ptr); } \
IGRAPH_FINALLY_REAL((igraph_finally_func_t*)(func), (ptr)); \
} while (0)
#if defined(__GNUC__)
#define IGRAPH_UNLIKELY(a) __builtin_expect(!!(a), 0)
#define IGRAPH_LIKELY(a) __builtin_expect(!!(a), 1)
#else
#define IGRAPH_UNLIKELY(a) a
#define IGRAPH_LIKELY(a) a
#endif
#if IGRAPH_VERIFY_FINALLY_STACK == 1
#define IGRAPH_CHECK(a) \
do { \
int enter_stack_size = IGRAPH_FINALLY_STACK_SIZE(); \
igraph_error_t igraph_i_ret=(a); \
if (IGRAPH_UNLIKELY(igraph_i_ret != IGRAPH_SUCCESS)) {\
IGRAPH_ERROR("", igraph_i_ret); \
} \
if (IGRAPH_UNLIKELY(enter_stack_size != IGRAPH_FINALLY_STACK_SIZE())) { \
IGRAPH_FATAL("Non-matching number of IGRAPH_FINALLY and IGRAPH_FINALLY_CLEAN."); \
} \
} while (0)
#else
/**
* \define IGRAPH_CHECK
* \brief Checks the return value of a function call.
*
* \param expr An expression, usually a function call. It is guaranteed to
* be evaluated only once.
*
* Executes the expression and checks its value. If this is not
* \c IGRAPH_SUCCESS, it calls \ref IGRAPH_ERROR with
* the value as the error code. Here is an example usage:
* \verbatim IGRAPH_CHECK(vector_push_back(&v, 100)); \endverbatim
*
* </para><para>There is only one reason to use this macro when writing
* \a igraph functions. If the user installs an error handler which
* returns to the auxiliary calling code (like \ref
* igraph_error_handler_ignore and \ref
* igraph_error_handler_printignore), and the \a igraph function
* signalling the error is called from another \a igraph function
* then we need to make sure that the error is propagated back to
* the auxiliary (i.e. non-igraph) calling function. This is achieved
* by using <function>IGRAPH_CHECK</function> on every \a igraph
* call which can return an error code.
*/
#define IGRAPH_CHECK(expr) \
do { \
igraph_error_t igraph_i_ret = (expr); \
if (IGRAPH_UNLIKELY(igraph_i_ret != IGRAPH_SUCCESS)) {\
IGRAPH_ERROR("", igraph_i_ret); \
} \
} while (0)
#endif
/**
* \define IGRAPH_CHECK_CALLBACK
* \brief Checks the return value of a callback.
*
* Identical to \ref IGRAPH_CHECK, but treats \c IGRAPH_STOP as a normal
* (non-erroneous) return code. This macro is used in some igraph functions
* that allow the user to hook into a long-running calculation with a callback
* function. When the user-defined callback function returns \c IGRAPH_SUCCESS,
* the calculation will proceed normally. Returning \c IGRAPH_STOP from the
* callback will terminate the calculation without reporting an error. Returning
* any other value from the callback is treated as an error code, and igraph
* will trigger the necessary cleanup functions before exiting the function.
*
* </para><para>
* Note that \c IGRAPH_CHECK_CALLBACK does not handle \c IGRAPH_STOP by any
* means except returning it in the variable pointed to by \c code. It is the
* responsibility of the caller to handle \c IGRAPH_STOP accordingly.
*
* \param expr An expression, usually a call to a user-defined callback function.
* It is guaranteed to be evaluated only once.
* \param code Pointer to an optional variable of type <type>igraph_error_t</type>;
* the value of this variable will be set to the error code if it is not a null
* pointer.
*/
#define IGRAPH_CHECK_CALLBACK(expr, code) \
do { \
igraph_error_t igraph_i_ret = (expr); \
*(code) = igraph_i_ret; \
if (IGRAPH_UNLIKELY(igraph_i_ret != IGRAPH_SUCCESS && igraph_i_ret != IGRAPH_STOP)) { \
IGRAPH_ERROR("", igraph_i_ret); \
} \
} while (0)
/**
* \define IGRAPH_CHECK_OOM
* \brief Checks for out-of-memory conditions after a memory allocation.
*
* This function should be called on pointers after memory allocations. The
* function checks whether the returned pointer is NULL, and if so, sets an
* error message with the \c IGRAPH_ENOMEM error code.
*
* \param ptr The pointer to check.
* \param message The error message to use when the pointer is \c NULL.
*/
#define IGRAPH_CHECK_OOM(ptr, message) \
do { \
if (IGRAPH_UNLIKELY(!ptr)) { \
IGRAPH_ERROR(message, IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ \
} \
} while (0)
/**
* \section about_igraph_warnings Warning messages
*
* <para>
* \a igraph also supports warning messages in addition to error
* messages. Warning messages typically do not terminate the
* program, but they are usually crucial to the user.
* </para>
*
* <para>
* \a igraph warnings are handled similarly to errors. There is a
* separate warning handler function that is called whenever
* an \a igraph function triggers a warning. This handler can be
* set by the \ref igraph_set_warning_handler() function. There are
* two predefined simple warning handlers,
* \ref igraph_warning_handler_ignore() and
* \ref igraph_warning_handler_print(), the latter being the default.
* </para>
*
* <para>
* To trigger a warning, \a igraph functions typically use the
* \ref IGRAPH_WARNING() macro, the \ref igraph_warning() function,
* or if more flexibility is needed, \ref igraph_warningf().
* </para>
*/
/**
* \typedef igraph_warning_handler_t
* \brief The type of igraph warning handler functions.
*
* Currently it is defined to have the same type as
* \ref igraph_error_handler_t, although the last (error code)
* argument is not used.
*/
typedef void igraph_warning_handler_t(const char *reason,
const char *file, int line);
IGRAPH_EXPORT igraph_warning_handler_t *igraph_set_warning_handler(igraph_warning_handler_t* new_handler);
IGRAPH_EXPORT extern igraph_warning_handler_t igraph_warning_handler_ignore;
IGRAPH_EXPORT extern igraph_warning_handler_t igraph_warning_handler_print;
IGRAPH_EXPORT void igraph_warning(const char *reason,
const char *file, int line);
/**
* \define IGRAPH_WARNINGF
* \brief Triggers a warning, with printf-like syntax.
*
* \a igraph functions can use this macro when they notice a warning and
* want to pass on extra information to the user about what went wrong.
* It calls \ref igraph_warningf() with the proper parameters and no
* error code.
* \param reason Textual description of the warning, a template string
* with the same syntax as the standard printf C library function.
* \param ... The additional arguments to be substituted into the
* template string.
*/
#define IGRAPH_WARNINGF(reason, ...) \
do { \
igraph_warningf(reason, IGRAPH_FILE_BASENAME, __LINE__, \
__VA_ARGS__); \
} while (0)
IGRAPH_FUNCATTR_PRINTFLIKE(1,4)
IGRAPH_EXPORT void igraph_warningf(const char *reason,
const char *file, int line, ...);
/**
* \define IGRAPH_WARNING
* \brief Triggers a warning.
*
* This is the usual way of triggering a warning from an igraph
* function. It calls \ref igraph_warning().
* \param reason The warning message.
*/
#define IGRAPH_WARNING(reason) \
do { \
igraph_warning(reason, IGRAPH_FILE_BASENAME, __LINE__); \
} while (0)
/**
* \section fatal_error_handlers Fatal errors
*
* <para>
* In some rare situations, \a igraph may encounter an internal error
* that cannot be fully handled. In this case, it will call the
* current fatal error handler. The default fatal error handler
* simply prints the error and aborts the program.
* </para>
*
* <para>
* Fatal error handlers do not return. Typically, they might abort the
* the program immediately, or in the case of the high-level \a igraph
* interfaces, they might return to the top level using a
* <code>longjmp()</code>. The fatal error handler is only called when
* a serious error has occurred, and as a result igraph may be in an
* inconsistent state. The purpose of returning to the top level is to
* give the user a chance to save their work instead of aborting immediately.
* However, the program session should be restarted as soon as possible.
* </para>
*
* <para>
* Most projects that use \a igraph will use the default fatal error
* handler.
* </para>
*/
/**
* \typedef igraph_fatal_handler_t
* \brief The type of igraph fatal error handler functions.
*
* Functions of this type \em must not return. Typically they
* call <code>abort()</code> or do a <code>longjmp()</code>.
*
* \param reason Textual description of the error.
* \param file The source file in which the error is noticed.
* \param line The number of the line in the source file which triggered the error.
*/
typedef void igraph_fatal_handler_t(const char *reason, const char *file, int line);
IGRAPH_EXPORT igraph_fatal_handler_t *igraph_set_fatal_handler(igraph_fatal_handler_t *new_handler);
/**
* \var igraph_fatal_handler_abort
* \brief Abort program in case of fatal error.
*
* The default fatal error handler, prints an error message and aborts the program.
*/
IGRAPH_EXPORT IGRAPH_FUNCATTR_NORETURN igraph_fatal_handler_t igraph_fatal_handler_abort;
IGRAPH_EXPORT IGRAPH_FUNCATTR_NORETURN void igraph_fatal(const char *reason,
const char *file, int line);
IGRAPH_FUNCATTR_PRINTFLIKE(1,4)
IGRAPH_EXPORT IGRAPH_FUNCATTR_NORETURN void igraph_fatalf(const char *reason,
const char *file, int line, ...);
/**
* \define IGRAPH_FATALF
* \brief Triggers a fatal error, with printf-like syntax.
*
* \a igraph functions can use this macro when a fatal error occurs and
* want to pass on extra information to the user about what went wrong.
* It calls \ref igraph_fatalf() with the proper parameters.
*
* \param reason Textual description of the error, a template string
* with the same syntax as the standard printf C library function.
* \param ... The additional arguments to be substituted into the
* template string.
*/
#define IGRAPH_FATALF(reason, ...) \
do { \
igraph_fatalf(reason, IGRAPH_FILE_BASENAME, __LINE__, \
__VA_ARGS__); \
} while (0)
/**
* \define IGRAPH_FATAL
* \brief Triggers a fatal error.
*
* This is the usual way of triggering a fatal error from an igraph
* function. It calls \ref igraph_fatal().
*
* </para><para>
* Use this macro only in situations where the error cannot be handled.
* The normal way to handle errors is \ref IGRAPH_ERROR().
*
* \param reason The error message.
*/
#define IGRAPH_FATAL(reason) \
do { \
igraph_fatal(reason, IGRAPH_FILE_BASENAME, __LINE__); \
} while (0)
/**
* \define IGRAPH_ASSERT
* \brief igraph-specific replacement for <code>assert()</code>.
*
* This macro is like the standard <code>assert()</code>, but instead of
* calling <code>abort()</code>, it calls \ref igraph_fatal(). This allows for returning
* the control to the calling program, e.g. returning to the top level in a high-level
* \a igraph interface.
*
* </para><para>
* Unlike <code>assert()</code>, <code>IGRAPH_ASSERT()</code> is not disabled
* when the \c NDEBUG macro is defined.
*
* </para><para>
* This macro is meant for internal use by \a igraph.
*
* </para><para>
* Since a typical fatal error handler does a <code>longjmp()</code>, avoid using this
* macro in C++ code. With most compilers, destructor will not be called when
* <code>longjmp()</code> leaves the current scope.
*
* \param condition The condition to be checked.
*/
#define IGRAPH_ASSERT(condition) \
do { \
if (IGRAPH_UNLIKELY(!(condition))) { \
igraph_fatal("Assertion failed: " #condition, IGRAPH_FILE_BASENAME, __LINE__); \
} \
} while (0)
IGRAPH_END_C_DECLS
#endif
|