Node:Creating Instances, Next:, Previous:Describing a New Type, Up:Defining New Types (Smobs)



18.3.2 Creating Instances

Like other non-immediate types, smobs start with a cell whose first word contains typing information, and whose remaining words are free for any use.

After the header word containing the type code, smobs can have either one, two or three additional words of data. These words store either a pointer to the internal C structure holding the smob-specific data, or the smob data itself. To create an instance of a smob type following these standards, you should use SCM_NEWSMOB, SCM_NEWSMOB2 or SCM_NEWSMOB3:1

void SCM_NEWSMOB(SCM value, scm_t_bits tag, void *data) Macro
void SCM_NEWSMOB2(SCM value, scm_t_bits tag, void *data1, void *data2) Macro
void SCM_NEWSMOB3(SCM value, scm_t_bits tag, void *data1, void *data2, void *data3) Macro
Make value contain a smob instance of the type with tag tag and smob data data (or data1, data2, and data3). value must be previously declared as C type SCM.

Since it is often the case (e.g., in smob constructors) that you will create a smob instance and return it, there is also a slightly specialized macro for this situation:

fn_returns SCM_RETURN_NEWSMOB(scm_t_bits tag, void *data) Macro
fn_returns SCM_RETURN_NEWSMOB2(scm_t_bits tag, void *data1, void *data2) Macro
fn_returns SCM_RETURN_NEWSMOB3(scm_t_bits tag, void *data1, void *data2, void *data3) Macro
This macro expands to a block of code that creates a smob instance of the type with tag tag and smob data data (or data1, data2, and data3), and causes the surrounding function to return that SCM value. It should be the last piece of code in a block.

Guile provides the following functions for managing memory, which are often helpful when implementing smobs:

char * scm_must_malloc (size_t len, char *what) Function
Allocate len bytes of memory, using malloc, and return a pointer to them.

If there is not enough memory available, invoke the garbage collector, and try once more. If there is still not enough, signal an error, reporting that we could not allocate what.

This function also helps maintain statistics about the size of the heap.

char * scm_must_realloc (char *addr, size_t olen, size_t len, char *what) Function
Resize (and possibly relocate) the block of memory at addr, to have a size of len bytes, by calling realloc. Return a pointer to the new block.

If there is not enough memory available, invoke the garbage collector, and try once more. If there is still not enough, signal an error, reporting that we could not allocate what.

The value olen should be the old size of the block of memory at addr; it is only used for keeping statistics on the size of the heap.

void scm_must_free (char *addr) Function
Free the block of memory at addr, using free. If addr is zero, signal an error, complaining of an attempt to free something that is already free.

This does no record-keeping; instead, the smob's free function must take care of that.

This function isn't usually sufficiently different from the usual free function to be worth using.

Continuing the above example, if the global variable image_tag contains a tag returned by scm_make_smob_type, here is how we could construct a smob whose CDR contains a pointer to a freshly allocated struct image:

struct image {
  int width, height;
  char *pixels;

  /* The name of this image */
  SCM name;

  /* A function to call when this image is
     modified, e.g., to update the screen,
     or SCM_BOOL_F if no action necessary */
  SCM update_func;
};

SCM
make_image (SCM name, SCM s_width, SCM s_height)
{
  struct image *image;
  int width, height;

  SCM_ASSERT (SCM_STRINGP (name), name, SCM_ARG1, "make-image");
  SCM_ASSERT (SCM_INUMP (s_width),  s_width,  SCM_ARG2, "make-image");
  SCM_ASSERT (SCM_INUMP (s_height), s_height, SCM_ARG3, "make-image");

  width = SCM_INUM (s_width);
  height = SCM_INUM (s_height);

  image = (struct image *) scm_must_malloc (sizeof (struct image), "image");
  image->width = width;
  image->height = height;
  image->pixels = scm_must_malloc (width * height, "image pixels");
  image->name = name;
  image->update_func = SCM_BOOL_F;

  SCM_RETURN_NEWSMOB (image_tag, image);
}

Footnotes

  1. The SCM_NEWSMOB2 and SCM_NEWSMOB3 variants will allocate double cells and thus use twice as much memory as smobs created by SCM_NEWSMOB.