/[cffi-objects]/freeable.lisp
ViewVC logotype

Contents of /freeable.lisp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (hide annotations)
Sat Jan 12 21:26:46 2013 UTC (15 months, 1 week ago) by rklochkov
File size: 7445 byte(s)
Added support for MESSAGE-OO and (lisp-name . c-name) syntax for structure fields
1 rklochkov 13 ;;;;<author>Roman Klochkov, monk@slavsoft.surgut.ru</author>
2     ;;;; Base classes for freeable and changeable CFFI types
3 rklochkov 1
4 rklochkov 13 (in-package #:cffi-objects)
5 rklochkov 1
6 rklochkov 13 ;;;[ [[* Memory freeing automation *]]
7    
8     #|<doc>
9     Most of new CFFI types introduced in my library will live in the dynamic
10     memory. There are different policies of memory control in different languages
11     and libraries. Sometimes caller should clean memory (like in GTK), sometimes
12     callee.
13    
14     In any case programmer should have possibility to say, if he would
15     like to free memory after function call. For example, in GTK it is common
16     for callback to return a newly-allocated string or structure, but in
17     parameters responsibility to clean memory remains to caller.
18    
19     Another common option for any type is a flag, that it is out-paramter,
20     so value of it should be translated back before freeing,
21    
22     For uniformity with CFFI :string I chose :free-from-foreign and
23     :free-to-foreign boolean flags to show, when we want to free memory. By default
24     "caller frees" model is used.
25     |#
26    
27     ;;;[ <class freeable-base>
28    
29     #|<doc> I divided freeable functional to two classes:
30     \begin{itemize}
31     \item [[freeable-base]] introduces all necessary fields and handlers
32     \item [[freeable]] have ready cffi-translator methods
33 rklochkov 18 \end{itemize}
34 rklochkov 13 |#
35    
36 rklochkov 1 (define-foreign-type freeable-base ()
37 rklochkov 13 ;; Should we free after translating from foreign?
38     ((free-from-foreign :initarg :free-from-foreign
39 rklochkov 8 :reader fst-free-from-foreign-p
40     :initform nil :type boolean)
41     ;; Should we free after translating to foreign?
42 rklochkov 13 (free-to-foreign :initarg :free-to-foreign
43     :reader fst-free-to-foreign-p
44     :initform t :type boolean)))
45 rklochkov 1
46 rklochkov 13 #|<doc>
47     Interface to [[freeable-base]] consists of three generics for describing,
48     how to free particular type: [[free-ptr]], [[free-sent-ptr]] and
49     [[free-returned-ptr]], and two functions to use in CFFI translators:
50     [[free-returned-if-needed]] and [[free-sent-if-needed]].
51     |#
52 rklochkov 8
53 rklochkov 13 ;;;[ <generic free-ptr (type ptr)>
54    
55     #|<doc>
56     This generic describes, how to free an object with CFFI type [[type]] and
57     pointer [[ptr]]. As [[type]] should be a symbol, you should specialize
58     this generic with EQL specifier if your objects shouldn't be freed with
59 rklochkov 18 [[foreign-free]].
60 rklochkov 13
61 rklochkov 18 One can ask, why normal specializer by type of object and [[object]] as
62 rklochkov 13 a first parameter is not used. Such strange API is developed,
63     because [[free-ptr]] is used in [[trivial-garbage:finalize]] and in some
64     implementation (for example, SBCL) finalizer shouldn't have reference
65     to finalized object.
66    
67     If you dislike it and you will not use finalizers, simply specialize or
68     redefine [[free-sent-ptr]] and [[free-returned-ptr]]
69     |#
70    
71 rklochkov 1 (defgeneric free-ptr (type ptr)
72 rklochkov 5 (:documentation "Called to free ptr, unless overriden free-sent-ptr
73 rklochkov 18 or free-returned-ptr. TYPE should be symbol and be specialized with EQL")
74 rklochkov 13 (:method (type ptr) (foreign-free ptr)))
75 rklochkov 1
76 rklochkov 13 ;;;[ <generic free-sent-ptr>
77    
78 rklochkov 18 #|<doc>
79     This generic describes, how to free an object with CFFI type [[type]] and
80     pointer [[ptr]] after sending to foreign space. It has the same parameters
81     as [[cffi:free-translated-object]]. If complex foreign type has additional
82     conditionals or any additional actions when freeing, specialize it on you type.
83    
84     Please, don't call it directly. Use [[free-sent-if-needed]] instead.
85     |#
86    
87 rklochkov 9 (defgeneric free-sent-ptr (cffi-type ptr param)
88 rklochkov 18 (:documentation "Will be called in free-translated-object.
89     CFFI-TYPE: type defined with define-foreign-type.
90     PTR: foreign pointer
91     PARAM: third parameter of free-translated-object ==
92     returned second value of translate-to-foreign.")
93 rklochkov 9 (:method ((cffi-type freeable-base) ptr param)
94 rklochkov 4 (unless (null-pointer-p ptr)
95 rklochkov 9 (free-ptr (type-of cffi-type) ptr))))
96 rklochkov 1
97 rklochkov 13 ;;;[ <generic free-returned-ptr>
98    
99 rklochkov 18 #|<doc>
100     This generic describes, how to free an object with CFFI type [[type]] and
101     pointer [[ptr]] after receiving from foreign space. It has the same parameters
102     as [[cffi:translate-to-foreign]]. If complex foreign type has additional
103     conditionals or any additional actions when freeing, specialize it on you type.
104    
105     Please, don't call it directly. Use [[free-returned-if-needed]] instead.
106     |#
107    
108    
109 rklochkov 9 (defgeneric free-returned-ptr (cffi-type ptr)
110 rklochkov 18 (:documentation "Will be called in translate-from-foreign after conversion.
111     CFFI-TYPE: type defined with define-foreign-type.
112     PTR: foreign pointer")
113 rklochkov 9 (:method ((cffi-type freeable-base) ptr)
114 rklochkov 4 (unless (null-pointer-p ptr)
115 rklochkov 9 (free-ptr (type-of cffi-type) ptr))))
116 rklochkov 1
117 rklochkov 13 ;;;[ <function free-sent-if-needed
118    
119 rklochkov 9 (defun free-sent-if-needed (cffi-type ptr param)
120 rklochkov 18 "This function should be placed in appropriate place of
121     free-translated-object"
122 rklochkov 9 (when (fst-free-to-foreign-p cffi-type)
123     (free-sent-ptr cffi-type ptr param)))
124 rklochkov 1
125 rklochkov 13 ;;;[ <function free-returned-if-needed
126    
127 rklochkov 9 (defun free-returned-if-needed (cffi-type ptr)
128 rklochkov 18 "This function should be placed in appropriate place of
129     translate-from-foreign"
130 rklochkov 9 (when (fst-free-from-foreign-p cffi-type)
131     (free-returned-ptr cffi-type ptr)))
132 rklochkov 1
133 rklochkov 13 ;;;[ <class freeable>
134    
135 rklochkov 18 #|<doc>
136     This is standard base class for freeable pointers. If you happy with
137     default free algorithm, which implies, that [[free-sent-ptr]] is called after
138     [[free-translated-object]] when type described with [[:free-to-foreign t]]
139     and [[free-returned-ptr]] is called when type described with
140     [[:free-from-foreign t]] after [[translate-from-foreign]].
141    
142     If you need more complicated logic (for example, to free object in
143     translate-from-foreign, not after), you should inherit your class from
144     [[freeable-base]] and
145     call [[free-sent-if-needed]] from [[free-translated-object]]
146     and [[free-returned-if-needed]] from [[translate-from-foreign]].
147     |#
148    
149 rklochkov 1 (defclass freeable (freeable-base) ()
150     (:documentation "Mixing to auto-set translators"))
151    
152     (defmethod free-translated-object :after (ptr (type freeable) param)
153 rklochkov 5 (free-sent-if-needed type ptr param))
154 rklochkov 1
155     (defmethod translate-from-foreign :after (ptr (type freeable))
156     (free-returned-if-needed type ptr))
157    
158 rklochkov 13 ;;;[ <class freeable-out>
159    
160 rklochkov 18 #|<doc>
161     This is standard base class for objects, that should be copied back
162     to lisp after foreign function: so-called ``out parameters''.
163    
164     For every class, inherited from [[freeable-out]], you must
165     implement method [[copy-from-foreign]].
166    
167     Then user of your class may set [[:out t]] in initargs for your class
168     and be sure, that all changed data will be copied back to the variables.
169    
170     When implementing [[translate-to-foreign]] you must return (values ptr value),
171     because second value will be passed to [[free-translated-object]], and then
172     as PLACE to [[copy-from-foreign]].
173     |#
174    
175 rklochkov 1 (define-foreign-type freeable-out (freeable)
176 rklochkov 12 ((out :accessor object-out :initarg :out :initform nil
177 rklochkov 1 :documentation "This is out param (for fill in foreign side)"))
178     (:documentation "For returning data in out params.
179 rklochkov 12 If OUT is t, then translate-to-foreign MUST return (values ptr place)"))
180 rklochkov 1
181 rklochkov 18 ;;;[ <generic copy-from-foreign>
182 rklochkov 1
183 rklochkov 18 #|<doc>
184     This generic must have an implementation for every class inherited from [[freeable-out]].
185     |#
186    
187     (defgeneric copy-from-foreign (cffi-type ptr place)
188     (:documentation "Transfers data from pointer PTR to PLACE.
189     CFFI-TYPE: type defined with define-foreign-type.
190     PTR: foreign pointer
191     PLACE: third parameter of free-translated-object ==
192     returned second value of translate-to-foreign"))
193    
194 rklochkov 1 (defmethod free-translated-object :before (ptr (type freeable-out) place)
195     (when (object-out type)
196     (copy-from-foreign type ptr place)))

  ViewVC Help
Powered by ViewVC 1.1.5