aboutsummaryrefslogtreecommitdiff
path: root/src/CODESTYLE
blob: d0233eb459eb094c57adeae5b6b409a0ab162631 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
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:

<surrounding code>
if (condition #1)
   then <if-condition-#1-true code>
   else <if-condition-#1-false code>
if (condition #2)
   then {
	<if-condition-#2-true code>
	<if-condition-#2-true code>
	}
   else {
	<if-condition-false code>
	<if-condition-false code>
	}

<surrounding code>
	while (condition)
	{
	<loop body>
	<loop body>
	}

<surrounding code>
	for (int i = 0 ; i < N ; ++i)
	{
	<loop body>
	<loop body>
	}

// 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
<surrounding code>
	  {
	for (int i = 0 ; i < N ; ++i)
	{
	<loop #1 body>
	<loop #1 body>
	}
	  }
	  {
	for (int i = 0 ; i < N ; ++i)
	{
	<loop #2 body>
	<loop #2 body>
	}
	  }


All switch statements should have a  default:  case (which often just
does an  error_exit()).

<surrounding code>
switch	(expression)
	{
case 42:
	<code for this case>
	<code for this case>
	break;
case 69:
	<code for this case>
	<code for this case>
	break;
case 105:
	<code for this case>
	<code for this case>
	break;
default:
	<code for this case>
	<code for this case>
	break;
	}

//
// block comment describing function
//
int foo(fp x, int bar, int baz)
{
<body of function>
<body of function>
}

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.