Go to the first, previous, next, last section, table of contents.


Interface

This section describes the details of the interface to nana library.

All of the files can be included multiple times without ill--effect since they use the C preprocessor to make sure the header declarations are only seen the first by the compiler. Each of the files can also be included individually.

If any of the following routines have an internal problem (e.g. malloc fails due to lack of memory) they will call the `nana_error' function defined in `nana_error.c'. By default this function prints a message and dumps core using `abort'. If you wish to override this behaviour you should define your own handler before linking in the nana library.

nana.h: the main header file

The `nana.h' file includes most of the other files in the library. In particular it `#include's' the following files:

I.h
DI.h
L.h
DL.h
Q.h
GDB.h

WITHOUT_NANA: disabling all nana code for portability.

If you wish to disable all nana code you can `#define' the `WITHOUT_NANA' macro. This selects versions of the macros defined in `I.h',`L.h', etc which map to `/* empty */'.

So if you are using nana for your development but don't wish to force your customers to use it you can add an option to your `configure' script to define/undefine `WITHOUT_NANA'. In addition you will need to distribute copies of the nana header files with your package to get the stubs.

Note that the `L.h' and `DL.h' macros use the macro variable number of arguments extension provided by GNU C. If you wish your code to be portable you should use the macros `VL((..))', etc rather than `L(..)' to avoid problems with non GNU C preprocessors which only take a fixed number of arguments.

I.h: C based invariant checking

This implements the C based invariant checking code and is a replacement for `assert.h'. The first two macros are the normal user interface; the remainder are used for configuring the behaviour on failure, etc.

Macro: void I (bool exprn)
The exprn should always be true if the program is correct. If the exprn is false a message will be printed, followed by core dump.(4)

Checking can be enabled and disabled by using the I_LEVEL and I_DEFAULT_GUARD macros. See the definitions below for these macros for further details.

Note that exprn should have no side-effects(5) since disabling checking shouldn't change your programs behaviour.

  I(z != 0); 
  x = y / z;

Macro: void N (bool exprn)
The opposite of `I', i.e. the expression must never ever be true if the program is working properly. It is equivelant to I(!(e)) and exists as a piece of syntactic sugar which may be helpful for complicated boolean expressions.

char* strdup(char *s) {
  N(s == NULL);
  ...;
}

Macro: int I_LEVEL
The `I_LEVEL' macro is used to globally enable and disable checking by the macros in this file. It can take on one of three values:

0
Disable all checking. Regardless of anything else no code will be generated for I, N, etc.
1
Enable checking only if the corresponding guard condition is true. The guard condition can be used to enable and disable checking at compile and run time.
2
Enable all checking regardless of guard conditions.

I_LEVEL defaults to 1.

Macro: bool I_DEFAULT_GUARD
The I_DEFAULT_GUARD is used to selectively enable or disable checking at compile or run time.

I_DEFAULT_GUARD defaults to TRUE, i.e. always enabled.

A user would typically define I_DEFAULT_GUARD to be global or local variable which is used to turn checking on or off at run--time. For example:

#define I_DEFAULT_GUARD i_guard > 0

extern int i_guard;

Macro: text I_DEFAULT_PARAMS
This is passed off to the I_DEFAULT_HANDLER and defaults to nothing, it is just some text and is intended to pass failure codes (e.g. IEH303) or requests (e.g. HW_DEAD) information off to the handler.

I_DEFAULT_PARAMS defaults to nothing.

Macro: void I_DEFAULT_HANDLER (char *exprn, char *file, int line, param)

When an error is detected the I_DEFAULT_HANDLER will be called to handle the error. The arguments are:

exprn
A string representation of the expression that has failed, e.g. "I(i>=0)".
file
The file that this error occurred in, i.e. __FILE__.
line
The line number for the error, i.e. __LINE__.
param
An optional parameter which can be passed across which defaults to I_DEFAULT_PARAMS. This can be used to pass failure codes or other information from the checking code to the handler.

All of the remaining macros are used to individually override the default values defined above. Normally these macros would be used in a system wide header file to define macros appropriate for the application. For example you might use `IH' to define different checking macros for hardware and software faults.

