Daala Coding Style

Overview

This document defines the coding style of the Daala project. In general, Daala tries to conform to C89, and avoid features which are not available in C89 in portable code. We try to minimize our dependence on libc (e.g., using macros around memory allocation functions).

General Rules

License Block

The top of each file should contain the following license header:

/*Daala video codec
Copyright (c) 2001-2013 Daala project contributors.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/

Make sure the copyright years are up to date.

In general, it is not necessary to list invididual copyright holders in each file (beyond "Daala project contributors"). Xiph does not require assignment of copyright.

Globals

Non-const global variables in portable code are not allowed. They make it impossible to write re-entrant code without introducing a dependency on a threading library.

Naming

All functions and types use the canonical C naming scheme: all lowercase with underscores for separators. #defines and global const variables use all uppercase with underscores for separators.

All functions and types begin with an od_ prefix. All #defines and global const variables begin with an OD_ prefix.

Do not prefix names with single letters indicating their role (m for member variables, k for constants, g for globals, etc.).

Do not use leading or trailing underscores in regular code.

Macro definitions which need to declare local variables should append two trailing underscores to their name to avoid conflicts with regular code.

Constructors/Destructors

Initialization and deinitialization routines for type od_foo are named od_foo_init() and od_foo_clear(). These should take an already-allocated pointer to an object of the appropriate type. If allocating versions of these functions are desired, they should be named od_foo_create() and od_foo_free(), and dispatch to od_foo_init() and od_foo_clear() respectively.

Formatting

Tabs

There are no tabs in source code. Do not use them, ever.

Trailing Whitespace

Remove all trailing whitespace at the end of a line.

Indentation

Use two-space indenting.

Line Length

Lines should be no more than 79 characters. This allows them to be displayed fully in a standard terminal even in diffs. The extra column on the right also makes long lines easier to spot.

Line Wrapping

If a line needs to be continued on to the next line, use a single additional space for all subsequent lines. Do not align subsequent lines with = operators, function parameters, etc. Do not add additional indentation to indicate open parentheses, etc. If this produces lines you think are confusing, break them up into multiple statements.

Prefer wrapping at lower-precedence operators.

Prefer making wrapped lines as close in length as possible, while minimizing the total number of lines.

All unary operators and the binary operators +, -, &&, and || belong to the start of the next line, not the end of the previous line.

struct fields and local variables

One variable/field per declaration (e.g., do not use int x, y, z;).

Do not attempt to align variable/field names.

Do not initialize variables in the declaration. This makes it harder to follow C89's "no declarations after a statement" rule and can hide logic errors that would be exposed by valgrind.

Comments

Do not use C++ comments (//).

Write properly punctuated comments that start with a capital letter.

Do not put comments to the right of code. Put them on a separate line.

Format multi-line comments as follows:

/*This is a multi-line comment.
  Each sentence starts on a new line, and all subsequent lines in the same
   sentence are indented a single space, making it easier to change the comment
   without re-flowing a whole paragraph.
  This gives better "blame" information, and makes diffs easier to read.

  Other notes:
  - Start the first sentence on the same line as the start of the comment, and
     do not add a space in front of it.
    The former ensures that single-line and multi-line comments have the same
     style, making it easier to convert between the two.
    The latter maximizes the space available for prose in heavily-indented
     code.
  - Align the start of subsequent sentences with the start of the first one.
  - End the comment on the same line as the last sentence, and do not add an
     extra space after that sentence.*/

Preprocessor Statements

All pre-processor statements begin with a # in the leftmost column. Indent pre-processor statements by adding spaces after the #, not before it.

Preprocessor statements inside an #if/#else/#endif block are indented by one space per level (after the leading #).

Use #if [!]defined(X) instead of #if[n]def X. The former makes it easier to extend to multiple conditions, zero out, etc., e.g., replacing

#if defined(X)
with
#if defined(X) && 0

Blank Lines

There should never be more than a single blank line in a row.

Do not add blank lines in the interior of a function, except inside of a multi-line comment. If you find yourself wanting to do this, use two functions instead.

Operator Spacing

