-
Notifications
You must be signed in to change notification settings - Fork 192
CodingGuidelines
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.
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.
All header files should have #define guard
s 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_
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.
Use standard order for readability and to avoid hidden dependencies: C library, C++ library, other libraries' .h, your project's .h
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.
Prefer nonmember functions within a namespace or static member functions to global functions; use completely global functions rarely.
Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.
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.
Provide a copy constructor and assignment operator only when necessary.
Use a struct only for passive objects that carry data; everything else is a class.
Composition is often more appropriate than inheritance. When using inheritance, make it public.
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.
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.
Use the specified order of declarations within a class: public: before private:, methods before data members (variables), etc.
Prefer small and focused functions.
We do not allow variable-length arrays or alloca()
Avoid using Run Time Type Information (RTTI)
For C++ code, prefer to use C++ based casts like static_cast<>(); this does not apply to C based code.
Use prefix form (++i) of the increment and decrement operators with iterators and other template objects
Use const as much as possible, both for variable and method declarations
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
Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing, comparisons, and structure alignment
Be very cautious with macros. Prefer inline functions, enums, and const variables to macros
Use 0 for integers, 0.0 for reals, nullptr (or NULL) for pointers, and '\0' for chars
Use sizeof(varname) instead of sizeof(type) whenever possible
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.
All of Boost is approved to be used in clMATH
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.
Function names, variable names, and filenames should be descriptive; eschew abbreviation. Types and variables should be nouns, while functions should be "command" verbs
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 start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum
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
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 are all lower-case, and based on project names and possibly their directory structure: google_awesome_project
Enumerators should be named either like constants or like macros: either kEnumName or ENUM_NAME
You're not really going to define a macro, are you? If you do, they're like this: MY_MACRO_THAT_SCARES_SMALL_CHILDREN
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
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
*/
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.
*/
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
*/
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
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
*/
Mark deprecated interface points with DEPRECATED comments
/*! \deprecated Feature X is deprecated
*/
Each line of text in your code should be at most 120 characters long
Non-ASCII characters should be rare, and must use UTF-8 formatting
Use only spaces, and indent 4 spaces at a time
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);
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
}
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.
Switch statements may use braces for blocks. Empty loop bodies should use {} or continue
The hash mark that starts a preprocessor directive should always be at the beginning of the line