Macro: void I (bool e)
Macro: void IG (bool e, bool g)
Macro: void IH (bool e, Macro h)
Macro: void IP (bool e, Text p)
Macro: void IGH (bool e, bool g, Macro h)
Macro: void IGP (bool e, bool g, Text p)
Macro: void IHP (bool e, Macro h, Text p)
Macro: void IGHP (bool e, bool g, Macro h, Text p)
Macro: void N (bool e)
Macro: void NG (bool e, bool g)
Macro: void NH (bool e, Macro h)
Macro: void NP (bool e, Text p)
Macro: void NGH (bool e, bool g, Macro h)
Macro: void NGP (bool e, bool g, Text p)
Macro: void NHP (bool e, Macro h, Text p)
Macro: void NGHP (bool e, bool g, Macro h, Text p)

We also provide support for referring to previous values of variables in postconditions. The ID macro is used to create variables to save the old state in. The IS and ISG macros are to set these values.

Macro: void ID (Text decln)
Macro: void IS (Text assignment)
Macro: void ISG (Text decln, bool g)

For example:

void ex(int &r) {
  ID(int oldr = r); /* save parameter */
  g(r);
  I(oldr == r); /* check r is unchanged */
  while(more()) {
    IS(oldr = r); /* assign r to oldr */
    h(r);
    I(oldr == r * r);
  }
}

DI.h: debugger based invariant checking

This implements the debugger based invariant checking code. The first two macros are the normal user interface; the remainder are used for configuring the behaviour on failure, etc. Note that these macros have no effect unless you run your program under the debugger and read in the commands generated by the `nana' command.

Macro: void DI (bool exprn)
The exprn should always be true if the program is working. If it is true then nothing happens otherwise the code given by `DI_DEFAULT_HANDLER' will be called which by default prints a message and dies just like `assert.h'.

The checking using DI can be enabled and disabled by using the DI_LEVEL and DI_DEFAULT_GUARD macros. See the definitions below for these macros for further details.

Note that exprn should have no side-effects(6) since disabling the checking shouldn't change your programs behaviour.

Macro: void DN (bool exprn)
The opposite of `DI', i.e. the expression must never ever be true if the program is working properly. It is equivelant to I(!(e)) and exists as piece of syntactic sugar which is helpful for complicated boolean expressions.

Macro: int DI_LEVEL
The `DI_LEVEL' macro is used to globally enable and disable checking, in particular it can take on one of three values:

0
Disable all checking. Regardless of anything else no code will be generated for DI, DN, etc.
1
Enable checking only if the corresponding guard condition is true. The guard condition can be used to enable and disable checking at compile and run time.
2
Enable all checking regardless of guard conditions, etc.

DI_LEVEL defaults to 1.

Macro: bool DI_DEFAULT_GUARD
The DI_DEFAULT_GUARD is used to selectively enable or disable checking at compile or run time.

DI_DEFAULT_GUARD defaults to TRUE, i.e. always enabled.

A user would typically define DI_DEFAULT_GUARD to be global or local variable which is used to turn checking on or off at run--time. For example:

#define DI_DEFAULT_GUARD (i_guard)

extern int i_guard;

Macro: text DI_DEFAULT_PARAMS
This is passed off to the DI_DEFAULT_HANDLER and defaults to nothing, it is just some text and is intended to pass failure codes (e.g. IEH303) or requests (e.g. HW_DEAD) information off to the handler.

DI_DEFAULT_PARAMS defaults to nothing.

Macro: void DI_DEFAULT_HANDLER (char *exprn, char *file, int line, param)

When an error is detected the DI_DEFAULT_HANDLER will be called to handle the error. The arguments are:

exprn
A string representation of the expression that has failed, e.g. "I(i>=0)".
file
The file that this error occurred in, i.e. __FILE__.
line
The line number for the error, i.e. __LINE__.
param
An optional parameter which can be passed across which defaults to DI_DEFAULT_PARAMS. This can be used to pass failure codes or other information from the checking code to the handler.

Macro: void DI_MAKE_VALID_BREAKPOINT (exprn e)
This macro is used to ensure that a breakpoint can be set at the location we are checking using DI, etc. It defaults to asm("nop") and can be redefined by the user.

Macro: void DI (bool e)
Macro: void DIG (bool e, bool g)
Macro: void DIH (bool e, Macro h)
Macro: void DIP (bool e, Text p)
Macro: void DIGH (bool e, bool g, Macro h)
Macro: void DIGP (bool e, bool g, Text p)
Macro: void DIHP (bool e, Macro h, Text p)
Macro: void DIGHP (bool e, bool g, Macro h, Text p)
Macro: void DN (bool e)
Macro: void DNG (bool e, bool g)
Macro: void DNH (bool e, Macro h)
Macro: void DNP (bool e, Text p)
Macro: void DNGH (bool e, bool g, Macro h)
Macro: void DNGP (bool e, bool g, Text p)
Macro: void DNHP (bool e, Macro h, Text p)
Macro: void DNGHP (bool e, bool g, Macro h, Text p)

All of these macros are used to individually override the default values defined above. Normally these macros would be used in a system wide header file to define macros appropriate for the application.

Macro: void DS (e)
Macro: void DSG (e, g)
These macros are used to assign values to convenience variables in the debugger. Convenience variables are dynamically typed, global in scope and initialised to 0. They start with a single $ and can be used be used for saving the state of program or for counting events. The `DS' macro executes e under the same rules as DI. The `DSG' macro executes e only if the the expression g is true.

Note that `DS' and `DSG' can also be used for modifying C variables and calling functions.

L.h: support for printf style logging

These routines are used to provide logging functions. Messages can be divided into classes and separately enabled and disabled.

Macro: void L (args...)
Used to log a message in a similar way to printf.

Defaults to a using fprintf on stderr.

Macro: void LG (bool guard, args...)
Macro: void LH (function handler, args...)
Macro: void LP (text param, args...)
Macro: void LGP (bool guard, text param, args...)
Macro: void LHP (function handler, text param, args...)
Macro: void LGHP (bool guard, function handler, text param, args...)
And all of the special functions.

The macros such as `L' depend on the GNU CC variable number of arguments to macros extension. If you wish to compile your code on other systems you might wish to use the following variations on `L', etc.

Macro: void VL ((args...))
Macro: void VLG ((bool guard, args...))
Macro: void VLH ((function handler, args...))
Macro: void VLP ((text param, args...))
Macro: void VLGP ((bool guard, text param, args...))
Macro: void VLHP ((function handler, text param, args...))
Macro: void VLGHP ((bool guard, function handler, text param, args...))
Each of these macros calls the corresponding function from the previous group, i.e. by default `VLG' is the same as a call to `LG'. If you define `WITHOUT_NANA' all these macros are translated to `/* empty */'.

Thus you can have nana under GCC whilst the code is still portable to other compilers. However debugging information will not be available on other platforms.

Note: the argument list is surrounded by two sets of brackets. For example:

   VL(("haze in darwin = %d\n", 3.4));

Macro: void L_LEVEL
Used to enable and disable logging independently of guard expressions.

2
Always print message
1
Print message only if the guard expression is true.
0
Never print any messages.

Defaults to 1.

Macro: text L_DEFAULT_HANDLER
The default handler for printing which is simply the name of the logging function or macro.

Defaults to fprintf

Macro: bool L_DEFAULT_GUARD
The default guard condition for logging.

Defaults to TRUE.

Macro: text L_DEFAULT_PARAMS
The default parameter passed off to the logging function or macro.

Defaults to stderr

Macro: void L_SHOW_TIME
If defined then display the time in front of each message.

Macro: char* L_SHOW_TIME_FORMAT
A format string for the time stamp in the log. By default it prints the time out in seconds.

Macro: value L_SHOW_TIME_NOW
The name of a function that returns the time for the time stamp. This defaults to the `now' function from `now.h'.

