Skip to content
Jay Kickliter edited this page Jun 7, 2018 · 2 revisions

This document is derived from the Google open source C++ style guide found at: Google Styleguide


v0.3

Version Date Author Change
0.3 8/12/2013 Kent Knox Ported to clMATH based upon Bolt
0.2 1/17/2013 Kent Knox Revised draft based upon team feedback
0.1 1/2/2013 Kent Knox Original draft

The following set of guidelines are the agreed principles the members of the AMD clMATH teams have agreed to follow, in writing and contributing code to the open source clMATH projects. Any and all code requests to check-in, pull or merge into the clMATH repositories should follow the code styles outlined below, at the discretion of the technical lead for the clMATH projects. These guidelines were written far after development on the projects began, so the current code is grandfathered as-is in its current non-conforming state. As development on clMATH continues over the coming months and years, the hope is that all the code will eventually conform to these written guidelines and have 100% conformance. If a developer finds themselves working in a non-conforming file, they should refactor the entire file as they work to achieve conformance. Diff tools normally highlight white space changes and the hope is to reduce the diff noise to one check-in, where all the code shuffling and whitespace changes apply.

Header Files

In general, every .cpp or .c file should have an associated .h file. There are common exceptions, such as unit test files and small .cpp files containing just a main() function.

#define Guard

All header files should have #define guards to prevent multiple inclusions. The format of the symbol name should be H. The #pragma once can optionally be included above the include guards, to help the compiler increase compilation speed, like so:

#pragma once
#ifndef CLFFT_SRC_LIBRARY_PLAN_H_
#define CLFFT_SRC_LIBRARY_PLAN_H_

.inl Files

You may use file names with an .inl suffix to define complex inline functions when needed. Typically all the content in .inl files should be declared in the detail:: namespace, as the contents of these files are typically implementation details.

Names and Order of Includes

Use standard order for readability and to avoid hidden dependencies: C library, C++ library, other libraries' .h, your project's .h

Scoping

Namespaces

Unnamed namespaces in .cpp files are encouraged. With named namespaces, choose the name based on the project, and possibly its path. Do not use a using-directive.

Nonmember, Static Member, and Global Functions

Prefer nonmember functions within a namespace or static member functions to global functions; use completely global functions rarely.

Local Variables

Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.

Classes

Doing Work in Constructors

Avoid doing complex initialization in constructors (in particular, initialization that can fail or that requires virtual method calls). Constructors should never call virtual functions or attempt to raise non-fatal failures. If your object requires non-trivial initialization, consider using a factory function or Init() method.

Copy Constructors

Provide a copy constructor and assignment operator only when necessary.

Structs vs. Classes

Use a struct only for passive objects that carry data; everything else is a class.

Inheritance

Composition is often more appropriate than inheritance. When using inheritance, make it public.

Multiple Inheritance

Only very rarely is multiple implementation inheritance actually useful. We allow multiple inheritance only when at most one of the base classes has an implementation; all other base classes must be pure interface classes tagged with the Interface suffix.

Access Control

Make data members private, and provide access to them through accessor functions as needed (for technical reasons, we allow data members of a test fixture class to be protected when using Google Test). Typically a variable would be called m_foo and the accessor function foo(). You may also want a mutator function set_foo(). Exception: static const data members need not be private.

Declaration Order

Use the specified order of declarations within a class: public: before private:, methods before data members (variables), etc.

Write Short Functions

Prefer small and focused functions.

Other C++ Features

Variable-Length Arrays and alloca()

We do not allow variable-length arrays or alloca()

Run-Time Type Information (RTTI)

Avoid using Run Time Type Information (RTTI)

Casting

For C++ code, prefer to use C++ based casts like static_cast<>(); this does not apply to C based code.

Preincrement and Predecrement

Use prefix form (++i) of the increment and decrement operators with iterators and other template objects

Use of const

Use const as much as possible, both for variable and method declarations

Integer Types

Of the built-in C++ integer types, the only one used is int. If a program needs a variable of a different size, use a precise-width integer type from <stdint.h>, such as int16_t

64-bit Portability

Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing, comparisons, and structure alignment

Preprocessor Macros

Be very cautious with macros. Prefer inline functions, enums, and const variables to macros

0 and nullptr/NULL

Use 0 for integers, 0.0 for reals, nullptr (or NULL) for pointers, and '\0' for chars

sizeof

Use sizeof(varname) instead of sizeof(type) whenever possible

auto

Use auto to avoid type names that are just clutter. Continue to use manifest type declarations when it helps readability, and never use auto for anything but local variables.

Boost

All of Boost is approved to be used in clMATH

C++11

