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