Commit baa946c3 authored by hbristow's avatar hbristow

Split MxArray out of bridge into standalone file. Does not depend on bridge.…

Split MxArray out of bridge into standalone file. Does not depend on bridge. Working to make it API complete with respect to mxArray, but with better calling syntax
parent 504558c0
......@@ -58,9 +58,9 @@ class MatlabWrapperGenerator(object):
# populate templates
for namespace in parse_tree.namespaces:
# functions
for function in namespace.functions:
populated = tfunction.render(fun=function, time=time, includes=namespace.name)
with open(output_source_dir+'/'+function.name+'.cpp', 'wb') as f:
for method in namespace.methods:
populated = tfunction.render(fun=method, time=time, includes=namespace.name)
with open(output_source_dir+'/'+method.name+'.cpp', 'wb') as f:
f.write(populated)
# classes
for clss in namespace.classes:
......
......@@ -13,7 +13,7 @@ class ParseTree(object):
babel = Translator()
for name, definitions in namespaces.items():
class_tree = {}
functions = []
methods = []
constants = []
for defn in definitions:
obj = babel.translate(defn)
......@@ -21,13 +21,13 @@ class ParseTree(object):
continue
if type(obj) is Class or obj.clss:
self.insertIntoClassTree(obj, class_tree)
elif type(obj) is Function:
functions.append(obj)
elif type(obj) is Method:
methods.append(obj)
elif type(obj) is Constant:
constants.append(obj)
else:
raise TypeError('Unexpected object type: '+str(type(obj)))
self.namespaces.append(Namespace(name, constants, class_tree.values(), functions))
self.namespaces.append(Namespace(name, constants, class_tree.values(), methods))
def insertIntoClassTree(self, obj, class_tree):
cname = obj.name if type(obj) is Class else obj.clss
......@@ -38,8 +38,8 @@ class ParseTree(object):
class_tree[cname] = Class(cname)
# insert the definition into the class
val = class_tree[cname]
if type(obj) is Function:
val.functions.append(obj)
if type(obj) is Method:
val.methods.append(obj)
elif type(obj) is Constant:
val.constants.append(obj)
else:
......@@ -63,7 +63,7 @@ class Translator(object):
# --- function ---
# functions either need to have input arguments, or not uppercase names
elif defn[3] or not self.translateName(defn[0]).split('_')[0].isupper():
return self.translateFunction(defn)
return self.translateMethod(defn)
# --- constant ---
else:
return self.translateConstant(defn)
......@@ -71,7 +71,7 @@ class Translator(object):
def translateClass(self, defn):
return Class()
def translateFunction(self, defn, class_tree=None):
def translateMethod(self, defn, class_tree=None):
name = self.translateName(defn[0])
clss = self.translateClassName(defn[0])
rtp = defn[1]
......@@ -83,7 +83,7 @@ class Translator(object):
if arg:
a = self.translateArgument(arg)
opt.append(a) if a.default else req.append(a)
return Function(name, clss, static, '', rtp, False, req, opt)
return Method(name, clss, static, '', rtp, False, req, opt)
def translateConstant(self, defn):
const = True if 'const' in defn[0] else False
......@@ -116,34 +116,35 @@ class Translator(object):
class Namespace(object):
def __init__(self, name='', constants=None, classes=None, functions=None):
def __init__(self, name='', constants=None, classes=None, methods=None):
self.name = name
self.constants = constants if constants else []
self.classes = classes if classes else []
self.functions = functions if functions else []
self.methods = methods if methods else []
def __str__(self):
return 'namespace '+self.name+' {\n\n'+\
(join((c.__str__() for c in self.constants), '\n')+'\n\n' if self.constants else '')+\
(join((f.__str__() for f in self.functions), '\n')+'\n\n' if self.functions else '')+\
(join((f.__str__() for f in self.methods), '\n')+'\n\n' if self.methods else '')+\
(join((o.__str__() for o in self.classes), '\n\n') if self.classes else '')+'\n};'
class Class(object):
def __init__(self, name='', namespace='', constants=None, functions=None):
def __init__(self, name='', namespace='', constants=None, methods=None):
self.name = name
self.namespace = namespace
self.constants = constants if constants else []
self.functions = functions if functions else []
self.methods = methods if methods else []
def __str__(self):
return 'class '+self.name+' {\n\t'+\
(join((c.__str__() for c in self.constants), '\n\t')+'\n\n\t' if self.constants else '')+\
(join((f.__str__() for f in self.functions), '\n\t') if self.functions else '')+'\n};'
(join((f.__str__() for f in self.methods), '\n\t') if self.methods else '')+'\n};'
class Function(object):
class Method(object):
def __init__(self, name='', clss='', static=False, namespace='', rtp='', const=False, req=None, opt=None):
self.name = name
self.clss = clss
self.constructor = True if name == clss else False
self.static = static
self.const = const
self.namespace = namespace
......
/*
* compose
* compose a function call
* This macro takes as input a Function object and composes
* This macro takes as input a Method object and composes
* a function call by inspecting the types and argument names
*/
/
{% macro compose(fun) %}
{# ----------- Return type ------------- #}
{%- if not fun.rtp|void -%} retval = {% endif -%}
{%- if fun.clss -%}inst.{%- else -%} cv:: {%- endif -%}
{%- if not fun.rtp|void and not fun.constructor -%} retval = {% endif -%}
{%- if fun.constructor -%}{{fun.clss}} obj = {% endif -%}
{%- if fun.clss and not fun.constructor -%}inst.{%- else -%} cv:: {%- endif -%}
{{fun.name}}(
{#- ----------- Required ------------- -#}
{%- for arg in fun.req -%}
......@@ -26,10 +26,39 @@
);
{%- endmacro %}
// create a full function invocation
{%- macro generate(fun) -%}
{% if fun|ninputs or fun|noutputs %}
/*
* composeWithExceptionHandler
* compose a function call wrapped in exception traps
* This macro takes an input a Method object and composes a function
* call through the compose() macro, then wraps the return in traps
* for cv::Exceptions, std::exceptions, and all generic exceptions
* and returns a useful error message to the Matlab interpreter
*/
{%- macro composeWithExceptionHandler(fun) -%}
// call the opencv function
// [out =] namespace.fun(src1, ..., srcn, dst1, ..., dstn, opt1, ..., optn);
try {
{{ compose(fun) }}
} catch(cv::Exception& e) {
error(std::string("cv::exception caught: ").append(e.what()).c_str());
} catch(std::exception& e) {
error(std::string("std::exception caught: ").append(e.what()).c_str());
} catch(...) {
error("Uncaught exception occurred in {{fun.name}}");
}
{%- endmacro %}
/*
* handleInputs
* unpack input arguments from the Bridge
* Given an input Bridge object, this unpacks the object from the Bridge and
* casts them into the correct type
*/
{%- macro handleInputs(fun) %}
{% if fun|ninputs or (fun|noutputs and not fun.constructor) %}
// unpack the arguments
{# ----------- Inputs ------------- #}
{% for arg in fun.req|inputs %}
......@@ -45,26 +74,24 @@
{% for opt in fun.opt|only|outputs %}
{{opt.tp}} {{opt.name}};
{% endfor %}
{% if not fun.rtp|void %}
{% if not fun.rtp|void and not fun.constructor %}
{{fun.rtp}} retval;
{% endif %}
{% endif %}
// call the opencv function
// [out =] namespace.fun(src1, ..., srcn, dst1, ..., dstn, opt1, ..., optn);
try {
{{ compose(fun) }}
} catch(cv::Exception& e) {
mexErrMsgTxt(std::string("cv::exception caught: ").append(e.what()).c_str());
} catch(std::exception& e) {
mexErrMsgTxt(std::string("std::exception caught: ").append(e.what()).c_str());
} catch(...) {
mexErrMsgTxt("Uncaught exception occurred in {{fun.name}}");
}
{%- endmacro %}
/*
* handleOutputs
* pack outputs into the bridge
* Given a set of outputs, this methods assigns them into the bridge for
* return to the calling method
*/
{%- macro handleOutputs(fun) %}
{% if fun|noutputs %}
// assign the outputs into the bridge
{% if not fun.rtp|void %}
{% if not fun.rtp|void and not fun.constructor %}
outputs[0] = retval;
{% endif %}
{% for arg in fun.req|outputs %}
......@@ -74,5 +101,4 @@
outputs[{{loop.index0 + fun.rtp|void|not + fun.req|outputs|length}}] = {{opt.name}};
{% endfor %}
{% endif %}
{% endmacro %}
{%- endmacro %}
......@@ -9,30 +9,41 @@
* Copyright {{time.strftime("%Y", time.localtime())}} The OpenCV Foundation
*/
#include "mex.h"
#include "map.hpp"
#include "bridge.hpp"
#include <vector>
//TODO: Standard C++ does not have an unordered_map (only C++11 and Boost)
#include <unordered_map>
#include <string>
#include <opencv2/core.hpp>
using namespace cv;
namespace {
typedef std::unordered_map Map;
typedef std::vector<Bridge> (*)({{clss.name}}&, const std::vector<Bridge>&) MethodSignature;
{% for function in clss.functions %}
{% for function in clss.methods %}
{% if function.constructor %}
// wrapper for {{function.name}}() constructor
{{ function.clss }} {{function.name}}(const std::vector<Bridge>& inputs) {
{{ functional.handleInputs(function) }}
{{ functional.compose(function) }}
return obj;
}
{% else %}
// wrapper for {{function.name}}() method
std::vector<Bridge> {{function.name}}({{clss.name}}& inst, const std::vector<Bridge>& args) {
{{ functional.generate(function) }}
std::vector<Bridge> {{function.name}}({{clss.name}}& inst, const std::vector<Bridge>& inputs) {
std::vector<Bridge> outputs{% if function|noutputs %}({{function|noutputs}}){% endif %};
{{ functional.handleInputs(function) }}
{{ functional.composeWithExceptionHandler(function) }}
{{ functional.handleOutputs(function) }}
return outputs;
}
{% endif %}
{% endfor %}
map<std::string, MethodSignature> createMethodMap() {
Map<std::string, MethodSignature> createMethodMap() {
Map<std::string, MethodSignature> m;
{% for function in clss.functions -%}
{% for function in clss.methods %}
m["{{function.name}}"] = &{{function.name}};
{% endfor %}
......@@ -82,4 +93,4 @@ void mexFunction(int nlhs, mxArray* plhs[],
}
}; // end namespace
} // end namespace
......@@ -44,9 +44,11 @@ void mexFunction(int nlhs, mxArray*{% if fun|noutputs %} plhs[]{% else %}*{% end
{% endif %}
{% endif %}
{{ functional.generate(fun) }}
{{ functional.handleInputs(fun) }}
{{ functional.composeWithExceptionHandler(fun) }}
{{ functional.handleOutputs(fun) }}
{%- if fun|noutputs %}
{% if fun|noutputs %}
// push the outputs back to matlab
for (size_t n = 0; n < static_cast<size_t>(nlhs); ++n) {
plhs[n] = outputs[n].toMxArray().releaseOwnership();
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment