362 lines
12 KiB
Markdown
362 lines
12 KiB
Markdown
|
|
Blades of Exile Coding Conventions
|
|
==================================
|
|
|
|
This file lists some guidelines for submitting code to the Open Blades
|
|
of Exile project. Most of these can be taken as guidelines rather than
|
|
hard rules.
|
|
|
|
The most important rule is, no formatting-only changes mixed in a commit
|
|
with actual code changes. Feel free to reformat a line that has been
|
|
otherwise touched, or re-indent a section that you've edited, but don't
|
|
change formatting just for the sake of changing formatting. If you make
|
|
a change that requires re-indenting a large block of code (about 10
|
|
lines or more), such as wrapping it in a loop, if, or try, we prefer it
|
|
to be split into two commits - one for the re-indenting, then one for
|
|
the actual logic.
|
|
|
|
With that out of the way, here's the actual guidelines. The coding
|
|
guidelines are loosely based on Google's style guide; the formatting
|
|
guidelines, however, are my own.
|
|
|
|
Header Files
|
|
============
|
|
|
|
Include Guards
|
|
--------------
|
|
|
|
All headers should have an include guard. The preferred format of the
|
|
include guard `#define` is `BOE_COMPONENT_FILENAME`.
|
|
|
|
Possible components are:
|
|
|
|
* `game` - files specific to the game
|
|
* `data` - files defining the game's data (currently kept in the classes
|
|
folder)
|
|
* `pced` - files specific to the player character editor
|
|
* `scened` - files specific to the scenario editor
|
|
* `dlog` - files that are part of the DialogXML framework
|
|
|
|
The COMPONENT can be omitted if none of the above apply.
|
|
|
|
Any hyphens or periods in the FILENAME should be replaced with
|
|
underscores in the include guard.
|
|
|
|
Declarations
|
|
------------
|
|
|
|
Whenever feasible, try to forward declare required classes instead of
|
|
including the file that defines them. With templates, however, it's
|
|
generally preferred to include. Don't use pointers solely for the
|
|
purpose of avoiding an include.
|
|
|
|
Unless dependencies make it impossible, the order of declarations in a
|
|
header should be:
|
|
|
|
* preprocessor defines
|
|
* typedef or using declarations
|
|
* enums
|
|
* simple struct or union types (usually with no member functions)
|
|
* classes
|
|
* global functions
|
|
|
|
However, it's preferred to not include classes, enums, and global
|
|
functions in the same file. Try to keep enum declarations in a separate
|
|
header file, and don't include functions in the same file as a class
|
|
unless they're directly related to the class.
|
|
|
|
One class per header is preferred. More is tolerated, if they're related
|
|
classes.
|
|
|
|
Never use a using namespace declaration in a header file.
|
|
|
|
Order of Includes
|
|
-----------------
|
|
|
|
Include files at the top of any file (header or source) should appear in
|
|
the following order:
|
|
|
|
* the source file's counterpart header (only applicable for source
|
|
files)
|
|
* System headers (eg WinAPI, Cocoa, CoreFoundation, POSIX, X)
|
|
* C or C++ standard library headers (use the cxx form instead of xx.h
|
|
for C headers)
|
|
* Boost library headers
|
|
* Other library headers (eg SFML, OpenGL, Zlib, TinyXML++, etc)
|
|
* DialogXML headers
|
|
* General Blades of Exile headers
|
|
* Component-specific Blades of Exile headers
|
|
|
|
All except the last three and the first one should use the angle
|
|
brackets include style. Normally, there should be a blank line
|
|
between groups; however, if there are only one or two headers in
|
|
a group, it can be merged with an adjacent group. The counterpart
|
|
header should always be followed by a blank line, however.
|
|
|
|
Try to make all includes explicit in the header files, rather than
|
|
relying on indirect includes by including one file that includes others.
|
|
|
|
Inline template definition headers should be included at the bottom of
|
|
the header.
|
|
|
|
Include by filename only for Blades of Exile headers; assume all project
|
|
folders containing headers are in the include path.
|
|
|
|
Scoping
|
|
=======
|
|
|
|
Never use a using namespace declaration in a header file. It's
|
|
acceptable in a source file, but discouraged. Using declarations are
|
|
fine in source files, but not in header files unless they're in an
|
|
inline function or class declaration. Namespace aliases are encouraged
|
|
for long namespaces. When using `std::bind` within a function, always put
|
|
a `using namespace std::placeholders;` line somewhere in the function.
|
|
|
|
Don't use nested classes.
|
|
|
|
Only put absolutely necessary functions in header files; if a function
|
|
only needs to be used in one file, it shouldn't be in a header. In this
|
|
case, it should be declared `static`. (Don't use an anonymous namespace
|
|
for this purpose.)
|
|
|
|
Local variables should be declared as close to the point of use as
|
|
possible. Much of the legacy code placed all variable declarations at
|
|
the top of the function, since this was required in C at that time;
|
|
don't do this in new code.
|
|
|
|
Whenever possible, eliminate global variables. It's accepted that some
|
|
global variables can't be helped, such as the global `cUniverse` and the
|
|
global `cScenario`, but if a global is just being used to pass information
|
|
between disparate functions, find another way. There are such variables
|
|
in the code currently which we would like to eliminate.
|
|
|
|
Classes
|
|
=======
|
|
|
|
Use the explicit keyword for constructors that have only one
|
|
non-defaultable argument, unless you actually intend to define an
|
|
implicit conversion. An operator bool should usually be declared
|
|
explicit as well.
|
|
|
|
Generally, you should use the `class` keyword (rather than the `struct`
|
|
keyword) to declare anything with member functions or non-public
|
|
members.
|
|
|
|
Operator overloading is encouraged, provided it doesn't change the basic
|
|
meaning of the operator being overloaded.
|
|
|
|
Declarations within a class should be in the following order:
|
|
|
|
* friend class declarations
|
|
* friend function declarations
|
|
* public member functions
|
|
* public member variables
|
|
* protected member functions
|
|
* protected member variables
|
|
* private member functions
|
|
* private member variables
|
|
|
|
Be sparing with friend declarations.
|
|
|
|
Functions
|
|
=========
|
|
|
|
If a function takes a parameter by reference or pointer and doesn't
|
|
modify it, the parameter should be const. Don't declare parameters const
|
|
if they are passed by value. Don't use const pointers for parameters (eg
|
|
`int*const`).
|
|
|
|
Overloading functions is encouraged.
|
|
|
|
Default arguments are encouraged.
|
|
|
|
Don't use `throw()` specifications.
|
|
|
|
General Coding Style
|
|
====================
|
|
|
|
Use of exceptions is encouraged, provided it makes sense, though you
|
|
should ensure that they get caught somewhere before `main()`.
|
|
|
|
Prefer C++-style casts to C-style casts.
|
|
|
|
Do not use the C-style stream functions `printf`, `fprintf`, or `perror`
|
|
to print diagnostic output to stdout or stderr. Use either `cout` or
|
|
`cerr` for this purpose. Do not use `clog` or `cin`. For other uses,
|
|
C++ streams are included. Do not use `sprintf` for anything. Do not
|
|
even use `snprintf`.
|
|
|
|
Use const whenever it makes sense. In particular, declare string
|
|
constants as `const char*const`.
|
|
|
|
Never use simple macros for constants. Create an enum instead. Macros
|
|
that take arguments may be acceptable, depending.
|
|
|
|
Don't use 0 where a pointer is expected; use `NULL` or `nullptr` instead.
|
|
|
|
Feel free to use `auto` if it simplifies the code, but generally only for
|
|
local variables.
|
|
|
|
Use of lambda functions, `std::function`, and `std::bind` is encouraged.
|
|
|
|
Use of Boost libraries is encouraged.
|
|
|
|
Naming Rules
|
|
============
|
|
|
|
Header files should have a "_.hpp_" extension. C++ source files should have
|
|
a "_.cpp_" extension, and Objective-C++ files should have a "_.mm_" extension.
|
|
|
|
Files specific to one component should be named with one of the prefixes
|
|
"_boe._", "_pc._", "_scen._".
|
|
|
|
Sometimes, a header will define an interface that has to be implemented
|
|
differently depending on the platform. In this case, the naming should
|
|
be as follows:
|
|
|
|
* _file.hpp_
|
|
* _file.win.cpp_
|
|
* _file.mac.mm_ (or _file.mac.cpp_ if it doesn't include Objective-C code)
|
|
* _file.linux.cpp_
|
|
|
|
If the Mac and Linux implementation happen to be the same due to only
|
|
using POSIX headers, use "_file.posix.cpp_".
|
|
|
|
For files containing inline template definitions, an extension of
|
|
"_.tpl.hpp_" is preferred.
|
|
|
|
In general, functions and variables should always start with a lowercase
|
|
letter. Both `underscore_separated` and `camelCase` names are acceptable.
|
|
|
|
Enums should be named with a lowercase `e` followed by an uppercase
|
|
letter.
|
|
|
|
Classes should either start with an uppercase letter or a lowercase `c`
|
|
followed by an uppercase letter.
|
|
|
|
Typedef or using declarations should usually end with `_t`.
|
|
|
|
Do not use a trailing underscore or `m_` prefix for member variables.
|
|
|
|
Names of constants (both enum constants and other constants) should
|
|
either be all uppercase and separated by underscores, or camelCase
|
|
starting with a lowercase k followed by an uppercase letter.
|
|
|
|
Macros, when present, should be all uppercase and separated by
|
|
underscores.
|
|
|
|
Comments and Annotations
|
|
========================
|
|
|
|
Generally, C++-style comments are preferred, but feel free to use
|
|
C-style comments for longer comments.
|
|
|
|
If we ever introduce Doxygen comments, they will be in the Javadoc style
|
|
- block comments start with `/**`, line comments start with `///`, and
|
|
directives start with `@`.
|
|
|
|
Comment whenever something's purpose may be unclear. If you're uncertain
|
|
of something's purpose, feel free to add a `TODO:` comment. Use `TODO:` for
|
|
anything that is temporary or not perfect, or in places where there
|
|
needs to be code that hasn't been written yet.
|
|
|
|
For organizing the function popup menu, use `MARK:` comments rather than
|
|
`#pragma mark`.
|
|
|
|
To mark parameters as unused, omit the name or surround it in block
|
|
comment syntax. Other unused entities should be removed or commented out
|
|
if you want to avoid warnings, though if you think it might have a use
|
|
in the future, it's reasonable to leave it in with a comment.
|
|
|
|
Do not use any kind of attributes, including `__attribute__`, `__declspec`.
|
|
Do not even use C++11 attributes, as one of our target compilers does not support them.
|
|
However, if attributes are absolutely required for something, they can be
|
|
hidden behind a macro so that the code looks clean but still works on all compilers.
|
|
|
|
Formatting
|
|
==========
|
|
|
|
There's no line limit, and breaking a long line up by simply adding line
|
|
breaks is discouraged. However, if a line is longer than about 100
|
|
character, you should probably consider writing it in a way to shorten
|
|
it, such as using more intermediate local variables or writing a
|
|
function to compute the value.
|
|
|
|
If you need non-ASCII characters in strings, make sure the file is saved
|
|
as UTF-8.
|
|
|
|
All indentation should be tabs. Assume four spaces per tab.
|
|
|
|
Never put whitespace at the end of a line (unless there's nothing else
|
|
on the line and the whitespace matches nearby indentation). Never have
|
|
more than two consecutive blank lines.
|
|
|
|
Do not put parentheses around return values. Do not put redundant
|
|
parentheses around comparisons mixed in with logical operators.
|
|
|
|
Do not put space after an open parenthesis or before a closing parenthesis.
|
|
Do not put a space between a function name and the following open parenthesis.
|
|
|
|
Control Statements
|
|
------------------
|
|
|
|
Braces go on the same line as the control statement or function
|
|
declaration. The else keyword shares its line with the closing brace of
|
|
the preceding if statement. The same goes for the catch keyword and the while of do..while.
|
|
|
|
Do not put space between a keyword and the following open parenthesis.
|
|
Do put a space before the opening brace.
|
|
|
|
For control statements spanning more than one line, always use braces. For control statements that fit entirely on one line, never use braces. It is acceptable to bundle an if and else all onto one line as long as they are both _very_ short.
|
|
|
|
If the sole content of an else block is another control statement such as try or for, it's acceptable to omit the braces on the else block and indent it as you would an else if.
|
|
|
|
Examples:
|
|
|
|
```
|
|
if(some_value) {
|
|
thing1 = 2;
|
|
do_another_thing();
|
|
} else while(some_value < 12) {
|
|
do_it_with(some_value++);
|
|
}
|
|
if(done) return result; else accum++;
|
|
```
|
|
|
|
Declarations
|
|
------------
|
|
|
|
In declarations of pointers and references, the pointer or reference
|
|
operator should bind to the type, not the variable. Never declare
|
|
another type in the same declaration as a pointer or reference.
|
|
|
|
Place const before the type, not after.
|
|
|
|
Okay:
|
|
```
|
|
int* thing;
|
|
int* another_thing;
|
|
int& ref;
|
|
const std::string bar;
|
|
```
|
|
|
|
Not okay:
|
|
```
|
|
int *thing, *another_thing;
|
|
int * whatever;
|
|
int &ref;
|
|
std::string const bat;
|
|
```
|
|
|
|
Constructors
|
|
------------
|
|
|
|
If a constructor initializer must be wrapped, put each variable on one line, indented one level. The first variable is prefixed by a colon, and all other variables are prefixed by a comma. The opening brace goes on the next line. Don't default-initialize fields unless they're primitive types such as numbers or pointers.
|
|
|
|
```
|
|
Thing::Thing()
|
|
: stuff(12)
|
|
, more_stuff(22)
|
|
{}
|
|
```
|