L_buffer.h: a circular buffer for logging.

A traditional embedded systems trick is to log messages to a circular buffer in core. This has the following benefits:

  1. Speed -- writing to a in core buffer is much faster than spitting out messages to a file on disk. It is often fast enough to leave at least most of the messages in the final product.
  2. Field debugging -- what the ... was the user doing before the system crashed. Oh lets ask them, I'm sure they'll give us a good problem report.

Type: struct L_BUFFER
Used to define buffer variables, it is similar to `FILE*' type in `stdio.h'. To create an instance use `L_buffer_create'.

Function: L_BUFFER* L_buffer_create (size_t size)
Function: L_BUFFER* L_buffer_delete (L_BUFFER *b)
These are used to create or delete a buffer which can contain size characters.

  L_BUFFER *lbuffer;

  lbuffer = L_buffer_create(32*1024); /* create a 32K buffer */
  ...;
  L_buffer_delete(lbuffer); /* and delete it after use */

Function: void L_buffer_wraparound (L_BUFFER *b, int w)
A buffer created by `L_buffer_create' is set up so that the new messages will overwrite the older messages in the buffer. If you wish to disable this overwriting, e.g. to keep the first 32K bytes of your system startup messages you should use `L_buffer_wraparound'. For example:

  L_BUFFER *lb = L_buffer_create(32*1024);
  L_buffer_wraparound(lb, 0); /* disable wraparound */

Function: void L_buffer_printf (L_BUFFER *b, const char *fmt, ...)
Function: void L_buffer_puts (L_BUFFER *b, const char *str)
Function: void L_buffer_putchar (L_BUFFER *b, char ch)
These are the routines which do that actual printing to the buffer.

  L_buffer_printf(lbuffer, "U: user input %c\n", c);
  L_buffer_puts(lbuffer, "warning: its too hot");
  L_buffer_putchar(lbuffer, '*');

Note: a null pointer passed to the `L_buffer_puts' function prints as `(null)'. (7)

Function: void L_buffer_clear (L_BUFFER *b)
Clear the log, i.e. remove all messages and start again.

Function: void L_buffer_dump (L_BUFFER *b, FILE *fp)
Dump the contents of the log *b to the file descriptor *fp. Typically *fp would be `stderr'.

Note that this does not change the contents of the buffer. This is important since we may have a hardware or software problem part of the way through the dump operation and you don't want to loose anything.

To reset the buffer after a successful dump use `L_buffer_clear'.

The output of `L_buffer_dump' consists of a starting message followed by the contents of the log. If a character in the log is not printable we print it out in hex on a line by itself.

* L_buffer_dump =
log message
and another
* non-printable character 0x1
more log messages
* end of dump

You also need to be able to integrate these functions into your design. See `examples/ott.c' for a complicated example. Here we will provide a simplified version which implements a new logging macro called `LFAST' which does a `printf' to the `log_buffer'. If you want to have all messages going to a `L_BUFFER' then you can redefine `L_DEFAULT_HANDLER'.

/* project.h - the project wide include file */

#include <nana.h>
#include <L_buffer.h>

/* LFAST(char *, ...) - log a message to the log_buffer */
/*     ##f translates as the rest of the arguments to LFAST */

#define LFAST(f...) LHP(L_buffer_printf,log_buffer,##f)

extern L_BUFFER *log_buffer; /* the log buffer */

The main program merely creates the log_buffer and eventually calls `L_buffer_dump' to print out the buffer when the system dies.

/* main.c - initialise the system and start things */

#include <project.h>

L_BUFFER *log_buffer;

main() {
  log_buffer = L_buffer_create(16000); 
  if(log_buffer == NULL) { /* not enough store */
    ...
  }
  LFAST("system starting at %f\n", now());
  ...;
}

void fatal_error() { /* called on fatal errors */
  FILE *f = fopen("project.errors","w");
  L_buffer_dump(b, stderr); /* print log to stderr */
  L_buffer_dump(b, f); /* print log to file */
}

