ITK/Coding Style Guide

From KitwarePublic
< ITK
Revision as of 18:08, 18 February 2017 by Jhlegarreta (talk | contribs) (→‎Documenting ivars: Correct where the ivar documentation should be placed.)
Jump to navigationJump to search

C++ Code Style

The document located HERE describes ITK coding conventions. Developers should follow these conventions when submitting contributions.

ITK Style Guide Insight Software Consortium

Purpose

The following document is a description of the accepted coding style for the NLM Insight Segmentation and Registration Toolkit (ITK). Developers who wish to contribute code to ITK should read and adhere to the standards described here.

Document Overview

This document is organized into the following sections.

  • System Overview & Philosophy | coding methodologies and motivation for the resulting style.
  • Copyright | the copyright header to be included in all files and other copyright issues.
  • File organization | how to organize source code; a guide to the ITK directory structure.
  • Naming conventions | patterns used to name classes, variables, template parameters, and instance variables.
  • Namespaces | the use of namespaces.
  • Code Layout and Indentation | accepted standards for arranging code including indentation style.
  • Doxygen Documentation System | basic Doxygen formatting instructions.
  • Using Standard Macros (itkMacro.h) | use of standard macros in header files.
  • Exception Handling | how to add exception handling to the system.
  • Documentation Style | a brief section describing the documentation philosophy adopted by the Insight consortium.

This style guide is an evolving document.

Please dialog with the ITK developers if you wish to add, modify, or delete the rules described in these guidelines.

See:

http://www.itk.org/ITK/help/mailing.html

for more information about joining the ITK developers mailing list. This forum is one of the best venues in which to propose changes to these style guidelines.

Style Guidelines

The following coding-style guidelines have been adopted by the ITK community. To a large extent these guidelines are a result of the fundamental architectural and implementation decisions made early in the project. For example, the decision was made to implement ITK with a C++ core using principles of generic programming, so the rules are oriented towards this style of implementation. Some guidelines are relatively arbitrary, such as indentation levels and style. However, an attempt was made to find coding styles consistent with accepted practices. The point is to adhere to a common style to assist developers and users of the future learn, use, maintain, and extend ITK. (See the ITK Requirements document for more information.) Please do your best to be a upstanding member of the ITK community. The rules described here have been developed with the community as a whole in mind. If you consistently violate these rules you will likely be harassed mercilessly, first privately and then publicly. If this does not result in correct code layout, your right to CVS write access (if you are developer and wish to contribute code) may be removed. Similarly, if you wish to contribute code and are not a developer, your code will not be accepted until the style is consistent with these guidelines.

System Overview & Philosophy

The following implementation strategies have been adopted by the ITK community. These directly and indirectly affect the resulting code style. Understanding these strategies motivate the reasons for many of the style guidelines described in this document.

Implementation Language

The core implementation language is C++. C++ was chosen for its flexibility, performance, and familiarity to consortium members. (Auxiliary, interpreted language bindings such as Tcl, Python, and/or Java are also planned. These are aimply (run-time interpreted) layers on the C++ code.) ITK uses the full spectrum of C++ features including const and volatile correctness, namespaces, partial template specialization, operator overloading, traits, and iterators.

Generic Programming and the STL

Compile-time binding using methods of generic programming and template instantiation is the preferred implementation style. This approach has demonstrated its ability to create efficient, flexible code. Use of the STL (Standard Template Library) is encouraged. STL is typically used by a class, rather than as serving as a base class for derivation of ITK classes. Other STL influences are iterators and traits. ITK defines a large set of iterators; however, the ITK iterator style differs in many cases from STL because STL iterators follow a linear traversal model; ITK iterators are often designed for 2D, 3D, and even n-D traversal. Traits are used heavily be ITK. ITK naming conventions supersede STL naming conventions; this difference is useful in that it indicates to the developer something of the boundary between ITK and STL.

Portability

ITK is designed to compile on a set of target operating system/compiler combinations.

These combinations include, but are not limited to:

  • Windows 9x/NT/2000/XP running
    • Microsoft Visual C++ version 7.1 to 10
  • Solaris with SunPro compiler
  • Linux running gcc
  • MacOSX running gcc
  • Intel compiler on Windows and Linux

For a full list of the compilers supported please see:

Multi-Layer Architecture

