Next: , Previous: , Up: Defining New Types (Smobs)   [Contents][Index]

5.5.2 Creating Smob Instances

Normally, smobs can have one immediate word of data. This word stores either a pointer to an additional memory block that holds the real data, or it might hold the data itself when it fits. The word is large enough for a SCM value, a pointer to void, or an integer that fits into a size_t or ssize_t.

You can also create smobs that have two or three immediate words, and when these words suffice to store all data, it is more efficient to use these super-sized smobs instead of using a normal smob plus a memory block. See Double Smobs, for their discussion.

Guile provides functions for managing memory which are often helpful when implementing smobs. See Memory Blocks.

To retrieve the immediate word of a smob, you use the macro SCM_SMOB_DATA. It can be set with SCM_SET_SMOB_DATA. The 16 extra bits can be accessed with SCM_SMOB_FLAGS and SCM_SET_SMOB_FLAGS.

The two macros SCM_SMOB_DATA and SCM_SET_SMOB_DATA treat the immediate word as if it were of type scm_t_bits, which is an unsigned integer type large enough to hold a pointer to void. Thus you can use these macros to store arbitrary pointers in the smob word.

When you want to store a SCM value directly in the immediate word of a smob, you should use the macros SCM_SMOB_OBJECT and SCM_SET_SMOB_OBJECT to access it.

Creating a smob instance can be tricky when it consists of multiple steps that allocate resources. Most of the time, this is mainly about allocating memory to hold associated data structures. Using memory managed by the garbage collector simplifies things: the garbage collector will automatically scan those data structures for pointers, and reclaim them when they are no longer referenced.

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

make_image (SCM name, SCM s_width, SCM s_height)
  SCM smob;
  struct image *image;
  int width = scm_to_int (s_width);
  int height = scm_to_int (s_height);

  /* Step 1: Allocate the memory block.
  image = (struct image *)
     scm_gc_malloc (sizeof (struct image), "image");

  /* Step 2: Initialize it with straight code.
  image->width = width;
  image->height = height;
  image->pixels = NULL;
  image->name = SCM_BOOL_F;
  image->update_func = SCM_BOOL_F;

  /* Step 3: Create the smob.
  smob = scm_new_smob (image_tag, image);

  /* Step 4: Finish the initialization.
  image->name = name;
  image->pixels =
    scm_gc_malloc_pointerless (width * height, "image pixels");

  return smob;

We use scm_gc_malloc_pointerless for the pixel buffer to tell the garbage collector not to scan it for pointers. Calls to scm_gc_malloc, scm_new_smob, and scm_gc_malloc_pointerless raise an exception in out-of-memory conditions; the garbage collector is able to reclaim previously allocated memory if that happens.

Next: , Previous: , Up: Defining New Types (Smobs)   [Contents][Index]