irccd

David Demelier 2018-07-19 Parent:1db04a685a8c

732:08189e3146cc Go to Latest

irccd/STYLE.md

Irccd: server style and cleanup

History
1 irccd CODING STYLE
2 ==================
4 C++
5 ===
7 Style
8 -----
10 - Always use 4 spaces as indentation,
11 - Use UTF-8 charset,
12 - Use Unix line endings,
13 - Do not exceed 120 characters for lines of code,
14 - Do not exceed 80 characters for comments,
15 - Never write two blank consecutives blank lines,
16 - Do not use bad words.
18 ### Braces
20 Braces follow the K&R style, they are never placed on their own lines except for
21 function definitions.
23 Do not put braces for single line statements except for clarity.
25 if (condition) {
26 apply();
27 add();
28 } else
29 ok();
31 if (condition)
32 validate();
34 if (foo) {
35 state = long + conditional + that + requires + several + lines +
36 to + complete;
37 }
39 Functions require braces on their own lines.
41 void function()
42 {
43 }
45 And a lambda has its braces on the same lines too:
47 sort([&] (auto&) {
48 return true;
49 });
51 ### Spaces
53 Each reserved keyword (e.g. `if`, `for`, `while`) requires a single space before
54 its argument.
56 Normal function calls do not require it.
58 if (foo)
59 destroy(sizeof (int));
61 ### References and pointers
63 References and pointers are always next to the type name and not the variable.
65 T& get(const std::string& name);
67 int* p = &x;
69 ### Naming
71 - English names,
72 - Member variables have trailing underscore (e.g foo\_bar\_),
73 - No hungarian notation.
75 Everything is in `underscore_case` except template parameters and macros.
77 #if defined(FOO)
78 # include <foo.hpp>
79 #endif
81 namespace baz {
83 class object {
84 private:
85 std::string name_;
87 public:
88 inline const std::string& name() const noexcept
89 {
90 return name_;
91 }
92 };
94 template <typename Archive>
95 void open(const Archive& ar)
96 {
97 bool is_valid = false;
98 }
100 } // !baz
102 ### Header guards
104 Do not use `#pragma once`.
106 Header guards are usually named **PROJECT_COMPONENT_FILENAME_HPP**.
108 #ifndef FOO_COMMON_UTIL_HPP
109 #define FOO_COMMON_UTIL_HPP
111 #endif // !FOO_COMMON_UTIL_HPP
113 ### Enums
115 Enumerations constants are always defined in separate line to allow commenting
116 them as doxygen.
118 Enum class are encouraged.
120 enum class color {
121 blue,
122 red,
123 green
124 };
126 ### Switch
128 In a switch case statement, you **must** not declare variables and not indent
129 cases.
131 switch (variable) {
132 case foo:
133 do_some_stuff();
134 break;
135 default:
136 break;
139 ### Files
141 - Use `.cpp` and `.hpp` as file extensions,
142 - Filenames are all lowercase.
144 ### Comments
146 Avoid useless comments in source files. Comment complex things or why it is done
147 like this. However any public function in the .hpp **must** be documented as
148 doxygen without exception.
150 /*
151 * Multi line comments look like
152 * this.
153 */
155 // Short comment
157 Use `#if 0` to comment blocks of code.
159 #if 0
160 broken_stuff();
161 #endif
163 ### Includes
165 The includes should always come in the following order.
167 1. C++ headers
168 2. C header
169 3. Third party libraries
170 4. Application headers in ""
172 #include <cstring>
173 #include <cerrno>
175 #include <sys/stat.h>
177 #include <libircclient.h>
179 #include "foo.h"
181 **Note**: always use C++ headers for C equivalent, stdio.h -> cstdio, etc.
183 ### Commit messages
185 Commit messages are written using the following syntax:
187 Topic: short message less than 80 characters
189 Optional additional description if needed.
191 Replace `Topic` with one of the following:
193 - **CMake**: for the build system,
194 - **Docs**: for the documentation,
195 - **Misc**: for miscellaneous files,
196 - **Tests**: for the unit tests.
198 Programming
199 -----------
201 ### C language
203 Do not use old C stuff like `void *`, `srand/rand`, `printf` or anything that
204 can be rewritten in modern C++.
206 ### RTTI
208 Usage of `dynamic_cast` and `typeid` are completely disallowed in any shape of
209 form.
211 ### Arguments
213 It is recommended to pass parameters by value or const reference. Usage of
214 non-const reference as output parameter is **discouraged** and should be avoided
215 in many case because it does not allow chaining of expressions like:
217 std::cout << reverse(upper(clean(" hello world! "))) << std::endl;
219 If your function is designed to return a modified value passed as argument, it
220 is better to take it by value and modify it directly.
222 std::string clean(std::string input)
224 if (!input.empty() && input.back() == '\r')
225 input.pop_back();
227 return input;
230 Never pass primitive types as const value.
232 ### Assertions
234 Use the `assert` macro from the cassert header file to verify programming
235 errors.
237 For example, you may use `assert` to verify that the developer access the data
238 between the bounds of an array:
240 T& operator[](unsigned index)
242 assert(index < length_);
244 return data_[index];
247 The `assert` macro is not meant to check that a function succeeded, this code
248 must not be written that way:
250 assert(listen(10));
252 ### Exceptions
254 You must use exceptions to indicate an error that was unexpected such as:
256 - Failing to open a file,
257 - I/O unexpected errors,
258 - Parsing errors,
259 - User errors.
261 You may use the C++ standard exceptions defined in the stdexcept header but if
262 you need to carry more data within your exception, you should derive from
263 `std::exception`.
265 ### Error code
267 You should not use error codes to indicate errors, instead use exceptions.
268 Error codes are allowed in Boost.Asio though.
270 ### Free functions
272 Basic utility functions should be defined in a namespace as a free function not
273 as a static member function, we're doing C++ not Java.
275 Example:
277 namespace util {
279 std::string clean(std::string input);
281 } // !util
283 ### Variables initialization
285 Use parentheses to initialize non primitive types:
287 throw std::runtime_error("foo");
289 my_class obj("bar");
291 Use brace initialization when you want to use an initializer list, type
292 elision:
294 std::vector<int> v{1, 2, 3};
296 foo({1, 2}); // type deduced
298 return { "true", false }; // std::pair returned
300 Use the assignment for primitive types:
302 int x = 123;
303 bool is_valid = true;
305 ### Classes
307 Classes are usually defined in the following order:
309 1. Public inner types (enums, classes),
310 2. Protected/private members
311 3. Public functions
313 class foo {
314 public:
315 enum class type {
316 a,
318 };
320 private:
321 int member_{0};
323 public:
324 void some_function();
325 };
327 ### Structs
329 Do not use C structs unless you have very good reason to do so. If you want to
330 pack some data, just use `class` and make all fields public.
332 class point {
333 public:
334 int x{0};
335 int y{0};
336 };
338 ### Return
340 The preferred style is to return early in case of errors. That makes the code
341 more linear and not highly indented.
343 This code is preferred:
345 if (a_condition_is_not_valid)
346 return nullptr;
347 if (an_other_condition)
348 return nullptr;
350 auto x = std::make_shared<object>();
352 x->start();
353 x->save();
355 return x;
357 Additional rules:
359 - Do never put parentheses between the returned value,
360 - Do not put a else branch after a return.
362 ### Auto
364 We encorage usage of `auto`, it reduces code maintainance as you don't need to
365 change your code when your rename types.
367 ````cpp
368 auto it = std::find_if(v.begin(), v.end(), [&] (const auto& obj) {
369 return obj.key() == "foo";
370 });
372 for (const auto& pair : a_map)
373 std::cout << pair.first << " = " << pair.second << std::endl;
374 ````
376 But do not use `auto` to write code like in python, this is not acceptable:
378 ````cpp
379 auto o = my_object("foo");
380 ````