ITK is designed with a multi-layer architecture in mind. That is, three layers, a templated layer, a run-time layer, and an application layer. The templated (or generic) layer is written in C++ and requires significant programming skills and domain knowledge. The run-time layer is generated automatically using the CableSwig wrapping system to produce language bindings to Tcl, Python, and Java. The interpreted layer is easier to use than the templated layer, and can be used for prototyping and smaller-sized application development. Finally, the application layer is not directly addressed by ITK other than providing simple examples of applications.

CMake Build Environment

The ITK build environment is CMake. CMake is an open-source, advanced cross-platform build system that enables developers to write simple \makefiles" (named CMakeLists.txt) that are processed to generated native build tools for a particular operating system/compiler combinations. See the CMake web pages at http://www.cmake.org for more information.

Doxygen Documentation System

The Doxygen open-source system is used to generate on-line documentation. Doxygen requires the embedding of simple comments in the code which is in turn extracted and formatted into documentation.

For more information about Doxygen, please see

  http://www.stack.nl/dimitri/doxygen/

vnl Math Library

ITK has adopted the vnl math library. Vnl is a portion of the vxl image understanding environment. See http://www.robots.ox.ac.uk/ vxl/ for more information about vxl and vnl.

Reference Counting

ITK has adopted reference counting via so-called "smart pointers" to manage object references. While alternative approaches such as automatic garbage collection were considered, their overhead due to memory requirements, performance, and lack of control as to when to delete memory, precluded these methods. Smart pointers manage the reference to objects, automatically incrementing and deleting an instance's reference count, deleting the object when the count goes to zero. These are the most important factors influencing the coding style found in Insight. Now we will look at the details.

Copyright

ITK has adopted a standard copyright. This copyright should be placed at the head of every source code file. The current copyright header and license reads as follows:

/*=========================================================================                                                                                      
 *                                                                                                                                                               
 *  Copyright Insight Software Consortium                                                                                                                        
 *                                                                                                                                                               
 *  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.txt                                                                                                        
 *                                                                                                                                                               
 *  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.                                                                                                                               
 *                                                                                                                                                               
 *=========================================================================*/

Copyright Header

File Organization

Classes are created and (usually) organized into a single class per file set. A file set consists of .h header file, .cxx implementation file, and/or a .hxx templated implementation file. Helper classes may also be defined in the file set, typically these are not visible to the system at large, or placed into a special namespace.

Source files must be placed in the correct directory for logical consistency with the rest of the system, and to avoid cyclic dependencies. Currently the ITK source directory structure is found in ITK/Modules and consists of the following subdirectories:

  • Bridge
  • Core
  • External
  • Filtering
  • GPU
  • IO
  • Nonunit
  • Numerics
  • Registration
  • Segmentation
  • ThirdParty

Each one of these directories represent a Group of Modules.

Please discuss with the ITK Developers about the best Module to place your new code.

For a full list of Modules, please see:

 http://www.itk.org/Doxygen/html/modules.html

Naming Conventions

In general,

  • Names are constructed by using case change to indicate separate words, as in TimeStamp

(versus Time Stamp).

  • Underscores are not used.
  • Variable names are chosen carefully with the intention to convey the meaning behind the code.
  • Names are generally spelled out; use of abbreviations is discouraged. (Abbreviation are allowable when in common use, and should be in

uppercase as in RGB.) While this does result in long names, it self-documents the code.

  • If you learn how to use name completion in your editor (e.g.,Vim, Emacs), this inconvenience can be minimized.

Depending on whether the name is a

  • class
  • file
  • variable
  • or other name

variations on this theme result as explained in the following subsections.

Naming Classes

  • Classes are named beginning with a capital letter.
  • Classes are placed in the appropriate namespace, typically itk:: (see namespaces below).
  • Classes are named according to the following general rule:

class name = <algorithm><input><concept>

  • In this formula, the name of the algorithm or process (possibly with an associated adjective or

adverb) comes first, followed by an input type (if the class is a filter), and completed by a concept name.

  • A concept is an informal classification describing what a class does. There are many

concepts, here are a few of them.

