summaryrefslogtreecommitdiff
path: root/code/amr_memory.c
blob: f92f14af6b50a1bb2f0dc7a516836d6f97f82601 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "amr_memory.h"

bool amr_IsPowerOfTwo(uintptr_t x)
{
  return (x & (x-1)) == 0;
}

uintptr_t amr_AlignForward(uintptr_t ptr, size_t align)
{
  uintptr_t p, a, modulo;

  assert(amr_IsPowerOfTwo(align));

  p = ptr;
  a = (uintptr_t)align;
  modulo = p & (a-1);

  if (modulo != 0)
  {
    p += a - modulo;
  }
  return p;
}

void *amr_ArenaAllocAlign(amr_DebugArena *Alloc, size_t Size, size_t Align)
{
  uintptr_t CurrOffset = (uintptr_t)Alloc->Buffer + (uintptr_t)Alloc->CurrOffset;
  uintptr_t AlignedOffset = amr_AlignForward(CurrOffset, Align);
  AlignedOffset -= (uintptr_t)(Alloc->Buffer);

  if (AlignedOffset + Size < Alloc->Size)
  {
    void *Ptr = &Alloc->Buffer[AlignedOffset];
    Alloc->PrevOffset = AlignedOffset;
    Alloc->CurrOffset = AlignedOffset + Size;

    PlatformZeroMemory(Ptr, Size);
    return Ptr;
  }
  return NULL;
}

void amr_ArenaInit(amr_DebugArena *Alloc, void* BackingBuffer, size_t Size)
{
  Alloc->Buffer = (u8 *)BackingBuffer;
  Alloc->Size = Size;
  Alloc->CurrOffset = 0;
  Alloc->PrevOffset = 0;
}

void *amr_ArenaAlloc(amr_DebugArena *Alloc, size_t Size)
{
  return amr_ArenaAllocAlign(Alloc, Size, DEFAULT_ALIGNMENT);
}

void amr_ArenaFree(amr_DebugArena *Alloc, void *Ptr)
{
  // @note: Arenas do not support freeing memory
  // this is here to let me know I have not forgotten to implement it
  return;
}

void *amr_ArenaResizeAlign(amr_DebugArena *Alloc, void *OldMem, size_t OldSize,
                        size_t NewSize, size_t Align)
{
  assert(amr_IsPowerOfTwo(Align));
  if (OldMem == NULL || OldSize == 0)
  {
    return amr_ArenaAllocAlign(Alloc, NewSize, Align);
  }
  else if (Alloc->Buffer < OldMem && OldMem < Alloc->Buffer + Alloc->Size)
  {
    // check if old_memory falls on prev_offset
    if (Alloc->Buffer + Alloc->PrevOffset == OldMem)
    {
      // re-use prev_offset and resize from there
      size_t _CurrOffset = Alloc->CurrOffset;
      Alloc->CurrOffset = Alloc->PrevOffset + NewSize;
      if (NewSize > OldSize)
      {
        PlatformZeroMemory(&Alloc->Buffer[_CurrOffset], NewSize - OldSize); 
      }
      return OldMem;
    }
    else
    {
      // generate new memory
      // will have some fragmentation
      void *NewMem = amr_ArenaAllocAlign(Alloc, NewSize, Align);
      size_t CopySize = OldSize < NewSize ? OldSize : NewSize;

      // copy old memory to new memory location
      PlatformCopyMemory(NewMem, OldMem, CopySize);
      return NewMem;
    }
  }
  else
  {
    assert(0 && "Memory is out of bounds of the buffer in this arena");
    return NULL;
  }
}

void *amr_ArenaResize(amr_DebugArena *Alloc, void *OldMem, size_t OldSize, size_t NewSize)
{
  return amr_ArenaResizeAlign(Alloc, OldMem, OldSize, NewSize, DEFAULT_ALIGNMENT);
}

void amr_ArenaFreeAll(amr_DebugArena *Alloc)
{
  Alloc->CurrOffset = 0;
  Alloc->PrevOffset = 0;
}