21.2 Implementation

These keep and drop calls for simple objects are generally implemented by using one of a set of standard functions. There are a range of these, depending on the expected size of the reference counts, and all handle the locking required to ensure thread safety:

void *fz_keep_imp(fz_context *ctx, void *p, int *refs); 
void *fz_keep_imp8(fz_context *ctx, void *p, int8_t *refs); 
void *fz_keep_imp16(fz_context *ctx, void *p, int16_t *refs); 
int fz_drop_imp(fz_context *ctx, void *p, int *refs); 
int fz_drop_imp8(fz_context *ctx, void *p, int8_t *refs); 
int fz_drop_imp16(fz_context *ctx, void *p, int16_t *refs);

As an example, a fz_path structure is defined as:

typedef struct { 
  int8_t refs; 
} fz_path;

and thus appropriate keep and drop functions can be defined simply:

fz_path *fz_keep_path(fz_context *ctx, fz_path *path) 
{ 
   return fz_keep_imp8(ctx, &path->refs); 
} 
 
void fz_drop_path(fz_context *ctx, fz_path *path) 
{ 
   if (!fz_drop_imp8(ctx, &path->refs)) 
      return; 
   /* code to free the contents of the path structure */ 
   ... 
}

More complex variations of these functions are available to cope with ‘storable’ objects, and still more complex versions to cope with ‘key storable’ objects - these are explained in the following sections.

However they are implemented, these objects all look basically the same to most users - they can simply be ‘kept’ and ‘dropped’ as required.