L_times.h: recording events and times.

This component is used to record events and times with a lower time and space overhead than the `L_buffer.h' component. Instead of using a `printf' style string we simply record the time and a pointer to a string identifying the event in a circular buffer.

Note 0: the string arguments should not be modified after a call since we record pointers to the strings rather than the strings themselves.

Note 1: there is no printf style formatting, e.g. `%d' in this package.

Type: struct L_TIMES
Used to define buffers, it is similar to `FILE*' type in `stdio.h'. To create an instance use `L_times_create'.

Function: L_TIMES* L_times_create (int size)
Function: L_TIMES* L_times_delete (L_BUFFER *b)
These are used to create or delete a buffer which can contain size messages.

Function: void L_times_wraparound (L_TIMES *b, int w)
A buffer created by `L_times_create' is set up so that the new messages will overwrite the oldest messages in the buffer. If you wish to disable this overwriting, e.g. to keep the first few messages messages you could use `L_times_wraparound(b,0)'.

Function: void L_times_add (L_BUFFER *b, char *m, NANA_TIME t)
Add an event identified by message m at time t to b. The type NANA_TIME defaults to `double'.

Function: void L_times_dump (L_TIMES *b, FILE *fd)
Dump the contents of the buffer out.

Function: void L_times_clear (L_TIMES *b)
Clear all the messages from b.

DL.h: support for printf style logging

These routines are used to provide logging functions. Messages can be divided into classes and separately enabled and disabled.

Macro: void DL (args...)
Used to log a message.

Defaults to a using fprintf on stderr.

Macro: void DLG (bool guard, args...)
Macro: void DLH (function handler, args...)
Macro: void DLP (text param, args...)
Macro: void DLGP (bool guard, text param, args...)
Macro: void DLHP (function handler, args...)
Macro: void DLGHP (bool guard, function handler, args...)
And all of the special functions.

The macros such as `DL' depend on the GNU CC variable number of arguments to macros extension. If you wish to compile your code on other systems you might wish to use the following variations on `DL', etc.

Macro: void VDL ((args...))
Macro: void VDLG ((bool guard, args...))
Macro: void VDLH ((function handler, args...))
Macro: void VDLP ((text param, args...))
Macro: void VDLGP ((bool guard, text param, args...))
Macro: void VDLHP ((function handler, args...))
Macro: void VDLGHP ((bool guard, function handler, args...))
Each of these macros calls the corresponding function from the previous group, i.e. by default `VDL' is equivelant to a call to `DL'. If `WITHOUT_NANA' is defined then the call too `VDL' is equivelant to `/* empty */'.

Thus you can have debugging under GCC whilst the code is still portable to other compilers. However debugging information will not be available on other platforms.

Note: the argument list is surrounded by two sets of brackets. For example:

   VDL(("haze in darwin = %d\n", 3.4));

Macro: int DL_LEVEL
Used to enable and disable logging independently of guard expressions.

2
Always print message
1
Print message only if the guard expression is true.
0
Never print any messages.

Defaults to 1.

Macro: text DL_DEFAULT_HANDLER
The default handler for printing which is simply the name of the printing function.

Defaults to fprintf

Macro: bool DL_DEFAULT_GUARD

Defaults to TRUE.

Macro: text DL_DEFAULT_PARAMS
Defaults to stderr

Macro: flag DL_SHOW_TIME
Each message can be given an individual time stamp by defining DL_SHOW_TIME. This causes the _L_gettime routine to be called before each message which generates the timestamp. A default version is provided by the nana library.

GDB.h: sending plain gdb commands to the debugger

`GDB.h' provides macros for generating user specified commands in the output of the `nana' command. They are not included by default in the `nana.h' file.

Macro: void GDB (command)
Emit a single line command when running this file through `nana'. Note that each line must be passed off separately to the `GDB' macro.

