933 lines
36 KiB
C
933 lines
36 KiB
C
/*
|
|
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
|