[sourcegen] Split accessor from constructor methods

This commit is contained in:
Ingmar Schoegl 2025-01-26 11:20:57 -06:00 committed by Ray Speth
parent 399d48d477
commit e936e267da
7 changed files with 68 additions and 54 deletions

View File

@ -23,10 +23,11 @@ based on a recipe, which is subsequently used to scaffold API functions using de
*Jinja* templates. The following recipe/CLib function types are differentiated: *Jinja* templates. The following recipe/CLib function types are differentiated:
- `function`: Regular function defined in the `Cantera` namespace. - `function`: Regular function defined in the `Cantera` namespace.
- `constructor`: A CLib constructor adds new (or existing) C++ objects to CLib storage. - `constructor`: A CLib constructor adds new C++ objects to CLib storage. Constructor
As all objects are handled via smart `shared_ptr<>`, a CLib constructor requires a names should start with `new`. As all objects are handled via smart `shared_ptr<>`,
C++ utility functions that returning a pointer to a new object or an object that is CLib constructors require C++ utility functions that return a pointer to a new
not yet added to CLib storage. Constructor names should start with `new`. object. Constructors with the name `new` will use the C++ default constructor.
- `accessor`: a CLib accessor adds existing or spawned C++ objects to CLib storage.
- `destructor`: A CLib destructor removes a C++ object from CLib. Destructor names - `destructor`: A CLib destructor removes a C++ object from CLib. Destructor names
should start with `del`. should start with `del`.
- `getter`: Implements a getter method of a C++ class. - `getter`: Implements a getter method of a C++ class.

View File

@ -27,9 +27,8 @@ recipes:
implements: newRatioFunction implements: newRatioFunction
- name: type - name: type
- name: eval - name: eval
- name: newDerivative - name: derivative
what: constructor what: accessor
implements: Func1::derivative
- name: write - name: write
- name: del - name: del
what: destructor what: destructor

View File

@ -9,15 +9,16 @@ base: Kinetics
parents: [] # List of parent classes parents: [] # List of parent classes
derived: [InterfaceKinetics] # List of specializations derived: [InterfaceKinetics] # List of specializations
recipes: recipes:
- name: kineticsType # previously getType - name: kineticsType # previously: getType
- name: nReactions - name: nReactions
- name: reaction # new - name: reaction # new
uses: nReactions uses: nReactions
what: constructor # registers object in CLib storage what: accessor
- name: nPhases - name: nPhases
- name: phase - name: phase
uses: nPhases uses: nPhases
what: constructor # registers object in CLib storage what: accessor
- name: reactionPhase # new
- name: phaseIndex - name: phaseIndex
- name: nTotalSpecies # previously: nSpecies - name: nTotalSpecies # previously: nSpecies
- name: reactantStoichCoeff - name: reactantStoichCoeff
@ -45,7 +46,7 @@ recipes:
- name: getDeltaSSGibbs # previously: part of getDelta - name: getDeltaSSGibbs # previously: part of getDelta
- name: getDeltaSSEntropy # previously: part of getDelta - name: getDeltaSSEntropy # previously: part of getDelta
# - name: getSourceTerms # <--- used by MATLAB interface for "massProdRate" # - name: getSourceTerms # <--- used by MATLAB interface for "massProdRate"
# - name: start # <--- appears to be unused # - name: start # <--- unused except for FORTRAN API
- name: del - name: del
what: noop what: noop
brief: Destructor; required by some APIs although object is managed by Solution. brief: Destructor; required by some APIs although object is managed by Solution.

View File

@ -26,12 +26,12 @@ recipes:
- name: transportModel - name: transportModel
- name: setTransportModel - name: setTransportModel
uses: [transport] uses: [transport]
what: constructor what: accessor
- name: nAdjacent - name: nAdjacent
- name: adjacent - name: adjacent
implements: Solution::adjacent(size_t) implements: Solution::adjacent(size_t)
uses: [nAdjacent, thermo, kinetics, transport] uses: [nAdjacent, thermo, kinetics, transport]
what: constructor # registers object in CLib storage what: accessor
- name: adjacentName - name: adjacentName
- name: source - name: source
- name: cabinetSize - name: cabinetSize

View File

@ -336,6 +336,9 @@ class CLibSourceGenerator(SourceGenerator):
elif recipe.what == "constructor": elif recipe.what == "constructor":
template = loader.from_string(self._templates["clib-constructor"]) template = loader.from_string(self._templates["clib-constructor"])
elif recipe.what == "accessor":
template = loader.from_string(self._templates["clib-accessor"])
elif recipe.what == "destructor": elif recipe.what == "destructor":
template = loader.from_string(self._templates["clib-destructor"]) template = loader.from_string(self._templates["clib-destructor"])

View File

@ -134,30 +134,62 @@ clib-function: |-
} }
clib-constructor: |- clib-constructor: |-
## CLib constructor template: ## CLib constructor template: instantiates new object
## may either instantiate new object or expose existing C++ object to CLib
// constructor: {{ cxx_implements }} // constructor: {{ cxx_implements }}
try { try {
{% for line in lines %} {% for line in lines %}
## add lines used for CLib/C++ variable crosswalk ## add lines used for CLib/C++ variable crosswalk
{{ line }} {{ line }}
{% endfor %} {% endfor %}
{% if handle and checks %}
## constructor accesses existing object and uses index checker (see: sol3_adjacent)
if ({{ c_args[1] }} < 0 || {{ c_args[1] }} >= {{ base }}Cabinet::at({{ handle }})->{{ checks[0] }}()) {
throw IndexError("{{ c_func }}", "", {{ c_args[1] }}, {{ base }}Cabinet::at({{ handle }})->{{ checks[0] }}() - 1);
}
{% endif %}{# handle and checks #}
{% if shared %} {% if shared %}
## instantiated object manages associated objects (see: sol3_newSolution) ## instantiated object manages associated objects (see: sol3_newSolution)
## storage of associated objects requires id (handle) of new object ## storage of associated objects requires id (handle) of new object
{% if handle %} auto obj = {{ cxx_name }}({{ ', '.join(cxx_args) }});
## constructor exposes existing C++ object to CLib int id = {{ base }}Cabinet::add(obj);
## the accessed C++ object may have a different base {% for typ, getter in shared %}
## add associated objects (see: sol3_newSolution, sol3_adjacent)
if (obj->{{ getter }}()) {
{{ typ }}Cabinet::add(obj->{{ getter }}(), id);
}
{% endfor %}
return id;
{% else %}{# not shared #}
## instantiated object has no associated objects; no id is needed
return {{ base }}Cabinet::add({{ cxx_name }}({{ ', '.join(cxx_args) }}));
{% endif %}{# shared #}
} catch (...) {
return handleAllExceptions({{ error[0] }}, {{ error[1] }});
}
clib-accessor: |-
## CLib accessor template: exposes existing C++ object to CLib
// accessor: {{ cxx_implements }}
try {
{% for line in lines %}
## add lines used for CLib/C++ variable crosswalk
{{ line }}
{% endfor %}
{% if checks %}
## accessor uses index checker (see: sol3_adjacent)
if ({{ c_args[1] }} < 0 || {{ c_args[1] }} >= {{ base }}Cabinet::at({{ handle }})->{{ checks[0] }}()) {
throw IndexError("{{ c_func }}", "", {{ c_args[1] }}, {{ base }}Cabinet::at({{ handle }})->{{ checks[0] }}() - 1);
}
{% endif %}{# checks #}
{% if shared %}
## accessed object manages associated objects (see: sol3_newSolution)
## storage of associated objects requires id (handle) of new object
{% if cxx_rbase %} {% if cxx_rbase %}
## method returns new object ## returned and accessed C++ objects may have a different bases
auto obj = {{ cxx_base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }}); auto obj = {{ cxx_base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
int id = {{ cxx_rbase }}Cabinet::add(obj); int id = {{ cxx_rbase }}Cabinet::add(obj);
## return handle of newly created / accessed object
{% for typ, getter in shared %}
## add associated objects (see: sol3_newSolution, sol3_adjacent)
if (obj->{{ getter }}()) {
{{ typ }}Cabinet::add(obj->{{ getter }}(), id);
}
{% endfor %}
return id;
{% else %}{# not cxx_rbase #} {% else %}{# not cxx_rbase #}
## method modifies associated objects (see: sol3_setTransportModel) ## method modifies associated objects (see: sol3_setTransportModel)
auto obj = {{ cxx_base }}Cabinet::at({{ handle }}); auto obj = {{ cxx_base }}Cabinet::at({{ handle }});
@ -169,22 +201,6 @@ clib-constructor: |-
} }
{% endfor %} {% endfor %}
obj->{{ cxx_name }}({{ ', '.join(cxx_args) }}); obj->{{ cxx_name }}({{ ', '.join(cxx_args) }});
{% endif %}{# cxx_rbase #}
{% else %}{# not handle #}
## constructor creates new object
auto obj = {{ cxx_name }}({{ ', '.join(cxx_args) }});
int id = {{ base }}Cabinet::add(obj);
{% endif %}{# handle #}
{% if cxx_rbase %}
## return handle of newly created / accessed object
{% for typ, getter in shared %}
## add associated objects (see: sol3_newSolution, sol3_adjacent)
if (obj->{{ getter }}()) {
{{ typ }}Cabinet::add(obj->{{ getter }}(), id);
}
{% endfor %}
return id;
{% else %}{# not cxx_rbase #}
## return handle to modified associated object (see: sol3_setTransportModel) ## return handle to modified associated object (see: sol3_setTransportModel)
{% for typ, getter in shared %} {% for typ, getter in shared %}
## shared should have single entry ## shared should have single entry
@ -193,14 +209,8 @@ clib-constructor: |-
{% endif %}{# cxx_rbase #} {% endif %}{# cxx_rbase #}
{% else %}{# not shared #} {% else %}{# not shared #}
## instantiated object has no associated objects; no id is needed ## instantiated object has no associated objects; no id is needed
{% if handle %} ## returned and accessed C++ objects may have a different bases
## constructor exposes existing C++ object to CLib
## the accessed C++ object may have a different base
return {{ cxx_rbase }}Cabinet::add({{ base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }})); return {{ cxx_rbase }}Cabinet::add({{ base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }}));
{% else %}{# not handle #}
## constructor creates new object
return {{ base }}Cabinet::add({{ cxx_name }}({{ ', '.join(cxx_args) }}));
{% endif %}{# handle #}
{% endif %}{# shared #} {% endif %}{# shared #}
} catch (...) { } catch (...) {
return handleAllExceptions({{ error[0] }}, {{ error[1] }}); return handleAllExceptions({{ error[0] }}, {{ error[1] }});

View File

@ -23,7 +23,7 @@ TEST(ctfunc3, sin)
ASSERT_GE(fcn, 0); ASSERT_GE(fcn, 0);
EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), sin(omega * 0.5)); EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), sin(omega * 0.5));
int dfcn = func13_newDerivative(fcn); int dfcn = func13_derivative(fcn);
EXPECT_DOUBLE_EQ(func13_eval(dfcn, 0.5), omega * cos(omega * 0.5)); EXPECT_DOUBLE_EQ(func13_eval(dfcn, 0.5), omega * cos(omega * 0.5));
int buflen = func13_write(fcn, "x", 0, 0); int buflen = func13_write(fcn, "x", 0, 0);
@ -40,7 +40,7 @@ TEST(ctfunc3, cos)
ASSERT_GE(fcn, 0); ASSERT_GE(fcn, 0);
EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), cos(omega * 0.5)); EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), cos(omega * 0.5));
int dfcn = func13_newDerivative(fcn); int dfcn = func13_derivative(fcn);
EXPECT_DOUBLE_EQ(func13_eval(dfcn, 0.5), -omega * sin(omega * 0.5)); EXPECT_DOUBLE_EQ(func13_eval(dfcn, 0.5), -omega * sin(omega * 0.5));
} }
@ -51,7 +51,7 @@ TEST(ctfunc3, exp)
ASSERT_GE(fcn, 0); ASSERT_GE(fcn, 0);
EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), exp(omega * 0.5)); EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), exp(omega * 0.5));
int dfcn = func13_newDerivative(fcn); int dfcn = func13_derivative(fcn);
EXPECT_DOUBLE_EQ(func13_eval(dfcn, 0.5), omega * exp(omega * 0.5)); EXPECT_DOUBLE_EQ(func13_eval(dfcn, 0.5), omega * exp(omega * 0.5));
} }
@ -62,7 +62,7 @@ TEST(ctfunc3, log)
ASSERT_GE(fcn, 0); ASSERT_GE(fcn, 0);
EXPECT_DOUBLE_EQ(func13_eval(fcn, 1. / omega), 0.); EXPECT_DOUBLE_EQ(func13_eval(fcn, 1. / omega), 0.);
int dfcn = func13_newDerivative(fcn); int dfcn = func13_derivative(fcn);
EXPECT_DOUBLE_EQ(func13_eval(dfcn, .5), omega / .5); EXPECT_DOUBLE_EQ(func13_eval(dfcn, .5), omega / .5);
} }
@ -73,7 +73,7 @@ TEST(ctfunc3, pow)
ASSERT_GE(fcn, 0); ASSERT_GE(fcn, 0);
EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), pow(0.5, exp)); EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), pow(0.5, exp));
int dfcn = func13_newDerivative(fcn); int dfcn = func13_derivative(fcn);
EXPECT_DOUBLE_EQ(func13_eval(dfcn, 0.5), exp * pow(0.5, exp - 1)); EXPECT_DOUBLE_EQ(func13_eval(dfcn, 0.5), exp * pow(0.5, exp - 1));
} }
@ -84,7 +84,7 @@ TEST(ctfunc3, constant)
ASSERT_GE(fcn, 0); ASSERT_GE(fcn, 0);
EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), a); EXPECT_DOUBLE_EQ(func13_eval(fcn, 0.5), a);
int dfcn = func13_newDerivative(fcn); int dfcn = func13_derivative(fcn);
EXPECT_DOUBLE_EQ(func13_eval(dfcn, .5), 0.); EXPECT_DOUBLE_EQ(func13_eval(dfcn, .5), 0.);
} }