Commit | Line | Data |
---|---|---|
3229f68b MV |
1 | @c -*-texinfo-*- |
2 | @c This is part of the GNU Guile Reference Manual. | |
097a793b | 3 | @c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2010, 2011 |
3229f68b MV |
4 | @c Free Software Foundation, Inc. |
5 | @c See the file guile.texi for copying conditions. | |
6 | ||
7 | @node Defining New Types (Smobs) | |
8 | @section Defining New Types (Smobs) | |
9 | ||
10 | @dfn{Smobs} are Guile's mechanism for adding new primitive types to | |
11 | the system. The term ``smob'' was coined by Aubrey Jaffer, who says | |
12 | it comes from ``small object'', referring to the fact that they are | |
13 | quite limited in size: they can hold just one pointer to a larger | |
14 | memory block plus 16 extra bits. | |
15 | ||
16 | To define a new smob type, the programmer provides Guile with some | |
17 | essential information about the type --- how to print it, how to | |
18 | garbage collect it, and so on --- and Guile allocates a fresh type tag | |
19 | for it. The programmer can then use @code{scm_c_define_gsubr} to make | |
20 | a set of C functions visible to Scheme code that create and operate on | |
21 | these objects. | |
22 | ||
23 | (You can find a complete version of the example code used in this | |
24 | section in the Guile distribution, in @file{doc/example-smob}. That | |
25 | directory includes a makefile and a suitable @code{main} function, so | |
26 | you can build a complete interactive Guile shell, extended with the | |
27 | datatypes described here.) | |
28 | ||
29 | @menu | |
30 | * Describing a New Type:: | |
eb12b401 | 31 | * Creating Smob Instances:: |
3229f68b MV |
32 | * Type checking:: |
33 | * Garbage Collecting Smobs:: | |
34 | * Garbage Collecting Simple Smobs:: | |
35 | * Remembering During Operations:: | |
36 | * Double Smobs:: | |
37 | * The Complete Example:: | |
38 | @end menu | |
39 | ||
40 | @node Describing a New Type | |
41 | @subsection Describing a New Type | |
42 | ||
43 | To define a new type, the programmer must write four functions to | |
44 | manage instances of the type: | |
45 | ||
46 | @table @code | |
47 | @item mark | |
48 | Guile will apply this function to each instance of the new type it | |
49 | encounters during garbage collection. This function is responsible for | |
50 | telling the collector about any other @code{SCM} values that the object | |
51 | has stored. The default smob mark function does nothing. | |
52 | @xref{Garbage Collecting Smobs}, for more details. | |
53 | ||
54 | @item free | |
55 | Guile will apply this function to each instance of the new type that is | |
56 | to be deallocated. The function should release all resources held by | |
57 | the object. This is analogous to the Java finalization method-- it is | |
58 | invoked at an unspecified time (when garbage collection occurs) after | |
59 | the object is dead. The default free function frees the smob data (if | |
60 | the size of the struct passed to @code{scm_make_smob_type} is non-zero) | |
61 | using @code{scm_gc_free}. @xref{Garbage Collecting Smobs}, for more | |
62 | details. | |
63 | ||
1a82e370 MV |
64 | This function operates while the heap is in an inconsistent state and |
65 | must therefore be careful. @xref{Smobs}, for details about what this | |
66 | function is allowed to do. | |
67 | ||
3229f68b MV |
68 | @item print |
69 | Guile will apply this function to each instance of the new type to print | |
70 | the value, as for @code{display} or @code{write}. The default print | |
71 | function prints @code{#<NAME ADDRESS>} where @code{NAME} is the first | |
0f7e6c56 | 72 | argument passed to @code{scm_make_smob_type}. |
3229f68b MV |
73 | |
74 | @item equalp | |
75 | If Scheme code asks the @code{equal?} function to compare two instances | |
76 | of the same smob type, Guile calls this function. It should return | |
77 | @code{SCM_BOOL_T} if @var{a} and @var{b} should be considered | |
78 | @code{equal?}, or @code{SCM_BOOL_F} otherwise. If @code{equalp} is | |
79 | @code{NULL}, @code{equal?} will assume that two instances of this type are | |
80 | never @code{equal?} unless they are @code{eq?}. | |
81 | ||
82 | @end table | |
83 | ||
84 | To actually register the new smob type, call @code{scm_make_smob_type}. | |
85 | It returns a value of type @code{scm_t_bits} which identifies the new | |
86 | smob type. | |
87 | ||
818d24b5 | 88 | The four special functions described above are registered by calling |
3229f68b MV |
89 | one of @code{scm_set_smob_mark}, @code{scm_set_smob_free}, |
90 | @code{scm_set_smob_print}, or @code{scm_set_smob_equalp}, as | |
91 | appropriate. Each function is intended to be used at most once per | |
92 | type, and the call should be placed immediately following the call to | |
93 | @code{scm_make_smob_type}. | |
94 | ||
95 | There can only be at most 256 different smob types in the system. | |
96 | Instead of registering a huge number of smob types (for example, one | |
97 | for each relevant C struct in your application), it is sometimes | |
8c3fa3e5 | 98 | better to register just one and implement a second layer of type |
3229f68b | 99 | dispatching on top of it. This second layer might use the 16 extra |
8c3fa3e5 | 100 | bits to extend its type, for example. |
3229f68b MV |
101 | |
102 | Here is how one might declare and register a new type representing | |
103 | eight-bit gray-scale images: | |
104 | ||
105 | @example | |
106 | #include <libguile.h> | |
107 | ||
108 | struct image @{ | |
109 | int width, height; | |
110 | char *pixels; | |
111 | ||
112 | /* The name of this image */ | |
113 | SCM name; | |
114 | ||
115 | /* A function to call when this image is | |
116 | modified, e.g., to update the screen, | |
117 | or SCM_BOOL_F if no action necessary */ | |
118 | SCM update_func; | |
119 | @}; | |
120 | ||
121 | static scm_t_bits image_tag; | |
122 | ||
123 | void | |
124 | init_image_type (void) | |
125 | @{ | |
126 | image_tag = scm_make_smob_type ("image", sizeof (struct image)); | |
127 | scm_set_smob_mark (image_tag, mark_image); | |
128 | scm_set_smob_free (image_tag, free_image); | |
129 | scm_set_smob_print (image_tag, print_image); | |
130 | @} | |
131 | @end example | |
132 | ||
133 | ||
eb12b401 NJ |
134 | @node Creating Smob Instances |
135 | @subsection Creating Smob Instances | |
3229f68b | 136 | |
818d24b5 MV |
137 | Normally, smobs can have one @emph{immediate} word of data. This word |
138 | stores either a pointer to an additional memory block that holds the | |
139 | real data, or it might hold the data itself when it fits. The word is | |
140 | large enough for a @code{SCM} value, a pointer to @code{void}, or an | |
141 | integer that fits into a @code{size_t} or @code{ssize_t}. | |
3229f68b MV |
142 | |
143 | You can also create smobs that have two or three immediate words, and | |
144 | when these words suffice to store all data, it is more efficient to use | |
145 | these super-sized smobs instead of using a normal smob plus a memory | |
146 | block. @xref{Double Smobs}, for their discussion. | |
147 | ||
fc038e5b MV |
148 | Guile provides functions for managing memory which are often helpful |
149 | when implementing smobs. @xref{Memory Blocks}. | |
150 | ||
3229f68b MV |
151 | To retrieve the immediate word of a smob, you use the macro |
152 | @code{SCM_SMOB_DATA}. It can be set with @code{SCM_SET_SMOB_DATA}. | |
153 | The 16 extra bits can be accessed with @code{SCM_SMOB_FLAGS} and | |
154 | @code{SCM_SET_SMOB_FLAGS}. | |
155 | ||
818d24b5 | 156 | The two macros @code{SCM_SMOB_DATA} and @code{SCM_SET_SMOB_DATA} treat |
fc038e5b MV |
157 | the immediate word as if it were of type @code{scm_t_bits}, which is |
158 | an unsigned integer type large enough to hold a pointer to | |
159 | @code{void}. Thus you can use these macros to store arbitrary | |
160 | pointers in the smob word. | |
161 | ||
162 | When you want to store a @code{SCM} value directly in the immediate | |
163 | word of a smob, you should use the macros @code{SCM_SMOB_OBJECT} and | |
164 | @code{SCM_SET_SMOB_OBJECT} to access it. | |
3229f68b MV |
165 | |
166 | Creating a smob instance can be tricky when it consists of multiple | |
167 | steps that allocate resources and might fail. It is recommended that | |
168 | you go about creating a smob in the following way: | |
169 | ||
170 | @itemize | |
171 | @item | |
172 | Allocate the memory block for holding the data with | |
173 | @code{scm_gc_malloc}. | |
174 | @item | |
175 | Initialize it to a valid state without calling any functions that might | |
176 | cause a non-local exits. For example, initialize pointers to NULL. | |
177 | Also, do not store @code{SCM} values in it that must be protected. | |
178 | Initialize these fields with @code{SCM_BOOL_F}. | |
179 | ||
180 | A valid state is one that can be safely acted upon by the @emph{mark} | |
181 | and @emph{free} functions of your smob type. | |
182 | @item | |
183 | Create the smob using @code{SCM_NEWSMOB}, passing it the initialized | |
184 | memory block. (This step will always succeed.) | |
185 | @item | |
186 | Complete the initialization of the memory block by, for example, | |
187 | allocating additional resources and making it point to them. | |
188 | @end itemize | |
189 | ||
fc038e5b MV |
190 | This procedure ensures that the smob is in a valid state as soon as it |
191 | exists, that all resources that are allocated for the smob are | |
192 | properly associated with it so that they can be properly freed, and | |
193 | that no @code{SCM} values that need to be protected are stored in it | |
72b3aa56 | 194 | while the smob does not yet completely exist and thus can not protect |
fc038e5b | 195 | them. |
3229f68b MV |
196 | |
197 | Continuing the example from above, if the global variable | |
198 | @code{image_tag} contains a tag returned by @code{scm_make_smob_type}, | |
199 | here is how we could construct a smob whose immediate word contains a | |
200 | pointer to a freshly allocated @code{struct image}: | |
201 | ||
202 | @example | |
203 | SCM | |
204 | make_image (SCM name, SCM s_width, SCM s_height) | |
205 | @{ | |
206 | SCM smob; | |
207 | struct image *image; | |
208 | int width = scm_to_int (s_width); | |
209 | int height = scm_to_int (s_height); | |
210 | ||
211 | /* Step 1: Allocate the memory block. | |
212 | */ | |
45867c2a NJ |
213 | image = (struct image *) |
214 | scm_gc_malloc (sizeof (struct image), "image"); | |
3229f68b MV |
215 | |
216 | /* Step 2: Initialize it with straight code. | |
217 | */ | |
218 | image->width = width; | |
219 | image->height = height; | |
220 | image->pixels = NULL; | |
221 | image->name = SCM_BOOL_F; | |
222 | image->update_func = SCM_BOOL_F; | |
223 | ||
224 | /* Step 3: Create the smob. | |
225 | */ | |
818d24b5 | 226 | SCM_NEWSMOB (smob, image_tag, image); |
3229f68b MV |
227 | |
228 | /* Step 4: Finish the initialization. | |
229 | */ | |
230 | image->name = name; | |
45867c2a NJ |
231 | image->pixels = |
232 | scm_gc_malloc (width * height, "image pixels"); | |
3229f68b MV |
233 | |
234 | return smob; | |
235 | @} | |
236 | @end example | |
237 | ||
238 | Let us look at what might happen when @code{make_image} is called. | |
239 | ||
240 | The conversions of @var{s_width} and @var{s_height} to @code{int}s might | |
241 | fail and signal an error, thus causing a non-local exit. This is not a | |
242 | problem since no resources have been allocated yet that would have to be | |
243 | freed. | |
244 | ||
245 | The allocation of @var{image} in step 1 might fail, but this is likewise | |
246 | no problem. | |
247 | ||
248 | Step 2 can not exit non-locally. At the end of it, the @var{image} | |
249 | struct is in a valid state for the @code{mark_image} and | |
250 | @code{free_image} functions (see below). | |
251 | ||
252 | Step 3 can not exit non-locally either. This is guaranteed by Guile. | |
253 | After it, @var{smob} contains a valid smob that is properly initialized | |
254 | and protected, and in turn can properly protect the Scheme values in its | |
255 | @var{image} struct. | |
256 | ||
257 | But before the smob is completely created, @code{SCM_NEWSMOB} might | |
258 | cause the garbage collector to run. During this garbage collection, the | |
259 | @code{SCM} values in the @var{image} struct would be invisible to Guile. | |
260 | It only gets to know about them via the @code{mark_image} function, but | |
261 | that function can not yet do its job since the smob has not been created | |
262 | yet. Thus, it is important to not store @code{SCM} values in the | |
263 | @var{image} struct until after the smob has been created. | |
264 | ||
265 | Step 4, finally, might fail and cause a non-local exit. In that case, | |
fc038e5b MV |
266 | the complete creation of the smob has not been successful, but it does |
267 | nevertheless exist in a valid state. It will eventually be freed by | |
268 | the garbage collector, and all the resources that have been allocated | |
269 | for it will be correctly freed by @code{free_image}. | |
3229f68b MV |
270 | |
271 | @node Type checking | |
272 | @subsection Type checking | |
273 | ||
818d24b5 MV |
274 | Functions that operate on smobs should check that the passed |
275 | @code{SCM} value indeed is a suitable smob before accessing its data. | |
276 | They can do this with @code{scm_assert_smob_type}. | |
3229f68b MV |
277 | |
278 | For example, here is a simple function that operates on an image smob, | |
279 | and checks the type of its argument. | |
280 | ||
281 | @example | |
282 | SCM | |
283 | clear_image (SCM image_smob) | |
284 | @{ | |
285 | int area; | |
286 | struct image *image; | |
287 | ||
818d24b5 | 288 | scm_assert_smob_type (image_tag, image_smob); |
3229f68b MV |
289 | |
290 | image = (struct image *) SCM_SMOB_DATA (image_smob); | |
291 | area = image->width * image->height; | |
292 | memset (image->pixels, 0, area); | |
293 | ||
294 | /* Invoke the image's update function. | |
295 | */ | |
296 | if (scm_is_true (image->update_func)) | |
297 | scm_call_0 (image->update_func); | |
298 | ||
299 | scm_remember_upto_here_1 (image_smob); | |
300 | ||
301 | return SCM_UNSPECIFIED; | |
302 | @} | |
303 | @end example | |
304 | ||
305 | See @ref{Remembering During Operations} for an explanation of the call | |
306 | to @code{scm_remember_upto_here_1}. | |
307 | ||
308 | ||
309 | @node Garbage Collecting Smobs | |
310 | @subsection Garbage Collecting Smobs | |
311 | ||
312 | Once a smob has been released to the tender mercies of the Scheme | |
313 | system, it must be prepared to survive garbage collection. Guile calls | |
314 | the @emph{mark} and @emph{free} functions of the smob to manage this. | |
315 | ||
316 | As described in more detail elsewhere (@pxref{Conservative GC}), every | |
317 | object in the Scheme system has a @dfn{mark bit}, which the garbage | |
318 | collector uses to tell live objects from dead ones. When collection | |
319 | starts, every object's mark bit is clear. The collector traces pointers | |
320 | through the heap, starting from objects known to be live, and sets the | |
321 | mark bit on each object it encounters. When it can find no more | |
322 | unmarked objects, the collector walks all objects, live and dead, frees | |
323 | those whose mark bits are still clear, and clears the mark bit on the | |
324 | others. | |
325 | ||
326 | The two main portions of the collection are called the @dfn{mark phase}, | |
327 | during which the collector marks live objects, and the @dfn{sweep | |
328 | phase}, during which the collector frees all unmarked objects. | |
329 | ||
330 | The mark bit of a smob lives in a special memory region. When the | |
331 | collector encounters a smob, it sets the smob's mark bit, and uses the | |
332 | smob's type tag to find the appropriate @emph{mark} function for that | |
333 | smob. It then calls this @emph{mark} function, passing it the smob as | |
334 | its only argument. | |
335 | ||
336 | The @emph{mark} function is responsible for marking any other Scheme | |
337 | objects the smob refers to. If it does not do so, the objects' mark | |
338 | bits will still be clear when the collector begins to sweep, and the | |
339 | collector will free them. If this occurs, it will probably break, or at | |
340 | least confuse, any code operating on the smob; the smob's @code{SCM} | |
341 | values will have become dangling references. | |
342 | ||
343 | To mark an arbitrary Scheme object, the @emph{mark} function calls | |
344 | @code{scm_gc_mark}. | |
345 | ||
346 | Thus, here is how we might write @code{mark_image}: | |
347 | ||
348 | @example | |
349 | @group | |
350 | SCM | |
351 | mark_image (SCM image_smob) | |
352 | @{ | |
353 | /* Mark the image's name and update function. */ | |
354 | struct image *image = (struct image *) SCM_SMOB_DATA (image_smob); | |
355 | ||
356 | scm_gc_mark (image->name); | |
357 | scm_gc_mark (image->update_func); | |
358 | ||
359 | return SCM_BOOL_F; | |
360 | @} | |
361 | @end group | |
362 | @end example | |
363 | ||
364 | Note that, even though the image's @code{update_func} could be an | |
365 | arbitrarily complex structure (representing a procedure and any values | |
366 | enclosed in its environment), @code{scm_gc_mark} will recurse as | |
367 | necessary to mark all its components. Because @code{scm_gc_mark} sets | |
368 | an object's mark bit before it recurses, it is not confused by | |
369 | circular structures. | |
370 | ||
371 | As an optimization, the collector will mark whatever value is returned | |
372 | by the @emph{mark} function; this helps limit depth of recursion during | |
373 | the mark phase. Thus, the code above should really be written as: | |
374 | @example | |
375 | @group | |
376 | SCM | |
377 | mark_image (SCM image_smob) | |
378 | @{ | |
379 | /* Mark the image's name and update function. */ | |
380 | struct image *image = (struct image *) SCM_SMOB_DATA (image_smob); | |
381 | ||
382 | scm_gc_mark (image->name); | |
383 | return image->update_func; | |
384 | @} | |
385 | @end group | |
386 | @end example | |
387 | ||
388 | ||
389 | Finally, when the collector encounters an unmarked smob during the sweep | |
390 | phase, it uses the smob's tag to find the appropriate @emph{free} | |
391 | function for the smob. It then calls that function, passing it the smob | |
392 | as its only argument. | |
393 | ||
394 | The @emph{free} function must release any resources used by the smob. | |
395 | However, it must not free objects managed by the collector; the | |
396 | collector will take care of them. For historical reasons, the return | |
397 | type of the @emph{free} function should be @code{size_t}, an unsigned | |
398 | integral type; the @emph{free} function should always return zero. | |
399 | ||
400 | Here is how we might write the @code{free_image} function for the image | |
401 | smob type: | |
402 | @example | |
403 | size_t | |
404 | free_image (SCM image_smob) | |
405 | @{ | |
406 | struct image *image = (struct image *) SCM_SMOB_DATA (image_smob); | |
407 | ||
45867c2a NJ |
408 | scm_gc_free (image->pixels, |
409 | image->width * image->height, | |
410 | "image pixels"); | |
3229f68b MV |
411 | scm_gc_free (image, sizeof (struct image), "image"); |
412 | ||
413 | return 0; | |
414 | @} | |
415 | @end example | |
416 | ||
417 | During the sweep phase, the garbage collector will clear the mark bits | |
418 | on all live objects. The code which implements a smob need not do this | |
419 | itself. | |
420 | ||
421 | There is no way for smob code to be notified when collection is | |
422 | complete. | |
423 | ||
424 | It is usually a good idea to minimize the amount of processing done | |
425 | during garbage collection; keep the @emph{mark} and @emph{free} | |
426 | functions very simple. Since collections occur at unpredictable times, | |
427 | it is easy for any unusual activity to interfere with normal code. | |
428 | ||
429 | ||
430 | @node Garbage Collecting Simple Smobs | |
431 | @subsection Garbage Collecting Simple Smobs | |
432 | ||
433 | It is often useful to define very simple smob types --- smobs which have | |
434 | no data to mark, other than the cell itself, or smobs whose immediate | |
435 | data word is simply an ordinary Scheme object, to be marked recursively. | |
436 | Guile provides some functions to handle these common cases; you can use | |
437 | this function as your smob type's @emph{mark} function, if your smob's | |
438 | structure is simple enough. | |
439 | ||
440 | If the smob refers to no other Scheme objects, then no action is | |
441 | necessary; the garbage collector has already marked the smob cell | |
442 | itself. In that case, you can use zero as your mark function. | |
443 | ||
fc038e5b MV |
444 | If the smob refers to exactly one other Scheme object via its first |
445 | immediate word, you can use @code{scm_markcdr} as its mark function. | |
446 | Its definition is simply: | |
3229f68b | 447 | |
fc038e5b MV |
448 | @smallexample |
449 | SCM | |
450 | scm_markcdr (SCM obj) | |
451 | @{ | |
452 | return SCM_SMOB_OBJECT (obj); | |
453 | @} | |
454 | @end smallexample | |
3229f68b MV |
455 | |
456 | @node Remembering During Operations | |
457 | @subsection Remembering During Operations | |
1176df85 | 458 | @cindex remembering |
3229f68b MV |
459 | |
460 | It's important that a smob is visible to the garbage collector | |
461 | whenever its contents are being accessed. Otherwise it could be freed | |
462 | while code is still using it. | |
463 | ||
464 | For example, consider a procedure to convert image data to a list of | |
465 | pixel values. | |
466 | ||
467 | @example | |
468 | SCM | |
469 | image_to_list (SCM image_smob) | |
470 | @{ | |
471 | struct image *image; | |
472 | SCM lst; | |
473 | int i; | |
818d24b5 MV |
474 | |
475 | scm_assert_smob_type (image_tag, image_smob); | |
3229f68b MV |
476 | |
477 | image = (struct image *) SCM_SMOB_DATA (image_smob); | |
478 | lst = SCM_EOL; | |
479 | for (i = image->width * image->height - 1; i >= 0; i--) | |
480 | lst = scm_cons (scm_from_char (image->pixels[i]), lst); | |
481 | ||
482 | scm_remember_upto_here_1 (image_smob); | |
483 | return lst; | |
484 | @} | |
485 | @end example | |
486 | ||
487 | In the loop, only the @code{image} pointer is used and the C compiler | |
488 | has no reason to keep the @code{image_smob} value anywhere. If | |
489 | @code{scm_cons} results in a garbage collection, @code{image_smob} might | |
490 | not be on the stack or anywhere else and could be freed, leaving the | |
491 | loop accessing freed data. The use of @code{scm_remember_upto_here_1} | |
492 | prevents this, by creating a reference to @code{image_smob} after all | |
493 | data accesses. | |
494 | ||
495 | There's no need to do the same for @code{lst}, since that's the return | |
496 | value and the compiler will certainly keep it in a register or | |
497 | somewhere throughout the routine. | |
498 | ||
499 | The @code{clear_image} example previously shown (@pxref{Type checking}) | |
500 | also used @code{scm_remember_upto_here_1} for this reason. | |
501 | ||
502 | It's only in quite rare circumstances that a missing | |
503 | @code{scm_remember_upto_here_1} will bite, but when it happens the | |
504 | consequences are serious. Fortunately the rule is simple: whenever | |
505 | calling a Guile library function or doing something that might, ensure | |
fc038e5b | 506 | that the @code{SCM} of a smob is referenced past all accesses to its |
3229f68b MV |
507 | insides. Do this by adding an @code{scm_remember_upto_here_1} if |
508 | there are no other references. | |
509 | ||
510 | In a multi-threaded program, the rule is the same. As far as a given | |
511 | thread is concerned, a garbage collection still only occurs within a | |
512 | Guile library function, not at an arbitrary time. (Guile waits for all | |
513 | threads to reach one of its library functions, and holds them there | |
514 | while the collector runs.) | |
515 | ||
516 | @node Double Smobs | |
517 | @subsection Double Smobs | |
518 | ||
519 | Smobs are called smob because they are small: they normally have only | |
fc038e5b MV |
520 | room for one @code{void*} or @code{SCM} value plus 16 bits. The |
521 | reason for this is that smobs are directly implemented by using the | |
522 | low-level, two-word cells of Guile that are also used to implement | |
0f7e6c56 | 523 | pairs, for example. (@pxref{Data Representation} for the |
8680d53b AW |
524 | details.) One word of the two-word cells is used for |
525 | @code{SCM_SMOB_DATA} (or @code{SCM_SMOB_OBJECT}), the other contains | |
526 | the 16-bit type tag and the 16 extra bits. | |
3229f68b MV |
527 | |
528 | In addition to the fundamental two-word cells, Guile also has | |
529 | four-word cells, which are appropriately called @dfn{double cells}. | |
530 | You can use them for @dfn{double smobs} and get two more immediate | |
531 | words of type @code{scm_t_bits}. | |
532 | ||
533 | A double smob is created with @code{SCM_NEWSMOB2} or | |
534 | @code{SCM_NEWSMOB3} instead of @code{SCM_NEWSMOB}. Its immediate | |
fc038e5b MV |
535 | words can be retrieved as @code{scm_t_bits} with |
536 | @code{SCM_SMOB_DATA_2} and @code{SCM_SMOB_DATA_3} in addition to | |
537 | @code{SCM_SMOB_DATA}. Unsurprisingly, the words can be set to | |
538 | @code{scm_t_bits} values with @code{SCM_SET_SMOB_DATA_2} and | |
539 | @code{SCM_SET_SMOB_DATA_3}. | |
540 | ||
541 | Of course there are also @code{SCM_SMOB_OBJECT_2}, | |
542 | @code{SCM_SMOB_OBJECT_3}, @code{SCM_SET_SMOB_OBJECT_2}, and | |
543 | @code{SCM_SET_SMOB_OBJECT_3}. | |
3229f68b MV |
544 | |
545 | @node The Complete Example | |
546 | @subsection The Complete Example | |
547 | ||
548 | Here is the complete text of the implementation of the image datatype, | |
549 | as presented in the sections above. We also provide a definition for | |
550 | the smob's @emph{print} function, and make some objects and functions | |
551 | static, to clarify exactly what the surrounding code is using. | |
552 | ||
553 | As mentioned above, you can find this code in the Guile distribution, in | |
554 | @file{doc/example-smob}. That directory includes a makefile and a | |
555 | suitable @code{main} function, so you can build a complete interactive | |
556 | Guile shell, extended with the datatypes described here.) | |
557 | ||
558 | @example | |
559 | /* file "image-type.c" */ | |
560 | ||
561 | #include <stdlib.h> | |
562 | #include <libguile.h> | |
563 | ||
564 | static scm_t_bits image_tag; | |
565 | ||
566 | struct image @{ | |
567 | int width, height; | |
568 | char *pixels; | |
569 | ||
570 | /* The name of this image */ | |
571 | SCM name; | |
572 | ||
573 | /* A function to call when this image is | |
574 | modified, e.g., to update the screen, | |
575 | or SCM_BOOL_F if no action necessary */ | |
576 | SCM update_func; | |
577 | @}; | |
578 | ||
579 | static SCM | |
580 | make_image (SCM name, SCM s_width, SCM s_height) | |
581 | @{ | |
582 | SCM smob; | |
583 | struct image *image; | |
584 | int width = scm_to_int (s_width); | |
585 | int height = scm_to_int (s_height); | |
586 | ||
587 | /* Step 1: Allocate the memory block. | |
588 | */ | |
45867c2a NJ |
589 | image = (struct image *) |
590 | scm_gc_malloc (sizeof (struct image), "image"); | |
3229f68b MV |
591 | |
592 | /* Step 2: Initialize it with straight code. | |
593 | */ | |
594 | image->width = width; | |
595 | image->height = height; | |
596 | image->pixels = NULL; | |
597 | image->name = SCM_BOOL_F; | |
598 | image->update_func = SCM_BOOL_F; | |
599 | ||
600 | /* Step 3: Create the smob. | |
601 | */ | |
818d24b5 | 602 | SCM_NEWSMOB (smob, image_tag, image); |
3229f68b MV |
603 | |
604 | /* Step 4: Finish the initialization. | |
605 | */ | |
606 | image->name = name; | |
45867c2a NJ |
607 | image->pixels = |
608 | scm_gc_malloc (width * height, "image pixels"); | |
3229f68b MV |
609 | |
610 | return smob; | |
611 | @} | |
612 | ||
613 | SCM | |
614 | clear_image (SCM image_smob) | |
615 | @{ | |
616 | int area; | |
617 | struct image *image; | |
618 | ||
818d24b5 | 619 | scm_assert_smob_type (image_tag, image_smob); |
3229f68b MV |
620 | |
621 | image = (struct image *) SCM_SMOB_DATA (image_smob); | |
622 | area = image->width * image->height; | |
623 | memset (image->pixels, 0, area); | |
624 | ||
625 | /* Invoke the image's update function. | |
626 | */ | |
627 | if (scm_is_true (image->update_func)) | |
628 | scm_call_0 (image->update_func); | |
629 | ||
630 | scm_remember_upto_here_1 (image_smob); | |
631 | ||
632 | return SCM_UNSPECIFIED; | |
633 | @} | |
634 | ||
635 | static SCM | |
636 | mark_image (SCM image_smob) | |
637 | @{ | |
638 | /* Mark the image's name and update function. */ | |
639 | struct image *image = (struct image *) SCM_SMOB_DATA (image_smob); | |
640 | ||
641 | scm_gc_mark (image->name); | |
642 | return image->update_func; | |
643 | @} | |
644 | ||
645 | static size_t | |
646 | free_image (SCM image_smob) | |
647 | @{ | |
648 | struct image *image = (struct image *) SCM_SMOB_DATA (image_smob); | |
649 | ||
45867c2a NJ |
650 | scm_gc_free (image->pixels, |
651 | image->width * image->height, | |
652 | "image pixels"); | |
3229f68b MV |
653 | scm_gc_free (image, sizeof (struct image), "image"); |
654 | ||
655 | return 0; | |
656 | @} | |
657 | ||
658 | static int | |
659 | print_image (SCM image_smob, SCM port, scm_print_state *pstate) | |
660 | @{ | |
661 | struct image *image = (struct image *) SCM_SMOB_DATA (image_smob); | |
662 | ||
663 | scm_puts ("#<image ", port); | |
664 | scm_display (image->name, port); | |
665 | scm_puts (">", port); | |
666 | ||
667 | /* non-zero means success */ | |
668 | return 1; | |
669 | @} | |
670 | ||
671 | void | |
672 | init_image_type (void) | |
673 | @{ | |
674 | image_tag = scm_make_smob_type ("image", sizeof (struct image)); | |
675 | scm_set_smob_mark (image_tag, mark_image); | |
676 | scm_set_smob_free (image_tag, free_image); | |
677 | scm_set_smob_print (image_tag, print_image); | |
678 | ||
679 | scm_c_define_gsubr ("clear-image", 1, 0, 0, clear_image); | |
680 | scm_c_define_gsubr ("make-image", 3, 0, 0, make_image); | |
681 | @} | |
682 | @end example | |
683 | ||
684 | Here is a sample build and interaction with the code from the | |
685 | @file{example-smob} directory, on the author's machine: | |
686 | ||
687 | @example | |
688 | zwingli:example-smob$ make CC=gcc | |
097a793b AW |
689 | gcc `pkg-config --cflags guile-@value{EFFECTIVE-VERSION}` -c image-type.c -o image-type.o |
690 | gcc `pkg-config --cflags guile-@value{EFFECTIVE-VERSION}` -c myguile.c -o myguile.o | |
691 | gcc image-type.o myguile.o `pkg-config --libs guile-@value{EFFECTIVE-VERSION}` -o myguile | |
3229f68b MV |
692 | zwingli:example-smob$ ./myguile |
693 | guile> make-image | |
694 | #<primitive-procedure make-image> | |
695 | guile> (define i (make-image "Whistler's Mother" 100 100)) | |
696 | guile> i | |
697 | #<image Whistler's Mother> | |
698 | guile> (clear-image i) | |
699 | guile> (clear-image 4) | |
700 | ERROR: In procedure clear-image in expression (clear-image 4): | |
48d8f659 | 701 | ERROR: Wrong type (expecting image): 4 |
3229f68b MV |
702 | ABORT: (wrong-type-arg) |
703 | ||
704 | Type "(backtrace)" to get more information. | |
705 | guile> | |
706 | @end example |