]> git.donarmstrong.com Git - lilypond.git/blob - lily/include/callback.hh
Imported Upstream version 2.19.45
[lilypond.git] / lily / include / callback.hh
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2016  David Kastrup <dak@gnu.org>
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 CALLBACK_HH
21 #define CALLBACK_HH
22
23 // A callback wrapper creates a Scheme-callable version of a fixed C++
24 // function.  It is generally used for calling template-generated
25 // trampoline functions leading to calling a particular member
26 // function on a given Smob.
27 //
28 // The class itself is not templated in order not to explode the
29 // number of smob types: each class can support a particular call
30 // signature.
31 //
32 // Check the GET_LISTENER call for a typical use case.
33
34 #include "smobs.hh"
35
36 class Callback_wrapper : public Simple_smob<Callback_wrapper>
37 {
38   // We use an ordinary function pointer pointing to a trampoline
39   // function (templated on the callback in question) instead of
40   // storing a member function pointer to a common base class like
41   // Smob_core.  The additional code for the trampolines is negligible
42   // and the performance implications of using member function
43   // pointers in connection with inheritance are somewhat opaque as
44   // this involves an adjustment of the this pointer from Smob_core to
45   // the scope containing the callback.
46   SCM (*trampoline_) (SCM, SCM);
47   Callback_wrapper (SCM (*trampoline) (SCM, SCM))
48     : trampoline_ (trampoline)
49   { } // Private constructor, use only in make_smob
50 public:
51   LY_DECLARE_SMOB_PROC (&Callback_wrapper::call, 2, 0, 0)
52   SCM call (SCM target, SCM arg)
53   {
54     return trampoline_ (target, arg);
55   }
56   // Callback wrappers are for an unchanging entity, so we do the Lisp
57   // creation just once on the first call of make_smob.  So we only
58   // get a single Callback_wrapper instance for each differently
59   // templated make_smob call.
60   template <SCM (*trampoline) (SCM, SCM)>
61   static SCM make_smob ()
62   {
63     static SCM res =
64       scm_permanent_object (Callback_wrapper (trampoline).smobbed_copy ());
65     return res;
66   }
67 };
68
69 class Callback2_wrapper : public Simple_smob<Callback2_wrapper>
70 {
71   // See Callback_wrapper for the details.  Callback2_wrapper just
72   // supports an additional SCM argument as compared to
73   // Callback_wrapper but is otherwise identical.
74   SCM (*trampoline_) (SCM, SCM, SCM);
75   Callback2_wrapper (SCM (*trampoline) (SCM, SCM, SCM))
76     : trampoline_ (trampoline)
77   { } // Private constructor, use only in make_smob
78 public:
79   LY_DECLARE_SMOB_PROC (&Callback2_wrapper::call, 3, 0, 0)
80   SCM call (SCM target, SCM arg1, SCM arg2)
81   {
82     return trampoline_ (target, arg1, arg2);
83   }
84
85   template <SCM (*trampoline) (SCM, SCM, SCM)>
86   static SCM make_smob ()
87   {
88     static SCM res =
89       scm_permanent_object (Callback2_wrapper (trampoline).smobbed_copy ());
90     return res;
91   }
92 };
93
94 class Callback0_wrapper : public Simple_smob<Callback0_wrapper>
95 {
96   // See Callback_wrapper for the details.  Callback0_wrapper does not
97   // pass arguments but is otherwise identical to Callback_wrapper.
98   SCM (*trampoline_) (SCM);
99   Callback0_wrapper (SCM (*trampoline) (SCM))
100     : trampoline_ (trampoline)
101   { } // Private constructor, use only in make_smob
102 public:
103   LY_DECLARE_SMOB_PROC (&Callback0_wrapper::call, 1, 0, 0)
104   SCM call (SCM target)
105   {
106     return trampoline_ (target);
107   }
108
109   template <SCM (*trampoline) (SCM)>
110   static SCM make_smob ()
111   {
112     static SCM res =
113       scm_permanent_object (Callback0_wrapper (trampoline).smobbed_copy ());
114     return res;
115   }
116   // Since there are no arguments at all, we might as well provide
117   // default trampolines
118   template <class T, SCM (T::*p)()>
119   static SCM trampoline (SCM target)
120   {
121     T *t = LY_ASSERT_SMOB (T, target, 1);
122     return (t->*p) ();
123   }
124
125   template <class T, void (T::*p)()>
126   static SCM trampoline (SCM target)
127   {
128     T *t = LY_ASSERT_SMOB (T, target, 1);
129     (t->*p) ();
130     return SCM_UNSPECIFIED;
131   }
132
133   template <class T, SCM (T::*p)()>
134   static SCM make_smob ()
135   {
136     return make_smob<trampoline<T, p> > ();
137   }
138
139   template <class T, void (T::*p)()>
140   static SCM make_smob ()
141   {
142     return make_smob<trampoline<T, p> > ();
143   }
144 };
145
146 // The following will usually be used unsmobbified, relying on its
147 // constituents being protected independently.
148
149 class Method_instance : public Simple_smob<Method_instance>
150 {
151   SCM method_, instance_;
152 public:
153   LY_DECLARE_SMOB_PROC (&Method_instance::call, 0, 0, 1)
154   SCM call (SCM rest)
155   {
156     return scm_apply_1 (method_, instance_, rest);
157   }
158
159   Method_instance (SCM method, SCM instance)
160     : method_ (method), instance_ (instance)
161   { }
162   Method_instance (SCM method, Smob_core *instance)
163     : method_ (method), instance_ (instance->self_scm ())
164   { }
165   SCM method () const { return method_; }
166   SCM instance () const { return instance_; }
167   SCM operator () () const
168   {
169     return scm_call_1 (method_, instance_);
170   }
171   SCM operator () (SCM arg) const
172   {
173     return scm_call_2 (method_, instance_, arg);
174   }
175   SCM operator () (SCM arg1, SCM arg2) const
176   {
177     return scm_call_3 (method_, instance_, arg1, arg2);
178   }
179   SCM mark_smob () const
180   {
181     scm_gc_mark (method_);
182     return instance_;
183   }
184 };
185
186 #endif