The more common or important concepts are underlined.

  • Accessor Access and convert between types.
  • Adaptor Provide access to a portion of a complex pixel type.
  • Boundary The boundary of a cell.
  • Calculator Compute information.
  • Classifier Classify a pixel.
  • Container A container of objects such as points or cells.
  • Estimator Estimate a value or condition.
  • Factory Object factories are used to create instances.
  • Filter A class that participates in the data processing pipeline. Filters typically take one or more inputs and produce one or more outputs.
  • Function Evaluate a function at a given position.
  • Identifier A unique id for accessing points, cells, or other entities.
  • Interface Classes that specify an abstract interface.
  • Interpolator Interpolate data values, for example at non-pixel values.
  • Iterator Traverse data in various ways (e.g., forward, backward, within a region, etc.)
  • Mapper Transform data from one form into another.
  • Metric Compute similarity between two objects.
  • Operator A class that applies a user-specified function to a region.
  • Optimizer A class that performs numerical optimization.
  • Pointer A smart pointer to an instance of a class. Almost all instance in ITK are referred to via smart pointers.
  • Reader A class that reads a single data object (e.g., image or mesh).
  • Reference A type that refers to another object.
  • Region A subset of a data object, such as an image region.
  • Source A filter that initiates the data processing pipeline such as a reader or a procedural data generator.
  • Threader A class that manages multi-threading.
  • Traits A collection of template parameters used to control the instantiation of other classes.
  • Transform Various types of transformations including affine, procedural, and so on.
  • Writer A filter that terminates the data processing pipeline by writing data to disk or to a communicationsport.


The naming of classes is an art form; please review existing names to catch the spirit of the naming convention.

Example names include:

  • ShrinkImageFilter
  • TriangleCell
  • ScalarImageRegionIterator
  • NeighborhoodIterator
  • MapContainer
  • DefaultImageTraits
  • BackwardDifferenceOperator

Naming Files

  • Files should have the same name as the class, with an "itk" prepended.
  • Header files are named .h, while implementation files are named either .cxx or .hxx, depending on whether they are implementations of templated classes.
    • For example, the class itk::Image
      • is declared in the file itkImage.h and
      • is defined in the file itkImage.hxx (because Image is templated).
    • The class itk::Object
      • is declared in the file itkObject.h
      • and is defined in the file itkObject.cxx

Naming Methods and Functions

Global functions and class methods, either static or class members, are named beginning with a capital letter. The biggest challenge when naming methods and functions is to be consistent with existing names. For example, given the choice between ComputeBoundingBox() and CalculateBoundingBox() (CalcBoundingBox() is not allowed because it is not spelled out), the choice is ComputeBoundingBox() because \Compute" is used elsewhere in the system in similar settings (The concepts described previously should be used whenever possible). When referring to class methods in code, an explicit this-> pointer should be used, as in this->ComputeBoundingBox(). The use of the explicit this-> pointer helps clarify exactly which method, and where it originates, is being invoked. Similarly the \::" global namespace should be used when referring to a global function.

Naming Class Data Members

Class data members are prepended with m as in m_Size. This clearly indicates the origin of data members, and differentiates them from all other variables.

Naming Local Variables

Local variables begin in lowercase. There is more flexibility in the naming of local variables; please remember that others will study, maintain, fix, and extend your code. Any bread crumbs that you can drop in the way of explanatory variable names and comments will go a long way towards helping other developers.

Naming Template Parameters

Template parameters follow the usual rules with naming except that they should start with either the capital letter T or V. Type parameters begin with the letter T while value template parameters begin with the letter V.

  • For template parameters the use of "typename" is preferred over "class". Very early c++ compilers did not have a "typename" keyword, and "class" was repurposed for declaring template parameters. It was later discovered that this lead to ambiguity in some valid code constructs, and the "typename" key word was added. It is often agreed (http://blogs.msdn.com/b/slippman/archive/2004/08/11/212768.aspx) that "typename" is marginally more expressive in its intent and ITK should consistently use "typename" instead of "class".

Naming Typedefs

Typedefs are absolutely essential in generic programming. They significantly improve the readibility of code, and facilitate the declaration of complex syntactic combinations. Unfortunately, creation of typedefs is tantamount to creating another programming language. Hence typedefs must be used in a consistent fashion. The general rule for typedef names is that they end in the word Type. For example typedef TPixel PixelType; However, there are many exceptions to this rule that recognize that ITK has several important concepts that are expressed partially in the names used to implement the concept. An iterator is a concept, as is a container or pointer. These concepts are used in preference to Type at the end of a typedef as appropriate. For example <source lang="cpp"> typedef typename ImageTraits::PixelContainer PixelContainer; </source> Here Container is a concept used in place of Type. ITK currently identifies the following concepts used when naming typedefs.

  • Self as in typedef Image Self;. All classes should define this typedef.
  • Superclass as in typedef ImageBase<VImageDimension> Superclass;. All classes should define the Superclass typedef.
  • Pointer as in a smart pointer to an object as in typedef SmartPointer<Self> Pointer;
  • Container is a type of container class.
  • Iterator an iterator over some container class.
  • Identifier or id such as a point or cell id.

Using Underscores

Don't use them. The only exception is when defining preprocessor variables and macros (which are discouraged). In this case, underscores are allowed to separate words.

Preprocessor Directives

  • Some of the worst code contains many preprocessor directives and macros. Do not use them except in a very limited sense (to support minor differences in compilers or operating systems).
  • If a class makes extensive use of preprocessor directives, it is a candidate for separation into multiple sub-classes.

Header Includes

Header includes use the style

<source lang="cpp">

  1. include "itkImage.h"

</source>

Only the required headers should be included. If an included header already includes a header for a class also used in the current file, the header for that class should not be included.

Header includes are preferred over forward declarations. Forward declarations are only used to prevent circular dependencies.

Namespaces

All classes should be placed in the itk:: namespace. Additional sub-namespaces are being designed to support special functionality.

Please see current documentation to determine if there is a subnamespace is relevant to your situation. Normally sub-namespaces are used for helper ITK classes.

Code should not use using namespace. This is to avoid namespace conflicts, but, more importantly, to improve readability.

When declaring or defining members of the "itk" namespace, for example, the 'itk::' namespace prefix should not be added. That is, code within "namespace itk { ... }" should not used "itk::".

Const Correctness

Const correctness is important. Please use it as appropriate to your class or method.

Code Layout and Indentation

The following are the accepted ITK code layout rules and indentation style. After reading this section, you may wish to visit many of the source files found in ITK. This will help crystallize the rules described here.

General Layout

  • Each line of code should take no more than 200 characters.
  • Break the code across multiple lines as necessary.
  • Use lots of whitespace to separate logical blocks of code, intermixed with comments.
  • To a large extent the structure of code directly expresses its implementation.
  • The appropriate indentation level is two spaces for each level of indentation.
  • DO NOT USE TABS.
    • Set up your editor to insert spaces. Using tabs may look good in your editor but will wreak havoc in others.
  • The declaration of variables within classes, methods, and functions should be one declaration per line.

<source lang="cpp"> int i; int j; char* stringname; </source>

Class Layout

Classes are defined using the following guidelines.

  • Begin with #include guards.
  • Follow with the necessary includes. Include only what is necessary to avoid dependency problems.
  • Place the class in the correct namespace.
  • Public methods come first.
  • Protected methods follow.
  • Private members come last.
  • Public data members are forbidden.
  • Templated classes require a special preprocessor directive to control the manual instantiation of templates. See the example below and look for ITK MANUAL INSTANTIATION.

The class layout looks something like this:

<source lang="cpp">

  1. ifndef itkImage_h
  2. define itkImage_h
  1. include "itkImageBase.h"
  2. include "itkPixelTraits.h"
  3. include "itkDefaultImageTraits.h"
  4. include "itkDefaultDataAccessor.h"

namespace itk {

/** \class Image

*  \brief Templated n-dimensional image class.
*
* .... detailed documentation....
*/

template< typename TPixel, unsigned int VImageDimension=2,

         typename TImageTraits=DefaultImageTraits< TPixel, VImageDimension > >

class Image: public ImageBase< VImageDimension > { public:

   //....stuff...

protected:

   //....stuff...

private:

   //....stuff...

};

} // end namespace itk

  1. ifndef ITK_MANUAL_INSTANTIATION
  2. include "itkImage.hxx"
  3. endif
  1. endif

</source>

Method Definition

  • Methods are defined across multiple lines. This is to accommodate the extremely long definitions possible when using templates.
  • The starting and ending brace should be in column one. For example:

<source lang="cpp"> template<typename TPixel, unsigned int VImageDimension, typename TImageTraits> const double * Image<TPixel, VImageDimension, TImageTraits>

GetSpacing() const

{

 //...stuff...

} </source>

  • The first line is the template declaration.
  • The second line is the method return type.
  • The third line is the class qualifier.
  • And the fourth line in the example above is the name of the method.

Use of Braces

  • Braces must be used to delimit the scope of an if, for, while, switch, or other control structure.
  • Braces are placed on a line by themselves:

<source lang="cpp"> for( unsigned int ii = 0; ii < 3; ++ii )

 {
 ...
 }

</source>


or when using an if:

<source lang="cpp"> if( condition )

 {
 ...
 }

else if( other condition )

 {
 ...
 }

else

 {
 ....
 }

</source>


Indentation Inside Braces

Source code in the body of the brackets must be aligned along with the brackets. As in

<source lang="cpp"> if ( condition )

 {
 unsigned int numberOfIterations = 100;
 filter->SetNumberOfIterations( numberOfIterations );
 filter->Update();
 filter->Print( std::cout );
 }

</source>

Doxygen Documentation System

  • Doxygen is an open-source, powerful system for automatically generating documentation from source code.
  • To use Doxygen effectively, the developer must insert comments, delimited in a special way, that Doxygen extracts to produce the documentation. While there are a large number of options to Doxygen, developers at a minimum should insert the following Doxygen commands.

See more at

 https://www.stack.nl/~dimitri/doxygen/manual/index.html

Documenting a Class

  • Classes should be documented using the class and brief Doxygen commands, followed by the detailed class description:

<source lang="cpp"> /** \class Object

  • \brief Base class for most itk classes.
  • Object is the second-highest level base class for most itk objects.
  • It extends the base object functionality of LightObject by
  • implementing debug flags/methods and modification time tracking.
  • /

</source>

Documenting a Method

  • Methods should be documented using the following comment block style as shown in the following example. Make sure you use correct English and complete, grammatically correct sentences. Finish your sentences with a period (.).

<source lang="cpp"> /** Access a pixel at a particular index location.

  • This version can be an lvalue. */

TPixel & operator[](const IndexType &index) { return this->GetPixel(index); } </source>

The key here is that the comment starts with /**, each subsequent line has an aligned *, and the comment block terminates with a */.

  • Method documentation should be placed in the declaration files (*.h): the documentation in the implementation causes ambiguity for Doxygen on which documentation to use, the declaration or definition.
    • If there is something that is appropriate for the definition only (*.cxx or *.hxx), it should be placed inside the method, and it could use either the /* */ or the // style comment, but it should not use /** */, which is for Doxygen comments.

Documenting ivars

  • Class member variables should be documented through their corresponding Set/Get methods, using a comment block style shown in the following example. Make sure you use correct English and grammatically correct sentences. Finish the documentation line with a period (.).

<source lang="cpp">

public:

 /** Set/Get the standard deviation of the Gaussian used for smoothing. */
 itkSetMacro( Sigma, SigmaArrayType );
 itkGetConstMacro( Sigma, SigmaArrayType );

private:

 SigmaArrayType m_Sigma;

</source>

Using Standard Macros (itkMacro.h)

  • There are several macros defined in the file itkMacro.h.
  • These macros should be used because they perform several important operations, that if not done correctly can cause serious, hard to debug problems in the system.
    • These operations are:
      • Object modified time is properly managed.
      • Debug information is printed.
      • Reference counting is handled properly.

Some of the more important object macros are as follows.

  • itkNewMacro(T) Creates the static class method New(void) that interacts with the object factory to instantiate objects. The method returns a SmartPointer<T> properly reference counted.
  • itkDebugMacro(x) If debug is set on a subclass of itk::Object, prints debug information to the appropriate output stream.
  • itkSetMacro(name,type) Creates a method SetName() that takes argument type type.
  • itkGetMacro(name,type) Creates a method GetName() that returns a non-const value of type type.
  • itkGetConstMacro(name,type) Creates a method GetName() that returns a const value of type type.
  • itkSetStringMacro(name) Creates a method SetName() that takes argument type const char*.
  • itkGetStringMacro(name) Creates a method GetName() that returns argument type const char*.
  • itkBooleanMacro(name) Creates two methods named NameOn and NameOff that sets true/false boolean values.
  • itkSetObjectMacro(name,type) Creates a method SetName() that takes argument type type *.
  • itkGetObjectMacro(name,type) Creates a method named GetName() that returns a smart pointer to a type type.
  • itkSetConstObjectMacro(name,type) Creates a method SetName() that takes argument type const type *.
  • itkGetConstObjectMacro(name,type) Creates a method named GetName() that returns a const smart pointer to a type type.

Please review this file and become familiar with these macros.

Exception Handling

Indicate that methods throw exceptions in the method declaration as in:

<source lang="cpp"> const float* foo() const throws itk </source>

Documentation Style

The Insight consortium has adopted the following guidelines for producing supplemental documentation (documentation not produced by Doxygen).

  • The common denominator for documentation is either PDF or HTML. All documents in the system should be available in these formats, even if they are mastered by another system.
  • Presentations are acceptable in Microsoft PowerPoint format.
  • Administrative and planning documents are acceptable in Microsoft Word format (either .doc or .rtf).
  • Larger documents, such as the user's or developer's guide, are written in LATEX.

CMake Style

A proposal style guide for CMake variables is presented HERE.



ITK: [Welcome | Site Map]