// -*- C++ -*-
// Exception.h: Exceptions used by Asap
//
// Copyright (C) 2001-2011 Jakob Schiotz and Center for Individual
// Nanoparticle Functionality, Department of Physics, Technical
// University of Denmark. Email: schiotz@fysik.dtu.dk
//
// This file is part of Asap version 3.
// Asap is released under the GNU Lesser Public License (LGPL) version 3.
// However, the parts of Asap distributed within the OpenKIM project
// (including this file) are also released under the Common Development
// and Distribution License (CDDL) version 1.0.
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// version 3 as published by the Free Software Foundation. Permission
// to use other versions of the GNU Lesser General Public License may
// granted by Jakob Schiotz or the head of department of the
// Department of Physics, Technical University of Denmark, as
// described in section 14 of the GNU General Public License.
//
// 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
// and the GNU Lesser Public License along with this program. If not,
// see .
// DESIGN NOTE:
// ============
//
// Error conditions in Asap are usually handled by throwing an AsapError
// exception. This exception is caught by the Python Interface methods,
// and converted to a Python exception. If errors are generated by Python
// in Python calls from Asap, the Python error condition is left in place,
// and the C++ code throws an AsapPythonError. This error is also caught
// by the Python Interface methods, but in this case the preexisting Python
// error condition is left unchanged, and the error condition is reported
// back to Python. This results in slightly strange tracebacks, as the
// path through the C++ code will be missing. A subclass of AsapPythonError
// is AsapNotImplementedError, which is thrown without a corresponding
// Python error, and converted into Python's NotImplementedError. Finally,
// assert statements can be changed to emit an AssertionFailed error that is
// also turned into a Python AssertionFailed error. This latter behaviour
// is normally disabled, and is totally incompatible with OpenMP.
//
// OpenMP note: OpenMP place so severe restrictions on throwing exceptions
// inside parallel sections that exceptions become almost useless, even if
// parallelism is disabled at runtime. Asap handles this by replacing the
// throw statement with a THROW() macro inside OpenMP enabled regions. If
// compiled without OpenMP support, this macro just expands to the throw
// statement. If OpenMP is enabled, it instead expands to a helper function
// that just stores the exception in a global variable. Subsequent function
// calls are then supposed to return immediately (thanks to the
// RETURNIFASAPERROR macro in the beginning of the functions) until control
// leaves the parallel section, and the exception is thrown by the
// PROPAGATEASAPERROR macro. These latter macros are empty if OpenMP is
// not enabled at compile time.
#ifndef _EXCEPTION_H
#define _EXCEPTION_H
#include "Asap.h"
#include
#include
#ifndef ASAPASSERT
#include
#endif // ASAPASSERT
using std::stringstream;
using std::string;
namespace ASAPSPACE {
// this AsapError class can be used as follows:
//
// throw AsapError("Error");
//
// throw AsapError("Error ") << n + 7 << " while opening file: " << filename;
class ASAP_PUBLIC AsapErrorBase
{
public:
virtual ~AsapErrorBase() {};
};
class ASAP_PUBLIC AsapError : public AsapErrorBase
{
public:
AsapError(const char *m);
AsapError(const AsapError& ex);
virtual ~AsapError();
template AsapError& operator<<(const T& x)
{
message << x;
return *this;
}
string GetMessage() const;
private:
stringstream message;
};
/// An exception for indicating that a Python error has occurred and
/// should be propagated.
class ASAP_PUBLIC AsapPythonError : public AsapErrorBase
{
public:
AsapPythonError() {};
};
/// An exception mapping to a Python NotImplementedError
class ASAP_PUBLIC AsapNotImplementedError : public AsapPythonError
{
public:
AsapNotImplementedError(const char *m);
};
class ASAP_PUBLIC AssertionFailed : public AsapErrorBase
{
public:
AssertionFailed(const char *expression, const char *file, int line,
const char *func = NULL);
AssertionFailed(const AssertionFailed& ex);
~AssertionFailed();
string GetMessage() const;
private:
stringstream message;
};
/// A helper define
#define NOTHREADSERROR throw AsapError("Threads not supported. ") << __FILE__ << ":" << __LINE__
/// Defining our own assert macro that throws an exception
#ifdef ASAPASSERT
#undef assert
#ifdef __GNUC__
#define assert(EX) if (!(EX)) \
throw AssertionFailed(#EX, __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else // __GNUC__
#define assert(EX) if (!(EX)) \
throw AssertionFailed(#EX, __FILE__, __LINE__, __func__)
#endif // __GNUC__
#endif // ASAPASSERT
// Define macros and helper functions for throwing exceptions within OpenMP constructs.
#ifdef _OPENMP
extern AsapErrorBase *AsapGlobalException;
void AsapThrowHelper(const AsapError &err);
void AsapThrowHelper(const AsapPythonError &err);
#define THROW(x) AsapThrowHelper(x)
#define THROW_RETURN(x) {AsapThrowHelper(x); return;}
#define CHECKNOASAPERROR assert(AsapGlobalException == NULL)
#define RETURNIFASAPERROR if (AsapGlobalException != NULL) return
#define RETURNIFASAPERROR2(x) if (AsapGlobalException != NULL) return (x)
#define PROPAGATEASAPERROR if (AsapGlobalException != NULL) { \
AsapError *err = dynamic_cast(AsapGlobalException); \
AsapPythonError *perr = dynamic_cast(AsapGlobalException); \
AsapGlobalException = NULL; \
std::cerr << "Propagating ASAP error [" << __FILE__ << ":" << __LINE__ << "] ..." << std::endl; \
if (err != NULL) throw *err; \
if (perr != NULL) throw *perr; \
throw AsapError("Error throwing exception."); }
#else // _OPENMP
#define THROW(x) throw x
#define THROW_RETURN(x) throw x
#define CHECKNOASAPERROR
#define RETURNIFASAPERROR
#define RETURNIFASAPERROR2(x)
#define PROPAGATEASAPERROR
#endif // _OPENMP
} // end namespace
#endif // _EXCEPTION_H