This could be used to set debugger options or to define procedures inside `gdb', e.g.

  GDB(define checkstack);
  GDB(  if 0 <= n && n <= 10);
  GDB(    print "stack ok");
  GDB(  else);
  GDB(    print "stack corrupted");
  GDB(  end);
  GDB(end);

Macro: void GDBCALL (command)
Causes a single gdb command to be executed whenever control passes through this line of code. After the users command is executed control automatically returns to the program.

  GDBCALL(set memory_check = 1)

These macros could used for instrumenting code or setting up test harnesses, e.g.


GDB(set $siocall = 0);
GDB(set $sioerr = 0);

void sio_driver() {
  GDBCALL(set $siocall++)
  if(SIO_REQ & 0x010) {
    GDBCALL(set $sioerr++); 
    ...
  }
}

Q.h: support for quantifiers

`Q.h' provides support for the quantifiers of predicate logic. For example to check that all elements in a data structure have some property we would use universal (forall, upside down A) quantification. To check that one or more values in a data structure have some property we would use existential (exists, back the front E) quantification. For example:

  /* all values in a[] must be between 0 and 10 */
  I(A(int i = 0, i < n_array, i++, 0 <= a[i] && a[i] <= 10));

  /* there exists a value in linked list l which is smaller than 10 */
  I(E(node *p = l, p != NULL, p = p->next, p->data <= 10));

The first three arguments to `A' and `E' are similar to a C `for' loop which iterates over the values we wish to check. The final argument is the expression that must be true.

The only minor difference from the C `for' loop is that variables may be declared at the start of the loop, even if you are using C rather than C++ which already supports this.(8)

The `Q.h' macros can also be nested and used anywhere a boolean value is required. For example:

  if(A(int i = 0, i < MAXX, i++,
       A(int j = 0, j < MAXY, j++,
         m[i][j] == (i == j ? 1 : 0)))) { 
        /* identity matrix, i.e. all 0's except for 1's on */
        /* the diagonal */
        ...
  } else {
        /* not an identity matrix */
        ...
  }

The results from these macros can also be combined using boolean operations, e.g.

  /* the values in a[i]  are either ALL positive or ALL negative */
  I(A(int i = 0, i < MAX, i++, a[i] >= 0)
    ||
    A(int i = 0, i < MAX, i++, a[i] < 0));

Portability: note the macros in this file require the GNU CC/C++ statement expression extension of GCC to work. If your not using GNU CC then for now you are out of luck. At some time in the future we may implement a method which will work for standard C++, standard C is a bit of a challenge.

Portability: unfortunately these macros do not for the `DI' and `DL' macros since the statement expression extension has not been implemented in GDB.

Macro: bool A (init,condition,next,exprn)
For all values generated by `for(int;condition;next)' the exprn must be true.
  I(A(int i = 0, i < MAX, i++, a[i] >= 0)); /* all a[i] are +ve */

Macro: bool E (init,condition,next,exprn)
There exists at least one value for exprn generated by `for (int;condition;next)' which is true.

  /* one or more a[i] >= 0 */
  I(E(int i = 0, i < MAX, i++, a[i] >= 0));

Macro: long C (init,condition,next,exprn)
Returns the number of times the exprn is true over the values generated by `for(int;condition;next)'.

  /* 3 elements of a[] are +ve */
  I(C(int i = 0, i < MAX, i++, a[i] >= 0) == 3); 

Macro: bool E1 (init,condition,next,exprn)
There exists only one value generated by `for(int;condition;next)' for which the exprn is true.

  /* a single elements of a[] is +ve */
  I(E1(int i = 0, i < MAX, i++, a[i] >= 0)); 

Macro: typeof(exprn) S (init,condition,next,exprn)
Sum the values generated by exprn for all values given by `for(int;condition;next)'. The type of the value returned is given by the type of the exprn.(9)

  /* sum of a[] is 10 */
  I(S(int i = 0, i < MAX, i++, a[i]) == 10);

  /* sum of all +ve numbers in a[] is 10 */
  I(S(int i = 0, i < MAX, i++, a[i] >= 0 ? a[i] : 0) == 10);

Macro: typeof(exprn) P (init,condition,next,exprn)
Returns the product of the values generated by exprn for all values given by `for(int;condition;next)'. The type returned is the type of the expression.

  /* product of all the values in a[] is 10 */
  I(P(int i = 0, i < MAX, i++, a[i]) == 10); 

  /* a = x^y i.e. x*x..*x y times */
  I(P(int i = 0, i < y, i++, x) == a);

