C++ Style Guide¶
Please follow these guidelines when submitting patches.
Whitespace¶
Use 4 spaces. Format if as follows:
if (d.find(t) == d.end()) {
d[t] = coef;
} else {
d[t] = d[t] + coef;
}
Pointers¶
Never use raw C++ pointers and never use the raw new and delete. Always use
the smart pointers provided by symengine_rcp.h (depending on
WITH_SYMENGINE_RCP, those are either Teuchos::RCP, or our own, faster
implementation), i.e. Ptr and RCP (and do not use the .get() method, only
the .ptr() method). In Debug mode, the pointers are 100% safe, i.e. no matter
how you use them the code will not segfault, but instead raise a nice exception
if a pointer becomes dangling or null. In Release mode, the Ptr is as fast as
a raw pointer and RCP is a lot faster, but no checks are done (so the code
can segfault).
Declaration¶
In the .cpp files you can declare:
using SymEngine::RCP;
using SymEngine::Ptr;
using SymEngine::outArg;
using SymEngine::make_rcp;
using SymEngine::rcp_dynamic_cast;
and then just use RCP or Ptr.
In the .h header files use the full name like SymEngine::RCP or SymEngine::Ptr.
Initialization¶
Initialize as follows:
RCP<Basic> x = make_rcp<Symbol>("x");
Never call the naked new, nor use the naked rcp. If available, use the
factory functions, e.g. in this case symbol() as follows:
RCP<Basic> x = symbol("x");
This does the same thing (internally it calls make_rcp), but it is easier to
use.
Freeing¶
The RCP pointer is released automatically. You never call the naked delete.
Passing To/From Functions¶
Use C++ references for objects that you are not passing around. If the object
is not modified, use const A &a:
RCP<const Integer> gcd(const Integer &a, const Integer &b)
{
integer_class g;
mp_gcd(g, a.as_integer_class(), b.as_integer_class());
return integer(std::move(g));
}
If it is modified, use A &a (see the first argument):
void Add::dict_add_term(umap_basic_num &d, const RCP<Integer> &coef,
const RCP<Basic> &t)
{
if (d.find(t) == d.end()) {
d[t] = coef;
} else {
d[t] = d[t] + coef;
}
}
If the objects are passed around, you have to use RCP. You also need to
use RCP whenever you call some function that uses RCP.
Declare functions with two input arguments (and one return value) as follows:
RCP<const Basic> multiply(const RCP<const Basic> &a,
const RCP<const Basic> &b)
{
...
return make_rcp<const Integer>(1);
}
Functions with one input and two output arguments are declared:
void as_coef_term(const RCP<const Basic> &self,
const Ptr<RCP<const Integer>> &coef,
const Ptr<RCP<const Basic>> &term)
{
...
*coef = make_rcp<const Integer>(1);
*term = self
...
}
and these are used as follows:
RCP<Integer> coef;
RCP<Basic> t;
as_coef_term(b, outArg(coef), outArg(t));
SymEngine objects are always immutable, so you always declare them as const.
And RCP is only used with SymEngine’s objects, so you always use const RCP<const Integer> &i. But if the Integer was somehow mutable (it’s not in
SymEngine), you would use const RCP<Integer> &i.
For returning objects from functions, simply declare the return type as RCP<const Basic> as shown above.
Casting¶
You can use dynamic cast as follows:
RCP<Basic> tmp;
RCP<Integer> coef;
coef = rcp_dynamic_cast<Integer>(tmp);
Namespaces¶
Never use “implicit imports”: using namespace std;.
In cpp files, either use the full name of the symbol (e.g. SymEngine::RCP),
or use “explicit import” as follows: using SymEngine::RCP;.
In header files, always use the full name (never import symbols there).