bump-allocator.hpp 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #pragma once
  2. namespace nall {
  3. struct bump_allocator {
  4. static constexpr uint32_t executable = 1 << 0;
  5. static constexpr uint32_t zero_fill = 1 << 1;
  6. ~bump_allocator() {
  7. reset();
  8. }
  9. explicit operator bool() const {
  10. return _memory;
  11. }
  12. auto reset() -> void {
  13. free(_memory);
  14. _memory = nullptr;
  15. }
  16. auto resize(uint32_t capacity, uint32_t flags = 0) -> bool {
  17. reset();
  18. _offset = 0;
  19. _capacity = capacity + 4095 & ~4095; //alignment
  20. _memory = (uint8_t*)malloc(_capacity);
  21. if(!_memory) return false;
  22. if(flags & executable) {
  23. #if defined(PLATFORM_WINDOWS)
  24. DWORD privileges;
  25. VirtualProtect((void*)_memory, _capacity, PAGE_EXECUTE_READWRITE, &privileges);
  26. #else
  27. mprotect(_memory, _capacity, PROT_READ | PROT_WRITE | PROT_EXEC);
  28. #endif
  29. }
  30. if(flags & zero_fill) {
  31. memset(_memory, 0x00, _capacity);
  32. }
  33. return true;
  34. }
  35. //release all acquired memory
  36. auto release(uint32_t flags = 0) -> void {
  37. _offset = 0;
  38. if(flags & zero_fill) memset(_memory, 0x00, _capacity);
  39. }
  40. auto capacity() const -> uint32_t {
  41. return _capacity;
  42. }
  43. auto available() const -> uint32_t {
  44. return _capacity - _offset;
  45. }
  46. //for allocating blocks of known size
  47. auto acquire(uint32_t size) -> uint8_t* {
  48. #ifdef DEBUG
  49. struct out_of_memory {};
  50. if((_offset + size + 15 & ~15) > _capacity) throw out_of_memory{};
  51. #endif
  52. auto memory = _memory + _offset;
  53. _offset = _offset + size + 15 & ~15; //alignment
  54. return memory;
  55. }
  56. //for allocating blocks of unknown size (eg for a dynamic recompiler code block)
  57. auto acquire() -> uint8_t* {
  58. #ifdef DEBUG
  59. struct out_of_memory {};
  60. if(_offset > _capacity) throw out_of_memory{};
  61. #endif
  62. return _memory + _offset;
  63. }
  64. //size can be reserved once the block size is known
  65. auto reserve(uint32_t size) -> void {
  66. #ifdef DEBUG
  67. struct out_of_memory {};
  68. if((_offset + size + 15 & ~15) > _capacity) throw out_of_memory{};
  69. #endif
  70. _offset = _offset + size + 15 & ~15; //alignment
  71. }
  72. private:
  73. uint8_t* _memory = nullptr;
  74. uint32_t _capacity = 0;
  75. uint32_t _offset = 0;
  76. };
  77. }