summaryrefslogtreecommitdiff
path: root/docs/CODING
blob: 6c56d0ddf97c590235f3605de58135dc7c2896a7 (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
Originally pulled from: https://wiki.inspircd.org/Coding_Guidelines

---

InspIRCd Coding Guidelines

The following are a set of guidelines for writing patches to InspIRCd, or for
creating modules for distribution with the official package. These guidelines
were written a time after InspIRCd development started, and so not all code
yet follows these. This will be rectified with time.


1. Comments

   * Multi Line
     Multiple line comments should follow the C-style comment, for example:
       /*
        * This is a multiple line comment, huzzah..
        */

   * Single Line
     Single line comments should also be in the C style, for example:
       /* This is a boring one-line comment */

   * Doxygen commenting
     If you wish your comment to show in doxygen, the comment should be directly
     above the item you are documenting (a class, function, enum, etc) and the
     first line should be "/**". For example:
       /** This is a doxygen multiline comment.
	*  Description of thingymebob here.
	*/

     The first line after the "**" is used as the short description of the item
     (up to the full stop) and everything afterwards as the detailed description.


2. Indentation

   Tabs. Tabs. ONLY TABS. Use a single tab for each level of indentation,
   for example:
     int main()
     {
     <tab>if (condition)
     <tab>{
     <tab><tab>code
     <tab>}
     }


3. Separation

   Always put a space in between a keyword like if/while and the condition,
   for example:
     if (foo == bar)
    NOT
     if(foo == bar)


4. Braces

   Always put braces opening and closing blocks on separate lines, see the
   indentation example. For example, place braces like this:
     if (apples == "green")
     {
         cout << "Apples are green" << endl;
     }

   and not:
     if (apples == "green") {
         cout << "Apples are green" << endl;
     }

   The one exception to this is if you are declaring a class method which is
   only one line long, in that case the following is acceptable in most cases:
     class foo : public bar
     {
         foo() { }
	 getrandomfoo() { return rand(); }
     };


5. Templates

   Where possible, use templates rather than #defines. Avoid use of RTTI.


6. Structs

   Structs should be declared in the following fashion:
     struct BodyPartBasket
     {
         int arms;
	 int legs;
	 int scrotalsacs;
     };
   and not like this:
     typedef struct
     {
         int arms;
	 int legs;
	 int scrotalsacs;
     } BodyPartBasket;

    The second way is not required in C++ to be able to do this:
      BodyPartBasket mybasket;

    Plus, placing the name at the bottom of the declaration makes readability
    more difficult (as you have to scroll down to the bottom of the struct to
    find its name). (where possible, call them classes rather than structs.)


7. Variable naming

   Class and struct names should be in camel case with a leading capital letter,
   for example "MyBagOfBones" and not "my_bag_of_bones" or "mybagofbones".
   Variable names can be in either camel case with a leading capital letter or
   alternatively all lower case, so long as the same naming convention is
   adhered to throughout the class. No classes or variables should be named in
   capitals unless this makes sense for the name (for example "class DNS").
   Constants and enum values should always be completely in CAPITALS and
   underscores may be used, for example:
     enum DecayState
     {
         DECAYED_MOULDY  = 0,
	 DECAYED_SMELLY  = 1,
	 DECAYED_MAGGOTS = 2
     };
   All value names in an enum should be started with the same text which should
   be related in some way to the enum's use. For example "DNS_CNAME, DNS_A,
   DNS_AAAA".


8. Use of references

   Wherever possible, when dealing with any complex class, pass a const reference
   rather than a copy of the class. For example:
     MyThingy::MyThingy(const std::string &thingyvalue)
     {
     }
   Of course, if you intended to change the string you can just omit the 'const'.


9. Use of char pointers

   Whenever you use char pointers (char*, char**) try to use const equivalents.
   This is much safer and avoids ugly and dangerous casts. For example:
     MyThingy::Thingify(const char* const* wotsits)
     {
     }
   If it is possible without performance loss, consider avoiding char pointers
   altogether and using std::string instead.


10. Use of STL

    For more information on use of STL in InspIRCd, please see the separate
    STL FAQ.


11. Making copies of data

   Never ever make a copy of a piece of data unless it is absolutely necessary.
   For example, don't use strlcpy() to make a copy of the const char* string
   returned by std::string::c_str(), if the change can be done to the std::string
   itself. The same goes for unnecessary variable assignments, especially those
   which assign large classes.


12. namespace std

   Avoid the following:
     using namespace std;
   It might take a bit more typing, but things work better if you don't set
   (then later assume) the namespace -- specify it explicitly when you want to
   use it.


13. Linefeeds

   Unix linefeeds only please. We do not like to see our screens covered in ^M.


14. Portability

   Always make sure your code is portable to all supported operating systems,
   remember of course that as of 1.1.8 this includes windows. Don't write code
   that only works on windows, or only works on Linux. Test your code on all
   platforms or ask for help from other developers who have the platforms you
   want to test on.

   * new() and delete(), malloc() and free()
     Apart from the fact that using malloc() and free() is bad practice in C++
     code, you must never use malloc() or free() in InspIRCd, within its modules
     or within the core. This is because if you use malloc() or free() in windows,
     the memory is claimed from the program's local heap.
     In windows, each shared object (module, dll) has its own heap, which is
     protected from other dlls and executables. To get around this issue and
     allow more posix-like memory access from other dlls in the program (other
     modules), InspIRCd overrides the operators new and delete to ensure that
     memory allocated by them comes from the windows global heap. If you use
     malloc() and free() for this, the ircd will segfault when another module
     tries to access the memory you have allocated!

   * strdup()
     As with malloc(), above, strdup() should be avoided. Where strdup() is
     absolutely necessary, use strnewdup() which is our strdup() implementation
     that calls operator new instead of using malloc().
     char arrays allocated by strnewdup() should be deleted with operator delete[].

   * CoreExport and DllImport
     Prefix all types you want to import or export to other modules with CoreExport
     and DllImport macros. These do nothing in POSIX operating systems, however
     in windows these are expanded to the instructions __declspec(dllimport) and
     __declspec(dllexport) respectively depending on where they are used and how.


15. External Dependencies

   If a module is compiled as standard, or the code is part of the core, you must
   not use any dependencies that are not available as standard on all supported
   operating systems beyond libstdc++, libc, and whatever else is currently
   required to build the core. Modules which use nonstandard dependencies belong
   in the modules/extra directory.


16. Profiling and Performance

   It is one thing to assume that code performs bad, it is another thing to prove
   that it actually is. A lot of experienced programmers talk about 'premature
   optimisation', and here is what it means: if you have a piece of code called
   once on startup that takes 10 seconds instead of one second to run, and a
   piece of code that takes 0.05 seconds to run when it should take 0.01, and
   it is called once per second, the second piece of code is the priority.

   In other words, make sure that what you think is slow, and a performance
   problem in Insp actually is.
   To do this, use the callgrind tool from Valgrind (valgrind --tool=cachegrind
   bin/inspircd -nofork -debug), and kcachegrind (or similar) to view the output
   files.