Skip to content

Instantly share code, notes, and snippets.

@Normynator
Last active April 10, 2019 17:58
Show Gist options
  • Save Normynator/e5b4610f8ea55eb8edf56d42df7100a9 to your computer and use it in GitHub Desktop.
Save Normynator/e5b4610f8ea55eb8edf56d42df7100a9 to your computer and use it in GitHub Desktop.

Welcome

Welcome to the rAthena Code Guidelines. This is here to help all developers in creating safe, maintainable, easily readable and understandable code.

References

These guidelines are inspired by the CppCoreGuidelines. Some of the examples below maybe taken directly from there. If you need more information that may not be listed here, please be sure to check out CppCoreGuidelines. If your questions are still unanswered after consulting this or CppCoreGuidelines, consider consulting the rAthena forum, rAthena's Discord, or add your concerns directly to a pull request.

Code Guidelines

1. Don't unnecessarily remove or add blank lines when commiting new code

Reason

Commits should be on point, documented and as small as possible.

Enforcement

Check for removed or added blank lines on each commit.

2. Use std::remove_if, std::remove & ... within std::vector::earse

Reason

std::vector requires to be shrinked after using std::remove. To avoid forgetting about proper shrinking after removing an element the removing should always be bound to a call to earse.

Note

If using a std::list one should rely on std::list::remove instead of std::remove.

Example
vec.erase(std::remove_if(vec.begin(), vec.end(), [](int a) {return a % 2 == 0;}), vec.end()); // good
Enforcement

Check for std::remove on datatype std::vector without being surrounded by an erase.

3. Don't add redundant == or != to conditions

Reason

Doing so avoids verbosity and eliminates some opportunities for mistakes. Helps make style consistent and conventional.

Example

By definition, a condition in an if-statement, while-statement, or a for-statement selects between true and false. A numeric value is compared to 0 and a pointer value to nullptr.

// These all mean "if `p` is not `nullptr`"
if (p) { ... }            // good
if (p != 0) { ... }       // redundant `!=0`; bad: don't use 0 for pointers
if (p != nullptr) { ... } // redundant `!=nullptr`, not recommended

Often, if (p) is read as "if p is valid" which is a direct expression of the programmers intent, whereas if (p != nullptr) would be a long-winded workaround.

All examples

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es87-dont-add-redundant--or--to-conditions

Note

Explicit comparison of an integer to 0 is in general not redundant. The reason is that (as opposed to pointers and Booleans) an integer often has more than two reasonable values. Furthermore 0 (zero) is often used to indicate success. Consequently, it is best to be specific about the comparison.

void f(int i)
{
    if (i)            // suspect
    // ...
    if (i == success) // possibly better
    // ...
}

Always remember that an integer can have more than two values.

Enforcement

Easy, just check for redundant use of != and == in conditions.

5. Avoid "magic constants"; use symbolic constants

Reason

Unnamed constants embedded in expressions are easily overlooked and often hard to understand:

Example
for (int m = 1; m <= 12; ++m)   // don't: magic constant 12
    cout << month[m] << '\n';

No, we don't all know that there are 12 months, numbered 1..12, in a year. Better:

// months are indexed 1..12
constexpr int first_month = 1;
constexpr int last_month = 12;

for (int m = first_month; m <= last_month; ++m)   // better
    cout << month[m] << '\n';

Better still, don't expose constants:

for (auto m : month)
    cout << m << '\n';
Enforcement

Flag literals in code. Give a pass to 0, 1, nullptr, \n, "", and others on a positive list.

4. Use auto to avoid redundant repetition of type names

Reason
  • Simple repetition is tedious and error-prone.
  • When you use auto, the name of the declared entity is in a fixed position in the declaration, increasing readability.
  • In a template function declaration the return type can be a member type.
Example

Consider:

auto p = v.begin();   // vector<int>::iterator
auto h = t.future();
auto q = make_unique<int[]>(s);
auto f = [](int x){ return x + 10; };

In each case, we save writing a longish, hard-to-remember type that the compiler already knows but a programmer could get wrong.

Exception

Avoid 'auto' when declaring a variable which is directly iniated with a return value of a function call which does not indicate the type. This is only required when using the fucnction call the first time within a method.

Also avoid auto for initializer lists and in cases where you know exactly which type you want and where an initializer might require conversion.

Example (bad)
auto lst = { 1, 2, 3 };   // lst is an initializer list
auto x{1};   // x is an int (in C++17; initializer_list in C++11)
Example (good)
void some_function()
{
    my_type a = my_function();
    auto b = my_function(); // here we already know the return type of 'my_function'
    ...
}
All examples

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es11-use-auto-to-avoid-redundant-repetition-of-type-names

Enforcement

Flag redundant repetition of type names in a declaration.

Style Guidelines

Brackets are broken from namespaces, classes, and function definitions.
Brackets are attached to statements within a function.

--style=kr

Indent using tabs. Convert 4 spaces to 1 tab.

--indent=tab=4

Indent 'class' and 'struct' blocks

--indent-classes

Indent multi-line preprocessor definitions ending with a backslash.

--indent-preprocessor --convert-tabs

Indent comments beginning in column one.

--indent-col1-comments

Indent labels.

--indent-labels

Indent cases.

--indent-cases

Indent switches.

--indent-switches

When a header is built of multiple lines, the lines will be aligned with the paren on the preceding line.

--min-conditional-indent=0

Remove extra space padding around parenthesis on the inside and outside.
Run before --pad-header so that the space added by --pad-header isn't removed.

--unpad-paren

Insert space padding after paren headers only (e.g. 'if', 'for', 'while'...).

--pad-header

Insert space padding after math operations.

--pad-oper

Don't break complex statements and multiple statements residing on a single line.

--keep-one-line-statements

Attach pointer operator to the variable name.

--align-pointer=name

Attach reference operator to the variable name.

--align-reference=name

Force use of the specified line and style.

--lineend=linux

Do not retain a backup of the original file. (your working copy has SVN History)

--suffix=none

For each directory in the command line, process all subdirectories recursively.

--recursive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment