f6e968a7 |
1 | Coding Rules {#dev_guides__coding_rules} |
2 | ====================================== |
3 | |
4 | @tableofcontents |
5 | |
49663e13 |
6 | @section occt_coding_rules_1 Introduction |
f6e968a7 |
7 | |
49663e13 |
8 | The purpose of this document is to define a common programming style for Open CASCADE Technology. |
f6e968a7 |
9 | |
49663e13 |
10 | The common style facilitates understanding and maintaining a code developed cooperatively by several programmers. In addition, it enables construction of tools that incorporate knowledge of these standards to help in the programming. |
f6e968a7 |
11 | |
49663e13 |
12 | OCCT programming style follows common and appropriate best practices, so some guidelines have been excerpted from the public domain. |
13 | |
14 | The guide can be improved in the future as new ideas and enhancements are added. |
15 | |
16 | @subsection occt_coding_rules_1_1 Scope of the document |
17 | |
18 | Rules in this document refer to C++ code. However, with minor exceptions due to language restrictions, they are applicable to any sources in Open CASCADE Technology framework, including: |
f6e968a7 |
19 | - C/C++ |
20 | - GLSL programs |
21 | - OpenCL kernels |
22 | - TCL scripts and test cases |
23 | |
49663e13 |
24 | @section occt_coding_rules_2 Naming Conventions |
f6e968a7 |
25 | |
49663e13 |
26 | @subsection occt_coding_rules_2_1 General naming rules |
f6e968a7 |
27 | |
49663e13 |
28 | The names considered in this section mainly refer to the interface of Open CASCADE Technology libraries or source code itself. |
f6e968a7 |
29 | |
30 | ### International language [MANDATORY] |
49663e13 |
31 | |
32 | Open CASCADE Technology is an open source platform available for an international community, thus all names need to be composed of English words or their abbreviations. |
33 | |
34 | ### Meaningful names |
35 | |
36 | Names should be meaningful or, at least, contain a meaningful part. To better understand this requirement, let us examine the existing names of toolkits, packages, classes and methods: |
37 | - Packages containing words *Geom* or *Geom2d* in their names are related to geometrical data and operations. |
38 | - Packages containing words *TopoDS* or *BRep* in their names are related to topological data and operations. |
39 | - In OCAF, packages that define transient, persistent data classes and drivers to map between them, have similar names prefixed by *T*, *P*, and *M* correspondingly (e.g. *TDocStd*, *PDocStd*, *MDocStd*). |
40 | - Packages ending with <i>...Test</i> define Draw Harness plugins. |
41 | - Methods starting with *Get...* and *Set...* are usually responsible for correspondingly retrieving and storing data. |
f6e968a7 |
42 | |
43 | ### Related names |
49663e13 |
44 | |
45 | Names related to a logically connected functionality should have the same prefix (start with the same letters) or, at least, have any other common part. |
46 | For example, method *GetCoord* returns a triple of real values and is defined for directions, vectors and points. The logical connection is obvious. |
f6e968a7 |
47 | |
48 | ### Camel Case style |
49 | Camel Case style is preferred for names. |
50 | For example: |
51 | |
52 | ~~~~~{.cpp} |
53 | Standard_Integer awidthofbox; // this is bad |
54 | Standard_Integer width_of_box; // this is bad |
55 | Standard_Integer aWidthOfBox; // this is OK |
56 | ~~~~~ |
57 | |
49663e13 |
58 | @subsection occt_coding_rules_2_2 Names of development units |
f6e968a7 |
59 | |
49663e13 |
60 | Usually a unit (e.g. a package) is a set of classes, methods, enumerations or any other sources implementing a common functionality, which is self-contained and independent from other parts of the library. |
f6e968a7 |
61 | |
49663e13 |
62 | ### No underscores in unit names [MANDATORY] |
f6e968a7 |
63 | |
49663e13 |
64 | Names of units should not contain underscores, unless the use of underscores is allowed explicitly. |
f6e968a7 |
65 | |
49663e13 |
66 | ### File name extensions [MANDATORY] |
67 | |
68 | The following extensions should be used for source files, depending on their type: |
f6e968a7 |
69 | |
49663e13 |
70 | * <i>.cdl</i> - CDL declaration files |
71 | * <i>.cxx</i> - C++ source files |
72 | * <i>.hxx</i> - C++ header files |
73 | * <i>.lxx</i> - headers with definitions of inline methods (CDL packages) |
f6e968a7 |
74 | |
49663e13 |
75 | ### Prefix for toolkit names [MANDATORY] |
76 | |
77 | Toolkit names are prefixed by *TK*, followed by a meaningful part of the name explaining the domain of functionality covered by the toolkit (e.g. *TKOpenGl*). |
f6e968a7 |
78 | |
79 | ### Names of classes |
f6e968a7 |
80 | |
49663e13 |
81 | Usually the names of source files located in a unit start from the unit name separated from the other part of the file name by underscore "_". |
82 | |
83 | Thus, the names of files containing sources of C++ classes that belong to a package are constructed according to the following template: |
84 | |
85 | ~~~~~ |
86 | <package-name>_<class-name>.cxx (or .hxx, or .cdl) |
87 | ~~~~~ |
f6e968a7 |
88 | |
49663e13 |
89 | For example, file *Adaptor2d_Curve2d.cxx* belongs to the package *Adaptor2d* |
f6e968a7 |
90 | |
49663e13 |
91 | Files that contain sources related to the whole unit are called by the unit name with appropriate extension. |
f6e968a7 |
92 | |
93 | ### Names of functions |
49663e13 |
94 | |
95 | The term **function** here is defined as: |
f6e968a7 |
96 | - Any class method |
97 | - Any package method |
98 | - Any non-member procedure or function |
99 | |
49663e13 |
100 | It is preferred to start names of public methods from an upper case character and to start names of protected and private methods from a lower case character. |
101 | |
f6e968a7 |
102 | |
103 | ~~~~~{.cpp} |
104 | class MyPackage_MyClass |
105 | { |
106 | |
107 | public: |
108 | |
109 | Standard_Integer Value() const; |
110 | void SetValue (const Standard_Integer theValue); |
111 | |
112 | private: |
113 | |
114 | void setIntegerValue (const Standard_Integer theValue); |
115 | |
116 | }; |
117 | ~~~~~ |
118 | |
49663e13 |
119 | @subsection occt_coding_rules_2_3 Names of variables |
120 | |
121 | There are several rules that describe currently accepted practices for naming variables. |
f6e968a7 |
122 | |
123 | ### Naming of variables |
49663e13 |
124 | |
125 | Name of a variable should not conflict with the existing or possible global names (for packages, macros, functions, global variables, etc.). |
126 | |
127 | The name of a variable should not start with an underscore. |
f6e968a7 |
128 | |
129 | See the following examples: |
130 | |
131 | ~~~~~{.cpp} |
132 | Standard_Integer Elapsed_Time = 0; // this is bad - possible class name |
133 | Standard_Integer gp = 0; // this is bad - existing package name |
134 | Standard_Integer aGp = 0; // this is OK |
135 | Standard_Integer _KERNEL = 0; // this is bad |
136 | Standard_Integer THE_KERNEL = 0; // this is OK |
137 | ~~~~~ |
138 | |
139 | ### Names of function parameters |
49663e13 |
140 | |
141 | The name of a function (procedure, class method) parameter should start with prefix *the* followed by the meaningful part of the name starting with a capital letter. |
f6e968a7 |
142 | |
143 | See the following examples: |
144 | |
145 | ~~~~~{.cpp} |
146 | void Package_MyClass::MyFunction (const gp_Pnt& p); // this is bad |
147 | void Package_MyClass::MyFunction (const gp_Pnt& theP); // this is OK |
148 | void Package_MyClass::MyFunction (const gp_Pnt& thePoint); // this is preferred |
149 | ~~~~~ |
150 | |
151 | ### Names of class member variables |
49663e13 |
152 | |
153 | The name of a class member variable should start with prefix *my* followed by the meaningful of the name starting with a capital letter. |
f6e968a7 |
154 | |
155 | See the following examples: |
156 | |
157 | ~~~~~{.cpp} |
158 | Standard_Integer counter; // This is bad |
159 | Standard_Integer myC; // This is OK |
160 | Standard_Integer myCounter; // This is preferred |
161 | ~~~~~ |
162 | |
163 | ### Names of global variables |
49663e13 |
164 | |
f6e968a7 |
165 | It is strongly recommended to avoid defining any global variables. |
49663e13 |
166 | However, as soon as a global variable is necessary, its name should be prefixed by the name of a class or a package where it is defined followed with *_my*. |
f6e968a7 |
167 | |
168 | See the following examples: |
169 | |
170 | ~~~~~{.cpp} |
171 | Standard_Integer MyPackage_myGlobalVariable = 0; |
172 | Standard_Integer MyPackage_MyClass_myGlobalVariable = 0; |
173 | ~~~~~ |
174 | |
49663e13 |
175 | Static constants within the file should be written in upper-case and begin with prefix *THE_*: |
f6e968a7 |
176 | ~~~~~{.cpp} |
177 | namespace |
178 | { |
179 | static const Standard_Real THE_CONSTANT_COEF = 3.14; |
180 | }; |
181 | ~~~~~ |
182 | |
183 | ### Names of local variables |
f6e968a7 |
184 | |
49663e13 |
185 | The name of a local variable should be distinguishable from the name of a function parameter, a class member variable and a global variable. |
186 | |
187 | It is preferred to prefix local variable names with *a* and *an* (or *is*, *to* and *has* for Boolean variables). |
188 | |
189 | See the following example: |
f6e968a7 |
190 | |
191 | ~~~~~{.cpp} |
192 | Standard_Integer theI; // this is bad |
193 | Standard_Integer i; // this is bad |
194 | Standard_Integer index; // this is bad |
195 | Standard_Integer anIndex; // this is OK |
196 | ~~~~~ |
197 | |
198 | ### Avoid dummy names |
49663e13 |
199 | Avoid dummy names, such as <i>i, j, k</i>. Such names are meaningless and easy to mix up. |
200 | |
201 | The code becomes more and more complicated when such dummy names are used there multiple times with different meanings, or in cycles with different iteration ranges, etc. |
f6e968a7 |
202 | |
203 | See the following examples for preferred style: |
204 | |
205 | ~~~~~{.cpp} |
206 | void Average (const Standard_Real** theArray, |
207 | Standard_Integer theRowsNb, |
208 | Standard_Integer theRowLen, |
209 | Standard_Real& theResult) |
210 | { |
211 | theResult = 0.0; |
212 | for (Standard_Integer aRow = 0; aRow < aRowsNb; ++aRow) |
213 | { |
214 | for (Standard_Integer aCol = 0; aCol < aRowLen; ++aCol) |
215 | { |
216 | theResult += theArray[aRow][aCol]; |
217 | } |
218 | theResult /= Standard_Real(aRowsNb * aRowLen); |
219 | } |
220 | } |
221 | ~~~~~ |
222 | |
49663e13 |
223 | @section occt_coding_rules_3 Formatting rules |
f6e968a7 |
224 | |
49663e13 |
225 | To improve the open source readability and, consequently, maintainability, the following set of rules is applied. |
f6e968a7 |
226 | |
227 | ### International language [MANDATORY] |
49663e13 |
228 | |
f6e968a7 |
229 | All comments in all sources must be in English. |
230 | |
231 | ### Line length |
49663e13 |
232 | |
233 | Try to stay within the limit of 120 characters per line in all sources. |
f6e968a7 |
234 | |
235 | ### C++ style comments |
49663e13 |
236 | |
f6e968a7 |
237 | Prefer C++ style comments in C++ sources. |
238 | |
239 | ### Commenting out unused code |
49663e13 |
240 | |
f6e968a7 |
241 | Delete unused code instead of commenting it or using #define. |
242 | |
243 | ### Indentation in sources [MANDATORY] |
49663e13 |
244 | |
f6e968a7 |
245 | Indentation in all sources should be set to two space characters. |
246 | Use of tabulation characters for indentation is disallowed. |
247 | |
248 | ### Separating spaces |
49663e13 |
249 | |
250 | Punctuation rules follow the rules of the English language. |
251 | * C/C++ reserved words, commas, colons and semicolons should be followed by a space character if they are not at the end of a line. |
252 | * There should be no space characters after '(' and before ')'. Closing and opening brackets should be separated by a space character. |
253 | * For better readability it is also recommended to surround conventional operators by a space character. See the following examples: |
f6e968a7 |
254 | |
255 | ~~~~~{.cpp} |
256 | while (true) // NOT: while( true ) ... |
257 | { |
258 | DoSomething (theA, theB, theC, theD); // NOT: DoSomething(theA,theB,theC,theD); |
259 | } |
260 | for (anIter = 0; anIter < 10; ++anIter) // NOT: for (anIter=0;anIter<10;++anIter){ |
261 | { |
262 | theA = (theB + theC) * theD; // NOT: theA=(theB+theC)*theD |
263 | } |
264 | ~~~~~ |
265 | |
266 | ### Separate logical blocks |
49663e13 |
267 | |
f6e968a7 |
268 | Separate logical blocks of code with one blank line and comments. |
49663e13 |
269 | |
f6e968a7 |
270 | See the following example: |
271 | |
272 | ~~~~~{.cpp} |
273 | // check arguments |
274 | Standard_Integer anArgsNb = argCount(); |
275 | if (anArgsNb < 3 || isSmthInvalid) |
276 | { |
277 | return THE_ARG_INVALID; |
278 | } |
279 | |
280 | // read and check header |
281 | ... |
282 | ... |
283 | |
284 | // do our job |
285 | ... |
286 | ... |
287 | ~~~~~ |
288 | |
289 | Notice that multiple blank lines should be avoided. |
290 | |
291 | ### Separate function bodies [MANDATORY] |
49663e13 |
292 | |
f6e968a7 |
293 | Use function descriptive blocks to separate function bodies from each other. |
49663e13 |
294 | Each descriptive block should contain at least a function name and purpose description. |
295 | |
f6e968a7 |
296 | See the following example: |
297 | |
298 | ~~~~~{.cpp} |
299 | // ---------------------------------------------- |
300 | // function : TellMeSmthGood |
301 | // purpose : Gives me good news |
302 | // ---------------------------------------------- |
303 | void TellMeSmthGood() |
304 | { |
305 | ... |
306 | } |
307 | |
308 | // ---------------------------------------------- |
309 | // function : TellMeSmthBad |
310 | // purpose : Gives me bad news |
311 | // ---------------------------------------------- |
312 | void TellMeSmthBad() |
313 | { |
314 | ... |
315 | } |
316 | ~~~~~ |
317 | |
318 | ### Block layout [MANDATORY] |
49663e13 |
319 | Figure brackets <i>{ }</i> and each operator <i>(for, if, else, try, catch)</i> should be written on a dedicated line. |
320 | |
321 | In general, the layout should be as follows: |
f6e968a7 |
322 | |
323 | ~~~~~{.cpp} |
324 | while (expression) |
325 | { |
326 | ... |
327 | } |
328 | ~~~~~ |
329 | |
49663e13 |
330 | Entering a block increases and leaving a block decreases the indentation by one tabulation. |
f6e968a7 |
331 | |
332 | ### Single-line operators |
49663e13 |
333 | |
334 | Single-line conditional operators <i>(if, while, for,</i> etc.) can be written without brackets on the following line. |
f6e968a7 |
335 | |
336 | ~~~~~{.cpp} |
337 | if (!myIsInit) return Standard_False; // bad |
338 | |
339 | if (thePtr == NULL) // OK |
340 | return Standard_False; |
341 | |
342 | if (!theAlgo.IsNull()) // preferred |
343 | { |
344 | DoSomething(); |
345 | } |
346 | ~~~~~ |
347 | |
49663e13 |
348 | Having all code in the same line is less convenient for debugging. |
f6e968a7 |
349 | |
49663e13 |
350 | ### Alignment |
351 | |
352 | Use alignment wherever it enhances the readability. See the following example: |
f6e968a7 |
353 | |
354 | ~~~~~{.cpp} |
355 | MyPackage_MyClass anObject; |
356 | Standard_Real aMinimum = 0.0; |
357 | Standard_Integer aVal = theVal; |
358 | switch (aVal) |
359 | { |
360 | case 0: computeSomething(); break; |
361 | case 12: computeSomethingElse (aMinimum); break; |
362 | case 3: |
363 | default: computeSomethingElseYet(); break; |
364 | } |
365 | ~~~~~ |
366 | |
367 | ### Indentation of comments |
49663e13 |
368 | |
369 | Comments should be indented in the same way as the code to which they refer or they can be in the same line if they are short. |
370 | |
371 | The text of the comment should be separated from the slash character by a single space character. |
372 | |
f6e968a7 |
373 | See the following example: |
374 | |
375 | ~~~~~{.cpp} |
376 | while (expression) //bad comment |
377 | { |
378 | // this is a long multi-line comment |
379 | // which is really required |
380 | DoSomething(); // maybe, enough |
381 | DoSomethingMore(); // again |
382 | } |
383 | ~~~~~ |
384 | |
385 | ### Early return statement |
49663e13 |
386 | |
387 | Use an early return condition rather than collect indentations. |
388 | |
389 | Write like this: |
f6e968a7 |
390 | |
391 | ~~~~~{.cpp} |
392 | Standard_Integer ComputeSumm (const Standard_Integer* theArray, |
393 | const Standard_Size theSize) |
394 | { |
395 | Standard_Integer aSumm = 0; |
396 | if (theArray == NULL || theSize == 0) |
397 | { |
398 | return 0; |
399 | } |
400 | |
401 | ... computing summ ... |
402 | return aSumm; |
403 | } |
404 | ~~~~~ |
405 | |
49663e13 |
406 | Rather than: |
f6e968a7 |
407 | |
408 | ~~~~~{.cpp} |
409 | Standard_Integer ComputeSumm (const Standard_Integer* theArray, |
410 | const Standard_Size theSize) |
411 | { |
412 | Standard_Integer aSumm = 0; |
413 | if (theArray != NULL && theSize != 0) |
414 | { |
415 | ... computing summ ... |
416 | } |
417 | return aSumm; |
418 | } |
419 | ~~~~~ |
420 | |
49663e13 |
421 | This helps to improve readability and reduce the unnecessary indentation depth. |
f6e968a7 |
422 | |
423 | ### Trailing spaces |
49663e13 |
424 | |
425 | Trailing spaces should be removed whenever possible. |
426 | Spaces at the end of a line are useless and do not affect functionality. |
f6e968a7 |
427 | |
428 | ### Headers order |
49663e13 |
429 | |
430 | Split headers into groups: system headers, headers per each framework, project headers; sort the list of includes alphabetically. |
431 | |
432 | This rule improves readability, allows detecting useless multiple header inclusions and makes 3rd-party dependencies clearly visible. |
f6e968a7 |
433 | |
434 | ~~~~~{.cpp} |
435 | // system headers |
436 | #include <iostream> |
437 | #include <windows.h> |
438 | |
439 | // Qt headers |
440 | #include <QDataStream> |
441 | #include <QString> |
442 | |
443 | // OCCT headers |
444 | #include <gp_Pnt.hxx> |
445 | #include <gp_Vec.hxx> |
446 | #include <NCollection_List.hxx> |
447 | ~~~~~ |
448 | |
49663e13 |
449 | @section occt_coding_rules_4 Documentation rules |
f6e968a7 |
450 | |
451 | The source code is one of the most important references for documentation. |
49663e13 |
452 | The comments in the source code should be complete enough to allow understanding the corresponding code and to serve as basis for other documents. |
f6e968a7 |
453 | |
49663e13 |
454 | The main reasons why the comments are regarded as documentation and should be maintained are: |
455 | - The comments are easy to reach - they are always together with the source code; |
456 | - It is easy to update a description in the comment when the source is modified; |
457 | - The source by itself is a good context to describe various details that would require much more explanations in a separate document; |
458 | - As a summary, this is the most cost-effective documentation. |
f6e968a7 |
459 | |
460 | The comments should be compatible with Doxygen tool for automatic documentation generation (thus should use compatible tags). |
461 | |
462 | ### Documenting classes [MANDATORY] |
49663e13 |
463 | |
f6e968a7 |
464 | Each class should be documented in its header file (.hxx or .cdl). |
49663e13 |
465 | The comment should give enough details for the reader to understand the purpose of the class and the main way of work with it. |
f6e968a7 |
466 | |
467 | ### Documenting class methods [MANDATORY] |
49663e13 |
468 | |
f6e968a7 |
469 | Each class or package method should be documented in the header file (.hxx or .cdl). |
49663e13 |
470 | |
f6e968a7 |
471 | The comment should explain the purpose of the method, its parameters, and returned value(s). |
472 | Accepted style is: |
473 | |
474 | @verbatim |
475 | //! Method computes the square value. |
476 | //! @param theValue the input value |
477 | //! @return squared value |
478 | Standard_Export Standard_Real Square (Standard_Real theValue); |
479 | @endverbatim |
480 | |
481 | ### Documenting C/C++ sources |
49663e13 |
482 | |
f6e968a7 |
483 | It is very desirable to put comments in the C/C++ sources of the package/class. |
f6e968a7 |
484 | |
49663e13 |
485 | They should be detailed enough to allow any person to understand what each part of code does. |
486 | |
487 | It is recommended to comment all static functions (like methods in headers), and to insert at least one comment per each 10-100 lines in the function body. |
488 | |
489 | There are also some rules that define how comments should be formatted, see <a href="#occt_coding_rules_3">Formatting Rules</a>. |
490 | |
491 | Following these rules is important for good comprehension of the comments. Moreover, this approach allows automatically generating user-oriented documentation directly from the commented sources. |
f6e968a7 |
492 | |
49663e13 |
493 | @section occt_coding_rules_5 Application design |
494 | |
495 | The following rules define the common style, which should be applied by any developer contributing to the open source. |
496 | |
497 | ### Allow possible inheritance |
f6e968a7 |
498 | |
f6e968a7 |
499 | Try to design general classes (objects) keeping possible inheritance in mind. |
49663e13 |
500 | This rule means that the user who makes possible extensions of your class should not encounter problems of private implementation. |
f6e968a7 |
501 | Try to use protected members and virtual methods wherever you expect extensions in the future. |
502 | |
503 | ### Avoid friend declarations |
49663e13 |
504 | |
505 | Avoid using 'friend' classes or functions except for some specific cases (for example, iteration) 'Friend' declarations increase coupling. |
f6e968a7 |
506 | |
507 | ### Set/get methods |
49663e13 |
508 | |
f6e968a7 |
509 | Avoid providing set/get methods for all fields of the class. |
510 | Intensive set/get functions break down encapsulation. |
511 | |
512 | ### Hiding virtual functions [MANDATORY] |
49663e13 |
513 | |
f6e968a7 |
514 | Avoid hiding a base class virtual function by a redefined function with a different signature. |
515 | Most of the compilers issue warning on this. |
516 | |
517 | ### Avoid mixing error reporting strategies |
49663e13 |
518 | |
519 | Try not to mix different error indication/handling strategies (exceptions or returned values) on the same application level. |
f6e968a7 |
520 | |
521 | ### Minimize compiler warnings [MANDATORY] |
49663e13 |
522 | |
f6e968a7 |
523 | When compiling the source pay attention to and try to minimize compiler warnings. |
524 | |
49663e13 |
525 | ### Avoid unnecessary inclusions |
f6e968a7 |
526 | |
49663e13 |
527 | Try to minimize compilation dependencies by removing unnecessary inclusions. |
f6e968a7 |
528 | |
49663e13 |
529 | @section occt_coding_rules_6 General C/C++ rules |
530 | |
531 | This section defines the rules for writing a portable and maintainable C/C++ source code. |
f6e968a7 |
532 | |
533 | ### Wrapping of global variables [MANDATORY] |
49663e13 |
534 | |
535 | Use package or class methods returning reference to wrap global variables to reduce possible name space conflicts. |
f6e968a7 |
536 | |
537 | ### Avoid private members |
49663e13 |
538 | |
539 | Use *protected* members instead of *private* wherever reasonable to enable future extensions. |
540 | Use *private* fields if future extensions should be disabled. |
f6e968a7 |
541 | |
542 | ### Constants and inlines over defines [MANDATORY] |
49663e13 |
543 | |
f6e968a7 |
544 | Use constant variables (const) and inline functions instead of defines (#define). |
545 | |
546 | ### Avoid explicit numerical values [MANDATORY] |
49663e13 |
547 | |
f6e968a7 |
548 | Avoid usage of explicit numeric values. Use named constants and enumerations instead. |
49663e13 |
549 | Numbers produce difficulties for reading and maintenance. |
f6e968a7 |
550 | |
551 | ### Three mandatory methods |
49663e13 |
552 | |
553 | If a class has a destructor, an assignment operator or a copy constructor, it usually needs the other two methods. |
f6e968a7 |
554 | |
555 | ### Virtual destructor |
49663e13 |
556 | |
f6e968a7 |
557 | A class with virtual function(s) ought to have a virtual destructor. |
558 | |
559 | ### Default parameter value |
49663e13 |
560 | |
f6e968a7 |
561 | Do not redefine a default parameter value in an inherited function. |
562 | |
563 | ### Use const modifier |
49663e13 |
564 | |
565 | Use *const* modifier wherever possible (functions parameters, return values, etc.) |
f6e968a7 |
566 | |
567 | ### Usage of goto [MANDATORY] |
49663e13 |
568 | Avoid *goto* statement unless it is really needed. |
f6e968a7 |
569 | |
570 | ### Declaring variable in for() header |
49663e13 |
571 | |
572 | Declare a cycle variable in the header of the *for()* statement if not used out of cycle. |
f6e968a7 |
573 | |
574 | ~~~~~{.cpp} |
575 | Standard_Real aMinDist = Precision::Infinite(); |
576 | for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter (theSequence); |
577 | aPntIter.More(); aPntIter.Next()) |
578 | { |
579 | aMinDist = Min (aMinDist, theOrigin.Distance (aPntIter.Value())); |
580 | } |
581 | ~~~~~ |
582 | |
583 | ### Condition statements within zero |
49663e13 |
584 | |
f6e968a7 |
585 | Avoid usage of C-style comparison for non-boolean variables: |
586 | |
587 | ~~~~~{.cpp} |
588 | void Function (Standard_Integer theValue, |
589 | Standard_Real* thePointer) |
590 | { |
591 | if (!theValue) // bad style - ambiguous logic |
592 | { |
593 | DoSome(); |
594 | } |
595 | |
596 | if (theValue == 0) // OK |
597 | { |
598 | DoSome(); |
599 | } |
600 | |
601 | if (thePointer != NULL) // OK, predefined NULL makes pointer comparison cleaner to reader |
602 | { // (nullptr should be used instead as soon as C++11 will be available) |
603 | DoSome2(); |
604 | } |
605 | } |
606 | ~~~~~ |
607 | |
49663e13 |
608 | @section occt_coding_rules_7 Portability issues |
f6e968a7 |
609 | |
610 | This chapter contains rules that are critical for cross-platform portability. |
611 | |
49663e13 |
612 | ### Provide code portability [MANDATORY] |
613 | |
614 | The source code must be portable to all platforms listed in the official 'Technical Requirements'. |
f6e968a7 |
615 | The term 'portable' here means 'able to be built from source'. |
616 | |
617 | The C++ source code should meet C++03 standard. |
49663e13 |
618 | Any usage of compiler-specific features or further language versions (for example, C++11, until all major compilers on all supported platforms implement all its features) should be optional (used only with appropriate preprocessor checks) and non-exclusive (an alternative implementation compatible with other compilers should be provided). |
f6e968a7 |
619 | |
620 | ### Avoid usage of global variables [MANDATORY] |
49663e13 |
621 | |
622 | Avoid usage of global variables. Usage of global variables may cause problems when accessed from another shared library. |
623 | |
624 | Use global (package or class) functions that return reference to static variable local to this function instead of global variables. |
625 | |
f6e968a7 |
626 | Another possible problem is the order of initialization of global variables defined in various libraries that may differ depending on platform, compiler and environment. |
627 | |
628 | ### Avoid explicit basic types |
f6e968a7 |
629 | |
49663e13 |
630 | Avoid explicit usage of basic types (*int*, *float*, *double*, etc.), use Open CASCADE Technology types from package *Standard: Standard_Integer, Standard_Real, Standard_ShortReal, Standard_Boolean, Standard_CString* and others or a specific *typedef* instead. |
631 | |
632 | ### Use *sizeof()* to calculate sizes [MANDATORY] |
f6e968a7 |
633 | |
49663e13 |
634 | Do not assume sizes of types. Use *sizeof()* instead to calculate sizes. |
635 | |
636 | ### Empty line at the end of file [MANDATORY] |
637 | |
638 | In accordance with C++03 standard source files should be trailed by an empty line. |
f6e968a7 |
639 | It is recommended to follow this rule for any plain text files for consistency and for correct work of git difference tools. |
640 | |
49663e13 |
641 | @section occt_coding_rules_8 Stability issues |
f6e968a7 |
642 | |
643 | The rules listed in this chapter are important for stability of the programs that use Open CASCADE Technology libraries. |
644 | |
49663e13 |
645 | ### Use *OSD::SetSignal()* to catch exceptions |
646 | |
647 | When using Open CASCADE Technology in an application, call *OSD::SetSignal()* function when the application is initialized. |
648 | |
649 | This will install C handlers for run-time interrupt signals and exceptions, so that low-level exceptions (such as access violation, division by zero, etc.) will be redirected to C++ exceptions |
650 | that use *try {...} catch (Standard_Failure) {...}* blocks. |
651 | |
f6e968a7 |
652 | The above rule is especially important for robustness of modeling algorithms. |
653 | |
654 | ### Cross-referenced handles |
f6e968a7 |
655 | |
49663e13 |
656 | Take care about cycling of handled references to avoid chains, which will never be freed. For this purpose, use a pointer at one (subordinate) side. |
f6e968a7 |
657 | |
49663e13 |
658 | See the following example: |
659 | |
660 | In *MyPackage.cdl* : |
661 | |
662 | ~~~~ |
f6e968a7 |
663 | class MyFirstHandle; |
664 | class MySecondHandle; |
665 | pointer MySecondPointer to MySecondHandle; |
666 | ... |
49663e13 |
667 | ~~~~ |
f6e968a7 |
668 | |
49663e13 |
669 | In *MyPackage_MyFirstHandle.cdl* : |
f6e968a7 |
670 | |
49663e13 |
671 | ~~~~ |
f6e968a7 |
672 | class MyFirstHandle from MyPackage |
673 | ... |
674 | is |
675 | ... |
676 | SetSecondHandleA (me: mutable; theSecond: MySecondHandle from MyPackage); |
677 | SetSecondHandleB (me: mutable; theSecond: MySecondHandle from MyPackage); |
678 | ... |
679 | fields |
680 | ... |
681 | mySecondHandle : MySecondHandle from MyPackage; |
682 | mySecondPointer : MySecondPointer from MyPackage; |
683 | ... |
684 | end MyFirstHandle from MyPackage; |
49663e13 |
685 | ~~~~ |
f6e968a7 |
686 | |
49663e13 |
687 | In *MyPackage_MySecondHandle.cdl* : |
f6e968a7 |
688 | |
49663e13 |
689 | ~~~~ |
f6e968a7 |
690 | class MySecondHandle from MyPackage |
691 | ... |
692 | is |
693 | ... |
694 | SetFirstHandle (me: mutable; theFirst: MyFirstHandle from MyPackage); |
695 | ... |
696 | fields |
697 | ... |
698 | myFirstHandle : MyFirstHandle from MyPackage; |
699 | ... |
700 | end MySecondHandle from MyPackage; |
49663e13 |
701 | ~~~~ |
f6e968a7 |
702 | |
703 | In C++ code: |
704 | |
705 | ~~~~~{.cpp} |
706 | void MyFunction() |
707 | { |
708 | Handle(MyPackage_MyFirstHandle) anObj1 = new MyPackage_MyFirstHandle(); |
709 | Handle(MyPackage_MySecondHandle) anObj2 = new MyPackage_MySecondHandle(); |
710 | Handle(MyPackage_MySecondHandle) anObj3 = new MyPackage_MySecondHandle(); |
711 | |
712 | anObj1->SetSecondHandleA(anObj2); |
713 | anObj1->SetSecondHandleB(anObj3); |
714 | anObj2->SetFirstHandle(anObj1); |
715 | anObj3->SetFirstHandle(anObj1); |
716 | |
717 | // memory is not freed here !!! |
718 | anObj1.Nullify(); |
719 | anObj2.Nullify(); |
720 | |
721 | // memory is freed here |
722 | anObj3.Nullify(); |
723 | } |
724 | ~~~~~ |
725 | |
726 | ### C++ memory allocation |
f6e968a7 |
727 | |
49663e13 |
728 | In C++ use *new* and *delete* operators instead of *malloc()* and *free()*. Try not to mix different memory allocation techniques. |
729 | |
730 | ### Match *new* and *delete* [MANDATORY] |
731 | |
f6e968a7 |
732 | Use the same form of new and delete. |
733 | |
734 | ~~~~~{.cpp} |
735 | aPtr1 = new TypeA[n]; ... ; delete[] aPtr1; |
736 | aPtr2 = new TypeB(); ... ; delete aPtr2; |
737 | aPtr3 = Standard::Allocate (4096); ... ; Standard::Free (aPtr3); |
738 | ~~~~~ |
739 | |
740 | ### Methods managing dynamical allocation [MANDATORY] |
49663e13 |
741 | |
f6e968a7 |
742 | Define a destructor, a copy constructor and an assignment operator for classes with dynamically allocated memory. |
743 | |
744 | ### Uninitialized variables [MANDATORY] |
49663e13 |
745 | |
f6e968a7 |
746 | Every variable should be initialized. |
747 | |
748 | ~~~~~{.cpp} |
749 | Standard_Integer aTmpVar1; // bad |
750 | Standard_Integer aTmpVar2 = 0; // OK |
751 | ~~~~~ |
752 | |
49663e13 |
753 | Uninitialized variables might be kept only within performance-sensitive code blocks and only when their initialization is guaranteed by subsequent code. |
f6e968a7 |
754 | |
49663e13 |
755 | ### Do not hide global *new* |
756 | |
757 | Avoid hiding the global *new* operator. |
f6e968a7 |
758 | |
759 | ### Assignment operator |
49663e13 |
760 | |
761 | In *operator=()* assign to all data members and check for assignment to self. |
f6e968a7 |
762 | |
763 | ### Float comparison |
49663e13 |
764 | |
f6e968a7 |
765 | Don't check floats for equality or non-equality; check for GT, GE, LT or LE. |
766 | |
767 | ~~~~~{.cpp} |
768 | if (Abs (theFloat1 - theFloat2) < theTolerance) |
769 | { |
770 | DoSome(); |
771 | } |
772 | ~~~~~ |
773 | |
49663e13 |
774 | Package *Precision* provides standard values for SI units and widely adopted by existing modeling algorithms: |
775 | |
776 | - *Precision::Confusion()* for lengths in meters; |
777 | - *Precision::Angular()* for angles in radians. |
f6e968a7 |
778 | |
49663e13 |
779 | as well as definition of infinite values within normal range of double precision: |
780 | - *Precision::Infinite()* |
781 | - *Precision::IsInfinite()* |
782 | - *Precision::IsPositiveInfinite()* |
783 | - *Precision::IsNegativeInfinite()* |
f6e968a7 |
784 | |
785 | ### Non-indexed iteration |
49663e13 |
786 | |
f6e968a7 |
787 | Avoid usage of iteration over non-indexed collections of objects. |
49663e13 |
788 | If such iteration is used, make sure that the result of the algorithm does not depend on the order of iterated items. |
f6e968a7 |
789 | |
49663e13 |
790 | Since the order of iteration is unpredictable in case of a non-indexed collection of objects, it frequently leads to different behavior of the application from one run to another, thus embarrassing the debugging process. |
791 | |
792 | It mostly concerns mapped objects for which pointers are involved in calculating the hash function. For example, the hash function of *TopoDS_Shape* involves the address of *TopoDS_TShape* object. Thus the order of the same shape in the *TopTools_MapOfShape* will vary in different sessions of the application. |
f6e968a7 |
793 | |
794 | ### Do not throw in destructors |
49663e13 |
795 | |
796 | Do not throw from within a destructor. |
f6e968a7 |
797 | |
798 | ### Assigning to reference [MANDATORY] |
f6e968a7 |
799 | |
49663e13 |
800 | Avoid the assignment of a temporary object to a reference. This results in a different behavior for different compilers on different platforms. |
801 | |
802 | @section occt_coding_rules_9 Performance issues |
f6e968a7 |
803 | |
804 | These rules define the ways of avoiding possible loss of performance caused by ineffective programming. |
805 | |
806 | ### Class fields alignment |
49663e13 |
807 | |
808 | Declare fields of a class in the decreasing order of their size for better alignment. |
f6e968a7 |
809 | Generally, try to reduce misaligned accesses since they impact the performance (for example, on Intel machines). |
810 | |
811 | ### Fields initialization order [MANDATORY] |
49663e13 |
812 | |
f6e968a7 |
813 | List class data members in the constructor's initialization list in the order they are declared. |
814 | |
815 | ~~~~~{.cpp} |
816 | class MyPackage_MyClass |
817 | { |
818 | |
819 | public: |
820 | |
821 | MyPackage_MyClass() |
822 | : myPropertyA (1), |
823 | myPropertyB (2) {} |
824 | |
825 | // NOT |
826 | // : myPropertyB (2), |
827 | // myPropertyA (1) {} |
828 | |
829 | private: |
830 | |
831 | Standard_Integer myPropertyA; |
832 | Standard_Integer myPropertyB; |
833 | |
834 | }; |
835 | ~~~~~ |
836 | |
837 | ### Initialization over assignment |
49663e13 |
838 | |
839 | Prefer initialization over assignment in class constructors. |
f6e968a7 |
840 | |
841 | ~~~~~{.cpp} |
842 | MyPackage_MyClass() |
843 | : myPropertyA (1) // preferred |
844 | { |
845 | myPropertyB = 2; // not recommended |
846 | } |
847 | ~~~~~ |
848 | |
849 | ### Optimize caching |
49663e13 |
850 | |
851 | When programming procedures with extensive memory access, try to optimize them in terms of cache behavior. Here is an example of how the cache behavior can be impacted: |
852 | |
f6e968a7 |
853 | On x86 this code |
854 | |
855 | ~~~~~{.cpp} |
856 | Standard_Real anArray[4096][2]; |
857 | for (Standard_Integer anIter = 0; anIter < 4096; ++anIter) |
858 | { |
859 | anArray[anIter][0] = anArray[anIter][1]; |
860 | } |
861 | ~~~~~ |
862 | |
49663e13 |
863 | is more efficient then |
f6e968a7 |
864 | |
865 | ~~~~~{.cpp} |
866 | Standard_Real anArray[2][4096]; |
867 | for (Standard_Integer anIter = 0; anIter < 4096; ++anIter) |
868 | { |
869 | anArray[0][anIter] = anArray[1][anIter]; |
870 | } |
871 | ~~~~~ |
872 | |
49663e13 |
873 | since linear access does not invalidate cache too often. |
874 | |
875 | @section occt_coding_rules_10 Draw Harness command |
876 | |
877 | Draw Harness provides TCL interface for OCCT algorithms. |
878 | |
879 | There is no TCL wrapper over OCCT C++ classes, instead interface is provided through the set of TCL commands implemented in C++. |
880 | |
881 | There is a list of common rules which should be followed to implement well-formed Draw Harness command. |
882 | |
883 | ### Return value |
884 | |
885 | Command should return 0 in most cases even if the executed algorithm has failed. Returning 1 would lead to a TCL exception, thus should be used in case of a command line syntax error and similar issues. |
886 | |
887 | ### Validate input parameters |
888 | |
889 | Command arguments should be validated before usage. The user should see a human-readable error description instead of a runtime exception from the executed algorithm. |
890 | |
891 | ### Validate the number of input parameters |
892 | |
893 | Command should warn the user about unknown arguments, including cases when extra parameters have been pushed for the command with a fixed number of arguments. |
894 | |
895 | ~~~~~{.cpp} |
896 | if (theArgsNb != 3) |
897 | { |
898 | std::cout << "Syntax error - wrong number of arguments!\n"; |
899 | return 1; |
900 | } |
901 | |
902 | Standard_Integer anArgIter = 1; |
903 | Standard_CString aResName = theArgVec[anArgIter++]; |
904 | Standard_CString aFaceName = theArgVec[anArgIter++]; |
905 | TopoDS_Shape aFaceShape = DBRep::Get (aFaceName); |
906 | if (aFaceShape.IsNull() |
907 | || aFaceShape.ShapeType() != TopAbs_FACE) |
908 | { |
909 | std::cout << "Shape " << aFaceName << " is empty or not a Face!\n"; |
910 | return 1; |
911 | } |
912 | DBRep::Set (aResName, aFaceShape); |
913 | return 0; |
914 | ~~~~~ |
915 | |
916 | ### Message printing |
917 | |
918 | Informative messages should be printed into standard output *std::cout*, whilst command results (if any) - into Draw Interpreter. |
919 | |
920 | Information printed into Draw Interpreter should be well-structured to allow usage in TCL script. |
921 | |
922 | ### Long list of arguments |
923 | |
924 | Any command with a long list of obligatory parameters should be considered as ill-formed by design. |
925 | Optional parameters should start with flag name (with '-' prefix) and followed by its values: |
926 | |
927 | ~~~~~{.tcl} |
928 | myCommand -flag1 value1 value2 -flag2 value3 |
929 | ~~~~~ |
f6e968a7 |
930 | |
49663e13 |
931 | ### Arguments parser |
f6e968a7 |
932 | |
f8eb9b17 |
933 | - Integer values should be read using *Draw::Atoi()* function. |
934 | - Real values should be read using *Draw::Atof()* function. |
49663e13 |
935 | - Flags names should be checked in case insensitive manner. |
936 | |
f8eb9b17 |
937 | Functions *Draw::Atof()* and *Draw::Atoi()* support expressions and read values in C-locale. |
49663e13 |
938 | |
939 | ~~~~~{.cpp} |
940 | Standard_Real aPosition[3] = {0.0, 0.0, 0.0}; |
941 | for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter) |
942 | { |
943 | Standard_CString anArg = theArgVec[anArgIter]; |
944 | TCollection_AsciiString aFlag (anArg); |
945 | aFlag.LowerCase(); //!< for case insensitive comparison |
946 | if (aFlag == "position") |
947 | { |
948 | if ((anArgIt + 3) >= theArgsNb) |
949 | { |
950 | std::cerr << "Wrong syntax at argument '" << anArg << "'!\n"; |
951 | return 1; |
952 | } |
953 | aPosition[0] = Draw::Atof (theArgVec[++anArgIt]); |
954 | aPosition[1] = Draw::Atof (theArgVec[++anArgIt]); |
955 | aPosition[2] = Draw::Atof (theArgVec[++anArgIt]); |
956 | } |
957 | else |
958 | { |
959 | std::cout << "Syntax error! Unknown flag '" << anArg << "'\n"; |
960 | return 1; |
961 | } |
962 | } |
963 | ~~~~~ |
964 | |
965 | @section occt_coding_rules_11 Examples |
966 | |
967 | ### Sample documented class |
f6e968a7 |
968 | |
969 | @verbatim |
f6e968a7 |
970 | class Package_Class |
971 | { |
972 | |
973 | public: //! @name public methods |
974 | |
975 | //! Method computes the square value. |
976 | //! @param theValue the input value |
977 | //! @return squared value |
978 | Standard_Export Standard_Real Square (const Standard_Real theValue); |
979 | |
49663e13 |
980 | private: //! \@name private methods |
f6e968a7 |
981 | |
982 | //! Auxiliary method |
983 | void increment(); |
984 | |
49663e13 |
985 | private: //! \@name private fields |
f6e968a7 |
986 | |
987 | Standard_Integer myCounter; //!< usage counter |
988 | |
989 | }; |
49663e13 |
990 | |
991 | |
f6e968a7 |
992 | @endverbatim |
993 | |
49663e13 |
994 | ~~~~~ |
f6e968a7 |
995 | #include <Package_Class.hxx> |
f6e968a7 |
996 | // ========================================================== |
997 | // function : Square |
998 | // purpose : Method computes the square value |
999 | // ========================================================== |
1000 | Standard_Real Package_Class::Square (const Standard_Real theValue) |
1001 | { |
1002 | increment(); |
1003 | return theValue * theValue; |
1004 | } |
1005 | |
1006 | // ========================================================== |
1007 | // function : increment |
1008 | // purpose : |
1009 | // ========================================================== |
1010 | void Package_Class::increment() |
1011 | { |
1012 | ++myCounter; |
1013 | } |
1014 | ~~~~~ |
1015 | |
49663e13 |
1016 | ### TCL script for Draw Harness |
1017 | |
f6e968a7 |
1018 | ~~~~~{.tcl} |
1019 | # show fragments (solids) in shading with different colors |
1020 | proc DisplayColored {theShape} { |
1021 | set aSolids [uplevel #0 explode $theShape so] |
1022 | set aColorIter 0 |
1023 | set THE_COLORS {red green blue1 magenta1 yellow cyan1 brown} |
1024 | foreach aSolIter $aSolids { |
1025 | uplevel #0 vdisplay $aSolIter |
1026 | uplevel #0 vsetcolor $aSolIter [lindex $THE_COLORS [expr [incr aColorIter] % [llength $THE_COLORS]]] |
1027 | uplevel #0 vsetdispmode $aSolIter 1 |
1028 | uplevel #0 vsetmaterial $aSolIter plastic |
1029 | uplevel #0 vsettransparency $aSolIter 0.5 |
1030 | } |
1031 | } |
1032 | |
1033 | # load modules |
1034 | pload MODELING VISUALIZATION |
1035 | |
1036 | # create boxes |
1037 | box bc 0 0 0 1 1 1 |
1038 | box br 1 0 0 1 1 2 |
1039 | compound bc br c |
1040 | |
1041 | # show fragments (solids) in shading with different colors |
1042 | vinit View1 |
1043 | vclear |
1044 | vaxo |
1045 | vzbufftrihedron |
1046 | DisplayColored c |
1047 | vfit |
1048 | vdump $imagedir/${casename}.png 512 512 |
1049 | ~~~~~ |
1050 | |
49663e13 |
1051 | ### GLSL program: |
f6e968a7 |
1052 | ~~~~~{.fs} |
1053 | vec3 Ambient; //!< Ambient contribution of light sources |
1054 | vec3 Diffuse; //!< Diffuse contribution of light sources |
1055 | vec3 Specular; //!< Specular contribution of light sources |
1056 | |
1057 | //! Computes illumination from light sources |
1058 | vec4 ComputeLighting (in vec3 theNormal, |
1059 | in vec3 theView, |
1060 | in vec4 thePoint) |
1061 | { |
1062 | // clear the light intensity accumulators |
1063 | Ambient = occLightAmbient.rgb; |
1064 | Diffuse = vec3 (0.0); |
1065 | Specular = vec3 (0.0); |
1066 | vec3 aPoint = thePoint.xyz / thePoint.w; |
1067 | for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex) |
1068 | { |
1069 | int aType = occLight_Type (anIndex); |
1070 | if (aType == OccLightType_Direct) |
1071 | { |
1072 | directionalLight (anIndex, theNormal, theView); |
1073 | } |
1074 | else if (aType == OccLightType_Point) |
1075 | { |
1076 | pointLight (anIndex, theNormal, theView, aPoint); |
1077 | } |
1078 | } |
1079 | |
1080 | return vec4 (Ambient, 1.0) * occFrontMaterial_Ambient() |
1081 | + vec4 (Diffuse, 1.0) * occFrontMaterial_Diffuse() |
1082 | + vec4 (Specular, 1.0) * occFrontMaterial_Specular(); |
1083 | } |
1084 | |
1085 | //! Entry point to the Fragment Shader |
1086 | void main() |
1087 | { |
1088 | gl_FragColor = computeLighting (normalize (Normal), |
1089 | normalize (View), |
1090 | Position); |
1091 | } |
1092 | ~~~~~ |