279 lines
6.7 KiB
Markdown
279 lines
6.7 KiB
Markdown
The purpose of a coding style and accompanying guidelines is to make the
|
|
reading and comprehension of the code easier. Reading prose would also be
|
|
much harder, should the punctuation rules differ from chapter and paragraph
|
|
to the next.
|
|
|
|
## Coding Style
|
|
### astyle
|
|
MaxScale comes with a Astyle configuration file used to format the source
|
|
code. To use it, run the following in the source root.
|
|
```
|
|
astyle --options=astylerc <path to source>
|
|
```
|
|
This will format the source file according to the MaxScale coding style.
|
|
|
|
## Consistency
|
|
Be consistent. In a particular context, everything should style wise look
|
|
the same.
|
|
|
|
### In Rome do as the romans do.
|
|
If something is done in a particular way in some context, then follow that
|
|
same way when doing modifications, even if it violates what is stated
|
|
here. If you want to fix the style of a file, then do so in one separate
|
|
change; not as part of other modifications.
|
|
|
|
## General
|
|
* Only spaces, no tabs.
|
|
* Indentation depth 4 spaces.
|
|
* No trailing white space.
|
|
* Maximum line length 110 characters.
|
|
|
|
## Indentation Style
|
|
|
|
We follow the
|
|
[Allman](https://en.wikipedia.org/wiki/Indentation_style#Allman_style)
|
|
indentation style.
|
|
|
|
Braces are always used and the brace associated with a control statement is
|
|
placed on the next line, indented to the same level as the control
|
|
statement. Statements within the braces are indented to the next level.
|
|
```
|
|
if (something)
|
|
{
|
|
do_this();
|
|
}
|
|
else
|
|
{
|
|
do_that();
|
|
}
|
|
```
|
|
|
|
## Punctuation
|
|
### Keywords are followed by a space.
|
|
```
|
|
if (something)
|
|
{
|
|
...;
|
|
}
|
|
|
|
while (something)
|
|
{
|
|
...;
|
|
}
|
|
```
|
|
Exceptions are `sizeof`, `typeof` and `alignof`.
|
|
|
|
### Function name and opening parenthesis are not separated by a space.
|
|
```
|
|
some_function();
|
|
```
|
|
### Operators
|
|
|
|
Use one space around (on each side of) most binary and ternary operators,
|
|
such as any of these:
|
|
```
|
|
= + - < > * / % | & ^ <= >= == != ? :
|
|
```
|
|
but no space after unary operators:
|
|
```
|
|
& * + - ~ ! sizeof typeof alignof __attribute__ defined
|
|
```
|
|
no space before the postfix increment & decrement unary operators:
|
|
```
|
|
++ --
|
|
```
|
|
no space after the prefix increment & decrement unary operators:
|
|
```
|
|
++ --
|
|
```
|
|
and no space around the `.` and `->` structure member operators.
|
|
|
|
### Comma is always followed by a space.
|
|
```
|
|
x = some_function(a, b, c + d);
|
|
```
|
|
### Opening parenthesis and square bracket are not followed by a space, and closing parenthesis and square bracket are not preceded by a space.
|
|
```
|
|
int len = strlen(name);
|
|
|
|
a = b[5];
|
|
```
|
|
|
|
## Naming
|
|
### enums
|
|
```
|
|
enum gwbuf_type { ... };
|
|
typedef enum { ... } gwbuf_type_t;
|
|
typedef enum gwbuf_type { ... } gwbuf_type_t;
|
|
```
|
|
### structs
|
|
A `struct` must be a POD type. It must have no non-POD members and it must
|
|
not have any member functions. Whether a `struct` has been declared in a C
|
|
or C++ header file, it must be declared as if it would be used from C.
|
|
|
|
In a C header, a `struct` is declared as:
|
|
```
|
|
typedef struct SOME_TYPE { ... } SOME_TYPE;
|
|
```
|
|
With this arrangement it is possible to refer to the type using `SOME_TYPE`
|
|
or `struct SOME_TYPE` from both C and C++ code.
|
|
|
|
In a C++ header, a `struct` is declared without the typedef.
|
|
```
|
|
struct SOME_TYPE;
|
|
```
|
|
|
|
### functions
|
|
|
|
Small caps and words separated by underscores
|
|
```
|
|
void server_set_status(SERVER *, int);
|
|
```
|
|
with the exception of names of function pointers in plugin interfaces
|
|
```
|
|
typedef struct filter_object {
|
|
FILTER *(*createInstance)(char **options, FILTER_PARAMETER **);
|
|
...
|
|
} FILTER_OBJECT;
|
|
```
|
|
that are _camelCase_.
|
|
|
|
## C++ naming
|
|
### namespaces
|
|
|
|
Small caps and words separated by underscores
|
|
```
|
|
namespace maxscale
|
|
{
|
|
|
|
class ...
|
|
|
|
}
|
|
...
|
|
namespace xyz_filter
|
|
{
|
|
...
|
|
}
|
|
```
|
|
Note that symbols within a namespace are not indented. Note also that the
|
|
namespace `maxscale` can only be used by classes belonging to the MaxScale
|
|
core. An exception is when a template in the MaxScale namespace is
|
|
specialized for a non MaxScale core class.
|
|
|
|
### classes
|
|
|
|
To distinguish them from plain-old-data, aka structs, class names use camel-case.
|
|
```
|
|
class CacheFilterSession
|
|
{
|
|
public:
|
|
int some_member_function();
|
|
...
|
|
};
|
|
```
|
|
Note that the naming of member functions follows the same conventions as the
|
|
naming of free functions, that is, snake-case is used.
|
|
|
|
### member variables
|
|
|
|
Member variables are prefixed with `m_` and static member variables are
|
|
prefixed with `s_`.
|
|
```
|
|
class MyClass
|
|
{
|
|
...
|
|
private:
|
|
int m_size;
|
|
static int s_max_size;
|
|
};
|
|
```
|
|
In general, a class should have no public member variables but all access
|
|
should be via public functions that can be inline.
|
|
|
|
### variable prefixes
|
|
|
|
The following prefixes are "standardized" and can be used when applied
|
|
consistently:
|
|
```
|
|
int *pAge; // p, for pointers.
|
|
shared_ptr<NiftyBuffer> sBuffer; // s, for smart pointers
|
|
unsigned nItems; // n, when a variable denotes a count.
|
|
```
|
|
Note that there is no underscore between the prefix and the actual variable
|
|
name, and that the character following the prefix is in large caps. Note
|
|
also that the prefixes can be stacked.
|
|
```
|
|
class SomeClass
|
|
{
|
|
private:
|
|
int* m_pIndex;
|
|
int** m_ppIndex;
|
|
shared_ptr<SomeClass> m_sNext;
|
|
};
|
|
```
|
|
## Guidelines
|
|
These are suggestions.
|
|
|
|
### Try to have only a single exit-point in each function.
|
|
|
|
**Rationale**: With multiple exit points it is very easy to overlook the release
|
|
of some resource in one of those places.
|
|
|
|
Reasonable exceptions to the single exit point rule are:
|
|
|
|
* Checking of preconditions at the beginning of the function.
|
|
```
|
|
int function(int a, int b)
|
|
{
|
|
if (a < 0)
|
|
return -1;
|
|
|
|
if (b > 5)
|
|
return -1;
|
|
|
|
int rv;
|
|
...
|
|
return rv;
|
|
}
|
|
```
|
|
* Functions that are basically only big switches.
|
|
```
|
|
char* toString(enum Color c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case RED:
|
|
return "RED";
|
|
|
|
case GREEN:
|
|
return "GREEN";
|
|
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
```
|
|
### Try to keep the line length less than 80 characters.
|
|
|
|
**Rationale**: In typography the optimal line length for readability is
|
|
considered to be around 60 characters. With 5 levels of nesting of 4
|
|
spaces each, that gives 80 characters. If it is hard to stay within that
|
|
limit, consider refactoring the function.
|
|
|
|
### Use parenthesis to make the precedence explicit, even if precedence rules would not require it.
|
|
```
|
|
if (a != b && !ready()) ...;
|
|
|
|
if ((a != b) && !ready()) ...;
|
|
```
|
|
**Rationale**: There can never be any doubt about what the _intended_ precedence is.
|
|
|
|
### Try to keep the length of each function less than what fits in one screen full (roughly 60 lines).
|
|
|
|
**Rationale**: That way it is possible with one glance to get a grasp of
|
|
what the function does. If it's hard to keep within the limit it may be a
|
|
sign that the function ought to be refactored.
|
|
|
|
### Use vertical space (i.e. empty lines) to introduce paragraphs and sections.
|
|
|
|
**Rationale**: Makes the reading easier. |