]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/smobs.hh
Merge branch 'issue4082'
[lilypond.git] / lily / include / smobs.hh
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2014 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 "warn.hh"
25 #include <string>
26
27 /*
28   Smobs are GUILEs mechanism of exporting C(++) objects to the Scheme
29   world.  They are documented in the GUILE manual.
30
31
32   In LilyPond, C++ objects can be placed under the control of GUILE's
33   type system and garbage collection mechanism by inheriting from one
34   of several Smob base classes.
35
36   There are two types of smob objects.
37
38   1. Simple smobs are intended for simple objects like numbers:
39   immutable objects that can be copied without change of meaning.
40
41   To obtain an SCM version of a simple smob, use the member function
42   SCM smobbed_copy ().
43
44   Simple smobs are created by deriving from Simple_smob<Classname>.
45
46   A simple smob is only optionally under the reign of the GUILE
47   garbage collector: its usual life time is that of a normal C++
48   object.  While a smobbed_copy () is fully under control of the
49   garbage collector and will have its mark_smob function called during
50   garbage collection, an automatic variable of this type will not have
51   mark_smob called, but rather have its memory image in the call stack
52   scanned for contained non-immediate SCM values.  Anything requiring
53   more complex mark_smob behavior is not suitable for a simple smob.
54
55   When you create a smobbed_copy, the _copy_ is fully managed by the
56   GUILE memory system.  As a corollary, multiple smobbed_copy calls
57   yield multiple GUILE objects generally not eq? to each other.
58
59   2. Complex smobs are objects that have an identity. These objects
60   carry this identity in the form of a self_scm () method, which is a
61   SCM pointer to the object itself.  Complex smobs are always under
62   control of the GUILE memory system.
63
64   The constructor for a complex smob should have 3 steps:
65
66   * initialize all SCM members to an immediate value (like SCM_EOL)
67
68   * call smobify_self ()
69
70   * initialize SCM members
71
72   For example,
73
74   Complex_smob::Complex_smob : public Smob<Complex_smob> () {
75   scm_member_ = SCM_EOL;
76   smobify_self ();
77   scm_member_ = <..what you want to store..>
78   }
79
80   after construction, the self_scm () field of a complex smob is
81   protected from Garbage Collection.  This protection should be
82   removed once the object is put into another (reachable) Scheme data
83   structure, i.e.
84
85   Complex_smob *p = new Complex_smob;
86   list = scm_cons (p->self_scm (), list);
87   p->unprotect ();
88
89   Since unprotect returns the SCM object itself, this particular case
90   can be written as
91
92   Complex_smob *p = new Complex_smob;
93   list = scm_cons (p->unprotect (), list);
94
95   Complex smobs are created by deriving from Smob<Classname>.
96
97   CALLING INTERFACE
98
99   Common public methods to C++ smob objects:
100
101   - unsmob (SCM x) - unpacks X and returns pointer to the C++ object,
102     or 0 if it has the wrong type.  This can be used as a boolean
103     condition at C++ level.
104   - smob_p (SCM x) returns #t or #f at Scheme level.
105
106   IMPLEMENTATION
107
108   For implementating a class, the following public members can be
109   provided in the top class itself:
110
111   - SCM equal_p (SCM a, SCM b) - compare A and B. Returns a Scheme
112     boolean.  If the class does not define this function, equal? will
113     be equivalent to eq?.  The function will only be called when both
114     objects are of the respective type and not eq? to each other.
115
116   - mark_smob () function, that calls scm_gc_mark () on all Scheme
117     objects in the class.  If the class does not define this function,
118     it must not contain non-immediate Scheme values.
119
120   - a print_smob () function, that displays a representation for
121     debugging purposes.  If the class does not define this function,
122     the output will be #<Classname> when printing.
123
124   - a static const type_p_name_[] string set to something like
125     "ly:grob?".  When provided, an accordingly named function for
126     checking for the given smob type will be available in Scheme.
127
128 */
129
130 // Initialization class.  Create a variable or static data member of
131 // this type at global scope (or creation will happen too late for
132 // Scheme initialization), initialising with a function to be called.
133 // Reference somewhere (like in the constructor of the containing
134 // class) to make sure the variable is actually instantiated.
135
136 class Scm_init {
137 public:
138   Scm_init () { }
139   Scm_init (void (*fun) (void))
140   {
141     add_scm_init_func (fun);
142   }
143 };
144
145 template <class Super>
146 class Smob_base
147 {
148   static scm_t_bits smob_tag_;
149   static Scm_init scm_init_;
150   static void init (void);
151   static string smob_name_;
152   static Super *unchecked_unsmob (SCM s)
153   {
154     return reinterpret_cast<Super *> (SCM_SMOB_DATA (s));
155   }
156 protected:
157   // reference scm_init_ in smob_tag which is sure to be called.  The
158   // constructor, in contrast, may not be called at all in classes
159   // like Smob1.
160   static scm_t_bits smob_tag () { (void) scm_init_; return smob_tag_; }
161   Smob_base () { }
162   static SCM register_ptr (Super *p);
163   static Super *unregister_ptr (SCM obj);
164 private:
165   // Those fallbacks are _only_ for internal use by Smob_base.  They
166   // are characterized by no knowledge about the implemented type
167   // apart from the type's name.  Overriding them as a template
168   // specialization is _not_ intended since a type-dependent
169   // implementation will in general need access to possibly private
170   // parts of the Super class.  So any class-dependent override should
171   // be done by redefining the respective function in the Super class
172   // (where it will mask the private template member) rather than
173   // specializing a different template function/pointer.
174   //
175   // Since we consider those internal-only, two of them are actually
176   // implemented as literal zero constant.  That allows us to fall
177   // back to GUILE's default implementation.  Arguably the same could
178   // be done for print_smob, but the resulting default output of, say,
179   // #<Context_mod 0x7352414> would depend on memory layout, thus
180   // being unsuitable for regtest comparisons unless filtered.
181
182   static const int mark_smob = 0;
183   static const int equal_p = 0;
184   static int print_smob (SCM, SCM, scm_print_state *);
185   static size_t free_smob (SCM obj)
186   {
187     delete Smob_base<Super>::unregister_ptr (obj);
188     return 0;
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 do things like with the other specializations.
201   static const int type_p_name_ = 0;
202 public:
203   static bool is_smob (SCM s)
204   {
205     return SCM_SMOB_PREDICATE (smob_tag (), s);
206   }
207   static SCM smob_p (SCM s)
208   {
209     return is_smob (s) ? SCM_BOOL_T : SCM_BOOL_F;
210   }
211   static Super *unsmob (SCM s)
212   {
213     return is_smob (s) ? Super::unchecked_unsmob (s) : 0;
214   }
215 };
216
217
218 template <class Super>
219 class Simple_smob : public Smob_base<Super> {
220 public:
221   SCM smobbed_copy () const
222   {
223     Super *p = new Super(*static_cast<const Super *> (this));
224     return Smob_base<Super>::register_ptr (p);
225   }
226 };
227
228 void protect_smob (SCM smob, SCM *prot_cons);
229 void unprotect_smob (SCM smob, SCM *prot_cons);
230
231 template <class Super>
232 class Smob : public Smob_base<Super> {
233 private:
234   SCM self_scm_;
235   SCM protection_cons_;
236 public:
237   SCM unprotected_smobify_self ()
238   {
239     self_scm_ = SCM_UNDEFINED;
240     self_scm_ = Smob_base<Super>::register_ptr (static_cast<Super *> (this));
241     return self_scm_;
242   }
243   void protect ()
244   {
245     protect_smob (self_scm_, &protection_cons_);
246   }
247   SCM unprotect ()
248   {
249     unprotect_smob (self_scm_, &protection_cons_);
250     return self_scm_;
251   }
252   void smobify_self () {
253     protection_cons_ = SCM_EOL;
254     self_scm_ = unprotected_smobify_self ();
255     protect ();
256   }
257   SCM self_scm () const { return self_scm_; }
258 };
259
260 extern bool parsed_objects_should_be_dead;
261 class parsed_dead
262 {
263   static vector<parsed_dead *> elements;
264   SCM data;
265   SCM readout_one ()
266   {
267     SCM res = data;
268     data = SCM_UNDEFINED;
269     return res;
270   }
271 public:
272   parsed_dead () : data (SCM_UNDEFINED)
273   {
274     elements.push_back (this);
275   }
276   void checkin (SCM arg) { data = arg; }
277   static SCM readout ();
278 };
279
280 #ifndef NDEBUG
281 #define ASSERT_LIVE_IS_ALLOWED(arg)                                     \
282   do {                                                                  \
283     static parsed_dead pass_here;                                       \
284     if (parsed_objects_should_be_dead)                                  \
285       pass_here.checkin (arg);                                          \
286   } while (0)
287 #else
288 #define ASSERT_LIVE_IS_ALLOWED(arg) do { (void)(arg); }  \
289   while (0)
290 #endif
291
292 #include "smobs.tcc"
293 #endif /* SMOBS_HH */