Simplify command::* memory management
[lsnes.git] / include / library / command.hpp
blob6dd9c721facce07a0a3f73c17f44996bdc894fa8
1 #ifndef _library_command__hpp__included__
2 #define _library_command__hpp__included__
4 #include <stdexcept>
5 #include <string>
6 #include <set>
7 #include <map>
8 #include <list>
9 #include "threads.hpp"
11 namespace command
13 class base;
14 class factory_base;
16 threads::lock& get_cmd_lock();
18 /**
19 * A set of commands.
21 class set
23 public:
24 /**
25 * Create a new set.
27 set() throw(std::bad_alloc);
28 /**
29 * Destroy a set.
31 ~set() throw();
32 /**
33 * Add a command to set.
35 void do_register(const std::string& name, factory_base& cmd) throw(std::bad_alloc)
37 threads::alock h(get_cmd_lock());
38 do_register_unlocked(name, cmd);
40 /**
41 * Remove a command from set.
43 void do_unregister(const std::string& name, factory_base& cmd) throw(std::bad_alloc)
45 threads::alock h(get_cmd_lock());
46 // do_unregister_unlocked(name, cmd);
48 /**
49 * Add a notification callback and call ccb on all.
51 * Parameter ccb: The create callback function.
52 * Parameter dcb: The destroy callback function.
53 * Parameter tcb: The terminate callback function.
54 * Returns: Callback handle.
56 uint64_t add_callback(std::function<void(set& s, const std::string& name, factory_base& cmd)> ccb,
57 std::function<void(set& s, const std::string& name)> dcb, std::function<void(set& s)> tcb)
58 throw(std::bad_alloc)
60 threads::alock h(get_cmd_lock());
61 return add_callback_unlocked(ccb, dcb, tcb);
63 /**
64 * Drop a notification callback and call dcb on all.
66 * Parameter handle: The handle of callback to drop.
68 void drop_callback(uint64_t handle) throw()
70 threads::alock h(get_cmd_lock());
71 drop_callback_unlocked(handle);
73 /**
74 * Obtain list of all commands so far.
76 std::map<std::string, factory_base*> get_commands()
78 threads::alock h(get_cmd_lock());
79 return get_commands_unlocked();
81 /**
82 * Unlocked versions of other functions.
84 void do_register_unlocked(const std::string& name, factory_base& cmd) throw(std::bad_alloc);
85 void do_unregister_unlocked(const std::string& name, factory_base& cmd) throw(std::bad_alloc);
86 uint64_t add_callback_unlocked(std::function<void(set& s, const std::string& name, factory_base& cmd)> ccb,
87 std::function<void(set& s, const std::string& name)> dcb, std::function<void(set& s)> tcb)
88 throw(std::bad_alloc);
89 void drop_callback_unlocked(uint64_t handle) throw();
90 std::map<std::string, factory_base*> get_commands_unlocked();
91 private:
92 char dummy;
95 /**
96 * A group of commands (with aliases).
98 class group
100 public:
102 * Create a new command group. This also places some builtin commands in that new group.
104 group() throw(std::bad_alloc);
106 * Destroy a group.
108 ~group() throw();
110 * Look up and invoke a command. The command will undergo alias expansion and recursion checking.
112 * parameter cmd: Command to exeucte.
114 void invoke(const std::string& cmd) throw();
116 * Get set of aliases.
118 std::set<std::string> get_aliases() throw(std::bad_alloc);
120 * Get alias
122 std::string get_alias_for(const std::string& aname) throw(std::bad_alloc);
124 * Set alias
126 void set_alias_for(const std::string& aname, const std::string& avalue) throw(std::bad_alloc);
128 * Is alias name valid.
130 bool valid_alias_name(const std::string& aname) throw(std::bad_alloc);
132 * Register a command.
134 void do_register(const std::string& name, base& cmd) throw(std::bad_alloc)
136 threads::alock h(get_cmd_lock());
137 do_register_unlocked(name, cmd);
140 * Unregister a command.
142 void do_unregister(const std::string& name, base& cmd) throw(std::bad_alloc)
144 threads::alock h(get_cmd_lock());
145 do_unregister_unlocked(name, cmd);
148 * Add all commands (including future ones) in given set.
150 void add_set(set& s) throw(std::bad_alloc)
152 threads::alock h(get_cmd_lock());
153 add_set_unlocked(s);
156 * Drop a set of commands.
158 void drop_set(set& s) throw()
160 threads::alock h(get_cmd_lock());
161 drop_set_unlocked(s);
164 * Set the output stream.
166 void set_output(std::ostream& s);
168 * Set the OOM panic routine.
170 void set_oom_panic(void (*fn)());
172 * Unlocked versions.
174 void do_register_unlocked(const std::string& name, base& cmd) throw(std::bad_alloc);
175 void do_unregister_unlocked(const std::string& name, base& cmd) throw(std::bad_alloc);
176 void add_set_unlocked(set& s) throw(std::bad_alloc);
177 void drop_set_unlocked(set& s) throw();
178 private:
179 std::set<std::string> command_stack;
180 std::map<std::string, std::list<std::string>> aliases;
181 std::ostream* output;
182 void (*oom_panic_routine)();
183 base* builtin[1];
187 * A command.
189 class base
191 public:
193 * Register a new command.
195 * parameter group: The group command will be part of.
196 * parameter cmd: The command to register.
197 * parameter dynamic: Should the object be freed when its parent group dies?
198 * throws std::bad_alloc: Not enough memory.
200 base(group& group, const std::string& cmd, bool dynamic) throw(std::bad_alloc);
203 * Deregister a command.
205 virtual ~base() throw();
208 * Invoke a command.
210 * parameter arguments: Arguments to command.
211 * throws std::bad_alloc: Not enough memory.
212 * throws std::runtime_error: Command execution failed.
214 virtual void invoke(const std::string& arguments) throw(std::bad_alloc, std::runtime_error) = 0;
216 * Get short help for command.
218 virtual std::string get_short_help() throw(std::bad_alloc);
221 * Get long help for command.
223 virtual std::string get_long_help() throw(std::bad_alloc);
225 * Get name of command.
227 const std::string& get_name() { return commandname; }
229 * Notify that the parent group died.
231 * Note: Assumed to be called with global lock held.
233 void group_died() throw();
234 private:
235 base(const base&);
236 base& operator=(const base&);
237 std::string commandname;
238 group* in_group;
239 bool is_dynamic;
243 * A command factory.
245 class factory_base
247 public:
248 factory_base() throw() {}
250 * Register a new command.
252 * parameter _set: The set command will be part of.
253 * parameter cmd: The command to register.
254 * throws std::bad_alloc: Not enough memory.
256 void _factory_base(set& _set, const std::string& cmd) throw(std::bad_alloc);
258 * Destructor.
260 virtual ~factory_base() throw();
262 * Make a new command.
264 virtual base* make(group& grp) = 0;
266 * Notify that the parent set died.
268 * Note: Assumed to be called with global lock held.
270 void set_died() throw();
271 private:
272 factory_base(const factory_base&);
273 factory_base& operator=(const factory_base&);
274 std::string commandname;
275 set* in_set;
279 * Mandatory filename
281 struct arg_filename
284 * The filename itself.
286 std::string v;
288 * Return the filename.
290 * returns: The filename.
292 operator std::string() { return v; }
296 * Run command function helper.
298 * parameter fn: Function pointer to invoke.
299 * parameter a: The arguments to pass.
301 template<typename... args>
302 void invoke_fn(void (*fn)(args... arguments), const std::string& a);
305 * Warp function pointer as command.
307 template<typename... args>
308 class _fnptr : public base
310 public:
312 * Create a new command.
314 * parameter group: The group command will be part of.
315 * parameter name: Name of the command
316 * parameter description Description for the command
317 * parameter help: Help for the command.
318 * parameter fn: Function to call on command.
319 * parameter dynamic: Should the object be freed when its parent group dies?
321 _fnptr(group& group, const std::string& name, const std::string& _description,
322 const std::string& _help, void (*_fn)(args... arguments), bool dynamic = false) throw(std::bad_alloc)
323 : base(group, name, dynamic)
325 description = _description;
326 help = _help;
327 fn = _fn;
330 * Destroy a commnad.
332 ~_fnptr() throw()
336 * Invoke a command.
338 * parameter a: Arguments to function.
340 void invoke(const std::string& a) throw(std::bad_alloc, std::runtime_error)
342 invoke_fn(fn, a);
345 * Get short description.
347 * returns: Description.
348 * throw std::bad_alloc: Not enough memory.
350 std::string get_short_help() throw(std::bad_alloc)
352 return description;
355 * Get long help.
357 * returns: help.
358 * throw std::bad_alloc: Not enough memory.
360 std::string get_long_help() throw(std::bad_alloc)
362 return help;
364 private:
365 void (*fn)(args... arguments);
366 std::string description;
367 std::string help;
371 * Function pointer command factory.
373 template<typename... args>
374 class fnptr : public factory_base
376 public:
378 * Create a new command.
380 * parameter _set: The set command will be part of.
381 * parameter name: Name of the command
382 * parameter description Description for the command
383 * parameter help: Help for the command.
384 * parameter fn: Function to call on command.
386 fnptr(set& _set, const std::string& _name, const std::string& _description,
387 const std::string& _help, void (*_fn)(args... arguments)) throw(std::bad_alloc)
389 description = _description;
390 name = _name;
391 help = _help;
392 fn = _fn;
393 _factory_base(_set, name);
396 * Destroy a commnad.
398 ~fnptr() throw()
402 * Make a command.
404 base* make(group& grp) throw(std::bad_alloc)
406 return new _fnptr<args...>(grp, name, description, help, fn, true);
408 private:
409 void (*fn)(args... arguments);
410 std::string description;
411 std::string help;
412 std::string name;
416 * Generic byname factory.
418 template<typename T>
419 class byname_factory : public factory_base
421 public:
423 * Create a new factory.
425 byname_factory(set& s, const std::string& _name)
427 name = _name;
428 _factory_base(s, name);
431 * Destroy.
433 ~byname_factory() throw()
437 * Make a command.
439 base* make(group& grp) throw(std::bad_alloc)
441 return new T(grp, name);
443 private:
444 std::string name;
447 #endif