Clipper
Conventions

Introduction

This page discusses the conventions of coding style and memory management adopted in the Clipper libraries.

Notation

Coding Style

Dialect

Clipper is written in C++, with extensive use of modern constructs such templates, and in particular the Standard Template Library (STL). The coding style of the library, and its API, both reflect this.

In particular, a developer writing code using Clipper objects should be able to do so with minimal or no use of pointers, or of the built-in new and delete operators. References are used in preference to pointers where possible. Heap objects, with the corresponding dangers of memory leakage, are avoided. (However, for the cases where the developer needs to use heap objects, an optional mechanism is provided for automatic garbage collection).

Clipper objects should generally be passed by reference rather than by value.

Floating-point representation.

The package may be compiled to use either float or double for the representation of floating-point numbers. This is acheived by defining floating-point values with a user-defined type ftype. This is set by a typedef in lib/clipper_util.h.

Data may have a different type. Since data objects may be large, these may be individually typed to save memory or provide additional precision as required. Data types are based on templates in lib/clipper_datatypes.h.

The type for Fast-Fourier transforms is dependent on the FFTw library to which Clipper is linked. FFTw may be compiled for float or double.

Since crystallographic FFTs generally have quite short dimensions (< 1000), float is recommended.

Namespaces

All Clipper objects belong to the Clipper namespace, and can be accessed by using the Clipper:: prefix or

using namespace Clipper;

Templates for reciprocal space datatypes are provided in the Clipper::datatypes namespace. Instantiations of these types for float and double data are provided in Clipper::data32 and Clipper::data64.

Classes are all named with an initial capital letter. Method names are all lowercase, with words separated by underscore ('_'). A handful of top level functions are implemented; these have an initial capital letter to distinguish them from standard library functions.

Memory management

All Clipper objects are designed to be created on the stack. Such objects are destroyed automatically when they go out of scope. Large or variable-sized data items within an object are generally held in STL vectors, and so are stored on the heap, and automatically destroyed with the associated object.

Sometimes it may be useful to create Clipper container objects on the heap. In this case, the developer can arrange for the object to be destroyed when it is no-longer needed. However an alternative, automatic, method for memory management is provided, in the form of a destroyed_with_parent flag. If in object is created on the heap (i.e. with new), this flag may be set as follows:

  Container* new_container = new Container( parent, "A container" );
  new_container->set_destroyed_with_parent();

Then, as soon as parent is destroyed, either by going out of scope, or by a delete operator, the new container will also be destroyed.

Passing objects

Clipper objects should generally be passed by reference rather than by value. In particular passing a container type by value will lead to a container which is orphaned from the tree.

Passing or assigning an object always results in a 'deep copy', i.e. all of the data associated with the object is copied.

Coding standards

Code in the Clipper library should obey the following standards. Some of these are stylistic, but most are simply good practice. Code which does not obey these standards will be rejected from my tree.

  1. No C-style casts.
  2. No reinterpret_cast<> except for conversion of external types.
  3. No static_cast<> without a very strong performance argument.
  4. No const_cast<>.
  5. No preprocessor macros, except for a stand-alone portability library.
  6. No global functions. Useful functions are contained in the Util class.
  7. Absolutely strict use of const, both for parameters and methods.
  8. Parameters are passed by reference.
  9. No pointers in public APIs.
  10. No pointers internally, expect for
    • testing for NULL after a dynamic_cast
    • member variables which point to other objects
  11. No 'new' or 'malloc'. Use STL containers. (Exception: for explicitly memory managed objects. There are still a couple of 'new's in the MTZ i/o layer).
  12. 'explicit' is used where necessary to prevent accidental type conversion.
  13. Access specifiers are ordered public, protected, private.

There are a few places where I haven't yet finished implementing all of these standards, but I'm working on it.