All non-unary operators with the precedence of + and - or less should have one space on either side, except for commas, which have a single following space.

There is no space before the opening parenthesis of a function call argument list, nor after a closing parenthesis followed by a comma or a semicolon.

Semicolons in for loop iterators also have a single following space, except when the following statement is empty.

Pointers

The * in pointer types hugs the variable name, not the type name.

Braces

Opening braces go on the same line as the start of the construct they are opening (function body, if, else, for, do, while, switch, etc.), separated by a single space.

Do not put spaces in empty braces.

Closing braces go on a line by themselves, indented at the same level as the opening line.

Array Initializers

If an array initializer fits on a single line, put a single space inside the brace on each end.

If an array initializer does not fit on a single line, do not wrap it as one long line. Instead, start a new line after the opening brace and indent the initialization data. Start new lines of initialization data as necessary, without the additional one space used to indent wrapped lines.

For multi-line multidimensional array initializers, place the comma on the same line as the closing brace for the inner array, and start the opening brace for the next element of the outer array on a new line.

Trailing Commas

Do not include trailing commas in array initializers, enums, or other lists. These cause warnings on some platforms.

Parentheses

Do not use syntactically unnecessary parentheses unless they would generate a warning with gcc, clang or MSVC.

Parentheses should be placed around every single-expression macro definition, including constants.

Keywords

A single space follows if, for, while, and switch keywords, before the parenthesized expression.

An else and the while in a do ... while loop begin on a new line, instead of being placed on the same line as the closing brace from the previous block. If the else's statement is a subsequent if, that if is placed on the same line as the else.

If you omit the break after a non-empty case statement where control reaches the end of the block, add a comment indicating you are falling through. If control reaches the end of the block in the last case statement in a switch block, do not omit the break. Use braces around the body of a case statement, unless the body is a single statement (excluding the break) and fits on one line (including the break).

Loop or conditional bodies with a single statement may be placed on the same line as the start of the loop/conditional without any braces. Such loops can easily be stepped over in a debugger. This is allowed even for if statements with an else clause. If a loop/conditional body has to extend to multiple lines for any reason (including exceeding the 79-character line limit, even if still a single statement), then it must be contained in braces (and the first statement start on a new line).

Use for (;;) for infinite loops, not while (1). Some compilers complain about conditional expressions that always evaluate to true.

return values are separated from the keyword by a single space, and are not enclosed in parentheses.

Examples:

for (i = 0; i < n; i++) x[i] = 0;
do something();
while (!done);
while (!done) {
  do_something();
  do_something_else();
}
if (test) do_this();
else do_that();
if (condition) {
  do_one_thing();
  then_another();
}
else if (another_condition) do_something_else();
switch (value) {
  case 1: {
    int foo;
    foo = compute_foo();
    use_foo(foo);
    break;
  }
  case 2: ignore_foo();
  /*Fall through.*/
  case 3: return -1;
  default: handle_default(); break;
}

Functions

Declarations

Put the return type and parameters on the same line as the function name, wrapping as necessary. Do not attempt to align the function names in a group of functions with different return types.

Function Parameter Ordering

If the function is associated with a single object, put that object first.

If the function has both inputs and outputs, the outputs go before the inputs (like memcpy(), which was designed to mimic the assignment operator).

When taking a variable-length array, the length/size/stride of the array goes after the pointer to the array.

Header Files

The #define guard

All header files should be wrapped in a define guard as follows:

#if !defined(_path_file_H)
# define _path_file_H (1)
...
#endif
Path elements should be sparated by underscores. The leading src component of the path is omitted. Path/file names should be lower case (as identifiers which match _[A-Z].* are reserved by POSIX).

Forward Declarations

Do not forward declare things in order to avoid additional includes. Processing includes is fast in C, unlike C++, where they contain most of the code, and recompiling C is also fast. It's not worth the maintenance burden of having one thing defined in many places to avoid including some extra files.

In header files which have circular dependencies, put any typedefs at the top, before including the headers which produce the cycle.

Inline Functions

Do not put inline functions in headers except in platform-specific sections. The inline keyword is not available in C89. Do not use static functions in headers as a substitute, as they generate warnings if unused.