Qstl.h: quantifiers for STL containers.

The Standard Template Library (STL) is a library for C++ that makes extensive use of templates to implement the standard container classes and much more. Each of the container classes provides an interface to iterate over all the objects in the container, e.g.

// MAP is an associate array from location(lat,long) onto the name.
typedef map<location,string,locationlt> MAP;

void print_map_names(MAP& m) { // print out all the names in the map
  for(MAP::iterator i = m.begin(); i != m.end(); ++i) {
    cout << (*i).second << "\n";
  }
}

`Qstl.h' provides the same facilities as `Q.h' but uses the standard STL iterator protocol shown above. The names in `Qstl.h' are generated by appending a `O' (O not zero!) to the names in `Q.h'. In particular:

Macro: bool AO (name,container,predicate)
For all values in the container class the predicate must be true. The predicate refers to individual values using name. See the STL documentation for more details. Another way of putting this is forall name in container the predicate must be true.

  map<int,char *,ltint> m;
  // all keys (or indexes) into m are positive	
  I(AO(i, m, (*i).first >= 0)); 

Macro: bool EO (name,container,predicate)
There exists one or more values in the container class for which the predicate is true.

  map<int,char,ltint> m;

  // one or more characters in m are '$'
  I(EO(i, m, (*i).second == '$')); 

Macro: bool E1O (name,container,predicate)
There exists one value in the container for which the predicate is true.

  map<int,char,ltint> m;

  // one characters in m is a '$'
  I(E1O(i, m, (*i).second == '$')); 

Macro: int CO (name,container,predicate)
Returns the number of times the predicate was true for all values in the container.

  map<int,char,ltint> m;
  int nalpha; 
  // count the number of alphabetic chars in the map
  nalpha = CO(i, m, isalpha((*i).second)); 

Macro: typeof(exprn) SO (name,container,exprn)
Sum the exprn for all values in the container.

  map<int,float,ltint> m;
  float sum;
  // sum all the values in m
  sum = SO(i, m, (*i).second); 

Macro: typeof(exprn) PO (name,container,exprn)
Take the product of the exprn for all values in the container.

  map<int,float,ltint> m;
  float product;
  // multiply all the values in m
  product = PO(i, m, (*i).second); 

now.h: measuring time

The `now.h' file provides some simple time measurement routines. It is not included in `nana.h' so you must include this file separately.

It uses the `gettimeofday' system call and has an accuracy of between 1us and 10ms depending on the operating system and hardware configuration.

See the IPM package if you require better measurement tools.(10)

Function: double now ()
Returns the time in seconds since the beginning of time as defined by your system. If you call `now_reset' the time will start again at 0.

Function: double now_reset ()
Reset the times returned by `now' to 0.

Function: double now_delta (double *dp)
Returns the elapsed time between *dp and now(). It then sets *dp to now, thus giving a delta time between particular events.

  t = now();
  for(;;) {
    ...; /* code that must finish in 50ms */
    I(now_delta(&t) <= 0.050);
  }

eiffel.h: eiffel type assertions

Eiffel is a very nice language which provides the assertion checking facilities of nana inside the language itself. The `eiffel.h' library is intended to provide a similar setup to Eiffel in the C++ language. It is a pretty poor emulation, but it is hopefully better than nothing.

Assertion checking is controlled by the EIFFEL_CHECK variable which can take on any of the following values:

