Coding Style
Abstract
This document discusses practices and style for programmers working on the BigWhoop compression library. The Guidelines are based on the C Coding Style recommended by the GNOME Developer Documentation and should be followed to promote a consistent, readable, and maintainable code base. The Guide offers solutions to common C, python and cmake programming issues and illustrates through examples of code
Content
The Single Most Important Rule
Above all, the following rule from the GNOME developer documentation should always be followed.
The single most important rule when writing code is this: check the surrounding code and try to imitate it.
As a maintainer it is dismaying to receive a patch that is obviously in a different coding style to the surrounding code. This is disrespectful, like someone tromping into a spotlessly-clean house with muddy shoes.
So, whatever this document recommends, if there is already written code and you are contributing to it, keep its current style consistent even if it is not your favorite style.
Most importantly, do not make your first contribution to a project a change in the coding style to suit your taste. That is incredibly disrespectful.
Formatting
Keep the length of source code lines to 100 characters or less to ensure maximum readability on most modern monitors with a reasonable font size. Longer lines of code are more difficult to read and understand. Too many indentations should be interpreted as an indication that code restructuring is required.
Indentation
Each new level is indented by 2 spaces, braces go on a line by themselves, and they are indented as well:
while (c = *str++)
{
if ((c >= 97) && (c <= 122))
{
c = c - 32;
}
hash = (hash * 33) ^ c;
}
Resist the urge to reindent everything, or to use an inconsisent style. Make sure that your preferred editor respects the indentation rules so your contribution is respectful of the code's customs.
Line Continuation
Continuation lines should align wrapped elements with the first argument (excluding reference operators) or use a hanging indent. When using a hanging indent, there should be no arguments on the first line and all subsequent "hanging" lines should be indented with 2 spaces in relation to the calling command:
Aligned Along First Deliminator
# Correct
error = initialize_tagtree (&prec_control->tag_inclusion,
prec_control->numCbX,
prec_control->numCbY,
prec_control->numCbZ,
prec_control->numCbTS)
exit (error);
# Wrong
error = initialize_tagtree (&prec_control->tag_inclusion,
prec_control->numCbX,
prec_control->numCbY,
prec_control->numCbZ,
prec_control->numCbTS)
exit (error);
Hanging Indent
# Correct
error = initialize_tagtree (
&prec_control->tag_inclusion,
prec_control->numCbX,
prec_control->numCbY,
prec_control->numCbZ,
prec_control->numCbTS);
exit (error);
# Wrong
error = initialize_tagtree (
&prec_control->tag_inclusion,
prec_control->numCbX,
prec_control->numCbY,
prec_control->numCbZ,
prec_control->numCbTS);
exit (error);
Forumlas always break before binary operations with the new lines aligned to the first operand in the mathematical formulation:
# Correct
prec_control->numCodeblocks_a = (uint64) (prec_control->numCbX
* prec_control->numCbY
* prec_control->numCbZ
* prec_control->numCbTS);
stream->L = stream->L
+ stream->Lmax
+ stream->t;
# Wrong
prec_control->numCodeblocks_a = (uint64) (prec_control->numCbX *
prec_control->numCbY *
prec_control->numCbZ *
prec_control->numCbTS);
stream->L = stream->L +
stream->Lmax +
stream->t;
Braces
Curly braces for function definitions should rest on a new line and should not add an indentation level:
uint64
bytes_used (bwc_stream const *const stream)
{
if (stream->T == 0xFF)
return stream->L + 1;
else
return stream->L;
}
A new block should always be placed on a new indentation level:
f = fopen('file');
{
if (stream->T == 0xFF)
return stream->L + 1;
else
return stream->L;
}
fclose(f);
Curly braces should not be used for single statement blocks
if (stream->T == 0xFF)
return stream->L + 1;
else
return stream->L;
unless one of the following 4 exceptions applies:
1. If either side of an if…else statement has braces
if (stream->T == 0xFF)
{
stream->L = stream->L + stream->t
return stream->L + 1;
}
else
{
return stream->L;
}
2. If a single statement covers multiple lines
if (stream->T == 0xFF)
{
stream->L = stream->L
+ stream->Lmax
+ stream->t;
}
else
{
return stream->L;
}
3. If the condition is composed of many lines
if (stream->L <= stream->Lmax
stream->T == 0xFF &&
stream->t == 8)
{
return stream->L + 1;
}
else
{
return stream->L;
}
4. Nested if, in which case the block should be placed on the outermost if
if (stream->L <= stream->Lmax)
{
if (stream->T == 0xFF)
return stream->L + 1;
else
return stream->L;
}
else
{
stream->L++;
}
The closing parenthesis in multiline constructs must be placed at the end of the last line of the construct, as in:
# Correct
DWT_5X3_FILTER[2][5] = {{DWT_5X3_H1, DWT_5X3_H0, 0, 0, 0},
{DWT_5X3_G2, DWT_5X3_G1, DWT_5X3_G0, 0, 0}};
Whitespace
Always put a space before an opening parenthesis but never after. For multiple opening parenthesis only a single space in front of the first parenthesis should be used:
while (c = *str++)
{
if ((c >= 97) && (c <= 122))
{
c = c - 32;
}
hash = (hash * 33) ^ c;
}
# Wrong
while(c = *str++)
{
if((c >= 97) && (c <= 122))
{
c = c - 32;
}
hash =(hash * 33) ^ c;
}
# Wrong
while (c = *str++)
{
if ( (c >= 97) && (c <= 122))
{
c = c - 32;
}
hash = (hash * 33) ^ c;
}
When declaring a structure type use newlines to separate logical sections of the structure:
typedef struct
{
uint16 CSsgc; // Flag signaling user control variable.
uchar resilience; // Flag signalling error resilience.
uint64 tileSizeX, tileSizeY; // Spatial tile size.
uint64 tileSizeZ, tileSizeTS; // Temporal tile size.
uint64 numTilesX, numTilesY; // Spatial number of tiles.
uint64 numTilesZ, numTilesTS; // Temporal number of tiles.
uint64 numTiles; // Global number of tiles.
⋮
} bwc_gl_ctrl;
Do not eliminate whitespace and newlines just because something would fit on a single line:
# Wrong
if (stream->T == 0xFF) return stream->L + 1; else return stream->L;
Do eliminate trailing whitespace on any line, preferably as a separate patch or commit. Never use empty lines at the beginning or at the end of a file.
Conditions
Boolean values should not be checked for equality to make the code more readable:
if (error)
return 1;
if (!error)
return 0;
The check for 0 should refer to the specific way the 0 is used: 0
for a numeric value, '\0'
for the end of a string, or NULL
for a pointer. In this way, the variable type can be derived implicitly by reading the comparison. For the FALSE boolean we refer to the rule about boolean equations.
if (buffer == NULL)
return NULL;
if (get_bit (stream) == 0)
node->value++;
if (bwc->info.file_ext [0] != '\0')
return 0;
Functions
The following general rules should be followed when defining a function in BigWhoop:
- Function name must be lowercase, optionally separated with underscore _ character
- Functions private to a translation unit need to be declared before they are called
- All private functions of a translation unit must appear before the public functions in their respective block, which is identified by the block header
private functions
: - All public functions of a translation unit must appear in their respective block, identified by the
public functions
block header:
Functions should be declared by placing the returned value on a separate line from the function name:
static void
free_tile (bwc_field *const field)
{
⋮
}
The argument list must be broken into a new line for each argument, with the argument names right aligned, taking into account pointers and const qualifiers:
static uchar
initialize_subband (bwc_field *const field,
bwc_parameter *const parameter,
bwc_resolution *const resolution,
bwc_subband *const subband,
int32 const level,
int16 const highband)
{
⋮
}
This alignment holds when calling the function:
initialize_subband (field,
parameter,
resolution,
&resolution->subband[m],
r,
l);
For header files, the function prototypes must be vertically aligned in six columns and separated by the function delimiter:
uchar bwc_open_file (bwc_field *const field,
char const *const filename,
char const *const mode);
//==========|==========================|======================|======|=======|====================
uchar bwc_load_file (bwc_field *const field,
char const *const filename);
//==========|==========================|======================|======|=======|====================
uchar bwc_compress (bwc_field *const field,
char *const rate_control);
//==========|==========================|======================|======|=======|====================
uchar bwc_decompress (bwc_field *const field,
uint8 const layer);
Each column is marked by the function delimiter with a |
with each element in the column right aligned to the column seperator. The delimiter must precede every function prototype except the first.