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