Advanced Code Formatting Guidelines
Coding guidelines for the entire PCSX2 project.
This guideline is subject to change as the need arises.
General Rules
Use Tabs For Indentation
// good
{
int foo = 0;
}
// bad
{
int foo = 0;
}
Always use tabs (4 width) for indentation. No exceptions.
Indent Namespaces
// good
namespace Util
{
class File
{
};
}
// bad
namespace Util
{
class File
{
};
}
Indent Members
// good
class Texture
{
public:
GSVector4i getSize() const;
private:
GSVector4i m_size;
};
// bad
class Texture
{
public:
GSVector4i getSize() const;
private:
GSVector4i m_size;
};
No Indentation For Labels
// good
class Texture
{
public:
bool isValid() const;
private:
bool m_valid;
};
// bad
class Texture
{
public:
bool isValid() const;
private:
bool m_valid;
};
Place The Public API First
// good
class Texture
{
public:
bool isValid() const;
GSVector4i getSize() const;
void setValid();
void setInvalid();
void setSize(const GSVector4i& size);
private:
bool m_valid;
GSVector4i m_size;
void onResize();
}
Don't distract other developers with implementation details. Place the public API first where it is easy to find.
Use Descriptive Names
// good
GSVector4i display_offset;
GSVector4i getDisplayOffset();
// bad
GSVector4i off;
GSVector4i getOffset();
Always use descriptive names when declaring variables and functions.
Do not shorten variable names for the sake of saving a few keystrokes. Code is meant to be easily read not easily written.
Avoid Operator Overloading
// good
auto sizer = new wxStaticBoxSizer(wxVERTICAL, this, L"Sizer");
sizer->Add(some_panel, StdExpand());
// awful
auto& sizer (*new wxStaticBoxSizer(wxVERTICAL, this, L"Sizer" ));
sizer += some_panel | StdExpand();
Do not make excessive use of operator overloading.
Exception: Some types are condusive to mathmatical operator overloading such as a simd or other wrapper type.
Exception: Sometimes it is acceptable to overload the assignment, move assignment or comparison operators.
Use Scoping Where Applicable
// good
// scope denotes a critical section
{
std::lock_guard<std::mutex> lk(mutex);
// ...
}
// good
// prevents a hack from polluting local scope
{
// HACK: Nvidia cards have an alignment issue
const bool should_offset = m_device->isNvidia() && m_hacks_enabled;
if (should_offset)
{
}
}
// good
// scope helps prevent name collisions in a large function
bool CreateState()
{
{
D3D11_DEPTH_STENCIL_DESC depth_stencil_desc = {};
depth_stencil_desc.DepthEnable = false;
depth_stencil_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
depth_stencil_desc.DepthFunc = D3D11_COMPARISON_NEVER;
HRESULT result = E_FAIL;
result = m_device->CreateDepthStencilState(
&depth_stencil_desc, &m_depth_no_write
);
if (FAILED(result))
return false;
}
{
D3D11_DEPTH_STENCIL_DESC depth_stencil_desc = {};
depth_stencil_desc.DepthEnable = true;
depth_stencil_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depth_stencil_desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
HRESULT result = E_FAIL;
hr = m_dev->CreateDepthStencilState(
&depth_stencil_desc, &m_depth_write
);
if (FAILED(result))
return false;
}
return true;
}
Variables
Snake Case For Variable Names
// good
int current_offset;
// bad
int currentOffset;
int CurrentOffset;
Prefix Member Variables With m_
class Texture
{
// good
bool m_valid;
// bad
GSVector4i size;
}
Prefix Static Variables With s_
// good
static s_device;
// bad
static device;
Mark Variables const
Where Applicable
// good - not going to change
const bool is_valid = texture && texture->isValid();
// good - deonte function won't modify the reference
void checkSize(const GSVector4i& size);
Encapsulate
// good
auto size = texture->getSize();
if (texture->isValid())
{
}
// bad
auto size = texture->m_size;
if (texture->m_valid)
{
}
Prefer STL Containers Where Applicable
// good
std::array<int, 2> foo;
std::unique_ptr<int> bar;
// bad
int foo[2];
int* bar;
Exception: It is a common idiom in gui toolkits such as wx to use raw pointers. In those instances you should prefer raw pointers to smart pointers.
Prefer static constexpr
For Compile Time Constants
// good
class Texture
{
static constexpr MAX_BUFFER_SIZE = 1920 * 1080;
using BufferType = std::array<uint32, MAX_BUFFER_SIZE>;
BufferType m_data;
}
// bad
#define MAX_BUFFER_SIZE 20736000
class Texture
{
using BufferType = std::array<uint32, MAX_BUFFER_SIZE>;
BufferType m_data;
}
Functions
Camel Case For Function Names
// good
GSVector4i getSize();
// bad
GSVector4i get_size();
GSVector4i GetSize();
All functions (global, member or otherwise) must be in camelCase form.
Avoid Excessive/Non-Obvious Parameter Usage
// good
TextureCache::LookupInfo lookup_info = {};
lookup_info.base = 0x0;
lookup_info.buffer_wdith = 10;
lookup_info.psm = PSM::CT32;
lookup_info.rectangle = GSVector4i(0, 0, 64, 64);
auto texture = m_texture_cache->Search(lookup_info);
// bad - not obvious
auto texture = m_texture_cache->Search(0x0, 10, PSM::CT32, 0, 0, 64, 64);
auto texture = m_texture_cache->Search({0x0, 10, PSM::CT32, 0, 0, 64, 64});
Avoid parameter usage which is non-obvious. Try to keep functions with in a reasonable amount of parameters. Consider the use of a struct
in instances where this is not avoidable.
The Windows calling convention passes the first 2 arguments (4 in x64) as registers.
Mark Member Functions const
Where Applicable
class Texture
{
private:
GSVector4i m_size;
bool m_valid;
public:
// good
GSVector4i getSize() const
{
return m_size;
}
// bad - doesn't modify the object, use const
bool isValid()
{
return m_valid;
}
}
Types
Capital Case For Type Names
// good
struct LookupInfo;
class CachedTexture;
enum ColorFormat;
// bad
struct lookupInfo;
class cached_texture;
enum COLOR_FORMAT;
Reference And Pointer Specifiers
// good
int& foo;
int&& foo;
int* bar_ptr;
int** ptr;
// bad
int &foo;
int &&foo;
int *bar;
int **bar;
Reference and pointer specifiers follow the type name and are immediately followed by a space. No exceptions.
Use Type Aliasing Where Applicable
// good
using BufferType = std::array<uint32, 1920 * 1080>;
BufferType buffer1;
BufferType buffer2;
BufferType buffer3;
// bad
std::array<uint32, 1920 * 1080> buffer1;
std::array<uint32, 1920 * 1080> buffer2;
std::array<uint32, 1920 * 1080> buffer3;
In addition to making the code more readable, this makes it easier to modify a shared type.
Namespace Enums
// good
namespace Format
{
enum PSM
{
CT32 = 0x0,
CT24 = 0x1,
// ...
};
}
case Format::PSM::CT32:
case Format::CT24:
// bad - pollutes the global namespace
enum PSM
{
PSMCT32 = 0x0,
PSMCT24 = 0x1,
// ...
};
Use Enum Types Explcitly
namespace Color
{
enum Format;
}
// good
void setFormat(Color::Format format);
// bad
void setFormat(int format);
Control Statements
Space Following The Keyword
// good
if (check)
while (true)
for (const auto& item : items)
// bad
if(check)
while(true)
for(const auto& item : items)
Use Spaces, Newlines And Intermediate Variables
// good
if (some_long_variable ||
some_other_variable &&
some_other_long_variable)
{
}
// good
const bool check = some_long_variable ||
some_other_variable &&
some_other_long_variable;
if (check)
{
}
// bad
if (some_long_variable || some_other_variable && some_other_long_variable)
Braces On Seperate Lines
// good
for (const auto& item : items)
{
// do something with item
}
// good
if (check)
{
}
// bad
if (check) {
}
// awful
if (check) { doSomething(); }
if (check) doSomething();
Exception: In the event that the body of the control statement is one line, the braces can be omitted.
// this is acceptable
if (some_check)
doSomething();
Prefer Ranged For Loops
// good
for (const auto& texture : cached_textures)
{
auto size = texture->getSize();
// ...
}
// bad
for (int i = 0; i < cached_texture.size(); i++)
{
auto size = textures[i]->getSize();
// ...
}
Preprocessor
Use #pragma once
// good
#pragma once
class Texture
{
}
// bad - define guard
#ifndef TEXTURE
#define TEXTURE
class Texture
{
}
#endif
Comments
Use //
// good
// an invalid texture here means we are recovering
// from an ealier error
// bad
/*
an invalid texture here means we are recovering
from an ealier error
*/
Prefer the usage of //
for all comments. Developers commonly need to comment an entire block of code and having a /* */
style comment in the middle often causes problems.
Avoid The Obvious
// good
// an invalid texture here means we are recovering
// from an earlier error
if (!texture->isValid())
{
}
// bad
// check if the texture is valid
if (!texture->isValid())
{
}
Avoid comments which outright state what the code is doing. Try to make comments describe what isn't obvious about the code.
Denote And Explain All Hacks
// good
// HACK: The data cache is too slow to reasonably emulate