forked from HeliumProject/Engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CODING
355 lines (281 loc) · 10.4 KB
/
CODING
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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
########################################################################
Helium Coding Guidelines
########################################################################
Naming Conventions
==================
In general, code should be as self documenting as possible. All names should be
composed of complete and descriptive words; words should not be shortened or
abbreviated except in rare and obvious (to the average developer) cases.
Namespaces
----------
Namespaces should be used sparingly to logically delineate code. Namespace
names should start with a capital letter and use camel casing, eg:
namespace ExampleNamespace
{
...
}
Structs and Classes
-------------------
Both structs and classes should using camel casing and begin with a capital
letter, eg:
class ExampleClass
{
...
}
struct ExampleStruct
{
...
}
Enums
-----
* Enums should be placed in their own explicit namespace - so as not to contaminate the containing namespace with extraneous symbols
** namespace name is plural - as the container for all of the enum symbols; the namespace name is used to refer to individual enum values as FileAccessFlags::Append rather than just Append
* enum – used to declare variables; the name is
** plural if an enum variable may contain more than one of the enum flags: and cannot share the same name as the encapsulating namespace: FindFileFlags::FindFlags flags
** singular if the enum values are mutually exclusive, allowing you to declare a variable that is ONE of many enum values: FileAccessFlags::FileMode mode
* enum member names should be CamelCase, with leading uppercase character; they should NOT be all caps or prefixed with a character indicator like “k_”
* use a typedef to shorten enum variable declaration – shortening FileAccessFlags::FileModes modes to FileModes modes; enum typedef shares the same name as the enum
Note: When you refer to an enum inside a type, you do not need to specify the name of the enum – which results in the following compiler warning:
warning C4482: nonstandard extension used: enum 'enum' used in qualified name
---------------------------------EXAMPLE--------------------------------
namespace FileAccessFlags
{
enum FileAccessFlag
{
Read = 1 << 0,
Write = 1 << 1,
Append = 1 << 2,
Truncate = 1 << 3,
RandomAccess = 1 << 4,
SequentialAccess = 1 << 5,
};
}
typedef u32 FileAccessFlag;
...
void MyFunc( FileAccessFlag flags )
{
if ( flags & FileAccessFlags::Append )
return OPEN_EXISTING;
}
...
FileAccessFlag flags = ( FileAccessFlag ) ( FileAccessFlags::Append | FileAccessFlags::Write );
------------------------------/END EXAMPLE------------------------------
---------------------------------EXAMPLE--------------------------------
namespace BrowserDisplayModes
{
enum BrowserDisplayMode
{
Details = 0,
List,
Thumbnail,
};
}
typedef BrowserDisplayModes::BrowserDisplayMode BrowserDisplayMode;
...
void MyFunc( BrowserDisplayMode modes )
{
if ( modes & BrowserDisplayModes::Append )
return OPEN_EXISTING;
}
...
BrowserDisplayMode modes = ( BrowserDisplayMode ) ( BrowserDisplayModes::Append | BrowserDisplayModes::Write );
------------------------------/END EXAMPLE------------------------------
Variables
---------
Local Variables
---------------
Local variables and function parameters should be camel case and begin
with a lower case letter, eg:
int localVariable = 0;
Member Variables
----------------
Member variables should be defined with the "m_" prefix and use camel case,
beginning with a capital letter following the member prefix, eg:
int m_MemberVariable;
Global Variables
----------------
Global variables, externalized from the source file, should be defined in the
header files with the "g_" prefix, use camel case and begin with a capital
letter following their prefix, eg:
extern MODULE_API int g_GlobalVariable;
Static Variables
----------------
Static variables should be defined in the source file with the "s_" prefix,
use camel case and begin with a capital letter following their prefix, eg:
static const char* s_StaticVariable = "Hello world\n";
Constants
---------
External
--------
Externalized constants, defined in the header file, should be made using
either Enums (see above) or the C convention of #define, written in all caps,
and underscore separated, eg:
#define POUND_DEFINED_CONSTANT 1024
Internal
--------
If a constant is never externalized from a source file, the C++ const
modifier may be used instead, and the constant should be defined as a Static
variable (see above).
Macros
------
In general, C-style macros should not be used when it is possible to use a C++
inline function instead. Where C-style macros are necessary, they should be
written in all caps with underscores to separate each word. Additionally, to
denote them as belonging to the Helium project, they should begin with the
'HELIUM_' prefix, eg:
HELIUM_ASSERT( ... )
Files & Fodlers
---------------
A file should be named after the class that it contains, and placed under a
folder related to its functionality or the module it belongs to, eg:
Module/
Module/Bar.h
namespace Helium
{
class Bar
{
public:
Bar();
~Bar();
void Func();
...
}
}
Module/Bar.cpp
using namespace Helium;
Bar::Bar()
{
}
Bar~Bar()
{
}
void Bar::Func()
{
}
Module/Subsystem/Blah.h
namespace Helium
{
class Blah
{
public:
Blah();
~Blah();
}
}
Module/Subsystem/Blah.cpp
using namespace Helium;
Blah::Blah()
{
}
Blah::~Blah();
{
}
Status/Error/Warning Message Formatting
=======================================
It is important that messages to the user (console printing, message box text,
and exception message bodies) be homogeneous and in good form:
- Use complete sentences, and do not abbreviate words (eg: "vert", "jnt")
- Use periods. Phrases are bad for code that amend other module's messages.
- Don't use exclamation points. Errors are raised with color coding so they
are unnecessary.
- Don't put code in messages. It only makes the messages harder to understand
for users.
- *Under no circumstances* should a message tell the user to go tell a
particular named programmer about a problem, or to get help directly from
them. (eg: "Tell Reddy", "Grab Sam")
- All references to assets and files should be surrounded in single
quotes (', not `).
- Do not use newline characters in exception message text.
Eg:
Good
----
throw IG::Exception( TXT( "Triangle vertex limit exceeded. The limit is 256 triangles." ) );
ERR( TXT( "Triangle vertex limit exceeded. The limit is 256 triangles.\n" ) );
Bad
---
throw IG::Exception( TXT( "Tri vert limit too far!!\nIncrease limit in TriPool.cpp (go tell Reddy or Fred)\n" ) );
throw IG::Exception( TXT( "mTracks[AT_ROTATE_X]->isSampled() && mTracks[AT_ROTATE_Y]->isSampled() && mTracks[AT_ROTATE_Z]->isSampled()\n" ) );
Spacing, Tabs, Newlines, etc.
=============================
- Use spaces instead of tab characters.
- Use 4-space indenting.
- Place curly braces on their own line.
- Put spaces after open parentheses and before close parentheses.
- Put spaces after open brackets and before close brackets.
- Prefer to add spacing to code to help make it more easily readable.
- Append reference/pointer qualifier to the data type as opposed to the
variable name, as it is more descriptive of the type of data that one
expects to be in the variable as opposed to the variable itself.
- Do *not* attempt to align variable declarations or function declarations in
classes using spaces, these tend to rot over time and are more trouble than
they are worth.
Eg:
void SomeClass::SomeFunction( const OtherClass& otherClass, FooClass* foo )
{
HELIUM_ASSERT( otherClass.IsOk() );
if ( !otherClass.IsReady() )
{
otherClass.MakeReady();
}
int buffer[ 1234 ];
otherClass.DoIt( &buffer, 1234 );
foo->Process( &buffer, 1234 );
}
Variable Declarations
---------------------
Good
----
...
int m_SomeInt;
float m_SomeFloat;
...
void SomeFunction();
int SomeOtherFunction();
...
Bad
---
...
// this will rot when someone changes a type, or it will take someone
// unnecessary time when they add a new variable that changes the spacing
int m_SomeInt; // note the unnecessary spaces following 'int' here
float m_SomeFloat;
...
void SomeFunction();
int SomeOtherFunction(); // again, note the unnecessary spaces
...
File Paths
==========
All internal paths are expected to contain only forward slashes; however, they
will be displayed to the user with the native platform's slashes. This makes
it easier for the user to cut/copy/paste the paths into a command prompt.
Internal folder paths should always have a trailing slash.
There are several functions in the File subsystem to help manage paths. The
Helium::Path object is the preferred way to work with a path (as opposed to
using a bare string). The Path object has a variety of useful functions and
static methods for working with (and modifying) paths.
Hints for Writing Clean Class Declarations
==========================================
- Write the header file to be easy to see what the interface is; write for
humans reading your code to see how to use it.
- Try to group similar functions (that work on similar data or support
related functionality) next to each other.
- Getter and setter functions should be adjoint.
- Since we read top-to-bottom, put publicly accessible things at the top.
Eg:
class FOUNDATION_API Example : public Helium::RefCountBase< Example >
{
public:
Example();
virtual ~Example();
virtual bool IsCool();
bool ConvertToInts( int* ints );
void DoTheThing();
protected:
virtual bool DoSomethingElse();
public:
std::string m_SomeString;
int32_t m_SomeInt;
private:
int32_t m_SomePrivateInt;
void Validate();
};