irccd

David Demelier 2018-11-30 Parent:8c44bbcbbab9

822:5120b9793d1f Go to Latest

irccd/STYLE.md

tests: add common server error tests

History
1 IRC Client Daemon CODING STYLE
2 ==============================
4 File content
5 ============
7 - Use UTF-8 charset,
8 - Use Unix line endings,
9 - Never write two blank consecutives blank lines.
11 Indent
12 ======
14 Use tabs to indent and spaces for alignment. Tabs are meant and designed for
15 indenting code and have the advantage of being configurable. On the other hand
16 to keep code clean, you must align content with spaces only *within* a line.
18 Note: we recommend 8 columns to avoid high number of indentations.
20 Example (show whitespace in your editor)
22 ```cpp
23 class foo {
24 public:
25 enum type {
26 dummy_value, // dummy comment
27 other_value // other comment
28 };
30 void long_function_name(very_long_type x1,
31 very_long_type x2)
32 {
33 const map<string, string> m{
34 { "hostname", "127.0.0.1" },
35 { "port", "6667" }
36 };
37 }
38 };
39 ```
41 As a rule of thumb, tabs must always be all length.
43 Example of incorrect usage:
45 ```cpp
46 { "hostname", "127.0.0.1" },
47 { "port", "6667" }
48 ```
50 This example will not align correctly if tabstops are not set to 8.
52 C++
53 ===
55 Style
56 -----
58 - Do not exceed 120 columns for lines of code,
59 - Do not exceed 80 columns for comments,
61 ### Braces
63 Braces follow the K&R style, they are never placed on their own lines except for
64 function definitions.
66 Do not put braces for single line statements.
68 ```cpp
69 if (condition) {
70 apply();
71 add();
72 } else
73 ok();
75 if (condition)
76 validate();
78 if (foo)
79 state = long + conditional + that + requires + several + lines +
80 to + complete;
81 ```
83 Functions require braces on their own lines.
85 ```cpp
86 void function()
87 {
88 }
89 ```
91 And a lambda has its braces on the same lines too:
93 ```cpp
94 sort([&] (auto&) {
95 return true;
96 });
97 ```
99 ### Spaces
101 Each reserved keyword (e.g. `if`, `for`, `while`) requires a single space before
102 its argument.
104 Normal function calls do not require it.
106 ```cpp
107 if (foo)
108 destroy(sizeof (int));
109 ```
111 ### References and pointers
113 References and pointers are always next to the type name and not the variable.
115 ```cpp
116 auto get(const std::string& name) -> T&;
118 int* p = &x;
119 ```
121 ### Trailing return syntax
123 We use trailing return syntax everywhere, it has the following benefits:
125 - Inner types don't need to be prefixed by class name,
126 - Functions are kept aligned correctly, focusing on the function name.
128 ```cpp
129 auto func() -> std::string;
130 ```
132 ### Naming
134 - English names,
135 - Member variables have trailing underscore (e.g foo\_bar\_),
136 - No hungarian notation.
138 Everything is in `underscore_case` except template parameters and macros.
140 ```cpp
141 #if defined(FOO)
142 # include <foo.hpp>
143 #endif
145 namespace baz {
147 class object {
148 private:
149 std::string name_;
151 public:
152 auto name() const noexcept -> const std::string&;
153 };
155 template <typename Archive>
156 void open(const Archive& ar)
158 bool is_valid = false;
161 } // !baz
162 ```
164 ### Header guards
166 Do not use `#pragma once`.
168 Header guards are usually named `PROJECT_COMPONENT_FILENAME_HPP`.
170 ```cpp
171 #ifndef FOO_COMMON_UTIL_HPP
172 #define FOO_COMMON_UTIL_HPP
174 #endif // !FOO_COMMON_UTIL_HPP
175 ```
177 ### Enums
179 Enumerations constants are always defined in separate line to allow commenting
180 them as doxygen.
182 Enum class are encouraged.
184 ```cpp
185 enum class color {
186 blue,
187 red,
188 green
189 };
190 ```
192 ### Switch
194 In a switch case statement, you **must** not declare variables and not indent
195 cases.
197 ```cpp
198 switch (variable) {
199 case foo:
200 do_some_stuff();
201 break;
202 default:
203 break;
205 ```
207 ### Files
209 - Use `.cpp` and `.hpp` as file extensions,
210 - Filenames are all lowercase.
212 ### Comments
214 Avoid useless comments in source files. Comment complex things or why it is done
215 like this. However any public function in the .hpp **must** be documented as
216 doxygen without exception.
218 ```cpp
219 /*
220 * Multi line comments look like
221 * this.
222 */
224 // Short comment
225 ```
227 Use `#if 0` to comment blocks of code.
229 ```cpp
230 #if 0
231 broken_stuff();
232 #endif
233 ```
235 ### Includes
237 The includes should always come in the following order.
239 1. C++ headers
240 2. C header
241 3. Third party libraries
242 4. Application headers in ""
244 ```cpp
245 #include <cstring>
246 #include <cerrno>
248 #include <sys/stat.h>
250 #include <libircclient.h>
252 #include "foo.h"
253 ```
255 Note: always use C++ headers for C equivalent, stdio.h -> cstdio, etc.
257 Programming
258 -----------
260 ### C language
262 Do not use old C stuff like `void*`, `srand/rand`, `printf` or anything that
263 can be rewritten in modern C++.
265 ### RTTI
267 Usage of `dynamic_cast` and `typeid` are completely disallowed in any shape of
268 form.
270 ### Arguments
272 It is recommended to pass parameters by value or const reference. Usage of
273 non-const reference as output parameter is **discouraged** and should be avoided
274 in many case because it does not allow chaining of expressions like:
276 ```cpp
277 std::cout << reverse(upper(clean(" hello world! "))) << std::endl;
278 ```
280 If your function is designed to return a modified value passed as argument, it
281 is better to take it by value and modify it directly.
283 ```cpp
284 auto clean(std::string input) -> std::string
286 if (!input.empty() && input.back() == '\r')
287 input.pop_back();
289 return input;
291 ```
293 Never pass primitive types as const value.
295 ### Assertions
297 Use the `assert` macro from the cassert header file to verify programming
298 errors.
300 For example, you may use `assert` to verify that the developer access the data
301 between the bounds of an array:
303 ```cpp
304 auto operator[](unsigned index) -> T&
306 assert(index < length_);
308 return data_[index];
310 ```
312 The `assert` macro is not meant to check that a function succeeded, this code
313 must not be written that way:
315 ```cpp
316 assert(listen(10));
317 ```
319 ### Exceptions
321 You must use exceptions to indicate an error that was unexpected such as:
323 - Failing to open a file,
324 - I/O unexpected errors,
325 - Parsing errors,
326 - User errors.
328 You may use the C++ standard exceptions defined in the stdexcept header but if
329 you need to carry more data within your exception, you should derive from
330 `std::exception`.
332 ### Error code
334 You should not use error codes to indicate errors, instead use exceptions.
335 Error codes are allowed in Boost.Asio though.
337 ### Free functions
339 Basic utility functions should be defined in a namespace as a free function not
340 as a static member function, we're doing C++ not Java.
342 Example:
344 ```cpp
345 namespace util {
347 auto clean(std::string input) -> std::string;
349 } // !util
350 ```
352 ### Variables initialization
354 Use parentheses to initialize non primitive types:
356 ```cpp
357 throw std::runtime_error("foo");
359 my_class obj("bar");
360 ```
362 Use brace initialization when you want to use an initializer list, type
363 elision:
365 ```cpp
366 std::vector<int> v{1, 2, 3};
368 foo({1, 2}); // type deduced
370 return { "true", false }; // std::pair returned
371 ```
373 Use the assignment for primitive types:
375 ```cpp
376 int x = 123;
377 bool is_valid = true;
378 ```
380 ### Classes
382 Classes are usually defined in the following order:
384 1. Public inner types (enums, classes),
385 2. Protected/private members and functions
386 3. Public static functions.
387 3. Public member functions
388 4. Public virtual functions.
390 ```cpp
391 class foo {
392 public:
393 enum class type {
394 a,
396 };
398 private:
399 int member_{0};
401 public:
402 void some_function();
403 };
404 ```
406 ### Structs
408 Use structs for objects that only need to store public data and have no
409 invariants. For example PODs and traits match this criteria:
411 ```cpp
412 struct point {
413 int x{0};
414 int y{0};
415 };
417 template <>
418 struct info_traits<point> {
419 template <typename Archive>
420 static void serialize(Archive& ar, const point& point)
422 ar.write(point.x);
423 ar.write(point.y);
425 };
426 ```
428 ### Return
430 The preferred style is to return early in case of errors. That makes the code
431 more linear and not highly indented.
433 This code is preferred:
435 ```cpp
436 if (a_condition_is_not_valid)
437 return nullptr;
438 if (an_other_condition)
439 return nullptr;
441 auto x = std::make_shared<object>();
443 x->start();
444 x->save();
446 return x;
447 ```
449 Additional rules:
451 - Do never put parentheses between the returned value,
452 - Do not put a else branch after a return.
454 ### Auto
456 We encorage usage of `auto`, it reduces code maintainance as you don't need to
457 change your code when your rename types.
459 ```cpp
460 auto it = std::find_if(v.begin(), v.end(), [&] (const auto& obj) {
461 return obj.key() == "foo";
462 });
464 for (const auto& pair : a_map)
465 std::cout << pair.first << " = " << pair.second << std::endl;
466 ```
468 But do not use `auto` to write code like in python, this is not acceptable:
470 ```cpp
471 auto o = my_object("foo");
472 ```
474 ### String views
476 Use `std::string_view` each time you need a string that you will not own, this
477 includes: temporary arguments, return values, compile time constants.
479 ```cpp
480 const std::string_view version("1.0");
482 void load(std::string_view id, std::string_view path)
484 std::cout << "loading: " << id << " from path: " << path << std::endl;
486 ```
488 ### Optional values
490 Use `std::optional` to indicate a null value considered as valid. For example,
491 searching a value that may not exist.
493 ```cpp
494 auto find(std::string_view id) -> std::optional<int>
496 if (auto it = foo.find(id); it != foo.end())
497 return it->second;
499 return std::nullopt;
501 ```
503 ### Avoid definitions in headers
505 Try to avoid as much as possible function definition in header file. It slow
506 down compilation because the compiler has to parse the syntax over and over.
507 It's even worse as you may need to recompile a lot of files when you change a
508 header rather than a source file.
510 CMake
511 =====
513 Style
514 -----
516 - Try to keep line shorter than 80 columns
518 ### Spaces
520 Each programming keyword (e.g. `if`, `foreach`, `while`) requires a single space
521 before its argument, otherwise write opening parenthese directly after.
523 ```cmake
524 foreach (c ${COMPONENTS})
525 string(TOUPPER ${c} CMP)
527 if (${WITH_${CMP}})
528 add_executable(${c} ${c}.cpp)
529 endif ()
530 endforeach ()
531 ```
533 ### Line breaks
535 When CMake lines goes too long, you should indent arguments at the same level,
536 it's also common to see named argument values indented even more.
538 ```cmake
539 set(
540 FILES
541 ${myapp_SOURCE_DIR}/main.cpp
542 ${myapp_SOURCE_DIR}/foo.cpp
543 ${myapp_SOURCE_DIR}/bar.cpp
546 command_with_lot_of_arguments(
547 TARGET foo
548 INSTALL On
549 SOURCES
550 ${myapp_SOURCE_DIR}/main.cpp
551 ${myapp_SOURCE_DIR}/foo.cpp
552 ${myapp_SOURCE_DIR}/bar.cpp
553 COMMENT "Some comment"
554 ```
556 Modern CMake
557 ------------
559 CMake evolves over time, if you have read very old articles there is a chance
560 that what you have read is actually deprecated and replaced by other features.
561 The following list is a short summary of modern CMake features that you must
562 use.
564 ### Imported targets
566 When they are available, use imported targets rather than plain variables. They
567 offer complete dependency tracking with options and include directories as well.
569 ```cmake
570 find_package(Boost COMPONENTS system)
571 target_link_libraries(main Boost::system)
572 ```
574 ### Generator expressions
576 Use generator expressions when it make sense. For example you should use them
577 for variables that are not used at generation time (e.g CMAKE\_BUILD\_TYPE).
579 ```cmake
580 target_include_directories(
581 myapp
582 $<BUILD_INTERFACE:${myapp_SOURCE_DIR}>
583 $<INSTALL_INTERFACE:include>
585 ```
587 Warning: do never test against `CMAKE_BUILD_TYPE` in any CMakeLists.txt, IDEs
588 like Visual Studio will mismatch what you'll put in the conditions.
590 ### Avoid global scoping
592 The following commands must be avoided as much as possible:
594 - `link_directories`,
595 - `link_libraries`,
596 - `include_directories`,
597 - `add_definitions`.
599 They pollute the global namespace, all targets defined after these commands will
600 be built against those settings. Instead, you should use the per-targets
601 commands.
603 ```cmake
604 target_include_directories(
605 mylib
606 PUBLIC
607 $<BUILD_INTERFACE:${mylib_SOURCE_DIR}>
608 $<INSTALL_INTERFACE:include>
610 target_link_libraries(mylib foo)
611 ```
613 ### Defining sources
615 You MUST never use any kind of `file(GLOB)` commands to list sources for an
616 executable. CMake is designed to be re-called by itself only when required,
617 having such a construct will not let CMake be able to detect if you have
618 added/removed files in your source directory. Instead, you MUST always specify
619 all source by hands.
621 ```cmake
622 set(
623 FILES
624 ${myapp_SOURCE_DIR}/main.cpp
625 ${myapp_SOURCE_DIR}/a.cpp
626 ${myapp_SOURCE_DIR}/b.cpp
629 add_executable(myapp ${FILES})
630 ```
632 Markdown
633 ========
635 Headers
636 -------
638 For 1st and 2nd level headers, use `===` and `---` delimiters and underline the
639 whole title. Otherwise use `###`.
641 ```markdown
642 Top level title
643 ===============
645 Sub title
646 ---------
648 ### Header 3
650 #### Header 4
652 ##### Header 5
654 ###### Header 6
657 Lists
658 -----
660 Use hyphens for unordered lists for consistency, do not indent top level lists,
661 then indent by two spaces each level
663 ```markdown
664 - unordered list 1
665 - unordered list 2
666 - sub unordered item
668 1. unordered list 1
669 2. unordered list 2
670 2.1. sub unordered item
673 Code blocks
674 -----------
676 You can use three backticks and the language specifier or just indent a block by
677 for leading spaces if you don't need syntax.
679 ```cpp
680 std::cout << "hello world" << std::endl;
681 ```
683 And without syntax:
685 ```markdown
686 This is simple code block.
689 Tables
690 ------
692 Tables are supported and formatted as following:
694 ```markdown
695 | header 1 | header 2 |
696 |----------|----------|
697 | item 1 | item 2 |
700 Alerts
701 ------
703 It's possible to prefix a paragraph by one of the following topic, it renders a
704 different block depending on the output format:
706 - Note:
707 - Warning:
708 - Danger:
710 Then, if the paragraph is too long, indent the text correctly.
712 ```markdown
713 Note: this is an information block that is too long to fit between the limits so
714 it is split and indented.