Skip to main content

Advanced Code Formatting Guidelines

Coding guidelines for the entire PCSX2 project.

note

This guideline is subject to change as the need arises.

General Rules

Use Tabs For Indentation

// good
{
int foo = 0;
}

// bad
{
int foo = 0;
}
warning

Always use tabs (4 width) for indentation. No exceptions.

Visual Studio Guide

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();
}

tip

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();
tip

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;
tip

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.

info

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;
warning

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();
tip

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
*/
tip

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())
{

}
tip

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