Files
pvData/pvDataApp/misc/epicsException.h
Michael Davidsaver 3cd2bfdef0 shared_vector implementation
Shared ownership of a single C array.

Tracks offset and length for each instance
allowing each owner to "view" a different
piece of the array.

Parts of shared_vector<T> which can work
for T=void are in shared_vector_base<T>.
Specializations shared_vector<void>
and shared_vector<const void> handle
un-typed arrays.

Allow casting to/from typed vector

Offsets and sizes of untyped vectors are tracked in
bytes.  Therefore casting to types where sizeof(T)>1
is undefined if the offset is not a multiple of
sizeof(T).
2013-05-08 18:21:34 -04:00

220 lines
5.8 KiB
C++

/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvData is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/*
* epicsException.hpp
*
* Created on: Oct 20, 2010
* Author: Matej Sekoranja
*/
/*
* Throwing exceptions w/ file+line# and, when possibly, a stack trace
*
* THROW_EXCEPTION1( std::bad_alloc );
*
* THROW_EXCEPTION2( std::logic_error, "my message" );
*
* THROW_EXCEPTION( mySpecialException("my message", 42, "hello", ...) );
*
* Catching exceptions
*
* catch(std::logic_error& e) {
* fprintf(stderr, "%s happened\n", e.what());
* PRINT_EXCEPTION2(e, stderr);
* cout<<SHOW_EXCEPTION(e);
* }
*
* If the exception was not thrown with the above THROW_EXCEPTION*
* the nothing will be printed.
*/
#ifndef EPICSEXCEPTION_H_
#define EPICSEXCEPTION_H_
#include <stdexcept>
#include <string>
#include <cstdio>
#include <stdio.h>
#include <stdlib.h>
// Users may redefine this for a large size if desired
#ifndef EXCEPT_DEPTH
# define EXCEPT_DEPTH 20
#endif
#if defined(__GLIBC__) || (defined(__APPLE__) && defined(__MACH__)) /* and possibly some BSDs */
# include <execinfo.h>
# include <cxxabi.h>
# define EXCEPT_USE_BACKTRACE
#elif defined(_WIN32) && !defined(__MINGW__) && !defined(SKIP_DBGHELP)
# define _WINSOCKAPI_
# include <windows.h>
# include <dbghelp.h>
# define EXCEPT_USE_CAPTURE
#else
# define EXCEPT_USE_NONE
#endif
namespace epics { namespace pvData {
/* Stores file and line number given, and when possible the call stack
* at the point where it was constructed
*/
class ExceptionMixin {
const char *m_file;
int m_line;
#ifndef EXCEPT_USE_NONE
void *m_stack[EXCEPT_DEPTH];
int m_depth; // always <= EXCEPT_DEPTH
#endif
public:
// allow the ctor to be inlined if possible
ExceptionMixin(const char* file, int line)
:m_file(file)
,m_line(line)
#if defined(EXCEPT_USE_BACKTRACE)
{
m_depth=backtrace(m_stack,EXCEPT_DEPTH);
}
#elif defined(EXCEPT_USE_CAPTURE)
{
m_depth=CaptureStackBackTrace(0,EXCEPT_DEPTH,m_stack,0);
}
#else
{}
#endif
void print(FILE *fp=stderr) const;
std::string show() const;
};
#ifndef THROW_EXCEPTION_COMPAT
namespace detail {
/* Combines user exception type with Mixin
*
* Takes advantage of the requirement that all exception classes
* must be copy constructable. Of course this also requires
* that an extra copy be constructed...
*/
template<typename E>
class ExceptionMixed : public E, public ExceptionMixin {
public:
// construct from copy of E
ExceptionMixed(const E& self,const char* file, int line)
:E(self), ExceptionMixin(file,line)
{}
// construct for E w/o arguments
ExceptionMixed(const char* file, int line)
:E(), ExceptionMixin(file,line)
{}
// construct for E one argument
template<typename A1>
ExceptionMixed(A1 arg1,const char* file, int line)
:E(arg1), ExceptionMixin(file,line)
{}
// construct for E two arguments
template<typename A1, typename A2>
ExceptionMixed(A1 arg1, A2 arg2,const char* file, int line)
:E(arg1,arg2), ExceptionMixin(file,line)
{}
};
// function template to deduce E from argument
template<typename E>
static inline
ExceptionMixed<E>
makeException(const E& self,const char* file, int line)
{
return ExceptionMixed<E>(self,file,line);
}
template<typename E>
static inline
std::string
showException(const E& ex)
{
const ExceptionMixin *mx=dynamic_cast<const ExceptionMixin*>(&ex);
if(!mx) return std::string();
return mx->show();
}
}
// Throw an exception of a mixed sub-class of the type of E
// The instance E is copied and discarded
#define THROW_EXCEPTION(E) \
do { \
throw ::epics::pvData::detail::makeException(E, __FILE__, __LINE__); \
} while(0)
// Throw an exception of a mixed sub-class of E, passing MSG as an argument
#define THROW_EXCEPTION1(TYPE) \
do { \
throw ::epics::pvData::detail::ExceptionMixed<TYPE>(__FILE__, __LINE__); \
}while(0)
// Throw an exception of a mixed sub-class of E, passing MSG as an argument
#define THROW_EXCEPTION2(TYPE,MSG) \
do { \
throw ::epics::pvData::detail::ExceptionMixed<TYPE>(MSG, __FILE__, __LINE__); \
}while(0)
#define PRINT_EXCEPTION2(EI, FP) \
do { \
ExceptionMixin *_em_p=dynamic_cast<ExceptionMixin*>(&EI); \
if (_em_p) {_em_p->print(FP);} \
}while(0)
#define PRINT_EXCEPTION(EI) PRINT_EXCEPTION2(EI,stderr)
#ifndef __GNUC__
# define SHOW_EXCEPTION(EI) ::epics::pvData::detail::showException(EI)
#else
# define SHOW_EXCEPTION(EI) \
({ ExceptionMixin *_mx=dynamic_cast<ExceptionMixin*>(&(EI)); \
_mx ? _mx->show() : std::string(); \
})
#endif
#else // THROW_EXCEPTION_COMPAT
/* For older compilers which have a problem with the above */
#define PRINT_EXCEPTION(EI) do{}while(0)
#define PRINT_EXCEPTION2(EI,FP) do{}while(0)
#define SHOW_EXCEPTION(EI) std::string()
#define THROW_EXCEPTION(E) do{throw (E);}while(0)
#define THROW_EXCEPTION1(E) do{throw (E)();}while(0)
#define THROW_EXCEPTION2(E,A) do{throw (E)(A);}while(0)
#endif // THROW_EXCEPTION_COMPAT
class BaseException : public std::logic_error {
public:
explicit BaseException(const std::string msg) : std::logic_error(msg) {}
virtual ~BaseException() throw(){};
virtual const char* what() const throw();
private:
mutable std::string base_msg;
};
#define THROW_BASE_EXCEPTION(msg) THROW_EXCEPTION2(::epics::pvData::BaseException, msg)
#define THROW_BASE_EXCEPTION_CAUSE(msg, cause) THROW_EXCEPTION2(::epics::pvData::BaseException, msg)
}
}
#endif /* EPICSEXCEPTION_H_ */