16.3.1. Naming
All exported symbols that will be publically available must be namespaced appropriately!
SUN_
orSUNDIALS_
for macrossun
for typedef’s to native types (e.g.,sunindextype
)SUN
for public functions that are not class functions (seeStyle.Classes
for class/struct naming conventions)sun
for private functions that are non-native.sundials::
for C++ code (nesting under sundials:: is OK)sundials::<somename>::impl
for C++ code that is private (implementation only)
Generally Pascal case (e.g. DoSomething
) is used for public names and
camelcase for private names (e.g. doSomething
).
16.3.1.1. Macros/Constants
Upper case should be used for macros and constants.
16.3.1.2. Variable names
Snake case is preferred for local variable names e.g. foo_bar
.
16.3.1.3. C function names
Functions should have a descriptive name that lets a reader know what it does.
For functions that return a boolean value, prefer the convention
Is<statement>
, e.g. IsOutputRank
. Pascal case (with the appropriate
namespace prefix) should be used for all public function names that are not
class functions (see Style.Classes for class naming conventions).
16.3.1.4. C++ function names
All functions should be in the sundials::
namespace. Pascal case should be
used for public function names. Camelcase should be used for private function
names.
16.3.1.5. Names for Vectors, Matrices, and Solvers
The SUNDIALS vector, matrix, linear solver, and nonlinear solver classes use the
naming convention <short class name><method>
for base class methods where
each component of the name uses Pascal case. See
Table 16.1 for examples.
Note
This naming convention only applies to the vector, matrix, and solver classes. All other classes should follow the naming convention described in Names for New Classes.
Base Class |
Short Name |
Operation |
Method |
|
|
Linear Sum |
|
|
|
Zero |
|
|
|
Setup |
|
|
|
Solve |
|
Derived class implementations of the base class methods should follow the naming
convention <short class name><method>_<implementation>
. See
Table 16.2 for examples.
Derived Class |
Base Class Method |
Method Implementation |
Serial |
|
|
Dense |
|
|
SPGMR |
|
|
Newton |
|
|
Implementation specific methods do not currently have a consistent naming
convention across the different derived classes. When adding new methods to an
existing class, follow the naming style used within that class. When adding a
new derived class, use the same style as above for implementations of the base
class method i.e., <short class name><method>_<implementation>
.
16.3.1.6. Names for New Classes
All new base classes should use the naming convention <class name>_<method>
for the base class methods. See
Table 16.3 for examples.
Base Class |
Operation |
Method |
|
Alloc |
|
Derived class implementations of the base class methods should follow the naming
convention <class name>_<method>_<implementation>
. See
Table 16.4 for examples.
Derived Class |
Base Class Method |
Method Implementation |
CUDA |
|
|
For destructor functions, use Destroy
rather than Free
or some other alternative.
16.3.1.7. Naming Convention for C++ Classes
C++ classes should have a descriptive name. The class name should not be
prefixed with SUN
, but it should reside in the sundials::
namespace.
Public C++ class functions should use Pascal case (e.g. DoSomething
).
Private C++ class functions should use camelcase (e.g. doSomething
).
C++ private class members should use snake case with a trailing underscore
(e.g. some_var_
).
16.3.2. Coding Conventions and Rules
Do not use language features that are not compatible with C99, C++14, and MSVC v1900+ (Visual Studio 2015). Examples of such features include variable-length arrays. Exceptions are allowed when interfacing with a library which requires a newer standard.
All new code added to SUNDIALS should be formatted with clang-format. See Formatting for details.
Spaces not tabs.
Comments should use proper spelling and grammar.
Following the Google Style Guide [GoogleStyle], TODO comments are used to note code that is “temporary, a short-term solution, or good-enough but not perfect.”
A consistent TODO comment format provides an easy to search for keyword with details on how to get more information. TODO comments should start with
TODO
followed by a unique identifier, enclosed in parentheses, for the person most knowledgeable about the issue and a brief description of the TODO item. Generally, these comments should be used sparingly and are not a substitute for creating an issue or bug report. When applicable, the comment should include the relevant issue or bug report number.Examples:
/* TODO(DJG): Update to new API in the next major release (Issue #256) */
All SUNDIALS data structures should hold onto a
SUNContext
object. Exceptions are theSUNLogger
andSUNProfiler
classes.All SUNDIALS functions should return a
SUNErrCode
. Many older functions do not do this and are exceptions to the rule for backwards compatibility. In addition, internal helper functions may or may-not return aSUNErrCode
.All SUNDIALS functions, with the exception of some functions that do not have access to a
SUNContext
, should begin with a call toSUNFunctionBegin()
. The argument toSUNFunctionBegin()
is aSUNContext
which should come from the first object in the function parameter list that has aSUNContext
. This macro is used for error handling and declares a local variable access via the macroSUNCTX_
.SUNErrCode N_VLinearCombination_Serial(int nvec, realtype* c, N_Vector* X, N_Vector z) { SUNFunctionBegin(X[0]->sunctx); // Correct int i; sunindextype j, N; realtype* zd=NULL; realtype* xd=NULL; /* invalid number of vectors */ SUNAssert(nvec >= 1, SUN_ERR_ARG_OUTOFRANGE); // ... } SUNErrCode N_VLinearCombination_Serial(int nvec, realtype* c, N_Vector* X, N_Vector z) { int i; sunindextype j, N; realtype* zd=NULL; realtype* xd=NULL; SUNFunctionBegin(X[0]->sunctx); // Incorrect, SUNFunctionBegin should occur as early as possible /* invalid number of vectors */ SUNAssert(nvec >= 1, SUN_ERR_ARG_OUTOFRANGE); // ... } int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele) { CVodeMem cv_mem; if (cvode_mem==NULL) { cvProcessError(NULL, CV_MEM_NULL, __LINE__, __func__, __FILE__, MSGCV_NO_MEM); return(CV_MEM_NULL); } cv_mem = (CVodeMem) cvode_mem; SUNFunctionBegin(cv_mem->sunctx); // Correct - this is as early as possible to call SUNFunctionBegin SUNFunctionBegin(ele->sunctx); // Incorrect - cvode_mem is first in the function parameter list // ... }
All references to
SUNContext
objects should be done via theSUNCTX_
macro. The only exceptions are functions in theSUNContext
class.All calls to SUNDIALS functions that return a
SUNErrCode
should have their return value checked with a macro from theSUNCheckCall
family. These macros are documented in the header filesundials/priv/sundials_errors_impl.h
andsundials/priv/sundials_mpi_errors_impl.h
.SUNCheckCall(N_VLinearCombination(...)); // Correct
Avoid storing the return value and then checking the stored value except when absolutely necessary.
SUNErrCode err; err = N_VLinearCombination(...); SUNCheckCall(err); // Avoid except when absolutely necessary.
All calls to SUNDIALS functions that do not return a
SUNErrCode
should be followed by checking the last error stored in theSUNContext
. The exception to this rule is for internal helper functions. These should not be checked unless they return aSUNErrCode
. These checks are done with theSUNCheckLastErr
macros.// Correct (void) N_VLinearSum(...); SUNCheckLastErr(); // Incorrect - we must check for errors in N_VDotProd before calling a second function sunrealtype norm2 = SUNRsqrt(N_VDotProd(...)); SUNCheckLastErr(); // Correct sunrealtype norm2 = N_VDotProd(...); SUNCheckLastErr(); norm2 = SUNRsqrt(norm2);
Programmer errors should be checked with the
SUNAssert
macro, that verifies whether its argument evaluates to “true”, and specifies an error flag otherwise. By programmer errors we mean, for example, illegal inputs such as mismatching dimensions or aNULL
value for something that should not be.SUNLinearSolver SUNLinSol_Band(N_Vector y, SUNMatrix A, SUNContext sunctx) { SUNFunctionBegin(sunctx); SUNLinearSolver S; SUNLinearSolverContent_Band content; sunindextype MatrixRows; // Correct - check these with SUNAssert SUNAssert(SUNMatGetID(A) == SUNMATRIX_BAND, SUN_ERR_ARG_WRONGTYPE); SUNAssert(SUNBandMatrix_Rows(A) == SUNBandMatrix_Columns(A), SUN_ERR_ARG_DIMSMISMATCH); SUNAssert(y->ops->nvgetarraypointer, SUN_ERR_ARG_INCOMPATIBLE); // ... }
If statements and loops should always have braces even if they are one line.
Return statements should not unnecessarily use parentheses. Prefer
return x;
toreturn(x);
. Note, however, lots of older SUNDIALS source code usesreturn(x);
.
16.3.2.1. Formatting
All new code added to SUNDIALS should be formatted with clang-format. The
.clang-format
files in the root of the project define our configurations
for the tools respectively. To apply clang-format you can run:
./scripts/format.sh <path to directories to format>
If clang-format breaks lines in a way that is unreadable, use //
to break the line. For example,
sometimes (mostly in C++ code) you may have code like this:
MyClass::callAFunctionOfSorts::doSomething().doAnotherThing().doSomethingElse();
That you would like to format as (for readability):
MyObject::callAFunctionOfSorts()
.doSomething()
.doAnotherThing()
.doSomethingElse();
Clang-format might produce something like:
MyObject::callAFunctionOfSorts().doSomething().doAnotherThing()
.doSomethingElse();
unless you add the //.
MyObject::callAFunctionOfSorts()
.doSomething() //
.doAnotherThing() //
.doSomethingElse(); //
There are other scenarios (e.g., a function call with a lot of parameters) where doing this type of line break is useful for readability too.
16.3.2.1.1. Indentation
Spaces not tabs
16.3.2.2. Comments
16.3.2.2.1. TODO Comments
Following the Google Style Guide , TODO comments are used to note code that is “temporary, a short-term solution, or good-enough but not perfect.”
A consistent TODO comment format provides an easy to search for keyword with details on how to get more information. TODO comments should start with
TODO
followed by a unique identifier, enclosed in parentheses, for the person most knowledgeable about the issue and a brief description of the TODO item. Generally, these comments should be used sparingly and are not a substitute for creating an issue or bug report. When applicable, the comment should include the relevant issue or bug report number.Examples:
/* TODO(DJG): Update to new API in the next major release (Issue #256) */