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

Contents of /freeable.lisp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (show annotations)
Sat Jan 12 21:26:46 2013 UTC (15 months ago) by rklochkov
File size: 7445 byte(s)
Added support for MESSAGE-OO and (lisp-name . c-name) syntax for structure fields
1 ;;;;<author>Roman Klochkov, monk@slavsoft.surgut.ru</author>
2 ;;;; Base classes for freeable and changeable CFFI types
3
4 (in-package #:cffi-objects)
5
6 ;;;[ [[* 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 \end{itemize}
34 |#
35
36 (define-foreign-type freeable-base ()
37 ;; Should we free after translating from foreign?
38 ((free-from-foreign :initarg :free-from-foreign
39 :reader fst-free-from-foreign-p
40 :initform nil :type boolean)
41 ;; Should we free after translating to foreign?
42 (free-to-foreign :initarg :free-to-foreign
43 :reader fst-free-to-foreign-p
44 :initform t :type boolean)))
45
46 #|<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
53 ;;;[ <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 [[foreign-free]].
60
61 One can ask, why normal specializer by type of object and [[object]] as
62 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 (defgeneric free-ptr (type ptr)
72 (:documentation "Called to free ptr, unless overriden free-sent-ptr
73 or free-returned-ptr. TYPE should be symbol and be specialized with EQL")
74 (:method (type ptr) (foreign-free ptr)))
75
76 ;;;[ <generic free-sent-ptr>
77
78 #|<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 (defgeneric free-sent-ptr (cffi-type ptr param)
88 (: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 (:method ((cffi-type freeable-base) ptr param)
94 (unless (null-pointer-p ptr)
95 (free-ptr (type-of cffi-type) ptr))))
96
97 ;;;[ <generic free-returned-ptr>
98
99 #|<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 (defgeneric free-returned-ptr (cffi-type ptr)
110 (:documentation "Will be called in translate-from-foreign after conversion.
111 CFFI-TYPE: type defined with define-foreign-type.
112 PTR: foreign pointer")
113 (:method ((cffi-type freeable-base) ptr)
114 (unless (null-pointer-p ptr)
115 (free-ptr (type-of cffi-type) ptr))))
116
117 ;;;[ <function free-sent-if-needed
118
119 (defun free-sent-if-needed (cffi-type ptr param)
120 "This function should be placed in appropriate place of
121 free-translated-object"
122 (when (fst-free-to-foreign-p cffi-type)
123 (free-sent-ptr cffi-type ptr param)))
124
125 ;;;[ <function free-returned-if-needed
126
127 (defun free-returned-if-needed (cffi-type ptr)
128 "This function should be placed in appropriate place of
129 translate-from-foreign"
130 (when (fst-free-from-foreign-p cffi-type)
131 (free-returned-ptr cffi-type ptr)))
132
133 ;;;[ <class freeable>
134
135 #|<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 (defclass freeable (freeable-base) ()
150 (:documentation "Mixing to auto-set translators"))
151
152 (defmethod free-translated-object :after (ptr (type freeable) param)
153 (free-sent-if-needed type ptr param))
154
155 (defmethod translate-from-foreign :after (ptr (type freeable))
156 (free-returned-if-needed type ptr))
157
158 ;;;[ <class freeable-out>
159
160 #|<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 (define-foreign-type freeable-out (freeable)
176 ((out :accessor object-out :initarg :out :initform nil
177 :documentation "This is out param (for fill in foreign side)"))
178 (:documentation "For returning data in out params.
179 If OUT is t, then translate-to-foreign MUST return (values ptr place)"))
180
181 ;;;[ <generic copy-from-foreign>
182
183 #|<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 (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