diff options
author | Josh Blum | 2013-07-13 11:23:41 -0700 |
---|---|---|
committer | Josh Blum | 2013-07-13 11:23:41 -0700 |
commit | 92c8b4646d77d569480d7c3120a00df6a9645aba (patch) | |
tree | 4b8543b56f57352d4656e140c10a765423326ea8 /tmpl | |
parent | f99744a072d97c83f5a7da6c0626a38475c4fc44 (diff) | |
download | sandhi-92c8b4646d77d569480d7c3120a00df6a9645aba.tar.gz sandhi-92c8b4646d77d569480d7c3120a00df6a9645aba.tar.bz2 sandhi-92c8b4646d77d569480d7c3120a00df6a9645aba.zip |
gras: work on generator scripts for template madness
Diffstat (limited to 'tmpl')
-rw-r--r-- | tmpl/callable.tmpl.hpp | 94 | ||||
-rw-r--r-- | tmpl/callable_detail.tmpl.hpp | 100 | ||||
-rw-r--r-- | tmpl/expand_template.py | 33 | ||||
-rw-r--r-- | tmpl/factory.tmpl.hpp | 63 | ||||
-rw-r--r-- | tmpl/factory_detail.tmpl.hpp | 64 | ||||
-rw-r--r-- | tmpl/regen_all.sh | 10 |
6 files changed, 364 insertions, 0 deletions
diff --git a/tmpl/callable.tmpl.hpp b/tmpl/callable.tmpl.hpp new file mode 100644 index 0000000..1c73910 --- /dev/null +++ b/tmpl/callable.tmpl.hpp @@ -0,0 +1,94 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#ifndef INCLUDED_GRAS_CALLABLE_HPP +#define INCLUDED_GRAS_CALLABLE_HPP + +#include <gras/gras.hpp> +#include <PMC/PMC.hpp> +#include <boost/shared_ptr.hpp> +#include <vector> +#include <string> + +namespace gras +{ + +/*! + * The callable interface allows subclasses to export public methods, + * but without actually exporting traditional library symbols. + * + * Callable handles the template magic so you don't have to: + * - registering subclass methods is simple and easy on the user. + * - users call registered methods with natural code aesthetics. + * + * Register a method (in the constructor of MyClass): + * this->register_call("set_foo", &MyClass::set_foo); + * + * Call a method on a instance of MyClass: + * my_class->x("set_foo", new_foo_val); + * + * Why x for the call method? + * - The "x" is short, one character of screen width. + * - The "x" looks like "*", which is commonly used. + * - The overloaded () operator sucks with pointers. + * - The overloaded () operator has template issues. + */ +class GRAS_API Callable +{ +public: + + //! Default constructor + Callable(void); + + //! Destructor (virtual for subclasses) + virtual ~Callable(void); + + //! Get a list of names for registered calls + std::vector<std::string> get_registered_names(void) const; + +protected: + /*! + * Unregister a previously registered call. + * Throws if the name is not found in the registry. + */ + void unregister_call(const std::string &name); + + /******************************************************************* + * Register API - don't look here, template magic, not helpful + ******************************************************************/ +protected: + #for $NARGS in range($MAX_ARGS) + template <typename ClassType, typename ReturnType, $expand('typename Arg%d', $NARGS)> + void register_call(const std::string &name, ReturnType(ClassType::*fcn)($expand('const Arg%d &', $NARGS))); + + template <typename ClassType, $expand('typename Arg%d', $NARGS)> + void register_call(const std::string &name, void(ClassType::*fcn)($expand('const Arg%d &', $NARGS))); + + #end for + /******************************************************************* + * Call API - don't look here, template magic, not helpful + ******************************************************************/ +public: + #for $NARGS in range($MAX_ARGS) + template <typename ReturnType, $expand('typename Arg%d', $NARGS)> + ReturnType x(const std::string &name, $expand('const Arg%d &', $NARGS)); + + template <$expand('typename Arg%d', $NARGS)> + void x(const std::string &name, $expand('const Arg%d &', $NARGS)); + + #end for + /******************************************************************* + * Private registration hooks + ******************************************************************/ +protected: + void _register_call(const std::string &, void *); +public: + virtual PMCC _handle_call(const std::string &, const PMCC &); +private: + boost::shared_ptr<void> _call_registry; +}; + +} //namespace gras + +#include <gras/detail/callable.hpp> + +#endif /*INCLUDED_GRAS_CALLABLE_HPP*/ diff --git a/tmpl/callable_detail.tmpl.hpp b/tmpl/callable_detail.tmpl.hpp new file mode 100644 index 0000000..ee11815 --- /dev/null +++ b/tmpl/callable_detail.tmpl.hpp @@ -0,0 +1,100 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#ifndef INCLUDED_GRAS_DETAIL_CALLABLE_HPP +#define INCLUDED_GRAS_DETAIL_CALLABLE_HPP + +#include <PMC/Containers.hpp> //PMCList + +namespace gras +{ + +/*********************************************************************** + * Registration entry base class + **********************************************************************/ +struct GRAS_API CallableRegistryEntry +{ + CallableRegistryEntry(void); + virtual ~CallableRegistryEntry(void); + virtual PMCC call(const PMCC &args) = 0; +}; + +#for $NARGS in range($MAX_ARGS) +/*********************************************************************** + * Registration for return with $NARGS args + **********************************************************************/ +template <typename ClassType, typename ReturnType, $expand('typename Arg%d', $NARGS)> +struct CallableRegistryEntryImpl$(NARGS) : CallableRegistryEntry +{ + typedef ReturnType(ClassType::*Fcn)($expand('const Arg%d &', $NARGS)); + CallableRegistryEntryImpl$(NARGS)(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC &args) + { + const PMCList &a = args.as<PMCList>(); + if (a.size() < $NARGS) throw a; + return PMC_M((_obj->*_fcn)($expand('a[%d].safe_as<Arg%d>()', $NARGS))); + } + ClassType *_obj; Fcn _fcn; +}; + +template <typename ClassType, typename ReturnType, $expand('typename Arg%d', $NARGS)> +void Callable::register_call(const std::string &name, ReturnType(ClassType::*fcn)($expand('const Arg%d &', $NARGS))) +{ + ClassType *obj = dynamic_cast<ClassType *>(this); + void *fr = new CallableRegistryEntryImpl$(NARGS)<ClassType, ReturnType, $expand('Arg%d', $NARGS)>(obj, fcn); + _register_call(name, fr); +} + +template <typename ClassType, $expand('typename Arg%d', $NARGS)> +struct CallableRegistryEntryImplVoid$(NARGS) : CallableRegistryEntry +{ + typedef void(ClassType::*Fcn)($expand('const Arg%d &', $NARGS)); + CallableRegistryEntryImplVoid$(NARGS)(ClassType *obj, Fcn fcn): + _obj(obj), _fcn(fcn){} + PMCC call(const PMCC &args) + { + const PMCList &a = args.as<PMCList>(); + if (a.size() < $NARGS) throw a; + (_obj->*_fcn)($expand('a[%d].safe_as<Arg%d>()', $NARGS)); return PMCC(); + } + ClassType *_obj; Fcn _fcn; +}; + +template <typename ClassType, $expand('typename Arg%d', $NARGS)> +void Callable::register_call(const std::string &name, void(ClassType::*fcn)($expand('const Arg%d &', $NARGS))) +{ + ClassType *obj = dynamic_cast<ClassType *>(this); + void *fr = new CallableRegistryEntryImplVoid$(NARGS)<ClassType, $expand('Arg%d', $NARGS)>(obj, fcn); + _register_call(name, fr); +} + +#end for +#for $NARGS in range($MAX_ARGS) +/*********************************************************************** + * Call implementations with $NARGS args + **********************************************************************/ +template <typename ReturnType, $expand('typename Arg%d', $NARGS)> +ReturnType Callable::x(const std::string &name, $expand('const Arg%d &a%d', $NARGS)) +{ + PMCList args($NARGS); + #for $i in range($NARGS): + args[$i] = PMC_M(a$i); + #end for + PMCC r = _handle_call(name, PMC_M(args)); + return r.safe_as<ReturnType>(); +} + +template <$expand('typename Arg%d', $NARGS)> +void Callable::x(const std::string &name, $expand('const Arg%d &a%d', $NARGS)) +{ + PMCList args($NARGS); + #for $i in range($NARGS): + args[$i] = PMC_M(a$i); + #end for + _handle_call(name, PMC_M(args)); +} + +#end for +} //namespace gras + +#endif /*INCLUDED_GRAS_DETAIL_CALLABLE_HPP*/ diff --git a/tmpl/expand_template.py b/tmpl/expand_template.py new file mode 100644 index 0000000..3941fb2 --- /dev/null +++ b/tmpl/expand_template.py @@ -0,0 +1,33 @@ +# Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +import os +import sys +from Cheetah.Template import Template + +MAX_ARGS = 11 + +def expand(t, n): + out = list() + for i in range(n): out.append(t.replace('%d', str(i))) + return ', '.join(out) + +def cleanup(code): + code = code.replace('template <>', 'inline') + code = code.replace(', >', '>') + code = code.replace(', )', ')') + code = code.replace('\\#', '#') + return code + +if __name__ == '__main__': + in_path = sys.argv[1] + out_path = sys.argv[2] + tmpl = open(in_path, 'r').read() + for key in ['define', 'include', 'if', 'endif', 'else', 'ifdef', 'ifndef']: + tmpl = tmpl.replace('#%s'%key, '\\#%s'%key) + code = str(Template(tmpl, dict( + MAX_ARGS=MAX_ARGS, expand=expand, + ))) + code = cleanup(code) + if not os.path.exists(out_path) or open(out_path, 'r').read() != code: + print 'write code to', out_path + open(out_path, 'w').write(code) diff --git a/tmpl/factory.tmpl.hpp b/tmpl/factory.tmpl.hpp new file mode 100644 index 0000000..66f3e3e --- /dev/null +++ b/tmpl/factory.tmpl.hpp @@ -0,0 +1,63 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#ifndef INCLUDED_GRAS_FACTORY_HPP +#define INCLUDED_GRAS_FACTORY_HPP + +#include <gras/gras.hpp> +#include <gras/element.hpp> +#include <PMC/PMC.hpp> +#include <string> + +/*! + * Register a block's factory function: + * Declare this macro at the global scope in a cpp file. + * The block will register at static initialization time. + */ +#define GRAS_REGISTER_FACTORY(name, fcn) \ + GRAS_STATIC_BLOCK(fcn) \ + {gras::Factory::register_make(name, &fcn);} + +namespace gras +{ + +/*! + * Element factory: + * - Register factory functions into the global factory. + * - Call make() to create element from global factory. + * + * Example register a factory function: + * gras::Factory::register_make("make_my_block", &make_my_block); + * + * Example call into the factory: + * gras::Element *my_block = gras::Factory::make("make_my_block", arg0, arg1); + */ +struct GRAS_API Factory +{ + /******************************************************************* + * Register API - don't look here, template magic, not helpful + ******************************************************************/ + #for $NARGS in range($MAX_ARGS) + template <typename ReturnType, $expand('typename Arg%d', $NARGS)> + static void register_make(const std::string &name, ReturnType(*fcn)($expand('const Arg%d &', $NARGS))); + + #end for + /******************************************************************* + * Make API - don't look here, template magic, not helpful + ******************************************************************/; + #for $NARGS in range($MAX_ARGS) + template <$expand('typename Arg%d', $NARGS)> + static Element *make(const std::string &name, $expand('const Arg%d &', $NARGS)); + + #end for + /******************************************************************* + * Private registration hooks + ******************************************************************/ + static void _register_make(const std::string &, void *); + static Element *_handle_make(const std::string &, const PMCC &); +}; + +} + +#include <gras/detail/factory.hpp> + +#endif /*INCLUDED_GRAS_FACTORY_HPP*/ diff --git a/tmpl/factory_detail.tmpl.hpp b/tmpl/factory_detail.tmpl.hpp new file mode 100644 index 0000000..1238c38 --- /dev/null +++ b/tmpl/factory_detail.tmpl.hpp @@ -0,0 +1,64 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#ifndef INCLUDED_GRAS_DETAIL_FACTORY_HPP +#define INCLUDED_GRAS_DETAIL_FACTORY_HPP + +#include <PMC/Containers.hpp> //PMCList + +namespace gras +{ + +/*********************************************************************** + * Factory entry base class + **********************************************************************/ +struct GRAS_API FactoryRegistryEntry +{ + FactoryRegistryEntry(void); + virtual ~FactoryRegistryEntry(void); + virtual Element *make(const PMCC &args) = 0; +}; + +#for $NARGS in range($MAX_ARGS) +/*********************************************************************** + * Templated registration - $NARGS args + **********************************************************************/ +template <typename ReturnType, $expand('typename Arg%d', $NARGS)> +struct FactoryRegistryEntryImpl$(NARGS) : FactoryRegistryEntry +{ + typedef ReturnType(*Fcn)($expand('const Arg%d &', $NARGS)); + FactoryRegistryEntryImpl$(NARGS)(Fcn fcn):_fcn(fcn){} + Element *make(const PMCC &args) + { + const PMCList &a = args.as<PMCList>(); + if (a.size() < $NARGS) throw a; + return _fcn($expand('a[%d].safe_as<Arg%d>()', $NARGS)); + } + Fcn _fcn; +}; + +template <typename ReturnType, $expand('typename Arg%d', $NARGS)> +void Factory::register_make(const std::string &name, ReturnType(*fcn)($expand('const Arg%d &', $NARGS))) +{ + void *r = new FactoryRegistryEntryImpl$(NARGS)<ReturnType, $expand('Arg%d', $NARGS)>(fcn); + Factory::_register_make(name, r); +} + +#end for +/*********************************************************************** + * Templated make implementations + **********************************************************************/ +#for $NARGS in range($MAX_ARGS) +template <$expand('typename Arg%d', $NARGS)> +Element *Factory::make(const std::string &name, $expand('const Arg%d &a%d', $NARGS)) +{ + PMCList args($NARGS); + #for $i in range($NARGS): + args[$i] = PMC_M(a$i); + #end for + return Factory::_handle_make(name, PMC_M(args)); +} + +#end for +} + +#endif /*INCLUDED_GRAS_DETAIL_FACTORY_HPP*/ diff --git a/tmpl/regen_all.sh b/tmpl/regen_all.sh new file mode 100644 index 0000000..f9f4c95 --- /dev/null +++ b/tmpl/regen_all.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +SCRIPT="`readlink -e $0`" +SCRIPTPATH="`dirname $SCRIPT`" +DEST=${SCRIPTPATH}/../include/gras + +python expand_template.py factory.tmpl.hpp ${DEST}/factory.hpp +python expand_template.py factory_detail.tmpl.hpp ${DEST}/detail/factory.hpp +python expand_template.py callable.tmpl.hpp ${DEST}/callable.hpp +python expand_template.py callable_detail.tmpl.hpp ${DEST}/detail/callable.hpp |