summaryrefslogtreecommitdiff
path: root/tmpl
diff options
context:
space:
mode:
authorJosh Blum2013-07-13 11:23:41 -0700
committerJosh Blum2013-07-13 11:23:41 -0700
commit92c8b4646d77d569480d7c3120a00df6a9645aba (patch)
tree4b8543b56f57352d4656e140c10a765423326ea8 /tmpl
parentf99744a072d97c83f5a7da6c0626a38475c4fc44 (diff)
downloadsandhi-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.hpp94
-rw-r--r--tmpl/callable_detail.tmpl.hpp100
-rw-r--r--tmpl/expand_template.py33
-rw-r--r--tmpl/factory.tmpl.hpp63
-rw-r--r--tmpl/factory_detail.tmpl.hpp64
-rw-r--r--tmpl/regen_all.sh10
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