QP is an event-driven, RTOS-like, active object framework for microcontrollers, such as mbed. The QP framework provides thread-safe execution of active objects (concurrent state machines) and support both manual and automatic coding of UML statecharts in readable, production-quality C or C++. Automatic code generation of QP code is supported by the free QM modeling tool.
Dependents: qp_hangman qp_dpp qp_blinky
QP/C++ (Quantum Platform in C++) is a lightweight, open source active object (actor) framework for building responsive and modular real-time embedded applications as systems of asynchronous event-driven active objects (actors). The QP/C++ framework is a member of a larger family consisting of QP/C++, QP/C, and QP-nano frameworks, which are all strictly quality controlled, thoroughly documented, and available under GPLv3 with a special Exception for mbed (see http://www.state-machine.com/licensing/QP-mbed_GPL_Exception.txt).
The behavior of active objects is specified in QP/C++ by means of hierarchical state machines (UML statecharts). The framework supports manual coding of UML state machines in C++ as well as automatic code generation by means of the free QM modeling tool (http://www.state-machine.com/qm).
Please see the "QP/C++ Reference Manual" (http://www.state-machine.com/qpcpp) for more information.
Diff: qp.h
- Revision:
- 6:01d57c81e96a
- Parent:
- 5:949864ba515c
- Child:
- 7:bf92d3a6625e
--- a/qp.h Sun Sep 25 18:10:41 2011 +0000 +++ b/qp.h Mon Sep 26 01:42:32 2011 +0000 @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // Product: QP/C++ -// Last Updated for QP ver: 4.1.06 (modified to fit in one file) -// Date of the Last Update: Jan 26, 2011 +// Last Updated for QP ver: 4.2.04 (modified to fit in one file) +// Date of the Last Update: Sep 25, 2011 // // Q u a n t u m L e a P s // --------------------------- @@ -28,6 +28,10 @@ #ifndef qp_h #define qp_h +#ifdef Q_USE_NAMESPACE +namespace QP { +#endif + // "qevent.h" ================================================================ /// \brief QEvent class and basic macros used by all QP components. /// @@ -40,7 +44,7 @@ /// \return version of the QP as a hex constant constant 0xXYZZ, where X is /// a 1-digit major version number, Y is a 1-digit minor version number, and /// ZZ is a 2-digit release number. -#define QP_VERSION 0x4106 +#define QP_VERSION 0x4204U #ifndef Q_ROM /// \brief Macro to specify compiler-specific directive for placing a @@ -97,9 +101,11 @@ /// This macro can be defined in the QEP port file (qep_port.h) to /// configure the ::QSignal type. When the macro is not defined, the /// default of 1 byte is chosen. - #define Q_SIGNAL_SIZE 1 + #define Q_SIGNAL_SIZE 2 #endif #if (Q_SIGNAL_SIZE == 1) + typedef uint8_t QSignal; +#elif (Q_SIGNAL_SIZE == 2) /// \brief QSignal represents the signal of an event. /// /// The relationship between an event and a signal is as follows. A signal @@ -109,12 +115,6 @@ /// event. (The signal conveys the type of the occurrence-what happened?) /// However, an event can also contain additional quantitative information /// about the occurrence in form of event parameters. Please refer to the - /// document - /// <A HREF="http://www.quantum-leaps.com/devzone/Recipe_IntroHSM.pdf"> - /// Brief Introduction to UML State Machines</A>) for more information - /// about state machine concepts. - typedef uint8_t QSignal; -#elif (Q_SIGNAL_SIZE == 2) typedef uint16_t QSignal; #elif (Q_SIGNAL_SIZE == 4) typedef uint32_t QSignal; @@ -137,7 +137,13 @@ /// \include qep_qevent.cpp struct QEvent { QSignal sig; ///< signal of the event instance - uint8_t dynamic_; ///< attributes of a dynamic event (0 for static event) + uint8_t poolId_; ///< pool ID (0 for static event) + uint8_t refCtr_; ///< reference counter + +#ifdef Q_EVT_CTOR + QEvent(QSignal s) : sig(s) {} + virtual ~QEvent() {} // virtual destructor +#endif }; ////////////////////////////////////////////////////////////////////////////// @@ -1179,6 +1185,11 @@ #error "QF_EVENT_SIZ_SIZE defined incorrectly, expected 1, 2, or 4" #endif +////////////////////////////////////////////////////////////////////////////// +#ifndef QF_MAX_EPOOL + /// \brief Default value of the macro configurable value in qf_port.h + #define QF_MAX_EPOOL 3 +#endif ////////////////////////////////////////////////////////////////////////////// #ifndef QF_ACTIVE_SUPER_ @@ -1306,7 +1317,7 @@ /// \include qf_start.cpp void start(uint8_t prio, QEvent const *qSto[], uint32_t qLen, - void *stkSto = (void *)0, uint32_t stkSize = 0, + void *stkSto, uint32_t stkSize, QEvent const *ie = (QEvent *)0); /// \brief Posts an event \a e directly to the event queue of the acitve @@ -1327,13 +1338,18 @@ /// queues, direct event dispatching is synchronous. Direct event /// dispatching occurs when you call QHsm::dispatch(), or QFsm::dispatch() /// function. +#ifndef Q_SPY void postFIFO(QEvent const *e); +#else + void postFIFO(QEvent const *e, void const *sender); +#endif /// \brief Posts an event directly to the event queue of the active object /// \a me using the Last-In-First-Out (LIFO) policy. /// - /// \note The LIFO policy should be used only with great caution because - /// it alters order of events in the queue. + /// \note The LIFO policy should be used only for self-posting and with + /// great caution because it alters order of events in the queue. + /// /// \sa QActive::postFIFO() void postLIFO(QEvent const *e); @@ -1451,14 +1467,14 @@ /// deferred event queue \a eq and posted (LIFO) to the event queue of /// the active object. /// - /// QActive::recall() returns the pointer to the recalled event to the - /// caller. The function returns NULL if no event has been recalled. + /// QActive::recall() returns 1 (TRUE) if an event has been recalled. + /// Otherwise the function returns 0. /// /// An active object can use multiple event queues to defer events of /// different kinds. /// /// \sa QActive::defer(), QEQueue, QActive::postLIFO() - QEvent const *recall(QEQueue *eq); + uint8_t recall(QEQueue *eq); public: /// \brief Un-subscribes from the delivery of all signals to the active @@ -1667,21 +1683,14 @@ /// expected in the active object's state machine. uint8_t rearm(QTimeEvtCtr nTicks); - // for backwards compatibility - - /// \brief Arm a one-shot time event for direct event posting (obsolete). + /// \brief Get the current value of the down-counter of a time event. /// - /// This facility is now obsolete, please use \sa QTimeEvt::postIn(). - void fireIn(QActive *act, QTimeEvtCtr nTicks) { - postIn(act, nTicks); - } - - /// \brief Arm a periodic time event for direct event posting (obsolete). + /// If the time event is armed, the function returns the current value of + /// the down-counter of the given time event. If the time event is not + /// armed, the function returns 0. /// - /// This facility is now obsolete, please use \sa QTimeEvt::postEvery(). - void fireEvery(QActive *act, QTimeEvtCtr nTicks) { - postEvery(act, nTicks); - } + /// /note The function is thread-safe. + QTimeEvtCtr ctr(void); private: @@ -1905,7 +1914,11 @@ /// event to multiple subscribers. This happens in the caller's thread /// with the scheduler locked to prevent preemptions during the multi- /// casting process. (Please note that the interrupts are not locked.) +#ifndef Q_SPY static void publish(QEvent const *e); +#else + static void publish(QEvent const *e, void const *sender); +#endif /// \brief Processes all armed time events at every clock tick. /// @@ -1921,7 +1934,11 @@ /// /// The following example illustrates the call to QF::tick(): /// \include qf_tick.cpp +#ifndef Q_SPY static void tick(void); +#else + static void tick(void const *sender); +#endif /// \brief Returns the QF version. /// @@ -1977,6 +1994,10 @@ /// Please use the macro #Q_NEW. static QEvent *new_(uint16_t evtSize, QSignal sig); +#ifdef Q_EVT_CTOR + #define Q_NEW(evtT_, sig_, ...) \ + (new(QF::new_(sizeof(evtT_), sig_)) evtT_((sig_), ##__VA_ARGS__)) +#else /// \brief Allocate a dynamic event. /// /// This macro returns an event pointer cast to the type \a evtT_. The @@ -1991,6 +2012,7 @@ /// The following example illustrates dynamic allocation of an event: /// \include qf_post.cpp #define Q_NEW(evtT_, sig_) ((evtT_ *)QF::new_(sizeof(evtT_), (sig_))) +#endif /// \brief Recycle a dynamic event. /// @@ -2086,6 +2108,157 @@ extern uint8_t const Q_ROM Q_ROM_VAR QF_div8Lkup[65]; ////////////////////////////////////////////////////////////////////////////// +#ifdef Q_EVT_CTOR +#include <new> // for placement new +#endif + +// from qf.h ----------------------------------------------------------------- +////////////////////////////////////////////////////////////////////////////// +// QS software tracing integration, only if enabled +#ifdef Q_SPY // QS software tracing enabled? + #define QS_TIME_SIZE 4 + #define QS_OBJ_PTR_SIZE 4 + #define QS_FUN_PTR_SIZE 4 + + /// \brief Invoke the system clock tick processing QF::tick(). This macro + /// is the recommended way of invoking clock tick processing, because it + /// provides the vital information for software tracing and avoids any + /// overhead when the tracing is disabled. + /// + /// This macro takes the argument \a sender_, which is a pointer to the + /// sender object. This argument is actually only used when QS software + /// tracing is enabled (macro #Q_SPY is defined). When QS software + /// tracing is disabled, the macro calls QF::tick() without any + /// arguments, so the overhead of passing this extra argument is + /// entirely avoided. + /// + /// \note the pointer to the sender object is not necessarily a poiner + /// to an active object. In fact, typically QF::TICK() will be called from + /// an interrupt, in which case you would create a unique object just to + /// unambiguously identify the ISR as the sender of the time events. + /// + /// \sa QF::tick() + #define TICK(sender_) tick(sender_) + + /// \brief Invoke the event publishing facility QF::publish(). This macro + /// is the recommended way of publishing events, because it provides the + /// vital information for software tracing and avoids any overhead when the + /// tracing is disabled. + /// + /// + /// This macro takes the last argument \a sender_, which is a pointer to + /// the sender object. This argument is actually only used when QS software + /// tracing is enabled (macro #Q_SPY is defined). When QS software + /// tracing is disabled, the macro calls QF::publish() without the + /// \a sender_ argument, so the overhead of passing this extra argument + /// is entirely avoided. + /// + /// \note the pointer to the sender object is not necessarily a poiner + /// to an active object. In fact, if QF::PUBLISH() is called from an + /// interrupt or other context, you can create a unique object just to + /// unambiguously identify the publisher of the event. + /// + /// \sa QF::publish() + #define PUBLISH(e_, sender_) publish((e_), (sender_)) + + /// \brief Invoke the direct event posting facility QActive::postFIFO(). + /// This macro is the recommended way of posting events, because it provides + /// the vital information for software tracing and avoids any overhead when + /// the tracing is disabled. + /// + /// + /// This macro takes the last argument \a sender_, which is a pointer to + /// the sender object. This argument is actually only used when QS software + /// tracing is disabled (macro #Q_SPY is defined). When QS software + /// tracing is not enabled, the macro calls QF_publish() without the + /// \a sender_ argument, so the overhead of passing this extra argument + /// is entirely avoided. + /// + /// \note the pointer to the sender object is not necessarily a poiner + /// to an active object. In fact, if ao->POST() is called from an + /// interrupt or other context, you can create a unique object just to + /// unambiguously identify the publisher of the event. + /// + /// \sa QActive::postFIFO() + #define POST(e_, sender_) postFIFO((e_), (sender_)) + + #if (QF_EQUEUE_CTR_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted event queue + /// counter data element + /// \note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE. + #define QS_EQC_(ctr_) QS::u8_(ctr_) + #elif (QF_EQUEUE_CTR_SIZE == 2) + #define QS_EQC_(ctr_) QS::u16_(ctr_) + #elif (QF_EQUEUE_CTR_SIZE == 4) + #define QS_EQC_(ctr_) QS::u32_(ctr_) + #else + #error "QF_EQUEUE_CTR_SIZE not defined" + #endif + + + #if (QF_EVENT_SIZ_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted event size + /// data element + /// \note the event size depends on the macro #QF_EVENT_SIZ_SIZE. + #define QS_EVS_(size_) QS::u8_(size_) + #elif (QF_EVENT_SIZ_SIZE == 2) + #define QS_EVS_(size_) QS::u16_(size_) + #elif (QF_EVENT_SIZ_SIZE == 4) + #define QS_EVS_(size_) QS::u32_(size_) + #endif + + + #if (QF_MPOOL_SIZ_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted memory pool + /// block-size data element + /// \note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE. + #define QS_MPS_(size_) QS::u8_(size_) + #elif (QF_MPOOL_SIZ_SIZE == 2) + #define QS_MPS_(size_) QS::u16_(size_) + #elif (QF_MPOOL_SIZ_SIZE == 4) + #define QS_MPS_(size_) QS::u32_(size_) + #endif + + #if (QF_MPOOL_CTR_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted memory pool + /// block-counter data element + /// \note the counter size depends on the macro #QF_MPOOL_CTR_SIZE. + #define QS_MPC_(ctr_) QS::u8_(ctr_) + #elif (QF_MPOOL_CTR_SIZE == 2) + #define QS_MPC_(ctr_) QS::u16_(ctr_) + #elif (QF_MPOOL_CTR_SIZE == 4) + #define QS_MPC_(ctr_) QS::u32_(ctr_) + #endif + + + #if (QF_TIMEEVT_CTR_SIZE == 1) + + /// \brief Internal QS macro to output an unformatted time event + /// tick-counter data element + /// \note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE. + #define QS_TEC_(ctr_) QS::u8_(ctr_) + #elif (QF_TIMEEVT_CTR_SIZE == 2) + #define QS_TEC_(ctr_) QS::u16_(ctr_) + #elif (QF_TIMEEVT_CTR_SIZE == 4) + #define QS_TEC_(ctr_) QS::u32_(ctr_) + #endif + +#else + #ifndef qs_dummy_h + #include "qs_dummy.h" // disable the QS software tracing + #endif + + #define TICK(dummy_) tick() + #define PUBLISH(e_, dummy_) publish((e_)) + #define POST(e_, dummy_) postFIFO((e_)) + +#endif // Q_SPY + +////////////////////////////////////////////////////////////////////////////// // QS software tracing #ifdef Q_SPY @@ -2140,7 +2313,7 @@ QS_QF_TIMEEVT_DISARM, ///< true disarming of an armed time event QS_QF_TIMEEVT_REARM, ///< rearming of a time event QS_QF_TIMEEVT_POST, ///< a time event posted itself directly to an AO - QS_QF_RESERVED7, + QS_QF_TIMEEVT_CTR, ///< a time event counter was requested QS_QF_INT_LOCK, ///< interrupts were locked QS_QF_INT_UNLOCK, ///< interrupts were unlocked QS_QF_ISR_ENTRY, ///< an ISR was entered @@ -2384,6 +2557,18 @@ /// client code directly. static void mem(uint8_t const *blk, uint8_t size); +#if (QS_OBJ_PTR_SIZE == 8) || (QS_FUN_PTR_SIZE == 8) + /// \brief Output uint64_t data element without format information + /// \note This function is only to be used through macros, never in the + /// client code directly. + static void u64_(uint64_t d); + + /// \brief Output uint64_t data element with format information + /// \note This function is only to be used through macros, never in the + /// client code directly. + static void u64(uint8_t format, uint64_t d); +#endif + // QS buffer access ...................................................... /// \brief Byte-oriented interface to the QS data buffer. @@ -2633,7 +2818,7 @@ /// to NULL. /// /// \sa Example of using QS filters in #QS_FILTER_ON documentation -#define QS_FILTER_AP_OBJ(obj_) (QS_apObj_ = (obj_)) +#define QS_FILTER_AP_OBJ(obj_) (QS::apObj_ = (obj_)) ////////////////////////////////////////////////////////////////////////////// @@ -2769,6 +2954,8 @@ #define QS_OBJ_(obj_) QS::u16_((uint16_t)(obj_)) #elif (QS_OBJ_PTR_SIZE == 4) #define QS_OBJ_(obj_) QS::u32_((uint32_t)(obj_)) +#elif (QS_OBJ_PTR_SIZE == 8) + #define QS_OBJ_(obj_) QS::u64_((uint64_t)(obj_)) #else /// \brief Internal QS macro to output an unformatted object pointer @@ -2785,6 +2972,8 @@ #define QS_FUN_(fun_) QS::u16_((uint16_t)(fun_)) #elif (QS_FUN_PTR_SIZE == 4) #define QS_FUN_(fun_) QS::u32_((uint32_t)(fun_)) +#elif (QS_FUN_PTR_SIZE == 8) + #define QS_FUN_(fun_) QS::u64_((uint64_t)(fun_)) #else /// \brief Internal QS macro to output an unformatted function pointer @@ -2822,7 +3011,10 @@ QS_MEM_T, ///< up to 255-bytes memory block format QS_SIG_T, ///< event signal format QS_OBJ_T, ///< object pointer format - QS_FUN_T ///< function pointer format + QS_FUN_T, ///< function pointer format + QS_I64_T, ///< signed 64-bit integer format + QS_U64_T, ///< unsigned 64-bit integer format + QS_U32_HEX_T ///< unsigned 32-bit integer in hex format }; /// \brief Output formatted int8_t to the QS record @@ -2857,6 +3049,18 @@ #define QS_F64(width_, data_) \ QS::f64((uint8_t)(((width_) << 4)) | QS_F64_T, (data_)) +/// \brief Output formatted int64_t to the QS record +#define QS_I64(width_, data_) \ + QS::u64((uint8_t)(((width_) << 4)) | QS_I64_T, (data_)) + +/// \brief Output formatted uint64_t to the QS record +#define QS_U64(width_, data_) \ + QS::u64((uint8_t)(((width_) << 4)) | QS_U64_T, (data_)) + +/// \brief Output formatted uint32_t to the QS record +#define QS_U32_HEX(width_, data_) \ + QS::u32((uint8_t)(((width_) << 4)) | QS_U32_HEX_T, (data_)) + /// \brief Output formatted zero-terminated ASCII string to the QS record #define QS_STR(str_) QS::str(str_) @@ -2875,6 +3079,8 @@ #define QS_OBJ(obj_) QS::u16(QS_OBJ_T, (uint16_t)(obj_)) #elif (QS_OBJ_PTR_SIZE == 4) #define QS_OBJ(obj_) QS::u32(QS_OBJ_T, (uint32_t)(obj_)) +#elif (QS_OBJ_PTR_SIZE == 8) + #define QS_OBJ(obj_) QS::u64(QS_OBJ_T, (uint64_t)(obj_)) #else /// \brief Output formatted object pointer to the QS record #define QS_OBJ(obj_) QS::u32(QS_OBJ_T, (uint32_t)(obj_)) @@ -2887,6 +3093,8 @@ #define QS_FUN(fun_) QS::u16(QS_FUN_T, (uint16_t)(fun_)) #elif (QS_FUN_PTR_SIZE == 4) #define QS_FUN(fun_) QS::u32(QS_FUN_T, (uint32_t)(fun_)) +#elif (QS_FUN_PTR_SIZE == 8) + #define QS_FUN(fun_) QS::u64(QS_FUN_T, (uint64_t)(fun_)) #else /// \brief Output formatted function pointer to the QS record #define QS_FUN(fun_) QS::u32(QS_FUN_T, (uint32_t)(fun_)) @@ -3159,7 +3367,9 @@ #define QS_U32(width_, data_) ((void)0) #define QS_F32(width_, data_) ((void)0) #define QS_F64(width_, data_) ((void)0) +#define QS_U64(width_, data_) ((void)0) #define QS_STR(str_) ((void)0) +#define QS_U32_HEX(width_, data_) ((void)0) #define QS_STR_ROM(str_) ((void)0) #define QS_MEM(mem_, size_) ((void)0) #define QS_SIG(sig_, obj_) ((void)0) @@ -3180,6 +3390,7 @@ #define QS_U8_(data_) ((void)0) #define QS_U16_(data_) ((void)0) #define QS_U32_(data_) ((void)0) +#define QS_U64_(data_) ((void)0) #define QS_TIME_() ((void)0) #define QS_SIG_(sig_) ((void)0) #define QS_EVS_(size_) ((void)0) @@ -3198,6 +3409,10 @@ #endif // Q_SPY +#ifdef Q_USE_NAMESPACE +} // namespace QP +#endif + ////////////////////////////////////////////////////////////////////////////// /** * \brief Customizable QP assertions. @@ -3207,19 +3422,23 @@ * programs. * * \note The preprocessor switch Q_NASSERT disables checking assertions. -* In particular macros \ref Q_ASSERT, \ref Q_REQUIRE, \ref Q_ENSURE, -* \ref Q_INVARIANT, and \ref Q_ERROR do NOT evaluate the test condition +* In particular macros #Q_ASSERT, #Q_REQUIRE, #Q_ENSURE, #Q_INVARIANT, +* #Q_ERROR as well as #Q_ASSERT_ID, #Q_REQUIRE_ID, #Q_ENSURE_ID, +* #Q_INVARIANT_ID, and #Q_ERROR_ID do NOT evaluate the test condition * passed as the argument to these macros. One notable exception is the -* macro \ref Q_ALLEGE, that still evaluates the test condition, but does +* macro #Q_ALLEGE, that still evaluates the test condition, but does * not report assertion failures when the switch Q_NASSERT is defined. */ #ifdef Q_NASSERT /* Q_NASSERT defined--assertion checking disabled */ #define Q_DEFINE_THIS_FILE #define Q_DEFINE_THIS_MODULE(name_) - #define Q_ASSERT(test_) ((void)0) - #define Q_ALLEGE(test_) ((void)(test_)) - #define Q_ERROR() ((void)0) + #define Q_ASSERT(test_) ((void)0) + #define Q_ASSERT_ID(id_, test_) ((void)0) + #define Q_ALLEGE(test_) ((void)(test_)) + #define Q_ALLEGE_ID(id_, test_) ((void)(test_)) + #define Q_ERROR() ((void)0) + #define Q_ERROR_ID(id_) ((void)0) #else /* Q_NASSERT not defined--assertion checking enabled */ @@ -3227,9 +3446,10 @@ extern "C" { #endif - /** callback invoked in case the condition passed to \ref Q_ASSERT, - * \ref Q_REQUIRE, \ref Q_ENSURE, \ref Q_ERROR, or \ref Q_ALLEGE - * evaluates to FALSE. + /** callback invoked in case the condition passed to #Q_ASSERT, + * #Q_REQUIRE, #Q_ENSURE, #Q_ERROR, #Q_ALLEGE as well as #Q_ASSERT_ID, + * #Q_REQUIRE_ID, #Q_ENSURE_ID, #Q_ERROR_ID, and #Q_ALLEGE_ID evaluates + * to FALSE. * * \param file file name where the assertion failed * \param line line number at which the assertion failed @@ -3258,50 +3478,116 @@ /** General purpose assertion that makes sure the \a test_ argument is * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates * to FALSE. - * \note the \a test_ is NOT evaluated if assertions are - * disabled with the Q_NASSERT switch. + * \note the \a test_ is NOT evaluated if assertions are disabled with + * the Q_NASSERT switch. + * \sa #Q_ASSERT_ID */ #define Q_ASSERT(test_) \ if (test_) { \ } \ - else (Q_onAssert(l_this_file, __LINE__)) + else (Q_onAssert(&l_this_file[0], __LINE__)) + + /** General purpose assertion that makes sure the \a test_ argument is + * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates + * to FALSE. The argument \a id_ is the ID number (unique within + * the file) of the assertion. This assertion style is better suited + * for unit testig, because it avoids the volatility of line numbers + * for indentifying assertions. + * \note the \a test_ is NOT evaluated if assertions are disabled with + * the Q_NASSERT switch. + * \sa #Q_ASSERT + */ + #define Q_ASSERT_ID(id_, test_) \ + if (test_) { \ + } \ + else (Q_onAssert(&l_this_file[0], (id_))) /** General purpose assertion that ALWAYS evaluates the \a test_ * argument and calls the Q_onAssert() callback if the \a test_ * evaluates to FALSE. - * \note the \a test_ argument IS always evaluated even when assertions are - * disabled with the Q_NASSERT macro. When the Q_NASSERT macro is + * \note the \a test_ argument IS always evaluated even when assertions + * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is * defined, the Q_onAssert() callback is NOT called, even if the * \a test_ evaluates to FALSE. + * \sa #Q_ALLEGE_ID */ #define Q_ALLEGE(test_) Q_ASSERT(test_) + /** General purpose assertion that ALWAYS evaluates the \a test_ + * argument and calls the Q_onAssert() callback if the \a test_ + * evaluates to FALSE. This assertion style is better suited + * for unit testig, because it avoids the volatility of line numbers + * for indentifying assertions. + * \note the \a test_ argument IS always evaluated even when assertions + * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is + * defined, the Q_onAssert() callback is NOT called, even if the + * \a test_ evaluates to FALSE. + * \sa #Q_ALLEGE + */ + #define Q_ALLEGE_ID(id_, test_) Q_ASSERT_ID(id_, test_) + /** Assertion that always calls the Q_onAssert() callback if * ever executed. * \note can be disabled with the Q_NASSERT switch. + * \sa #Q_ERROR_ID */ #define Q_ERROR() \ (Q_onAssert(l_this_file, __LINE__)) + /** Assertion that always calls the Q_onAssert() callback if + * ever executed. This assertion style is better suited for unit + * testig, because it avoids the volatility of line numbers for + * indentifying assertions. + * \note can be disabled with the Q_NASSERT switch. + * \sa #Q_ERROR + */ + #define Q_ERROR_ID(id_) \ + (Q_onAssert(l_this_file, (id_))) + + #endif /* Q_NASSERT */ /** Assertion that checks for a precondition. This macro is equivalent to -* \ref Q_ASSERT, except the name provides a better documentation of the +* #Q_ASSERT, except the name provides a better documentation of the * intention of this assertion. +* \sa #Q_REQUIRE_ID */ -#define Q_REQUIRE(test_) Q_ASSERT(test_) +#define Q_REQUIRE(test_) Q_ASSERT(test_) + +/** Assertion that checks for a precondition. This macro is equivalent to +* #Q_ASSERT_ID, except the name provides a better documentation of the +* intention of this assertion. +* \sa #Q_REQUIRE +*/ +#define Q_REQUIRE_ID(id_, test_) Q_ASSERT_ID(id_, test_) /** Assertion that checks for a postcondition. This macro is equivalent to -* \ref Q_ASSERT, except the name provides a better documentation of the +* #Q_ASSERT, except the name provides a better documentation of the * intention of this assertion. +* \sa #Q_ENSURE_ID */ -#define Q_ENSURE(test_) Q_ASSERT(test_) +#define Q_ENSURE(test_) Q_ASSERT(test_) + +/** Assertion that checks for a postcondition. This macro is equivalent to +* #Q_ASSERT_ID, except the name provides a better documentation of the +* intention of this assertion. +* \sa #Q_ENSURE +*/ +#define Q_ENSURE_ID(id_, test_) Q_ASSERT_ID(id_, test_) /** Assertion that checks for an invariant. This macro is equivalent to -* \ref Q_ASSERT, except the name provides a better documentation of the +* #Q_ASSERT, except the name provides a better documentation of the * intention of this assertion. +* \sa #Q_INVARIANT_ID */ -#define Q_INVARIANT(test_) Q_ASSERT(test_) +#define Q_INVARIANT(test_) Q_ASSERT(test_) + +/** Assertion that checks for an invariant. This macro is equivalent to +* #Q_ASSERT_ID, except the name provides a better documentation of the +* intention of this assertion. +* \sa #Q_INVARIANT +*/ +#define Q_INVARIANT_ID(id_, test_) Q_ASSERT_ID(id_, test_) /** Compile-time assertion exploits the fact that in C/C++ a dimension of * an array cannot be negative. The following declaration causes a compilation