]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/smobs.hh
Issue 4365: non-member unsmob<T> replaces T::unsmob and T::is_smob
[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 global functions for accessing C++ smob objects:
101
102   - unsmob<T> (SCM x) - unpack X and return a pointer to the C++ object,
103     or 0 if it has the wrong type.
104
105   IMPLEMENTATION
106
107   For implementating a class, the following public members can be
108   provided in the top class itself:
109
110   - SCM equal_p (SCM a, SCM b) - compare A and B. Returns a Scheme
111     boolean.  If the class does not define this function, equal? will
112     be equivalent to eq?.  The function will only be called when both
113     objects are of the respective type and not eq? to each other.
114
115   - mark_smob () function, that calls scm_gc_mark () on all Scheme
116     objects in the class.  If the class does not define this function,
117     it must not contain non-immediate Scheme values.
118
119   - a print_smob () function, that displays a representation for
120     debugging purposes.  If the class does not define this function,
121     the output will be #<Classname> when printing.
122
123   - a static const type_p_name_[] string set to something like
124     "ly:grob?".  When provided, an accordingly named function for
125     checking for the given smob type will be available in Scheme.
126
127 */
128
129 // Initialization class.  Create a variable or static data member of
130 // this type at global scope (or creation will happen too late for
131 // Scheme initialization), initialising with a function to be called.
132 // Reference somewhere (like in the constructor of the containing
133 // class) to make sure the variable is actually instantiated.
134
135 class Scm_init {
136   static const Scm_init * list_;
137   void (*const fun_)(void);
138   Scm_init const * const next_;
139   Scm_init ();          // don't use default constructor, don't define
140   Scm_init (const Scm_init &);  // don't define copy constructor
141 public:
142   Scm_init (void (*fun) (void)) : fun_ (fun), next_ (list_)
143   { list_ = this; }
144   static void init ();
145 };
146
147 template <class Super>
148 class Smob_base
149 {
150   static scm_t_bits smob_tag_;
151   static Scm_init scm_init_;
152   static void init (void);
153   static string smob_name_;
154 protected:
155   static Super *unchecked_unsmob (SCM s)
156   {
157     return reinterpret_cast<Super *> (SCM_SMOB_DATA (s));
158   }
159   // reference scm_init_ in smob_tag which is sure to be called.  The
160   // constructor, in contrast, may not be called at all in classes
161   // like Smob1.
162   static scm_t_bits smob_tag () { (void) scm_init_; return smob_tag_; }
163   Smob_base () { }
164   static SCM register_ptr (Super *p);
165   static Super *unregister_ptr (SCM obj);
166 private:
167   // Those fallbacks are _only_ for internal use by Smob_base.  They
168   // are characterized by no knowledge about the implemented type
169   // apart from the type's name.  Overriding them as a template
170   // specialization is _not_ intended since a type-dependent
171   // implementation will in general need access to possibly private
172   // parts of the Super class.  So any class-dependent override should
173   // be done by redefining the respective function in the Super class
174   // (where it will mask the private template member) rather than
175   // specializing a different template function/pointer.
176   //
177   // Most default functions are do-nothings.  void init() will
178   // recognize their address when not overriden and will then refrain
179   // altogether from passing the the respective callbacks to GUILE.
180   SCM mark_smob (void);
181   static SCM mark_trampoline (SCM); // Used for calling mark_smob
182   static size_t free_smob (SCM obj);
183   static SCM equal_p (SCM, SCM);
184   int print_smob (SCM, scm_print_state *);
185   static int print_trampoline (SCM, SCM, scm_print_state *);
186   static void smob_proc_init (scm_t_bits) { };
187
188   // type_p_name_ can be overriden in the Super class with a static
189   // const char [] string.  This requires both a declaration in the
190   // class as well as a single instantiation outside.  Using a
191   // template specialization for supplying a different string name
192   // right in Smob_base<Super> itself seems tempting, but the C++
193   // rules would then require a specialization declaration at the
194   // class definition site as well as a specialization instantiation
195   // in a single compilation unit.  That requires just as much source
196   // code maintenance while being harder to understand and quite
197   // trickier in its failure symptoms when things go wrong.  So we
198   // just use a static zero as "not here" indication.
199   static const int type_p_name_ = 0;
200
201   // LY_DECLARE_SMOB_PROC is used in the Super class definition for
202   // making a smob callable like a function.  Its first argument is a
203   // function member pointer constant, to a function taking the
204   // correct number of SCM arguments and returning SCM.  The function
205   // itself has to be defined separately.
206
207 #define LY_DECLARE_SMOB_PROC(PMF, REQ, OPT, VAR)                        \
208   static void smob_proc_init (scm_t_bits smob_tag)                      \
209   {                                                                     \
210     scm_set_smob_apply (smob_tag,                                       \
211                         (scm_t_subr)smob_trampoline<PMF>,               \
212                         REQ, OPT, VAR);                                 \
213   }
214
215   // Well, function template argument packs are a C++11 feature.  So
216   // we just define a bunch of trampolines manually.
217   template <SCM (Super::*pmf)(void)>
218   static SCM smob_trampoline (SCM self)
219   {
220     return (Super::unchecked_unsmob (self)->*pmf)();
221   }
222   template <SCM (Super::*pmf)(SCM)>
223   static SCM smob_trampoline (SCM self, SCM arg1)
224   {
225     return (Super::unchecked_unsmob (self)->*pmf)(arg1);
226   }
227   template <SCM (Super::*pmf)(SCM, SCM)>
228   static SCM smob_trampoline (SCM self, SCM arg1, SCM arg2)
229   {
230     return (Super::unchecked_unsmob (self)->*pmf)(arg1, arg2);
231   }
232   template <SCM (Super::*pmf)(SCM, SCM, SCM)>
233   static SCM smob_trampoline (SCM self, SCM arg1, SCM arg2, SCM arg3)
234   {
235     return (Super::unchecked_unsmob (self)->*pmf)(arg1, arg2, arg3);
236   }
237
238   static bool is_smob (SCM s)
239   {
240     return SCM_SMOB_PREDICATE (smob_tag (), s);
241   }
242   static SCM smob_p (SCM s)
243   {
244     return is_smob (s) ? SCM_BOOL_T : SCM_BOOL_F;
245   }
246
247   template <class T>
248   friend T *unsmob (SCM s);
249
250   template <class T>
251   friend T *ly_assert_smob (SCM s, int number, const char *fun);
252 };
253
254 template <class T>
255 inline T *unsmob (SCM s)
256 {
257   return T::is_smob (s) ? dynamic_cast<T *> (T::unchecked_unsmob (s)) : 0;
258 }
259
260 // Simple smobs
261 template <class Super>
262 class Simple_smob : public Smob_base<Super> {
263 public:
264   static size_t free_smob (SCM obj)
265   {
266     delete Smob_base<Super>::unregister_ptr (obj);
267     return 0;
268   }
269   SCM smobbed_copy () const
270   {
271     Super *p = new Super(*static_cast<const Super *> (this));
272     return Smob_base<Super>::register_ptr (p);
273   }
274 };
275
276 void protect_smob (SCM smob, SCM *prot_cons);
277 void unprotect_smob (SCM smob, SCM *prot_cons);
278
279 // The Smob_core class is not templated and contains material not
280 // depending on the Super class.
281
282 class Smob_core {
283 protected:
284   SCM self_scm_;
285   Smob_core () : self_scm_ (SCM_UNDEFINED) { };
286 public:
287   SCM self_scm () const { return self_scm_; }
288   Listener get_listener (SCM callback);
289 };
290
291 template <class Super>
292 class Smob : public Smob_core, public Smob_base<Super> {
293 private:
294   SCM protection_cons_;
295   Smob (const Smob<Super> &); // Do not define!  Not copyable!
296 protected:
297   Smob () : protection_cons_ (SCM_EOL) { };
298 public:
299   static size_t free_smob (SCM obj)
300   {
301     delete Smob_base<Super>::unregister_ptr (obj);
302     return 0;
303   }
304   SCM unprotected_smobify_self ()
305   {
306     SCM s = Smob_base<Super>::register_ptr (static_cast<Super *> (this));
307     self_scm_ = s;
308     return s;
309   }
310   void protect ()
311   {
312     protect_smob (self_scm_, &protection_cons_);
313   }
314   void smobify_self () {
315     protect_smob (unprotected_smobify_self (), &protection_cons_);
316   }
317   SCM unprotect ()
318   {
319     SCM s = self_scm_;
320     unprotect_smob (s, &protection_cons_);
321     return s;
322   }
323 };
324
325 extern bool parsed_objects_should_be_dead;
326 class parsed_dead
327 {
328   static vector<parsed_dead *> elements;
329   SCM data;
330   SCM readout_one ()
331   {
332     SCM res = data;
333     data = SCM_UNDEFINED;
334     return res;
335   }
336 public:
337   parsed_dead () : data (SCM_UNDEFINED)
338   {
339     elements.push_back (this);
340   }
341   void checkin (SCM arg) { data = arg; }
342   static SCM readout ();
343 };
344
345 // This does not appear to work with GUILEv2's garbage collector:
346 // Objects are found in the GC phase but printing them will crash at
347 // least some, so they are apparently not protected in spite of being
348 // included in the GC scans.  So it would appear that scanning smobs
349 // is not equivalent to marking them.  Ugh.
350 #if defined(DEBUG) && !GUILEV2
351 #define ASSERT_LIVE_IS_ALLOWED(arg)                                     \
352   do {                                                                  \
353     static parsed_dead pass_here;                                       \
354     if (parsed_objects_should_be_dead)                                  \
355       pass_here.checkin (arg);                                          \
356   } while (0)
357 #else
358 #define ASSERT_LIVE_IS_ALLOWED(arg) do { (void)(arg); }  \
359   while (0)
360 #endif
361
362 #include "smobs.tcc"
363 #endif /* SMOBS_HH */