Styling
This style guide lists the conventions used in the Coffee-Engine project. The goal is to make the codebase more readable and maintainable. The project uses an auto-formating tool called clang-format to enforce a consistent coding style.
Hopefully, this guide will help you to understand the codebase and contribute to the project.
Note
Don’t hesitate to look at the project’s source code to see examples of how these conventions are applied.
General Rules
Use English for all code, comments, and documentation.
Use 4 spaces for indentation.
Header files should have the .h extension, and source files should have the .cpp extension.
Include guards should be used in header files.
1 #pragma once
Includes
The includes should be ordered: internal headers, external headers, standard library headers.
The includes should be grouped by type and separated by a blank line.
The includes should be at the top of the file.
The includes can be at the .h or .cpp file, but it is recommended to put them in the .cpp file.
1 // Includes
2 #include "Coffee/Core/Log.h"
3 #include "Coffee/Core/Application.h"
4
5 #include <SDL3/SDL.h>
6 #include <GLM/glm.hpp>
7 #include <GLM/gtc/matrix_transform.hpp>
8
9 #include <iostream>
10 #include <vector>
11 #include <string>
12 #include <unordered_map>
Constants
Use constexpr instead of #define for constants.
Use const for variables that are not meant to be modified.
1 // Constexpr over Defines
2 constexpr int MAX_SPEED = 5 /*over #define MAX_SPEED = 5*/
3
4 // Constants
5 const int SOME_NUMBER = 42;
6 const std::string GREETING = "Hello, World!";
Enums
Note
This needs to be revised.
Use enum class instead of enum.
Use PascalCase for enum names.
Use PascalCase for named enum values.
Use UPPER_SNAKE_CASE for types enum values.
1 enum class Named
2 {
3 Thing1,
4 Thing2,
5 AnotherThing = -1
6 };
7
8 enum class Types
9 {
10 PERSPECTIVE,
11 ORTHOGRAPHIC
12 };
Classes
Use PascalCase for class names.
Use camelCase with an initial lowercase “m” for member variables.
Use PascalCase for member functions.
Place public members first, followed by public protected and private functions, and finally protected and private members.
1 class MyClass
2 {
3 public:
4 //Public variables
5 int PublicNumber = 5;
6
7 public:
8 // Constructor
9 MyClass() : m_IntNumber(5), m_Name("Luigi Mangione 🫶"),
10 m_Numbers({1, 2, 3}), m_UnorderedMap({ {"key", 1} };)
11 {
12 /*
13 Note that there is COFFEE_INFO and COFFEE_CORE_INFO.
14 COFFEE_INFO is used for the application and COFFEE_CORE_INFO for the engine.
15 */
16
17 COFFEE_CORE_INFO("Constructed!");
18 COFFEE_INFO("My name is: {0}", m_Name);
19 }
20
21 // Example public function
22
23 const std::vector<int>& SomeFunction(int first, int last)
24 {
25 std::vector<int> v;
26
27 for (int i = first; i < last; ++i)
28 {
29 v.push_back(i);
30 }
31
32 return v;
33 }
34
35 const void SetName(const std::string& name) { m_Name = name; }
36 const std::string& GetName() const { return m_Name; }
37
38 protected:
39 void ProtectedFunction() { /* Do something */ }
40
41 private:
42 void PrivateFunction() { /* Do something */ }
43
44 protected:
45 bool m_ProctectedBool = false;
46
47 private:
48 int m_IntNumber;
49 std::string m_Name;
50 std::vector<int> m_Numbers;
51 std::unordered_map<std::string, int> m_UnorderedMap;
52 };
Conditionals
1 const int localConst = 5;
2
3 if (param1 < localConst)
4 {
5 COFFEE_INFO("param1: {0}", param1);
6 }
7 else if (param2 > 5)
8 {
9 COFFEE_INFO("param2: {0}", param2);
10 }
11 else
12 {
13 COFFEE_ERROR("Fail!");
14 }
Loops
1// For loop
2 for (int i = 0; i < 20; ++i)
3 {
4 COFFEE_INFO("Loop index: {0}", i);
5 }
6
7// Range-based for loop
8 vector<int> v = {1, 2, 3, 4, 5};
9 for (int i : arr)
10 {
11 COFFEE_INFO("{0} ", i);
12 }
13
14// While loop
15 while (param2 != 0)
16 {
17 --param2;
18 }
19
20// Iterators
21std::vector<int> v = {1, 2, 3, 4, 5};
22for (auto it = v.begin(); it != v.end(); ++it)
23{
24 COFFEE_INFO("{0} ", *it);
25}
Switch
Use the using enum directive to avoid repeating the enum name in each case.
Use braces for each case and default.
Use a new line for each case and default.
1Types type = Types::PERSPECTIVE
2
3switch (type)
4{
5 using enum Types;
6 case PERSPECTIVE:
7 {
8 COFFEE_INFO("type is PERSPECTIVE!");
9 break;
10 }
11 case ORTHOGRAPHIC:
12 {
13 COFFEE_INFO("type is ORTHOGRAPHIC!");
14 }
15 default:
16 {
17 COFFEE_INFO("type is not a type of the enum!");
18 }
19}
Note
If you have any questions or suggestions, don’t hesitate to tell us in the #coding channel on Discord.