#pragma once #include #include template constexpr inline T is_aligned(T value) { return (value % alignment == 0); } static_assert(is_aligned<512>(1024u)); static_assert(!is_aligned<32>(235u)); static_assert(is_aligned<4096>(40960u)); template constexpr inline T align_down(T value) { return value - value % alignment; } static_assert(align_down<512>(598ul) == 512ul); static_assert(align_down<64>(194ul) == 192ul); static_assert(align_down<32>(64ul) == 64ul); template constexpr inline T align_up(T value) { if (is_aligned(value)) return value; return align_down(value) + alignment; } static_assert(align_up<512>(598ul) == 1024ul); static_assert(align_up<64>(194ul) == 256ul); static_assert(align_up<32>(64ul) == 64ul); template constexpr T get_blocks_from_size(T value, T block_size) { return (value + (block_size - 1)) / block_size; } static_assert(get_blocks_from_size(40960, 4096) == 10); static_assert(get_blocks_from_size(194, 64) == 4); static_assert(get_blocks_from_size(2, 32) == 1); static_assert(get_blocks_from_size(0, 256) == 0); // Offset a pointer by exactly bytes, no matter the type. Useful to avoid the quirks that come from C pointer // arithmetic. template constexpr inline T* offset_ptr(T* ptr, Offset offset) { return (T*)((u8*)ptr + offset); }