Previous: , Up: ccnames   [Contents][Index]


A.3 Well known names for trait types.

The macros for “well known trait functions” define an API to implement trait struct types; an trait is a set of operations we can apply to a data struct; multiple data struct types can implement multiple traits. The following macros are defined in the header file ccnames.h.

Macro: ccname_trait_new_type (TRAIT_TYPE)
Macro: ccname_trait_new_type (TRAIT_TYPE, STRUCT_TYPE)
Macro: ccname_trait_new_type (TRAIT_TYPE, STRUCT_TYPE, VARIANT)

Given an trait type name, an optional struct name and an optional variant specification: expand into the function type name of trait implementation constructors. Constructors of such type must build instances of TRAIT_TYPE as implemented by STRUCT_TYPE, as specified for the variant VARIANT.

Macro: ccname_trait_new (TRAIT_TYPE, STRUCT_TYPE)
Macro: ccname_trait_new (TRAIT_TYPE, STRUCT_TYPE, VARIANT)

Given an trait type name, a struct type name, an optional variant specification: expand into the name of the API function new() that instantiates that variant of the trait for the struct.

Macro: ccname_trait_table_type (TRAIT_TYPE)
Macro: ccname_trait_table_type (TRAIT_TYPE, VARIANT)

Given an trait type name and an optional variant specification: expand into the name of the methods table type for the trait type.

Macro: ccname_trait_table (TRAIT_TYPE, STRUCT_TYPE)
Macro: ccname_trait_table (TRAIT_TYPE, STRUCT_TYPE, VARIANT)

Given an trait type name, a struct type name, and an optional variant specification: expand into the name of the methods table for that variant of the trait implementation for the struct type.

Macro: ccname_trait_method_type (TRAIT_TYPE, METHOD_NAME)
Macro: ccname_trait_method_type (TRAIT_TYPE, VARIANT, METHOD_NAME)

Given an trait type name, an optional variant specification, and a method name: expand into the type name of the method function for that variant of the trait implementation.

Macro: ccname_trait_method (TRAIT_TYPE, STRUCT_TYPE, METHOD_NAME)
Macro: ccname_trait_method (TRAIT_TYPE, STRUCT_TYPE, VARIANT, METHOD_NAME)

Given an trait type name, a struct type name, an optional variant specification, and a method name: expand into the name of the method function for that variant of the trait implementation for the struct type.

Let’s say we have this struct definition:

typedef struct my_coords_t      my_coords_t;

struct my_coords_t {
  double        X;
  double        Y;
};

and we want to define an trait type my_printable_T to print the struct on a standard stream, both in rectangular and polar forms.

Every trait must have a struct acting as table of pointers to functions, whose functions implements the trait methods. The trait struct type is unique, the methods table struct type is unique; for every data struct that implements the trait: we need a methods table and an trait constructor.

The trait struct type and the methods table struct type are defined as follows:

typedef struct my_printable_T   my_printable_T;
typedef struct ccname_trait_table_type(my_printable_T) \
  ccname_trait_table_type(my_printable_T);

struct my_printable_T {
  ccname_trait_table_type(my_printable_T)  const * methods;
  ccstructs_core_t                         const * self;
};

typedef void ccname_trait_method_type(my_printable_T, print) \
  (my_printable_T I, FILE * stream);

struct ccname_trait_table_type(my_printable_T) {
  ccname_trait_method_type(my_printable_T, print) * print_rec;
  ccname_trait_method_type(my_printable_T, print) * print_pol;
};

The my_printable_T trait API is defined as follows:

my_printable_T
my_printable_new (ccstructs_core_t const * S,
                  ccname_trait_table_type(my_printable_T) const * M)
{
  my_printable_T        I = {
    .methods    = M,
    .self       = S
  };
  return I;
}

ccstructs_core_t const *
my_printable_self (my_printable_T I)
{
  return I.self;
}

void
my_printable_print_rec (my_printable_T I, FILE * stream)
{
  I.methods->print_rec(I, stream);
}

void
my_printable_print_pol (my_printable_T I, FILE * stream)
{
  I.methods->print_pol(I, stream);
}

The implementation of my_printable_T for the data struct my_coords_t is defined as follows:

static void
ccname_trait_method(my_printable_T, my_coords_t, print_rec) (my_printable_T I, FILE * stream)
{
  CCSTRUCTS_PC(my_coords_t, S, my_printable_self(I));

  fprintf(stream, "X=%f, Y=%f\n", S->X, S->Y);
}

static void
ccname_trait_method(my_printable_T, my_coords_t, print_pol) (my_printable_T I, FILE * stream)
{
  CCSTRUCTS_PC(my_coords_t, S, my_printable_self(I));
  double        RHO   = hypot(S->X, S->Y);
  double        THETA = atan2(S->Y, S->X);

  fprintf(stream, "RHO=%f, THETA=%f\n", RHO, THETA);
}

static ccname_trait_table_type(my_printable_T) const ccname_trait_table(my_printable_T, my_coords_t) = {
  .print_rec    = ccname_trait_method(my_printable_T, my_coords_t, print_rec),
  .print_pol    = ccname_trait_method(my_printable_T, my_coords_t, print_pol)
};

my_printable_T
ccname_trait_new(my_printable_T, my_coords_t) (my_coords_t * S)
{
  return my_printable_new(ccstructs_core(S), &ccname_trait_table(my_printable_T, my_coords_t));
}

We can use the trait as follows:

int
main (void)
{
  cce_location_t        L[1];
  my_coords_t *         S;
  my_printable_T        I;

  if (cce_location(L)) {
    cce_run_catch_handlers_final(L);
  } else {
    S = ccname_new(my_coords_t, rec)(L, 1.0, 2.0);
    I = ccname_trait_new(my_printable_T, my_coords_t)(S);

    my_printable_print_rec(I, stdout);
    my_printable_print_pol(I, stdout);
    ccname_delete(my_coords_t)(S);
  }
  exit(EXIT_SUCCESS);
}

Previous: , Up: ccnames   [Contents][Index]

This document describes version 0.3.0-devel.3 of CCStructs.