Next: conditions descriptors, Up: conditions [Contents][Index]
The purpose of CCExceptions’s exceptional–condition objects module is to allow us to write code like this:
cce_location_t L[1];
if (cce_location(L)) {
// handle the exceptional condition
if (my_condition_is_alpha(cce_condition(L)))
{
// react to exception "alpha"
}
else if (my_condition_is_beta(cce_condition(L)))
{
// react to exception "beta"
}
else
{
// default reaction to any exception
}
cce_run_catch_handlers_final(L);
} else {
// do something useful
cce_run_body_handlers(L);
}
in which we use some, previously defined, exceptional–condition object–types ‘alpha’ and ‘beta’.
If we need to hand the exceptional–condition object to an upper level location we can do it as follows:
void
upper_function (void)
{
cce_location_t L[1];
if (cce_location(L)) {
fprintf(stderr, "log: %s\n", \
cce_condition_static_message(cce_condition(L)));
cce_run_catch_handlers_final(L);
} else {
lower_function(L);
cce_run_body_handlers(L);
}
}
void
lower_function (cce_location_t * upper_L)
{
cce_location_t L[1];
if (cce_location(L)) {
cce_run_catch_handlers_raise(L, upper_L);
} else {
do_something();
if (an_error_occurred()) {
cce_raise(L, select_condition_object());
}
cce_run_body_handlers(L);
}
}
From the point of view of our ability to react to an exception at runtime: a flexible situation is the one in which the exceptional–condition object–types are organised in a tree hierarchy. It allows us to select the level of granularity we desire in the branching logic. The tree hierarchy implemented by CCExceptions uses single inheritance; multiple inheritance would be more general, but also more complex.
Exceptional–condition objects are C language structures referencing a type descriptor, which is also a C language structure. Type descriptors are usually statically allocated and mostly have a hard–coded initialisation. Exceptional–condition objects are either dynamically allocated and initialised or statically allocated with hard–coded initialisation.
Every type descriptor data structure encloses a data structure of type cce_descriptor_t,
which must be its first field. The instances of cce_descriptor_t hold the pointers that
define the tree hierarchy; every type descriptor can be referenced by multiple
exceptional–condition objects: it can represent the type of multiple objects; every type descriptor
has a single parent and can have zero, one or more children. Each pointer to
cce_descriptor_t is a unique runtime value identifying the type of
exceptional–condition objects.
Every exceptional–condition object’s data structure encloses a data structure of type
cce_condition_t, which must be its first field. The exceptional–condition object holds a
pointer to the associated type descriptor.
The root of the tree is represented by the object–type descriptor cce_descriptor_root_t
and objects of such type are struct of type cce_condition_root_t. We can think of
the root structure types as follows:
typedef struct cce_condition_root_t cce_descriptor_root_t;
typedef struct cce_condition_root_t cce_condition_root_t;
struct cce_descriptor_root_t {
cce_descriptor_t descriptor;
};
struct cce_condition_root_t {
cce_condition_t condition;
};
extern cce_descriptor_root_t const * const cce_descriptor_root_ptr;
We declare the struct types needed to define a new exceptional–condition object–type, child
of the root type, as follows:
typedef struct my_descriptor_error_t my_descriptor_error_t;
typedef struct my_condition_error_t my_condition_error_t;
struct my_descriptor_error_t {
cce_descriptor_t descriptor;
/* Put some custom fields here. */
};
struct my_condition_error_t {
cce_condition_root_t root;
/* Put some custom fields here. */
};
the field of type cce_descriptor_t is the first in its data structure type; the field of
type cce_condition_root_t is the first in its data structure type.
In the following picture: the alpha descriptor is a child of the root descriptor; the beta descriptor is a child of the type ‘alpha’ descriptor. We can say that:
-----------------
| descriptor root |
-----------------
^
|
------------------ --------------
| descriptor alpha | <-- | object alpha |
------------------ --------------
^
|
----------------- -------------
| descriptor beta | <--- | object beta |
----------------- -------------
The data types that represent such hierarchy look as follows:
typedef struct my_descriptor_alpha_t my_descriptor_alpha_t;
typedef struct my_descriptor_beta_t my_descriptor_beta_t;
typedef struct my_condition_alpha_t my_condition_alpha_t;
typedef struct my_condition_beta_t my_condition_beta_t;
/*** Descriptors types. ***/
struct my_descriptor_alpha_t {
cce_descriptor_t descriptor;
};
struct my_descriptor_beta_t {
cce_descriptor_t descriptor;
};
/*** Object types. ***/
struct my_condition_alpha_t {
cce_condition_root_t root;
};
struct my_condition_beta_t {
my_condition_alpha_t alpha;
};
we can statically allocate and initialise the type descriptors as follows:
my_descriptor_alpha_t my_descriptor_alpha = {
.descriptor.parent = NULL
};
my_descriptor_beta_t my_descriptor_beta = {
.descriptor.parent = &my_descriptor_alpha.descriptor
};
void
initialisation_function (void)
{
cce_descriptor_set_parent_to(cce_descriptor_root_t) \
(&my_descriptor_alpha.descriptor);
}
Next: conditions descriptors, Up: conditions [Contents][Index]
This document describes version 0.9.0-devel.3 of CCExceptions.