AHFinderDirect Code Style ========================= $Header: /usr/local/svn/cvs-repositories/numrelcvs/AEIThorns/AHFinderDirect/src/CODESTYLE,v 1.6 2003-08-18 10:01:01 jthorn Exp $ This file documents some general programming conventions used in this thorn. File Naming =========== *.c, *.h C code, headers *.cc, *.hh C++ code, headers At least as of version 7, Maple doesn't have a usable preprocessor, so I've written my own (in Perl); it lives in misc/mpp. *.maple Maple code (input to my Maple preprocessor) *.minc Maple headers to be @included by my Maple preprocessor *.mm Maple code (output from my Maple preprocessr) None of my header files ever #includes another file, so in theory there's no problem with multiple inclusion. However, to work around C++ compiler problems, some header files are still explicitly protected against multiple inclusion with the standard #ifndef trick; see "C++ Templates" below for details. Configuration ============= Only a few options are configured at compile-time; these use #defines in src/include/config.h. Code Layout/Indentation ======================== Most comments are C++-style //-to-end-of-line comments. In C files, or in header files which have to be C-compatible, I use C-style /* comments */. I like to make the two branches of an if-else statement look symmetrical: so I use #define then /* empty */ with usage as shown below. A lot of the code uses the generic floating-point data type typedef CCTK_REAL fp; Almost (but not quite) all the code fits into 80 columns. The indentation style is a bit unusual, and is best described by the following examples. Roughly speaking, indentation depth reflects execution frequency. Normal indentation is 1 tab stop = 8 spaces. Sometimes a block of code is "outdented" back towards the left margin if it's too deeply indented to fit easily in an 80-column window. Examples: if (condition #1) then else if (condition #2) then { } else { } while (condition) { } for (int i = 0 ; i < N ; ++i) { } // if there are multiple for-loops in the same scope using the same // loop variable, I add extra (redundant) { } around the loops so the // code will compile unchanged under both the archaic and the modern // for-loop declaration scope rules { for (int i = 0 ; i < N ; ++i) { } } { for (int i = 0 ; i < N ; ++i) { } } All switch statements should have a default: case (which often just does an error_exit()). switch (expression) { case 42: break; case 69: break; case 105: break; default: break; } // // block comment describing function // int foo(fp x, int bar, int baz) { } All code should be fully type-secure: there is no aliasing of different data types. const qualifiers are used wherever possible, and all code should be const-correct. Most casts are new-style const_cast<...>(...) or static_cast<...>(...) . There are no reinterpret_cast<...>(...) or dynamic_cast<...>(...) . There are no C-style casts (type) value . The only function-style casts type(value) are to cast numeric datatypes to int/double for printf()-style printing, eg // // we don't know at compile-time whether the type fp is // C float or double // void print_x(fp x) { printf("x=%g\n", double(x)); } Error Handling ============== For historical reasons, the code uses two slightly different mechanisms for "print an error message and abort the Cactus run" error handling: * Lower-level code (in src/{jtutil,patch,gr,elliptic}/) uses error_exit() (defined in src/include/stdc.h): if (user input was very bad) then error_exit(ERROR_EXIT, "***** function_name(): user input was really bad\n" " printf(3)-style string and following arguments\n" " to describe what went wrong" , foo, var, double(baz)); /*NOTREACHED*/ Here the first argument is ERROR_EXIT for "bad user input" errors, or PANIC_EXIT for "this should never happen" failure of internal consistency checks. For this thorn, error_exit() is implemented as a call to... * Higher-level code (in src/{driver,elliptic,gr}) uses the standard Cactus CCTK_VWarn(), generally giving FATAL_ERROR (defined in src/include/config.h) as the warning level. The code uses the standard Cactus CCTK_VInfo() to print informational messages describing what it's doing. C++ Classes and Libraries ========================= All the main data structures are C++ classes, but there are also plenty of C-style structs. struct foo is for "dumb data", and has at most contructors. class foo is for full-fledged C++ classes; these have no public data members. data members are always declared at the end of the class, and have names with a trailing underscore; no other identifiers in this thorn have such names. Most "large" classes are non-copyable and non-assignable. Right now I write this explicitly in each class; once compilers improve a bit more and boost becomes more widely deployed it would be cleaner to convert this to inheriting from boost::noncopyable. In the same genre, once compilers improve a *lot* more :), most/all of the raw new[]-array references should probably be converted to boost::array, and my jtutil::array[1234]d<> classes should be converted to boost::multi_array. C++ Templates ============= I use C++ templates, but not for anything fancy, just simple containers. I instantiate all templates explicitly. Some C++ compilers offer "automatic" template instantiation. In practice this often causes compilation to fail when the compiler can't find .cc files in other directories, so I highly recommend turning *off* all automatic template instantiation "features" when compiling this thorn. When using the DEC/Compaq/HP/whatever-their-corporate-name-is-this-week C++ compiler (version 6.3.6.8) under Alpha Linux, even with automatic template instiation disabled, the compiler *still* seems to include some header files multiple times. To avoid duplicate-definition errors caused by this, I have protected all the header files in the subdirectories include/ jtutil/ elliptic/ against multiple inclusion with the standard #ifndef trick. Miscellaneous ============= All I/O is done using C stdio (printf() and friends); the C++ iostreams system isn't used. Some Cactus parameter names, and some C++ enumeration and function names, contain the substring "__" (two consecutive underscores). According to the C++ standard, such names are reserved to the [compiler] implementation, so this code isn't strictly legal. In practice, so far I haven't had any problems... Each .cc source file should begin with a "table of comments" block comment listing all the functions defined in the file. Functions with a "///" comment (or "**" for C) are local to the file; functions with a "//" comment (or "*" for C) are visible to the linker.