## Things to try when a function has major differences
The following actions should help when basic blocks are in the wrong order, or when there are weird issues that involve comparisons or conditionals:
* Invert conditionals.
* Introduce inline functions. Or manually inline code.
* Add or eliminate return statements.
* Duplicate or deduplicate code.
* Independent memory loads/stores can be reordered, so you might need to reorder statements or conditions in the source code. For example, `if (x || y)` might have to be written as `if (y || x)`.
* Turn if/else into ternaries and vice versa. This doesn't always make a difference, though.
* uintptr_t do not always produce the same code as pointers, even for simple operations such as comparisons.
* Loops:
* Index-based loops
* u32 / s32 can make a difference, in particular for loop unrolling.
*`<` vs `!=` can affect codegen. If the trip count is known at compile-time, Clang will usually change `<` into `!=`, but you should still try `<` first.
* In some rare cases, Nintendo will use `!=` instead of `<`.
* Iterator loops
* Since we are targeting C++17, the preferred way to iterate over a container is to use a range-based for loop (e.g. `for (auto x : array)`).
* Sometimes, making the iterator appear explicitly is required to match the original code. Example: `for (auto it = array.begin(), end = array.end(); it != end; ++it)`
* In some rare cases, the end iterator is not kept in a variable, and instead it's recalculated at the end of each iteration. Example: `for (auto it = array.begin(); it != array.end(); ++it)`
* Sometimes it is possible to use `<algorithm>` functions (e.g. std::for_each, std::all_of, etc.) for simpler loops.
* And in some very rare cases (when dealing with EventFlow for example) it is sometimes *required* to use `<algorithm>` to match.
## Minor differences
* Incorrect comparison flags (getting >= instead of > for example)
* Invert conditionals.
* For integers: make sure you are using the correct signedness.
* For example, HI means that you should be using an unsigned integer.
* For floating-point, keep in mind that `x > 5.0` and `!(x <= 5.0)` are not equivalent because of NaN. This can reveal how an if/else statement is supposed to be written.
* Swapped CSEL operands
* Invert conditionals. (For ternaries, also swap the ? and : operands, obviously.)
* In some rare cases, `ptr == nullptr` and `!ptr` do not generate the same code.
* Extraneous function prologue/epilogue: this can happen when returning references. Change the return type to a pointer.
* If the second argument of a `_cxa_atexit` call is nullptr and the destructor is a nullsub, the object in question is likely a C-style array (not a std::array or a sead::SafeArray).
This section lists some inline functions that are often used throughout the codebase.
### sead
sead is Nintendo's C++ standard library. It provides basic data structures such as strings and tree maps and many other essential components (e.g. threads, critical sections, file IO, etc.)
#### Strings
##### `sead::SafeString` constructor
```cpp
x.vptr = &sead::SafeString::vt;
x.cstr = "some string here";
```
⬇️
```cpp
sead::SafeString x = "some string here";
```
Note that the SafeString constructor is also implicitly called whenever a string literal is converted into an sead::SafeString (because it was passed as an argument to a function that expects an sead::SafeString for example).
---
##### `sead::FixedSafeString<N>` constructor
A `sead::FixedSafeString<N>` is a fixed-length SafeString. It derives from sead::BufferedSafeString (which derives from sead::SafeString) and contains a char[N] buffer right after the length.
Note: the field assignments may be in a different order.
```cpp
x._.cstr = (char*)&xxx; // some buffer right after `x`
sead::SafeString::cstr returns a `const char*`, like std::string::c_str. You can expect it to be called whenever a SafeString needs to be passed to a function that takes a C-style string (`const char*`).
```cpp
string.vptr->assureTermination(...);
const char* ptr = string.cstr;
// do stuff with string.cstr
// note that the variable may not exist in the pseudocode
```
⬇️
```cpp
const char* ptr = string.cstr();
```
---
##### sead::SafeString::calcLength
```cpp
x.vptr->assureTermination(&x);
v12 = x.cstr;
str_length = 0LL;
v14 = (signed __int64)(v12 + 1);
while ( v12[str_length] != sead::SafeStringBase<char>::cNullChar )
If each item is a trivially constructible type (e.g. the buffer stores ints or pointers) then there will be no loop that calls a constructor and the compiler will not store the size of the array in the first 8 bytes of the allocation.