Skip to content

Commit

Permalink
CPLErrorStateBackuper: restore error count, and allow specifying the …
Browse files Browse the repository at this point in the history
…error handler as CPLQuietErrorHandler is used > 95% of time combined with it
  • Loading branch information
rouault committed Apr 6, 2024
1 parent f3432cf commit be71b41
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 29 deletions.
55 changes: 44 additions & 11 deletions port/cpl_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,17 +845,8 @@ void CPL_STDCALL CPLErrorReset()
* CPLErrorSetState()
**********************************************************************/

/**
* Restore an error state, without emitting an error.
*
* Can be useful if a routine might call CPLErrorReset() and one wants to
* preserve the previous error state.
*
* @since GDAL 2.0
*/

void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
const char *pszMsg)
static void CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
const char *pszMsg, GUInt32 *pnErrorCounter)
{
CPLErrorContext *psCtx = CPLGetErrorContext();
if (psCtx == nullptr)
Expand Down Expand Up @@ -891,6 +882,23 @@ void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
memcpy(pszLastErrMsg, pszMsg, size);
pszLastErrMsg[size] = '\0';
psCtx->eLastErrType = eErrClass;
if (pnErrorCounter)
psCtx->nErrorCounter = *pnErrorCounter;
}

/**
* Restore an error state, without emitting an error.
*
* Can be useful if a routine might call CPLErrorReset() and one wants to
* preserve the previous error state.
*
* @since GDAL 2.0
*/

void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
const char *pszMsg)
{
CPLErrorSetState(eErrClass, err_no, pszMsg, nullptr);
}

/**********************************************************************
Expand Down Expand Up @@ -1563,3 +1571,28 @@ void CPLUninstallErrorHandlerAccumulator()
{
CPLPopErrorHandler();
}

/************************************************************************/
/* CPLErrorStateBackuper::CPLErrorStateBackuper() */
/************************************************************************/

CPLErrorStateBackuper::CPLErrorStateBackuper(CPLErrorHandler hHandler)
: m_nLastErrorNum(CPLGetLastErrorNo()),
m_nLastErrorType(CPLGetLastErrorType()),
m_osLastErrorMsg(CPLGetLastErrorMsg()),
m_nLastErrorCounter(CPLGetErrorCounter()),
m_poErrorHandlerPusher(
hHandler ? std::make_unique<CPLErrorHandlerPusher>(hHandler)
: nullptr)
{
}

/************************************************************************/
/* CPLErrorStateBackuper::~CPLErrorStateBackuper() */
/************************************************************************/

CPLErrorStateBackuper::~CPLErrorStateBackuper()
{
CPLErrorSetState(m_nLastErrorType, m_nLastErrorNum,
m_osLastErrorMsg.c_str(), &m_nLastErrorCounter);
}
53 changes: 35 additions & 18 deletions port/cpl_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,13 @@ CPL_C_END
#define VALIDATE_POINTER_ERR CE_Failure
#endif

#if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS) && \
!defined(DOXYGEN_SKIP)
/*! @endcond */

#if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS)

extern "C++"
{
/*! @cond Doxygen_Suppress */
template <class T> T *CPLAssertNotNull(T *x) CPL_RETURNS_NONNULL;

template <class T> T *CPLAssertNotNull(T *x)
Expand All @@ -250,58 +252,73 @@ extern "C++"
return x;
}

#include <memory>
#include <string>

class CPLErrorHandlerPusher
/*! @endcond */

/** Class that installs a (thread-local) error handler on construction, and
* restore the initial one on destruction.
*/
class CPL_DLL CPLErrorHandlerPusher
{
public:
/** Constructor that installs a thread-local temporary error handler
* (typically CPLQuietErrorHandler)
*/
explicit CPLErrorHandlerPusher(CPLErrorHandler hHandler)
{
CPLPushErrorHandler(hHandler);
}

/** Constructor that installs a thread-local temporary error handler,
* and its user data.
*/
CPLErrorHandlerPusher(CPLErrorHandler hHandler, void *user_data)
{
CPLPushErrorHandlerEx(hHandler, user_data);
}

/** Destructor that restores the initial error handler. */
~CPLErrorHandlerPusher()
{
CPLPopErrorHandler();
}
};

class CPLErrorStateBackuper
/** Class that saves the error state on construction, and
* restores it on destruction.
*/
class CPL_DLL CPLErrorStateBackuper
{
CPLErrorNum m_nLastErrorNum;
CPLErr m_nLastErrorType;
std::string m_osLastErrorMsg;
GUInt32 m_nLastErrorCounter;
std::unique_ptr<CPLErrorHandlerPusher> m_poErrorHandlerPusher;

public:
CPLErrorStateBackuper()
: m_nLastErrorNum(CPLGetLastErrorNo()),
m_nLastErrorType(CPLGetLastErrorType()),
m_osLastErrorMsg(CPLGetLastErrorMsg())
{
}

~CPLErrorStateBackuper()
{
CPLErrorSetState(m_nLastErrorType, m_nLastErrorNum,
m_osLastErrorMsg.c_str());
}
/** Constructor that backs up the error state, and optionally installs
* a thread-local temporary error handler (typically CPLQuietErrorHandler).
*/
CPLErrorStateBackuper(CPLErrorHandler hHandler = nullptr);

/** Destructor that restores the error state to its initial state
* before construction.
*/
~CPLErrorStateBackuper();
};
}

#ifdef GDAL_COMPILATION
/*! @cond Doxygen_Suppress */
// internal only
bool CPLIsDefaultErrorHandlerAndCatchDebug();
/*! @endcond */
#endif

#endif

/*! @endcond */

/** Validate that a pointer is not NULL */
#define VALIDATE_POINTER0(ptr, func) \
do \
Expand Down

0 comments on commit be71b41

Please sign in to comment.