CHECK_NO
Disable all checking.
CHECK_REQUIRE
Check the preconditions for each method.
CHECK_ENSURE
And also check the postconditions.
CHECK_INVARIANT
And also check the class invariant before and after each method is called. The programmer should provide a class method called `invariant' which returns `true' if the object is consistent, `false' otherwise.
CHECK_LOOP
And also check the loop invariants.
CHECK_ALL
And also check any assertions using the `CHECK' instruction.

A typical compile flag to the compile might be:

% g++ -c -DEIFFEL_CHECK=CHECK_ALL play.cc

And then we have the actual assertion macros.

Macro: void REQUIRE (exprn)
Called at the beginning of each method. This checks the precondition to a method and the class invariant.

Macro: void ENSURE (exprn)
Called at the end of each method. This checks the postcondition to a method and the class invariant.

Macro: void INVARIANT (exprn)
Used to check a loop invariant.

Macro: void CHECK (exprn)
Used for any other inline assertions.

And finally a small example:

#include <eiffel.h>

class example {
  int nobjects;
  map<location,string,locationlt> layer;
public:
  bool invariant();
  void changeit(location l);
};

bool example::invariant() {
  return AO(i,layer,valid_location((*i).first)) && 
         nobjects >= 0;
}

void example::changeit(string n, location l) {
  REQUIRE(E1O(i,layer,(*i).second == n));
  ...;
  while(..) {
    INVARIANT(...);
    ...
    INVARIANT(...);
  }
  ...
  CHECK(x == 5);
  ...
  ENSURE(layer[l] == n);
}

Note that the invariant checking macro `example::invariant' is called automatically on function entry/exit using the `REQUIRE' and `ENSURE' macros.

assert.h: a drop in replacement for assert.h

A drop in replacement for `assert.h' is provided in the `src' directory. It is not installed by default. If you wish to use it then you need to copy it to your include directory by hand.

This might be of use if you are already using `assert.h' and wish to save some code space since the nana implementation is more space efficient.

Calls to `assert' are translated to calls to `I' and can be disabled by defining `NDEBUG'.

calls.h: checking/printing many objects/facts.

The `calls' module implements a simple list of functions which can be modified and executed at run-time. It is similar in spirit to the ANSI C `atexit' function. It is intended to be used for:

Type: typedef FUNC
A pointer to a `void' function which takes a single `void*' argument. The `void *' argument is intended to be used to pass information such as arguments or pointers to objects (e.g. `this' in C++). All of the checking/printing functions must be of this type, e.g.

void print_object(void *f) {
  ...;
}

Type: struct CALL
This structure represents a single call to a function, i.e. a function pointer (`FUNC') and the `void*' argument.

	CALL *head = 0;

Function: void calls_add (CALL **head, FUNC fp, *arg)
Adds a call to function `fp' with argument `arg' to the list pointed to by `head'.

	CALL *global_checks = 0;

	calls_add(&global_checks,complex_ok,(void *)x); 

Function: void calls_exec (CALL **head, FUNC fp, void *arg)
Execute all/some of the calls in the list given by `head'. The arguments `fp' and `arg' must both match for each individual call. The null pointer (`0') matches anything whilst any other value requires an exact match between the `CALL' and the arguments to `calls_exec'. For example:

calls_exec(&l,0,0); /* execute all functions in l  */
calls_exec(&l,complex_print,0); /* calls complex_print(*) in l */
calls_exec(&l,0,(void*) &b); /* calls *(&b) in l */
calls_exec(&l,f,(void*) &b); /* calls f(&b) in l */

Function: void calls_delete (CALL **head, FUNC fp, void *arg)
Delete all/some of the calls in the list given by `head'. The arguments `fp' and `arg' must both match for each individual call. The null pointer (`0') matches anything whilst any other value requires an exact match between the `CALL' and the arguments to `calls_delete'. For example:

calls_delete(&l,0,0); /* delete all functions in l  */
calls_delete(&l,complex_print,0); /* delete complex_print(*) in l */
calls_delete(&l,0,(void*) &b); /* delete *(&b) in l */
calls_delete(&l,f,(void*) &b); /* delete f(&b) in l */

Note: that calls are added to the head of the list rather than the tail. This means that the most recently added call will be executed first (as in a stack).


Go to the first, previous, next, last section, table of contents.