summaryrefslogtreecommitdiff
path: root/CONTRIBUTING.md
blob: e946c8d9f46366b9009da10cb95399c5d10aed6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# Contributing Guidelines

This document outlines the conventions to follow when contributing to this project.

## Commit Policy

### Run Tests Before Committing

Before preparing or proposing a commit, you **must** run the entire local test suite and ensure that all tests pass. This is a critical step to prevent regressions and maintain the stability of the codebase.

Refer to the "Testing" section in `HOWTO.md` for instructions on how to build and run the tests.

### Format Code Before Committing

All code **must** be formatted using `clang-format` before committing. This ensures a consistent coding style across the entire codebase.

To format your code, run the following command from the project root:
```bash
clang-format -i $(git ls-files | grep -E '\.(h|cc)$' | grep -vE '^(assets|archive|third_party)/')
```

Refer to the `.clang-format` file in the project root for the specific style rules.

### Ensure Newline at End of File

All source files (`.h`, `.cc`, `.cpp`, etc.) must end with a newline character. This prevents "No newline at end of file" errors from linters and ensures consistent file handling.

### Source File Headers

Every source file (`.h`, `.cc`) must begin with a concise 3-line comment header describing its purpose.

Example:
```cpp
// This file is part of the 64k demo project.
// It implements the core audio synthesis engine.
// This is not a user-facing header, but an internal one.
```

### Function and method comments

Functions and methods, especially if they are internal non user-facing,
should at least have a 1-line comment describing what they do or their
how/when they should be called. Except if they are just 1-line function
or very very short, obvious ones.

### '#endif' directive

The closing #endif directive must recall the corresponding opening #ifdef
clause they are closing

Example:
```cpp
#ifdef MY_TAG
...some code
#endif /* MY TAG */
```

We must also prefer '#if defined(MY_QUITE_LONG_TAG)' over '#ifdef MY_QUITE_LONG_TAG'
especially if there's a risk of having later something like:
```cpp
#if defined(MY_TAG_1) && !defined(MY_TAG_2)
```

### use and abuse 'const' directives

Especially for local variable, use 'const' qualification as much as
possible.

As an example, don't use:
```cpp
StructA variable_name = StructA(...);
```

but prefer instead:
```cpp
const StructA variable_name = StructA(...);
```

if variable_name is not mutated afterward.

Also: pass parameter as "const ref" as much as possible
(```const Struct& param``` instead of pointers or non-const refs)

### put spaces around code and operators (cosmetics)

Don't compact the code to much horizontally, and prefer adding extra
spaces around code and operators.

Example:
```cpp
const bool v = my_variable && (my_function() / 3. > (1. / x));
const y = function_call(3, x, 2.);
for (int x = 0; x < 24; ++x) { ... }
```

instead of
```cpp
const bool v=my_variable&&my_function()/3.>(1./x);
const y = function_call(3,x,2);
for(int x=0;x<24;++x){ ... }
```

### prefer prefixed incrementation over suffixed

Use pre-incrementation:
```cpp
++x
```

instead of post-incrementation:

```cpp
x++
```

### use extra () for boolean operations

Even if they are not strictly needed due to operator precedence rules,
prefer adding extra ()'s around tests for clarity, with parcimony.