The use of C++11 features are approved, as long as the code maintains portability across the compilers that the projects officially support, listed in the README.md file of the respective repo. This means that the use of the 'auto' keyword is OK, but the use of variadic templates breaks our use of microsoft compilers.

Naming

General Naming Rules

Function names, variable names, and filenames should be descriptive; eschew abbreviation. Types and variables should be nouns, while functions should be "command" verbs

File Names

Filenames should be all lowercase and can include underscores (_), dashes (-) or periods(.). This is a descriptive name for the contents of the file, specified in a convention most people are familiar with.

Type Names

Type names start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum

Variable Names

Variable names are all lowercase, with underscores between words. Class member variables have an m_ prefix. For instance: my_exciting_local_variable, m_my_exciting_member_variable

Function Names

Regular functions have mixed case; accessors and mutators match the name of the variable: MyExcitingFunction(), MyExcitingMethod(), my_exciting_member_variable(), set_my_exciting_member_variable()

Namespace Names

Namespace names are all lower-case, and based on project names and possibly their directory structure: google_awesome_project

Enumerator Names

Enumerators should be named either like constants or like macros: either kEnumName or ENUM_NAME

Macro Names

You're not really going to define a macro, are you? If you do, they're like this: MY_MACRO_THAT_SCARES_SMALL_CHILDREN

Comments

clMATH uses Doxygen style code comments, which are comments that can be pulled out of the code and formatted using an external program. The syntax and style of doxygen comments is documented here: http://www.stack.nl/~dimitri/doxygen/manual/index.html

File Comments

Start each file with license boilerplate, followed by a description of its contents

/***************************************************************************
*   Licensed under the Apache License, Version 2.0 (the "License");
*   you may not use this file except in compliance with the License.
*   You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
*   Unless required by applicable law or agreed to in writing, software
*   distributed under the License is distributed on an "AS IS" BASIS,
*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*   See the License for the specific language governing permissions and
*   limitations under the License.
***************************************************************************/

In addition, each file should also contain doxygen tags at the top to annotate the file, which is necessary to enable the doxygen processor to parse the file for contents.

/*! \file clFFT.h
 * Public header file for the project
 */

Class Comments

Every class definition should have an accompanying comment that describes what it is for and how it should be used The following is an example of the relevant doxygen tags for classes

/*! \brief This class contains objects that we wish to retain between individual calls into the FFT interface
*   \ingroup Repo
*   \details  These objects will be shared across different individual FFT plans, and we wish to keep only  
*   one copy of these programs, objects and events.  When the client decides that they either want to reset  
*   the library or release all resources, this Repo will release all acquired resources and clean itself up.  
*   It is implemented as a Singleton object.
*/

Function Comments

Declaration comments describe use of the function; comments at the definition of a function describe operation The following is an example of the relevant doxygen tags for functions

/*! \addtogroup GETTERS
*   \ingroup PLAN
*   \{
*/
	/*! @brief Retrieve the floating point precision of the FFT data
	 *  @details User should pass a reference to an clfftPrecision variable, which will be set to the
	 *  precision of the FFT complex data in the plan.
	 *  @param[in] plHandle Handle to a plan previously created
	 *  @param[out] precision Reference to user clfftPrecision enum
	 *  @return Enum describing error condition; superset of OpenCL error codes
	 */

Variable Comments

In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. In certain cases, more comments are required

TODO Comments

Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect Doxygen provides a \todo tag, that it uses to produce a documented page that gathers all of the TODO items into one list

/*!   \todo Need to implement feature X
*/

Deprecation Comments

Mark deprecated interface points with DEPRECATED comments

/*!   \deprecated Feature X is deprecated
*/

Formatting

Line Length

Each line of text in your code should be at most 120 characters long

Non-ASCII Characters

Non-ASCII characters should be rare, and must use UTF-8 formatting

Spaces vs. Tabs

Use only spaces, and indent 4 spaces at a time

Function Declarations and Definitions

If the declaration fits on one line, that is the appropriate style. If it doesn’t fit on one line, use many lines to make in easily readable, with each new line having 1 ‘tabs’

bool retval = DoSomething(argument1, argument2, argument3);
bool retval = DoSomething(
    argument1,
    argument2,
    argument3,
    argument4);

Defining code scope

The style is to use squigglies to demark ‘bodies’ of code, including functions, loops and conditionals. This means that every squiggly is on its own line. An example for a conditional branch would look like

if( … )
{
    // code
}
else
{
    // code
}

Namespace Formatting

The contents of namespaces are not indented. Files that have multiple nested namespaces at file scope should still have code that begins in column 1 of the file.

Loops and Switch Statements

Switch statements may use braces for blocks. Empty loop bodies should use {} or continue

Preprocessor Directives

The hash mark that starts a preprocessor directive should always be at the beginning of the line