Advertisement
justin_hanekom

dbc.h design-by-contract C/C++ header file

Feb 1st, 2025
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.27 KB | None | 0 0
  1. // File: dbc.h
  2. // SPDX-License-Identifier: Unlicensed
  3. //
  4. // This is free and unencumbered software released into the public domain.
  5.  
  6. /*!
  7.  * \file dbc.h
  8.  *
  9.  * \brief   This header file defines macros that implement the
  10.  *          Design By Contract (DBC) protocol.
  11.  *
  12.  * The macro functions \c DBC_REQUIRE, \c DBC_ENSURE, and \c DBC_INVARIANT
  13.  * are defined.
  14.  *
  15.  * If the macro \c DBC_ALL has been defined before this header file is
  16.  * included, or none of the macros \c DBC_DISABLE, \c DBC_ENABLE_REQUIRE,
  17.  * \c DBC_ENABLE_ENSURE, or \c DBC_ENABLE_INVARIANT have been defined then all
  18.  * of the DBC-check macro functions perform the specified checks and report
  19.  * error if appropriate.
  20.  *
  21.  * If only certain macro functions are required to perform their function then
  22.  * the required macro functions can be enabled by defining the appropriate
  23.  * \c DBC_ENABLE_REQUIRE, \c DBC_ENABLE_ENSURE, and/or DBC_ENABLE_INVARIANT
  24.  * macros before including the \c dbc.h header file.
  25.  *
  26.  * \version 1.0
  27.  * \date    2023
  28. */
  29.  
  30. #ifndef DBC_H_
  31. #define DBC_H_
  32.  
  33. #ifndef DBC_DISABLE
  34.  
  35. #include <stdio.h>      // for fprintf, stderr
  36. #include <stdbool.h>    // for _Bool, true, false
  37. #include <stdlib.h>     // for exit, EXIT_FAILURE
  38.  
  39. /*!
  40.  * \internal
  41.  *
  42.  * \def     DBC_ALL
  43.  *
  44.  * \brief   If this macro is defined then all of the \c DBC macros will be
  45.  *          defined.
  46.  *
  47.  * If none of the macros \c DBC_DISABLE, \c DBC_ENABLE_REQUIRE,
  48.  * \c DBC_ENABLE_ENSURE, or \c DBC_ENABLE_INVARIANT have been defined then
  49.  * all the DBC-check macros are implicitly defined.
  50.  *
  51.  * \endinternal
  52.  */
  53. #if !( defined( DBC_ALL ) || defined( DBC_ENABLE_REQUIRE ) \
  54. || defined( DBC_ENABLE_ENSURE ) || defined( DBC_ENABLE_INVARIANT ) )
  55.  
  56. // If none of the macros that control whether or not DBC
  57. // checks are enabled are defined then define them all
  58. #define DBC_ALL
  59. #define DBC_ENABLE_REQUIRE
  60. #define DBC_ENABLE_ENSURE
  61. #define DBC_ENABLE_INVARIANT
  62. #endif
  63.  
  64. /*!
  65.  * \def     DBC_REQUIRE( pred )
  66.  *
  67.  * \brief   This macro function is used to ensure that conditions are met at
  68.  *          the beginning of a function call.
  69.  *
  70.  * If the \c DBC_ENABLE_REQUIRE macro is defined then the \c DBC_REQUIRE macro
  71.  * is defined, otherwise this macro does nothing.
  72.  *
  73.  * \param   [in] pred   The predicate that is to be tested to ensure that it
  74.  *                      is true.
  75.  */
  76. #ifndef DBC_REQUIRE
  77. #ifdef DBC_ENABLE_REQUIRE
  78. #define DBC_REQUIRE( pred )     DBC_ASSERT( pred, "Precondition", #pred, \
  79.     __func__, __FILE__, __LINE__ )
  80.  
  81. #else   // if DBC_REQUIRE is not defined
  82. #define DBC_REQUIRE( ... )
  83. #endif
  84.  
  85. #else   // if DBC_REQUIRE is already defined
  86. #error "DBC_REQUIRE already defined"
  87. #endif
  88.  
  89. /*!
  90.  * \def     DBC_ENSURE( pred )
  91.  *
  92.  * \brief   This macro function is used to ensure that conditions are met at
  93.  *          the end of a function call.
  94.  *
  95.  * If the \c DBC_ENABLE_ENSURE macro is defined then the \c DBC_ENSURE
  96.  * macro is defined, otherwise this macro does nothing.
  97.  *
  98.  * \param   [in] pred   The predicate that is to be tested to ensure that it
  99.  *                      is true.
  100.  */
  101. #ifndef DBC_ENSURE
  102. #ifdef DBC_ENABLE_ENSURE
  103. #define DBC_ENSURE( pred )      DBC_ASSERT( pred, "Postcondition", #pred, \
  104.     __func__, __FILE__, __LINE__ )
  105.  
  106. #else   // if DBC_ENSURE is not defined
  107. #define DBC_ENSURE( pred )
  108. #endif
  109.  
  110. #else   // if DBC_ENSURE is already defined
  111. #error "DBC_ENSURE already defined"
  112. #endif
  113.  
  114. /*!
  115.  * \def     DBC_INVARIANT( pred )
  116.  *
  117.  * \brief   This macro function is used to ensure that conditions are met at
  118.  *          any point in the programs execution.
  119.  *
  120.  * If the \c DBC_ENABLE_INVARIANT macro is defined then the \c DBC_INVARIANT
  121.  * macro is defined, otherwise this macro does nothing.
  122.  *
  123.  * \param   [in] pred   The predicate that is to be tested to ensure that it
  124.  *                      is true.
  125.  */
  126. #ifndef DBC_INVARIANT
  127. #if defined( DBC_ENABLE_INVARIANT )
  128. #define DBC_INVARIANT( pred )   DBC_ASSERT( pred, "Invariant", #pred, \
  129.     __func__, __FILE__, __LINE__ )
  130.  
  131. #else   // if DBC_INVARIANT is not defined
  132. #define DBC_INVARIANT( pred )
  133. #endif
  134.  
  135. #else   // if DBC_INVARIANT is already defined
  136. #error "DBC_INVARIANT already defined"
  137. #endif
  138.  
  139. /*!
  140.  * \internal
  141.  *
  142.  * \def     DBC_ASSERT( PRED, DBC_DESC, PRED_STR, FN_NAME, FILENAME, LINE )
  143.  *
  144.  * \brief   This function is used to ensure that a condition is met.
  145.  *
  146.  *  This macro function is used by all of the \c DBC-check macros.
  147.  *
  148.  * If the \p pred is not met then an error message is written to \c stderr and
  149.  * the program is exited with exit code \c EXIT_FAILURE.
  150.  *
  151.  * \param   [in] pred       The predicate that is to be tested to ensure that
  152.  *                          it is true.
  153.  * \param   [in] dbc_desc   The type of DBC assertion (i.e. require, ensure,
  154.  *                          or invariant). This parameter is used in the
  155.  *                          construction of the assertion failure message that
  156.  *                          is written to \c stderr if \p pred is not true.
  157.  * \param   [in] pred_str   A string representation of the \p pred that is
  158.  *                          being tested.
  159.  * \param   [in] fn_name    The name of the function where the \p pred is
  160.  *                          being tested.
  161.  * \param   [in] filename   The name of the file where the \p fn_name resides.
  162.  * \param   [in] line       The line number of the file where the test is
  163.  *                          occurring.
  164.  *
  165.  * \see     DBC_REQUIRE
  166.  * \see     DBC_ENSURE
  167.  * \see     DBC_INVARIANT
  168.  *
  169.  * \endinternal
  170.  */
  171. #ifndef DBC_ASSERT
  172. #define DBC_ASSERT( pred, dbc_desc, pred_str, fn_name, filename, line ) \
  173.     do { \
  174.         if ( !( pred ) ) { \
  175.             fprintf( stderr, \
  176.                 "%s: Assertion failed: Error " \
  177.                 "%s: <%s> file <%s> line %d.\n", \
  178.                 dbc_desc, pred_str, fn_name, filename, line ); \
  179.             exit( EXIT_FAILURE ); \
  180.         } \
  181.     } while (0)
  182.  
  183. #else   // if DBC_ASSERT is already defined
  184. #error "DBC_ASSERT already defined"
  185. #endif
  186.  
  187. #else   // if DBC_DISABLE is defined
  188.  
  189. // Define the DBC_REQUIRE, DBC_ENSURE, DBC_INVARIANT, and DBC_ASSERT macros,
  190. // thereby disabling all DBC-checks.
  191. #define DBC_REQUIRE( ... )
  192. #define DBC_ENSURE( ... )
  193. #define DBC_INVARIANT( ... )
  194. #define DBC_ASSERT( ... )
  195. #endif
  196.  
  197. #endif // DBC_H_
  198.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement