Beast - Music Synthesizer and Composer  0.11.1+10.g2da35
sfivisitors.hh
Go to the documentation of this file.
1  // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
2 #ifndef __SFI_VISITORS_HH__
3 #define __SFI_VISITORS_HH__
4 
5 #include <sfi/sfiparams.hh>
6 
7 namespace Bse { // BseCore
8 
9 template<class Visitable> void sfi_rec_to_visitable (SfiRec *rec, Visitable &visitable);
10 template<class Visitable> SfiRec* sfi_rec_new_from_visitable (Visitable &visitable);
11 template<class Visitable> void sfi_seq_to_visitable (SfiSeq *seq, Visitable &visitable);
12 template<class Visitable> SfiSeq* sfi_seq_new_from_visitable (Visitable &visitable);
13 template<class Visitable> SfiRecFields sfi_pspecs_rec_fields_from_visitable (Visitable &visitable);
14 template<class Visitable> GParamSpec* sfi_pspec_seq_field_from_visitable (Visitable &visitable);
15 template<class Visitable> const std::vector<GParamSpec*>& sfi_pspecs_fields_from_accessor_visitable (Visitable &visitable);
16 bool sfi_pspecs_rec_fields_cache (const std::type_info &type_info, SfiRecFields *rf, bool assign = false); // internal
17 bool sfi_pspecs_seq_field_cache (const std::type_info &type_info, GParamSpec **pp, bool assign = false); // internal
18 bool sfi_pspecs_acs_fields_cache (const std::type_info &type_info, std::vector<GParamSpec*>**, bool assign = false); // internal
19 
20 class PspecVisitor : public VisitorDispatcher<PspecVisitor> {
21  std::vector<GParamSpec*> &pspecs_;
23  String get_min (Name name, Name fallback) { return get_aux (name, "min", fallback); }
24  String get_max (Name name, Name fallback) { return get_aux (name, "max", fallback); }
25  String get_step (Name name) { return get_aux (name, "step"); }
26  String get_dflt (Name name) { return get_aux (name, "default"); }
27  String get_label (Name name) { return get_aux (name, "label"); }
28  String get_blurb (Name name) { return get_aux (name, "blurb"); }
29  String get_hints (Name name) { return get_aux (name, "hints"); }
30  String get_aux (const char *field, const char *key, const char *fallback = "")
31  {
32  const String name = String() + field + "." + key + "=";
33  for (const String &kv : aux_)
34  if (name.compare (0, name.size(), kv, 0, name.size()) == 0)
35  return kv.substr (name.size());
36  return fallback;
37  }
38  void
39  add_group (Name name, GParamSpec *pspec)
40  {
41  const String group = get_aux (name, "group");
42  if (!group.empty())
43  sfi_pspec_set_group (pspec, group.c_str());
44  }
45 public:
46  PspecVisitor (std::vector<GParamSpec*> &pspecs, const std::vector<String> &aux_data) : pspecs_ (pspecs), aux_ (aux_data) {}
47  template<class A> void
48  visit_bool (A &a, Name name)
49  {
50  const bool dfl = string_to_bool (get_dflt (name));
51  GParamSpec *pspec = sfi_pspec_bool (name, get_label (name).c_str(), get_blurb (name).c_str(), dfl, get_hints (name).c_str());
52  add_group (name, pspec);
53  pspecs_.push_back (pspec);
54  }
55  template<class A> void
56  visit_integral (A &a, Name name)
57  {
58  const int64 dfl = string_to_int (get_dflt (name));
59  const int64 mi = string_to_int (get_min (name, "-9223372036854775808"));
60  const int64 ma = string_to_int (get_max (name, "+9223372036854775807"));
61  const int64 ms = string_to_int (get_step (name));
62  GParamSpec *pspec = sfi_pspec_num (name, get_label (name).c_str(), get_blurb (name).c_str(), dfl, mi, ma, ms, get_hints (name).c_str());
63  add_group (name, pspec);
64  pspecs_.push_back (pspec);
65  }
66  template<class A> void
67  visit_float (A &a, Name name)
68  {
69  const double dfl = string_to_double (get_dflt (name));
70  const double mi = string_to_double (get_min (name, "-1.79769313486231570815e+308"));
71  const double ma = string_to_double (get_max (name, "+1.79769313486231570815e+308"));
72  const double ms = string_to_double (get_step (name));
73  GParamSpec *pspec = sfi_pspec_real (name, get_label (name).c_str(), get_blurb (name).c_str(), dfl, mi, ma, ms, get_hints (name).c_str());
74  add_group (name, pspec);
75  pspecs_.push_back (pspec);
76  }
77  void
78  visit_string (::std::string &a, Name name)
79  {
80  GParamSpec *pspec = sfi_pspec_string (name, get_label (name).c_str(), get_blurb (name).c_str(),
81  get_dflt (name).c_str(), get_hints (name).c_str());
82  add_group (name, pspec);
83  pspecs_.push_back (pspec);
84  }
85  template<class A> void
86  visit_enum (A &a, Name name)
87  {
88  GParamSpec *pspec = sfi_pspec_choice (name, get_label (name).c_str(), get_blurb (name).c_str(), get_dflt (name).c_str(),
89  Bse::choice_values_from_enum<A>(), get_hints (name).c_str());
90  add_group (name, pspec);
91  pspecs_.push_back (pspec);
92  }
93  template<class A> void
94  visit_visitable (A &a, Name name)
95  {
96  SfiRecFields recfields = sfi_pspecs_rec_fields_from_visitable (a);
97  GParamSpec *pspec = sfi_pspec_rec (name, get_label (name).c_str(), get_blurb (name).c_str(), recfields, get_hints (name).c_str());
98  add_group (name, pspec);
99  pspecs_.push_back (pspec);
100  }
101  template<class SeqA> void
102  visit_vector (SeqA &a, Name name)
103  { // Note, if A=bool, SeqA is *derived* from std::vector<bool>, so StdVectorValueHandle<> doesn't match
104  GParamSpec *pspec = sfi_pspec_seq_field_from_visitable (a); // this needs the real SeqA type
105  if (pspec)
106  {
107  GParamSpec *seq_pspec = sfi_pspec_seq (name, get_label (name).c_str(), get_blurb (name).c_str(), pspec, get_hints (name).c_str());
108  add_group (name, seq_pspec);
109  pspecs_.push_back (seq_pspec);
110  }
111  }
112  template<class A> void
113  visit_class (A &a, Name name)
114  {
115  GParamSpec *pspec = sfi_pspec_proxy (name, get_label (name).c_str(), get_blurb (name).c_str(), get_hints (name).c_str());
116  add_group (name, pspec);
117  pspecs_.push_back (pspec);
118  }
119 };
120 
121 class ToRecVisitor : public VisitorDispatcher<ToRecVisitor> {
122  SfiRec *rec_;
123 public:
124  ToRecVisitor (SfiRec *rec) : rec_ (rec) {}
125  template<class A> void
126  visit_bool (A &a, Name name)
127  {
128  sfi_rec_set_bool (rec_, name, a);
129  }
130  template<class A> void
131  visit_integral (A &a, Name name)
132  {
133  sfi_rec_set_num (rec_, name, a);
134  }
135  template<class A> void
136  visit_float (A &a, Name name)
137  {
138  sfi_rec_set_real (rec_, name, a);
139  }
140  void
141  visit_string (::std::string &a, Name name)
142  {
143  sfi_rec_set_string (rec_, name, a.c_str());
144  }
145  template<class A> void
146  visit_enum (A &a, Name name)
147  {
148  sfi_rec_set_choice (rec_, name, Rapicorn::Aida::enum_info<A>().value_to_string (a).c_str());
149  }
150  template<class SeqA> void
151  visit_vector (SeqA &a, Name name)
152  { // Note, if A=bool, SeqA is *derived* from std::vector<bool>, so StdVectorValueHandle<> doesn't match
153  SfiSeq *field_seq = sfi_seq_new_from_visitable (a);
154  sfi_rec_set_seq (rec_, name, field_seq);
155  sfi_seq_unref (field_seq);
156  }
157  template<class A> void
158  visit_visitable (A &a, Name name)
159  {
160  SfiRec *field_rec = sfi_rec_new();
161  ToRecVisitor rec_visitor (field_rec);
162  a.__accept__ (rec_visitor);
163  sfi_rec_set_rec (rec_, name, field_rec);
164  sfi_rec_unref (field_rec);
165  }
166  template<class A> void
167  visit_class (A &a, Name name)
168  {
169  sfi_rec_set_proxy (rec_, name, a);
170  }
171 };
172 
173 class FromRecVisitor : public VisitorDispatcher<FromRecVisitor> {
174  SfiRec *rec_;
175 public:
176  FromRecVisitor (SfiRec *rec) : rec_ (rec) {}
177  template<class A> void
178  visit_bool (A &a, Name name)
179  {
180  a = sfi_rec_get_bool (rec_, name);
181  }
182  template<class A> void
183  visit_integral (A &a, Name name)
184  {
185  a = sfi_rec_get_num (rec_, name);
186  }
187  template<class A> void
188  visit_float (A &a, Name name)
189  {
190  a = sfi_rec_get_real (rec_, name);
191  }
192  void
193  visit_string (::std::string &a, Name name)
194  {
195  const char *s = sfi_rec_get_string (rec_, name);
196  a = s ? s : "";
197  }
198  template<class A> void
199  visit_enum (A &a, Name name)
200  {
201  const char *c = sfi_rec_get_choice (rec_, name);
202  a = !c ? (A) 0 : Rapicorn::Aida::enum_value_from_string<A>(c);
203  }
204  template<class SeqA> void
205  visit_vector (SeqA &a, Name name)
206  { // Note, if A=bool, SeqA is *derived* from std::vector<bool>, so StdVectorValueHandle<> doesn't match
207  SfiSeq *field_seq = sfi_rec_get_seq (rec_, name);
208  sfi_seq_to_visitable (field_seq, a);
209  }
210  template<class A> void
211  visit_visitable (A &a, Name name)
212  {
213  SfiRec *field_rec = sfi_rec_get_rec (rec_, name);
214  if (field_rec)
215  {
216  FromRecVisitor rec_visitor (field_rec);
217  a.__accept__ (rec_visitor);
218  }
219  }
220  template<class A> void
221  visit_class (A &a, Name name)
222  {
223  a = sfi_rec_get_proxy (rec_, name);
224  }
225 };
226 
227 template<class Visitable> void
228 sfi_seq_to_visitable (SfiSeq *seq, Visitable &visitable)
229 {
230  if (!seq)
231  {
232  visitable.resize (0);
233  return;
234  }
235  const size_t n = sfi_seq_length (seq);
236  visitable.resize (n);
237  SfiRec *tmp_rec = sfi_rec_new();
238  for (size_t i = 0; i < n; i++)
239  {
240  sfi_rec_set (tmp_rec, "seqelement", sfi_seq_get (seq, i));
241  FromRecVisitor rec_visitor (tmp_rec);
242  typedef typename Visitable::value_type A; // assumes Visitable derives std::vector
243  typename StdVectorValueHandle<::std::vector<A>>::type value_handle = visitable[i];
244  rec_visitor (value_handle, "seqelement");
245  if (StdVectorValueHandle<::std::vector<A>>::value) // copy-by-value
246  visitable[i] = value_handle;
247  }
248  sfi_rec_unref (tmp_rec);
249 }
250 
251 template<class Visitable> SfiSeq*
252 sfi_seq_new_from_visitable (Visitable &visitable)
253 {
254  SfiSeq *seq = sfi_seq_new();
255  SfiRec *tmp_rec = sfi_rec_new();
256  for (size_t i = 0; i < visitable.size(); i++)
257  {
258  ToRecVisitor rec_visitor (tmp_rec);
259  typedef typename Visitable::value_type A; // assumes Visitable derives std::vector
260  typename StdVectorValueHandle<::std::vector<A>>::type value_handle = visitable[i];
261  rec_visitor (value_handle, "seqelement");
262  if (StdVectorValueHandle<::std::vector<A>>::value) // copy-by-value
263  visitable[i] = value_handle;
264  GValue *element = sfi_rec_get (tmp_rec, "seqelement");
265  if (element)
266  {
267  sfi_seq_append (seq, element);
268  sfi_rec_clear (tmp_rec);
269  }
270  else
271  break;
272  }
273  sfi_rec_unref (tmp_rec);
274  return seq;
275 }
276 
277 template<class Visitable> SfiRec*
278 sfi_rec_new_from_visitable (Visitable &visitable)
279 {
280  SfiRec *rec = sfi_rec_new();
281  ToRecVisitor rec_visitor (rec);
282  visitable.__accept__ (rec_visitor);
283  return rec;
284 }
285 
286 template<class Visitable> void
287 sfi_rec_to_visitable (SfiRec *rec, Visitable &visitable)
288 {
289  FromRecVisitor rec_visitor (rec);
290  visitable.__accept__ (rec_visitor);
291 }
292 
293 template<class Visitable> SfiRecFields
294 sfi_pspecs_rec_fields_from_visitable (Visitable &visitable)
295 {
296  SfiRecFields rec_fields;
297  if (sfi_pspecs_rec_fields_cache (typeid (Visitable), &rec_fields))
298  return rec_fields;
300  PspecVisitor pspec_visitor (pspecs, visitable.__aida_aux_data__());
301  visitable.__accept__ (pspec_visitor);
302  rec_fields.n_fields = pspecs.size();
303  rec_fields.fields = g_new0 (GParamSpec*, rec_fields.n_fields);
304  for (size_t i = 0; i < rec_fields.n_fields; i++)
305  {
306  g_param_spec_ref (pspecs[i]);
307  g_param_spec_sink (pspecs[i]);
308  rec_fields.fields[i] = pspecs[i];
309  }
310  sfi_pspecs_rec_fields_cache (typeid (Visitable), &rec_fields, true);
311  return rec_fields;
312 }
313 
314 template<class Visitable> GParamSpec*
315 sfi_pspec_seq_field_from_visitable (Visitable &visitable)
316 {
317  GParamSpec *pspec = NULL;
318  if (sfi_pspecs_seq_field_cache (typeid (Visitable), &pspec))
319  return pspec;
321  PspecVisitor pspec_visitor (pspecs, visitable.__aida_aux_data__());
322  typedef typename Visitable::value_type A;
323  A example_element = A();
324  pspec_visitor (example_element, "seqelement");
325  if (pspecs.size() == 1)
326  {
327  pspec = pspecs[0];
328  g_param_spec_ref (pspec);
329  g_param_spec_sink (pspec);
330  sfi_pspecs_seq_field_cache (typeid (Visitable), &pspec, true);
331  }
332  for (size_t i = 0; i < pspecs.size(); i++)
333  {
334  g_param_spec_ref (pspecs[i]);
335  g_param_spec_sink (pspecs[i]);
336  g_param_spec_unref (pspecs[i]);
337  }
338  return pspec;
339 }
340 
341 template<class Visitable> const std::vector<GParamSpec*>&
342 sfi_pspecs_fields_from_accessor_visitable (Visitable &visitable)
343 {
344  std::vector<GParamSpec*> *pspecsp = NULL;
345  if (sfi_pspecs_acs_fields_cache (typeid (Visitable), &pspecsp))
346  return *pspecsp;
348  PspecVisitor pspec_visitor (pspecs, visitable.__aida_aux_data__());
349  visitable.__accept_accessor__ (pspec_visitor);
350  for (size_t i = 0; i < pspecs.size(); i++)
351  {
352  g_param_spec_ref (pspecs[i]);
353  g_param_spec_sink (pspecs[i]);
354  }
355  pspecsp = &pspecs;
356  sfi_pspecs_acs_fields_cache (typeid (Visitable), &pspecsp, true);
357  pspecsp = NULL;
358  bool success = sfi_pspecs_acs_fields_cache (typeid (Visitable), &pspecsp);
359  RAPICORN_ASSERT (success && pspecsp);
360  return *pspecsp;
361 }
362 
363 } // Bse
364 
365 #endif // __SFI_VISITORS_HH__
T empty(T...args)
Definition: sfivisitors.hh:173
The Bse namespace contains all functions of the synthesis engine.
Definition: bstbseutils.cc:91
Definition: sfivisitors.hh:121
STL class.
T push_back(T...args)
Pointer sized integer object handle.
Definition: sfitypes.hh:29
T size(T...args)
int64_t int64
T c_str(T...args)
T substr(T...args)
double string_to_double(const String &string)
#define RAPICORN_ASSERT(cond)
bool string_to_bool(const String &string, bool fallback)
T compare(T...args)
int64 string_to_int(const String &string, uint base)
Definition: sfivisitors.hh:20