C++ Tricks
Call constructor on already allocated memory #
#include <new>
Foo* foo = new (your_memory_address_here) Foo ();
Memory Stripes #
#include <stdio.h>
#include <cstdlib>
struct v3 {
float x, y, z;
v3() : x(1), y(2), z(3) {}
};
v3* p_arr;
const int count = 10;
int main(int argc, const char* argv[]) {
p_arr = new v3[count];
srand(1);
const int stride = 3;
float* p_x = &p_arr->x;
float* p_y = &p_arr->y;
float* p_z = &p_arr->z;
for (int i = 0; i < count; i ++)
{
int idx = i * stride;
printf("%f, %f, %f \n", p_x[idx], p_y[idx], p_z[idx]);
}
printf("- - - - - -\n");
for (int i = 0, l = count * stride; i < l; i += stride) {
printf("%f, %f, %f \n", p_x[i], p_y[i], p_z[i]);
}
delete[] p_arr;
return 0;
}
Currying with std::bind #
void my_function(int x, int y, int z) {
printf("Called my_function with (%d, %d, %d)\n", x, y, z);
}
int main () {
my_function(1, 2, 3);
auto my_function2 = std::bind(my_function, 1, std::placeholders::_1, std::placeholders::_2);
my_function2(77, 666);
auto my_function3 = std::bind(my_function2, std::placeholders::_1, 666);
my_function3(88);
auto my_function4 = std::bind(my_function, 1, std::placeholders::_1, 999);
my_function4(6969696);
}
Bit shifting union #
struct Color
{
union
{
unsigned int RGBA = 0;
struct {
unsigned char A;
unsigned char B;
unsigned char G;
unsigned char R;
};
};
};
Color c;
c.R = 166;
c.G = 44;
c.B = 22;
c.A = 255;
printf("RGBA: %d\n", c.RGBA);
unsigned char Rout = (c.RGBA & 0xff000000) >> 24;
unsigned char Gout = (c.RGBA & 0x00ff0000) >> 16;
unsigned char Bout = (c.RGBA & 0x0000ff00) >> 8;
unsigned char Aout = (c.RGBA & 0x000000ff) >> 0;
printf("R: %d => %d\n", c.R, Rout);
printf("G: %d => %d\n", c.G, Gout);
printf("B: %d => %d\n", c.B, Bout);
printf("A: %d => %d\n", c.A, Aout);
c.RGBA = 0x0;
c.RGBA = 0x110011ff;
printf("R: %d\n", c.R);
printf("G: %d\n", c.G);
printf("B: %d\n", c.B);
printf("A: %d\n", c.A);
Bitmasks #
Bitmasking is a technique used to perform operations at the bit level. Leveraging bitmasks often leads to faster runtime complexity and helps limit memory usage
- Test kth bit: s & (1 << k);
- Set kth bit: s |= (1 << k);
- Turn off kth bit: s &= ~(1 << k);
- Toggle kth bit: s ^= (1 << k);
- Multiple by 2n: s << n;
- Divide by 2n: s >> n;
- Intersection: s & t;
- Union: s | t;
- Set Subtraction: s & ~t;
- Extract lowest set bit: s & (-s);
- Extract lowest unset bit: ~s & (s + 1);
- Swap Values: x ^= y; y ^= x; x ^= y;
Align memory on boundary #
inline uint32 Align256( uint32 memory_size ) {
return ( memory_size + 255 ) & ~255;
}
inline uint32 Align16( uint32 memory_size ) {
return ( memory_size + 15 ) & ~15;
}
#define __align_16 __declspec(align(16))
__align_16 struct my_struct {
float x, y, z, w;
};
struct my_struct_2 {
float x, y, z, w;
} __align_16;
Calculate Mip Map Count #
uint32 CalculateMipMapLevels( uint32 width, uint32 height ) {
return 1 + static_cast<uint32>(floor(log2(std::max(width, height))));
}
Member offset in bytes #
struct Test {
float x, z, y;
};
auto offset_in_bytes = unsigned int(&(((Test*)0)->z));
Negative int indexing #
- Use positive/negative int32 values in same field to represent different meanings
- Negative index (-1 remaps to start at 0)
int32_t Index = -1;
int32_t NegativeIndex = (-1 -Index);
int32_t NegativeIndex = ~Index;