]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/smobs.hh
e775a70bc5cb6078e6004c334e205b39514bd9bb
[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
26 /*
27   Smobs are GUILEs mechanism of exporting C(++) objects to the Scheme
28   world.  They are documented in the GUILE manual.
29
30
31   In LilyPond, smobs are created from C++ objects through macros.
32   There are two types of smob objects.
33
34   1. Simple smobs are intended for simple objects like numbers:
35   immutable objects that can be copied without change of meaning.
36
37   To obtain an SCM version of a simple smob, use the member function
38   SCM smobbed_copy ().
39
40   Simple smobs are created by adding the
41   DECLARE_SIMPLE_SMOBS(Classname) to the declaration
42
43   A simple smob is only optionally under the reign of the GUILE
44   garbage collector: its usual life time is that of a normal C++
45   object.  While a smobbed_copy () is fully under control of the
46   garbage collector and will have its mark_smob function called during
47   garbage collection, an automatic variable of this type will not have
48   mark_smob called, but rather have its memory image in the call stack
49   scanned for contained non-immediate SCM values.  Anything requiring
50   more complex mark_smob behavior is not suitable for a simple smob.
51
52   When you create a smobbed_copy, the _copy_ is fully managed by the
53   GUILE memory system.  As a corollary, multiple smobbed_copy calls
54   yield multiple GUILE objects generally not eq? to each other.
55
56   2. Complex smobs are objects that have an identity. These objects
57   carry this identity in the form of a self_scm () method, which is a
58   SCM pointer to the object itself.  Complex smobs are always under
59   control of the GUILE memory system.
60
61   The constructor for a complex smob should have 3 steps:
62
63   * initialize all SCM members to an immediate value (like SCM_EOL)
64
65   * call smobify_self ()
66
67   * initialize SCM members
68
69   For example,
70
71   Complex_smob::Complex_smob () {
72   scm_member_ = SCM_EOL;
73   smobify_self ();
74   scm_member_ = <..what you want to store..>
75   }
76
77   after construction, the self_scm () field of a complex smob is
78   protected from Garbage Collection.  This protection should be
79   removed once the object is put into another (reachable) Scheme data
80   structure, i.e.
81
82   Complex_smob *p = new Complex_smob;
83   list = scm_cons (p->self_scm (), list);
84   p->unprotect ();
85
86   Since unprotect returns the SCM object itself, this particular case
87   can be written as
88
89   Complex_smob *p = new Complex_smob;
90   list = scm_cons (p->unprotect (), list);
91
92   Complex smobs are made with DECLARE_SMOBS (Classname) in the class
93   declaration.
94
95   CALLING INTERFACE
96
97   Common public methods to C++ smob objects:
98
99   unsmob (SCM x)  - unpacks X and returns pointer to the C++ object, or 0
100   if it has the wrong type.
101
102   SCM equal_p (SCM a, SCM b) - compare A and B. Returns a Scheme boolean
103
104
105   IMPLEMENTATION
106
107   For implementating a class, the following should be provided
108
109   - an equal_p () function (a default is in the
110   IMPLEMENT_DEFAULT_EQUAL_P macro in ly-smobs.icc)
111
112   - mark_smob () function, that calls scm_gc_mark () on all Scheme
113   objects in the class
114
115   - a print_smob () function, that displays a representation for
116   debugging purposes
117
118   - A call to one of the IMPLEMENT_SMOBS or IMPLEMENT_SIMPLE_SMOBS macros
119   from file "ly-smobs.icc"
120 */
121
122 #define DECLARE_SIMPLE_SMOBS(CL)                \
123   public:                                       \
124   SCM smobbed_copy () const;                    \
125   DECLARE_BASE_SMOBS (CL)
126
127 #define DECLARE_BASE_SMOBS(CL)                                  \
128   friend class Non_existent_class;                              \
129   private:                                                      \
130   static const char* smob_name_; \
131   static scm_t_bits smob_tag_;                                  \
132   static SCM mark_smob (SCM);                                   \
133   static size_t free_smob (SCM s);                              \
134   static int print_smob (SCM s, SCM p, scm_print_state*);       \
135   public:                                                       \
136   static SCM equal_p (SCM a, SCM b);                            \
137   static CL *unsmob (SCM s) __attribute__((pure))               \
138   {                                                             \
139     if (SCM_NIMP (s) && SCM_CELL_TYPE (s) == smob_tag_)         \
140       return (CL *) SCM_CELL_WORD_1 (s);                        \
141     else                                                        \
142       return 0;                                                 \
143   }                                                             \
144   static SCM smob_p (SCM);                                      \
145   static void init_smobs ();                                    \
146   private:
147
148 #define DECLARE_SMOBS(CL)                       \
149   DECLARE_BASE_SMOBS (CL)                       \
150     protected:                                  \
151   virtual ~CL ();                               \
152   SCM unprotected_smobify_self ();              \
153   private:                                      \
154   void smobify_self ();                         \
155   SCM self_scm_;                                \
156   SCM protection_cons_;                         \
157   public:                                       \
158   SCM unprotect ();                             \
159   void protect ();                              \
160   SCM self_scm () const { return self_scm_; }   \
161   private:
162
163 void protect_smob (SCM smob, SCM *prot_cons);
164 void unprotect_smob (SCM smob, SCM *prot_cons);
165
166 extern bool parsed_objects_should_be_dead;
167 class parsed_dead
168 {
169   static vector<parsed_dead *> elements;
170   SCM data;
171   SCM readout_one ()
172   {
173     SCM res = data;
174     data = SCM_UNDEFINED;
175     return res;
176   }
177 public:
178   parsed_dead () : data (SCM_UNDEFINED)
179   {
180     elements.push_back (this);
181   }
182   void checkin (SCM arg) { data = arg; }
183   static SCM readout ();
184 };
185
186 #ifndef NDEBUG
187 #define ASSERT_LIVE_IS_ALLOWED(arg)                                     \
188   do {                                                                  \
189     static parsed_dead pass_here;                                       \
190     if (parsed_objects_should_be_dead)                                  \
191       pass_here.checkin (arg);                                          \
192   } while (0)
193 #else
194 #define ASSERT_LIVE_IS_ALLOWED(arg) do { (void)(arg); }  \
195   while (0)
196 #endif
197
198 #endif /* SMOBS_HH */
199