]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/smobs.hh
Issue 4400: Rework LY_DECLARE_SMOB_PROC to declare a member function
[lilypond.git] / lily / include / smobs.hh
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef SMOBS_HH
21 #define SMOBS_HH
22
23 #include "lily-guile.hh"
24 #include "lily-proto.hh"
25 #include "warn.hh"
26 #include <string>
27
28 /*
29   Smobs are GUILEs mechanism of exporting C(++) objects to the Scheme
30   world.  They are documented in the GUILE manual.
31
32
33   In LilyPond, C++ objects can be placed under the control of GUILE's
34   type system and garbage collection mechanism by inheriting from one
35   of several Smob base classes.
36
37   There are two types of smob objects.
38
39   1. Simple smobs are intended for simple objects like numbers:
40   immutable objects that can be copied without change of meaning.
41
42   To obtain an SCM version of a simple smob, use the member function
43   SCM smobbed_copy ().
44
45   Simple smobs are created by deriving from Simple_smob<Classname>.
46
47   A simple smob is only optionally under the reign of the GUILE
48   garbage collector: its usual life time is that of a normal C++
49   object.  While a smobbed_copy () is fully under control of the
50   garbage collector and will have its mark_smob function called during
51   garbage collection, an automatic variable of this type will not have
52   mark_smob called, but rather have its memory image in the call stack
53   scanned for contained non-immediate SCM values.  Anything requiring
54   more complex mark_smob behavior is not suitable for a simple smob.
55
56   When you create a smobbed_copy, the _copy_ is fully managed by the
57   GUILE memory system.  As a corollary, multiple smobbed_copy calls
58   yield multiple GUILE objects generally not eq? to each other.
59
60   2. Complex smobs are objects that have an identity. These objects
61   carry this identity in the form of a self_scm () method, which is a
62   SCM pointer to the object itself.  Complex smobs are always under
63   control of the GUILE memory system.
64
65   The constructor for a complex smob should have 3 steps:
66
67   * initialize all SCM members to an immediate value (like SCM_EOL)
68
69   * call smobify_self ()
70
71   * initialize SCM members
72
73   For example,
74
75   Complex_smob::Complex_smob : public Smob<Complex_smob> () {
76   scm_member_ = SCM_EOL;
77   smobify_self ();
78   scm_member_ = <..what you want to store..>
79   }
80
81   after construction, the self_scm () field of a complex smob is
82   protected from Garbage Collection.  This protection should be
83   removed once the object is put into another (reachable) Scheme data
84   structure, i.e.
85
86   Complex_smob *p = new Complex_smob;
87   list = scm_cons (p->self_scm (), list);
88   p->unprotect ();
89
90   Since unprotect returns the SCM object itself, this particular case
91   can be written as
92
93   Complex_smob *p = new Complex_smob;
94   list = scm_cons (p->unprotect (), list);
95
96   Complex smobs are created by deriving from Smob<Classname>.
97
98   CALLING INTERFACE
99
100   Common public methods to C++ smob objects:
101
102   - unsmob (SCM x) - unpacks X and returns pointer to the C++ object,
103     or 0 if it has the wrong type.  This can be used as a boolean
104     condition at C++ level.
105   - smob_p (SCM x) returns #t or #f at Scheme level.
106
107   IMPLEMENTATION
108
109   For implementating a class, the following public members can be
110   provided in the top class itself:
111
112   - SCM equal_p (SCM a, SCM b) - compare A and B. Returns a Scheme
113     boolean.  If the class does not define this function, equal? will
114     be equivalent to eq?.  The function will only be called when both
115     objects are of the respective type and not eq? to each other.
116
117   - mark_smob () function, that calls scm_gc_mark () on all Scheme
118     objects in the class.  If the class does not define this function,
119     it must not contain non-immediate Scheme values.
120
121   - a print_smob () function, that displays a representation for
122     debugging purposes.  If the class does not define this function,
123     the output will be #<Classname> when printing.
124
125   - a static const type_p_name_[] string set to something like
126     "ly:grob?".  When provided, an accordingly named function for
127     checking for the given smob type will be available in Scheme.
128
129 */
130
131 // Initialization class.  Create a variable or static data member of
132 // this type at global scope (or creation will happen too late for
133 // Scheme initialization), initialising with a function to be called.
134 // Reference somewhere (like in the constructor of the containing
135 // class) to make sure the variable is actually instantiated.
136
137 class Scm_init {
138   static const Scm_init * list_;
139   void (*const fun_)(void);
140   Scm_init const * const next_;
141   Scm_init ();          // don't use default constructor, don't define
142   Scm_init (const Scm_init &);  // don't define copy constructor
143 public:
144   Scm_init (void (*fun) (void)) : fun_ (fun), next_ (list_)
145   { list_ = this; }
146   static void init ();
147 };
148
149 template <class Super>
150 class Smob_base
151 {
152   static scm_t_bits smob_tag_;
153   static Scm_init scm_init_;
154   static void init (void);
155   static string smob_name_;
156   static Super *unchecked_unsmob (SCM s)
157   {
158     return reinterpret_cast<Super *> (SCM_SMOB_DATA (s));
159   }
160 protected:
161   // reference scm_init_ in smob_tag which is sure to be called.  The
162   // constructor, in contrast, may not be called at all in classes
163   // like Smob1.
164   static scm_t_bits smob_tag () { (void) scm_init_; return smob_tag_; }
165   Smob_base () { }
166   static SCM register_ptr (Super *p);
167   static Super *unregister_ptr (SCM obj);
168 private:
169   // Those fallbacks are _only_ for internal use by Smob_base.  They
170   // are characterized by no knowledge about the implemented type
171   // apart from the type's name.  Overriding them as a template
172   // specialization is _not_ intended since a type-dependent
173   // implementation will in general need access to possibly private
174   // parts of the Super class.  So any class-dependent override should
175   // be done by redefining the respective function in the Super class
176   // (where it will mask the private template member) rather than
177   // specializing a different template function/pointer.
178   //
179   // Most default functions are do-nothings.  void init() will
180   // recognize their address when not overriden and will then refrain
181   // altogether from passing the the respective callbacks to GUILE.
182   SCM mark_smob (void);
183   static SCM mark_trampoline (SCM); // Used for calling mark_smob
184   static size_t free_smob (SCM obj);
185   static SCM equal_p (SCM, SCM);
186   int print_smob (SCM, scm_print_state *);
187   static int print_trampoline (SCM, SCM, scm_print_state *);
188   static void smob_proc_init (scm_t_bits) { };
189
190   // type_p_name_ can be overriden in the Super class with a static
191   // const char [] string.  This requires both a declaration in the
192   // class as well as a single instantiation outside.  Using a
193   // template specialization for supplying a different string name
194   // right in Smob_base<Super> itself seems tempting, but the C++
195   // rules would then require a specialization declaration at the
196   // class definition site as well as a specialization instantiation
197   // in a single compilation unit.  That requires just as much source
198   // code maintenance while being harder to understand and quite
199   // trickier in its failure symptoms when things go wrong.  So we
200   // just use a static zero as "not here" indication.
201   static const int type_p_name_ = 0;
202
203   // LY_DECLARE_SMOB_PROC is used in the Super class definition for
204   // making a smob callable like a function.  Its first argument is a
205   // function member pointer constant, to a function taking the
206   // correct number of SCM arguments and returning SCM.  The function
207   // itself has to be defined separately.
208
209 #define LY_DECLARE_SMOB_PROC(PMF, REQ, OPT, VAR)                        \
210   static void smob_proc_init (scm_t_bits smob_tag)                      \
211   {                                                                     \
212     scm_set_smob_apply (smob_tag,                                       \
213                         (scm_t_subr)smob_trampoline<PMF>,               \
214                         REQ, OPT, VAR);                                 \
215   }
216
217   // Well, function template argument packs are a C++11 feature.  So
218   // we just define a bunch of trampolines manually.
219   template <SCM (Super::*pmf)(void)>
220   static SCM smob_trampoline (SCM self)
221   {
222     return (Super::unchecked_unsmob (self)->*pmf)();
223   }
224   template <SCM (Super::*pmf)(SCM)>
225   static SCM smob_trampoline (SCM self, SCM arg1)
226   {
227     return (Super::unchecked_unsmob (self)->*pmf)(arg1);
228   }
229   template <SCM (Super::*pmf)(SCM, SCM)>
230   static SCM smob_trampoline (SCM self, SCM arg1, SCM arg2)
231   {
232     return (Super::unchecked_unsmob (self)->*pmf)(arg1, arg2);
233   }
234   template <SCM (Super::*pmf)(SCM, SCM, SCM)>
235   static SCM smob_trampoline (SCM self, SCM arg1, SCM arg2, SCM arg3)
236   {
237     return (Super::unchecked_unsmob (self)->*pmf)(arg1, arg2, arg3);
238   }
239
240 public:
241   static bool is_smob (SCM s)
242   {
243     return SCM_SMOB_PREDICATE (smob_tag (), s);
244   }
245   static SCM smob_p (SCM s)
246   {
247     return is_smob (s) ? SCM_BOOL_T : SCM_BOOL_F;
248   }
249   static Super *unsmob (SCM s)
250   {
251     return is_smob (s) ? Super::unchecked_unsmob (s) : 0;
252   }
253 };
254
255 // derived_unsmob includes a dynamic_cast:
256
257 template <class T>
258 inline T *derived_unsmob (SCM arg)
259 {
260   return dynamic_cast<T *> (T::unsmob (arg));
261 }
262
263 // Simple smobs
264 template <class Super>
265 class Simple_smob : public Smob_base<Super> {
266 public:
267   static size_t free_smob (SCM obj)
268   {
269     delete Smob_base<Super>::unregister_ptr (obj);
270     return 0;
271   }
272   SCM smobbed_copy () const
273   {
274     Super *p = new Super(*static_cast<const Super *> (this));
275     return Smob_base<Super>::register_ptr (p);
276   }
277 };
278
279 void protect_smob (SCM smob, SCM *prot_cons);
280 void unprotect_smob (SCM smob, SCM *prot_cons);
281
282 // The Smob_core class is not templated and contains material not
283 // depending on the Super class.
284
285 class Smob_core {
286 protected:
287   SCM self_scm_;
288   Smob_core () : self_scm_ (SCM_UNDEFINED) { };
289 public:
290   SCM self_scm () const { return self_scm_; }
291   Listener get_listener (SCM callback);
292 };
293
294 template <class Super>
295 class Smob : public Smob_core, public Smob_base<Super> {
296 private:
297   SCM protection_cons_;
298   Smob (const Smob<Super> &); // Do not define!  Not copyable!
299 protected:
300   Smob () : protection_cons_ (SCM_EOL) { };
301 public:
302   static size_t free_smob (SCM obj)
303   {
304     delete Smob_base<Super>::unregister_ptr (obj);
305     return 0;
306   }
307   SCM unprotected_smobify_self ()
308   {
309     SCM s = Smob_base<Super>::register_ptr (static_cast<Super *> (this));
310     self_scm_ = s;
311     return s;
312   }
313   void protect ()
314   {
315     protect_smob (self_scm_, &protection_cons_);
316   }
317   void smobify_self () {
318     protect_smob (unprotected_smobify_self (), &protection_cons_);
319   }
320   SCM unprotect ()
321   {
322     SCM s = self_scm_;
323     unprotect_smob (s, &protection_cons_);
324     return s;
325   }
326 };
327
328 extern bool parsed_objects_should_be_dead;
329 class parsed_dead
330 {
331   static vector<parsed_dead *> elements;
332   SCM data;
333   SCM readout_one ()
334   {
335     SCM res = data;
336     data = SCM_UNDEFINED;
337     return res;
338   }
339 public:
340   parsed_dead () : data (SCM_UNDEFINED)
341   {
342     elements.push_back (this);
343   }
344   void checkin (SCM arg) { data = arg; }
345   static SCM readout ();
346 };
347
348 // This does not appear to work with GUILEv2's garbage collector:
349 // Objects are found in the GC phase but printing them will crash at
350 // least some, so they are apparently not protected in spite of being
351 // included in the GC scans.  So it would appear that scanning smobs
352 // is not equivalent to marking them.  Ugh.
353 #if defined(DEBUG) && !GUILEV2
354 #define ASSERT_LIVE_IS_ALLOWED(arg)                                     \
355   do {                                                                  \
356     static parsed_dead pass_here;                                       \
357     if (parsed_objects_should_be_dead)                                  \
358       pass_here.checkin (arg);                                          \
359   } while (0)
360 #else
361 #define ASSERT_LIVE_IS_ALLOWED(arg) do { (void)(arg); }  \
362   while (0)
363 #endif
364
365 #include "smobs.tcc"
366 #endif /* SMOBS_HH */