mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-12-27 02:01:51 +01:00
99 lines
4.1 KiB
Markdown
99 lines
4.1 KiB
Markdown
|
|
# Coding style guidelines for Cemu
|
|
|
|
This document describes the latest version of our coding-style guidelines. Since we did not use this style from the beginning, older code may not adhere to these guidelines. Nevertheless, use these rules even if the surrounding code does not match.
|
|
|
|
Cemu comes with a `.clang-format` file which is supported by most IDEs for formatting. Avoid auto-reformatting whole files, PRs with a lot of formatting changes are difficult to review.
|
|
|
|
## Names for variables, functions and classes
|
|
|
|
- Always prefix class member variables with `m_`
|
|
- Always prefix static class variables with `s_`
|
|
- For variable names: Camel case, starting with a lower case letter after the prefix. Examples: `m_option`, `s_audioVolume`
|
|
- For functions/class names: Use camel case starting with a capital letter. Examples: `MyClass`, `SetActive`
|
|
- Avoid underscores in variable names after the prefix. Use `m_myVariable` instead of `m_my_variable`
|
|
|
|
## About types
|
|
|
|
Cemu provides its own set of basic fixed-width types. They are:
|
|
`uint8`, `sint8`, `uint16`, `sint16`, `uint32`, `sint32`, `uint64`, `sint64`. Always use these types over something like `uint32_t`. Using `size_t` is also acceptable where suitable. Avoid C types like `int` or `long`. The only exception is when interacting with external libraries which expect these types as parameters.
|
|
|
|
## When and where to put brackets
|
|
|
|
Always put curly-brackets (`{ }`) on their own line. Example:
|
|
|
|
```
|
|
void FooBar()
|
|
{
|
|
if (m_hasFoo)
|
|
{
|
|
...
|
|
}
|
|
}
|
|
```
|
|
As an exception, you can put short lambdas onto the same line:
|
|
```
|
|
SomeFunc([]() { .... });
|
|
```
|
|
You can skip brackets for single-statement `if`. Example:
|
|
```
|
|
if (cond)
|
|
action();
|
|
```
|
|
|
|
## Printing
|
|
|
|
Avoid sprintf and similar C-style formatting API. Use `fmt::format()`.
|
|
In UI related code you can use `formatWxString`, but be aware that number formatting with this function will be locale dependent!
|
|
|
|
## Strings and encoding
|
|
|
|
We use UTF-8 encoded `std::string` where possible. Some conversions need special handling and we have helper functions for those:
|
|
```cpp
|
|
// std::filesystem::path <-> std::string (in precompiled.h)
|
|
std::string _pathToUtf8(const fs::path& path);
|
|
fs::path _utf8ToPath(std::string_view input);
|
|
|
|
// wxString <-> std::string
|
|
wxString wxString::FromUTF8(const std::string& s)
|
|
wxString to_wxString(std::string_view str); // in gui/helpers.h
|
|
std::string wxString::utf8_string();
|
|
|
|
```
|
|
|
|
## Logging
|
|
|
|
If you want to write to log.txt use `cemuLog_log()`. The log type parameter should be mostly self-explanatory. Use `LogType::Force` if you always want to log something. For example:
|
|
`cemuLog_log(LogType::Force, "The value is {}", 123);`
|
|
|
|
## HLE and endianness
|
|
|
|
A pretty large part of Cemu's code base are re-implementations of various Cafe OS modules (e.g. `coreinit.rpl`, `gx2.rpl`...). These generally run in the context of the emulated process, thus special care has to be taken to use types with the correct size and endianness when interacting with memory.
|
|
|
|
Keep in mind that the emulated Espresso CPU is 32bit big-endian, while the host architectures targeted by Cemu are 64bit little-endian!
|
|
|
|
To keep code simple and remove the need for manual endian-swapping, Cemu has templates and aliases of the basic types with explicit endian-ness.
|
|
For big-endian types add the suffix `be`. Example: `uint32be`
|
|
|
|
When you need to store a pointer in the guest's memory. Use `MEMPTR<T>`. It will automatically store any pointer as 32bit big-endian. The pointer you store must point to memory that is within the guest address space.
|
|
|
|
## HLE interfaces
|
|
|
|
The implementation for each HLE module is inside a namespace with a matching name. E.g. `coreinit.rpl` functions go into `coreinit` namespace.
|
|
|
|
To expose a new function as callable from within the emulated machine, use `cafeExportRegister` or `cafeExportRegisterFunc`. Here is a short example:
|
|
```cpp
|
|
namespace coreinit
|
|
{
|
|
uint32 OSGetCoreCount()
|
|
{
|
|
return Espresso::CORE_COUNT;
|
|
}
|
|
|
|
void Init()
|
|
{
|
|
cafeExportRegister("coreinit", OSGetCoreCount, LogType::CoreinitThread);
|
|
}
|
|
}
|
|
```
|
|
You may also see some code which uses `osLib_addFunction` directly. This is a deprecated way of registering functions. |