Anklang-0.3.0.dev797+g4e3241f3 anklang-0.3.0.dev797+g4e3241f3
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
gadget.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "gadget.hh"
3#include "jsonipc/jsonipc.hh"
4#include "utils.hh"
5#include "project.hh"
6#include "serialize.hh"
7#include "internal.hh"
8#include "randomhash.hh"
9
10namespace Ase {
11
12// == Gadget ==
13Gadget::Gadget()
14{}
15
16// == GadgetImpl ==
17GadgetImpl::~GadgetImpl()
18{}
19
21GadgetImpl::gadget_flags (uint64_t setbits, uint64_t mask)
22{
23 gadget_flags_ &= mask;
24 gadget_flags_ |= setbits;
25 return gadget_flags_;
26}
27
28void
30{
31 if (parent)
32 assert_return (parent_ == nullptr);
33 else // !parent
34 assert_return (parent_ != nullptr);
35 parent_ = parent;
36}
37
39GadgetImpl::fallback_name () const
40{
41 return type_nick();
42}
43
45GadgetImpl::canonify_key (const String &input)
46{
47 String key = string_canonify (input, string_set_a2z() + string_set_A2Z() + "_0123456789.", "_");
48 if (key.size() && key[0] == '.')
49 key = "_" + key;
50 return key;
51}
52
53Value
54GadgetImpl::get_data (const String &key) const
55{
56 const String ckey = canonify_key (key);
57 return session_data_[ckey];
58}
59
60bool
61GadgetImpl::set_data (const String &key, const Value &v)
62{
63 const String ckey = canonify_key (key);
64 return_unless (ckey.size(), false);
65 session_data_[ckey] = v;
66 emit_event ("data", ckey);
67 return true;
68}
69
70void
72{
73 // name
74 String current_name = name();
75 if (xs.in_save() && current_name != fallback_name())
76 xs["name"] & current_name;
77 if (xs.in_load() && xs.has ("name"))
78 {
79 String new_name;
80 xs["name"] & new_name;
81 if (current_name != new_name) // avoid fixating a fallback
82 name (new_name);
83 }
84 // Serializable
86 // properties
87 for (PropertyP p : access_properties())
88 {
89 const String hints = p->hints();
90 if (!string_option_check (hints, "S"))
91 continue;
92 if (xs.in_save() && string_option_check (hints, "r"))
93 {
94 Value v = p->value();
95 xs[p->ident()] & v;
96 }
97 if (xs.in_load() && string_option_check (hints, "w") && xs.has (p->ident()))
98 {
99 Value v;
100 xs[p->ident()] & v;
101 p->value (v);
102 }
103 }
104 // data
105 if (xs.in_save())
106 {
107 ValueR cdata;
108 for (const ValueField &f : session_data_)
109 if (f.name[0] != '_' && f.value)
110 cdata[f.name] = *f.value;
111 if (cdata.size())
112 xs["custom_data"] & cdata;
113 }
114 if (xs.in_load())
115 {
116 ValueR cdata;
117 xs["custom_data"] & cdata;
118 for (const ValueField &f : cdata)
119 if (f.value)
120 set_data (f.name, *f.value);
121 }
122}
123
124String
125GadgetImpl::type_nick () const
126{
127 String tname = Jsonipc::rtti_typename (*this);
128 ssize_t colon = tname.rfind (':');
129 if (colon != ssize_t (tname.npos))
130 tname = tname.substr (colon + 1);
131 if (string_endswith (tname, "Impl"))
132 tname = tname.substr (0, tname.size() - 4);
133 return tname;
134}
135
136static CustomDataKey<String> gadget_name_key;
137
138String
139GadgetImpl::name () const
140{
141 if (!has_custom_data (&gadget_name_key))
142 return fallback_name();
143 return get_custom_data (&gadget_name_key);
144}
145
146void
147GadgetImpl::name (const std::string &n)
148{
149 String newname = string_strip (n);
150 if (newname.empty())
151 del_custom_data (&gadget_name_key);
152 else
153 set_custom_data (&gadget_name_key, newname);
154 emit_notify ("name");
155}
156
157PropertyS
159{
160 if (props_.empty())
161 create_properties();
162 return { begin (props_), end (props_) };
163}
164
165// == Gadget ==
168{
169 Gadget *last = const_cast<Gadget*> (this);
170 for (Gadget *parent = last->_parent(); parent; parent = last->_parent())
171 last = parent;
172 return dynamic_cast<ProjectImpl*> (last);
173}
174
177{
178 PropertyS props = access_properties();
179 StringS names;
180 names.reserve (props.size());
181 for (const PropertyP &prop : props)
182 names.push_back (prop->ident());
183 return names;
184}
185
186PropertyP
188{
189 for (const auto &p : access_properties())
190 if (p->ident() == ident)
191 return p;
192 return {};
193}
194
195Value
197{
198 PropertyP prop = access_property (ident);
199 return prop ? prop->value() : Value {};
200}
201
202bool
204{
205 PropertyP prop = access_property (ident);
206 return prop && prop->value (v);
207}
208
210 const char *member_typeid_name = nullptr;
211 ptrdiff_t memb_offset = -1;
213 GadgetImpl::MemberInfosP infosp = nullptr;
215 uint64_t flags = 0;
216};
217
219 /*key*/
220 const char *class_typeid_name = nullptr;
221 /*payload*/
222 GadgetImpl::MemberClassT classtest = nullptr;
224};
225
226static auto&
227cml_set()
228{
229 static auto gcml_hash = [] (const GadgetClassMemberList &m) {
230 return fnv1a_consthash64 (m.class_typeid_name);
231 };
232 static auto gcml_equal = [] (const GadgetClassMemberList &a, const GadgetClassMemberList &b) {
233 return !strcmp (a.class_typeid_name, b.class_typeid_name);
234 };
235 using MemberAccessorSet = std::unordered_set<GadgetClassMemberList, decltype (gcml_hash), decltype (gcml_equal)>;
236 static MemberAccessorSet mas (0, gcml_hash, gcml_equal);
237 return mas;
238}
239
240bool
241GadgetImpl::requires_accessor (const char *ot, const char *mt, ptrdiff_t offset)
242{
243 auto &cml = cml_set();
244 const GadgetClassMemberList key { .class_typeid_name = ot };
245 auto it = cml.find (key);
246 if (it != cml.end())
247 for (const MemberAccessor *maf : it->members)
248 if (!strcmp (mt, maf->member_typeid_name)) {
249 assert_return (maf->memb_offset == offset, false);
250 return false;
251 }
252 return true;
253}
254
255void
256GadgetImpl::register_accessor (const char *ot, const char *mt, ptrdiff_t offset, MemberClassT classtest,
257 const Param::ExtraVals &ev, MemberAccessF &&accessfunc,
258 MemberInfosP infosp, uint64_t flags)
259{
260 auto &cml = cml_set();
261 auto [celement, inserted] = cml.emplace (ot, classtest);
262 assert_return (celement != cml.end());
263 GadgetClassMemberList *element = const_cast<GadgetClassMemberList*> (&*celement);
264 element->members.push_back (new MemberAccessor {mt, offset, std::move (accessfunc), infosp, ev, flags});
265 //printerr ("%s: %s+%s=%+zd\n", __func__, ot, mt, offset);
266}
267
268void
269GadgetImpl::create_properties ()
270{
271 /* When creating the properties for an instance, walk through the known
272 * GadgetClassMemberList entries, test each via dynamic_cast and thus
273 * identify all class member lists that match the instance.
274 */
275 auto &cml = cml_set();
276 for (const GadgetClassMemberList &ml : cml)
277 if (ml.classtest (*this))
278 for (const MemberAccessor *m : ml.members) {
279 PropertyGetter getter = [this,m] (Value &value) { m->func (this, nullptr, &value); };
280 PropertySetter setter = [this,m] (const Value &value) { return m->func (this, &value, nullptr); };
281 PropertyLister lister = nullptr;
282 StringS infos = m->infosp();
283 String hints = kvpairs_fetch (infos, "hints");
284 if (m->flags & MemberDetails::READABLE)
285 hints += ":r";
286 if (m->flags & MemberDetails::WRITABLE)
287 hints += ":w";
288 if (m->flags & MemberDetails::STORAGE)
289 hints += ":S";
290 if (m->flags & MemberDetails::GUI)
291 hints += ":G";
292 kvpairs_assign (infos, "hints=" + hints);
293 Param param { .extras = m->ev, .metadata = infos };
294 this->props_.push_back (PropertyImpl::make_shared (param, getter, setter, lister));
295 }
296}
297
298} // Ase
T get_custom_data(CustomDataKey< T > *key) const
Retrieve contents of the custom keyed data member, returns DataKey::fallback if nothing was set.
Definition utils.hh:102
bool has_custom_data(CustomDataKey< T > *key) const
Retrieve wether contents of the custom keyed data member exists.
Definition utils.hh:105
bool del_custom_data(CustomDataKey< T > *key)
Delete the current contents of the custom keyed data member, invokes DataKey::destroy.
Definition utils.hh:108
void set_custom_data(CustomDataKey< T > *key, T data)
Assign data to the custom keyed data member, deletes any previously set data.
Definition utils.hh:99
void emit_notify(const String &detail) override
Emit notify:detail, multiple notifications maybe coalesced if a CoalesceNotifies instance exists.
Definition object.cc:164
Base type for classes that have a Property.
Definition gadget.hh:12
PropertyS access_properties() override
Retrieve handles for all properties.
Definition gadget.cc:158
Value get_data(const String &key) const override
Retrieve session data.
Definition gadget.cc:54
bool set_data(const String &key, const Value &v) override
Assign session data, prefix ephemerals with '_'.
Definition gadget.cc:61
void _set_parent(GadgetImpl *parent) override
Assign parent container.
Definition gadget.cc:29
void serialize(WritNode &xs) override
Serialize members and childern.
Definition gadget.cc:71
Base type for classes that have a Property.
Definition api.hh:174
virtual StringS list_properties()
List all property identifiers.
Definition gadget.cc:176
virtual PropertyP access_property(String ident)
Retrieve handle for a Property.
Definition gadget.cc:187
virtual PropertyS access_properties()=0
Retrieve handles for all properties.
ProjectImpl * _project() const
Find Project in parent ancestry.
Definition gadget.cc:167
virtual GadgetImpl * _parent() const =0
Retrieve parent container.
Value get_value(String ident)
Get native property value.
Definition gadget.cc:196
bool set_value(String ident, const Value &v)
Set native property value.
Definition gadget.cc:203
virtual void serialize(WritNode &xs)=0
Serialize members and childern.
Definition serialize.cc:379
One entry in a Writ serialization document.
Definition serialize.hh:24
bool in_load() const
Return true during deserialization.
Definition serialize.hh:175
bool in_save() const
Return true during serialization.
Definition serialize.hh:181
T find(T... args)
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
Definition internal.hh:29
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
Definition internal.hh:73
The Anklang C++ API namespace.
Definition api.hh:9
bool string_option_check(const String &optionlist, const String &feature)
Check if an option is set/unset in an options list string.
Definition strings.cc:1412
std::vector< String > StringS
Convenience alias for a std::vector<std::string>.
Definition cxxaux.hh:36
std::function< ChoiceS(const ParameterProperty &)> PropertyLister
Function type to list Choice Property values.
Definition properties.hh:76
const String & string_set_a2z()
Returns a string containing all of a-z.
Definition strings.cc:102
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:35
String string_canonify(const String &string, const String &valid_chars, const String &substitute)
Enforce a canonical charset for a string.
Definition strings.cc:68
String string_strip(const String &input)
Strip whitespaces from the left and right of a string.
Definition strings.cc:1126
const String & string_set_A2Z()
Returns a string containing all of A-Z.
Definition strings.cc:110
std::function< void(Value &)> PropertyGetter
Function type for Property value getters.
Definition properties.hh:70
bool string_endswith(const String &string, const String &fragment)
Returns whether string ends with fragment.
Definition strings.cc:863
std::function< bool(const Value &)> PropertySetter
Function type for Property value setters.
Definition properties.hh:73
T push_back(T... args)
T reserve(T... args)
T rfind(T... args)
T size(T... args)
typedef uint64_t
strcmp
Helper to specify parameter ranges.
Definition parameter.hh:21
Value type used to interface with various property types.
Definition value.hh:54
T substr(T... args)
typedef ssize_t