1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "memheap.h"
4
5#include <base/math.h>
6#include <base/system.h>
7
8#include <cstdint>
9#include <cstdlib>
10
11// allocates a new chunk to be used
12void CHeap::NewChunk(size_t ChunkSize)
13{
14 // the chunk structure is located in the beginning of the chunk
15 // init it and return the chunk
16 CChunk *pChunk = static_cast<CChunk *>(malloc(size: sizeof(CChunk) + ChunkSize));
17 if(!pChunk)
18 return;
19 pChunk->m_pMemory = static_cast<char *>(static_cast<void *>(pChunk + 1));
20 pChunk->m_pCurrent = pChunk->m_pMemory;
21 pChunk->m_pEnd = pChunk->m_pMemory + ChunkSize;
22 pChunk->m_pNext = nullptr;
23
24 pChunk->m_pNext = m_pCurrent;
25 m_pCurrent = pChunk;
26}
27
28//****************
29void *CHeap::AllocateFromChunk(unsigned int Size, unsigned Alignment)
30{
31 size_t Offset = reinterpret_cast<uintptr_t>(m_pCurrent->m_pCurrent) % Alignment;
32 if(Offset)
33 Offset = Alignment - Offset;
34
35 // check if we need can fit the allocation
36 if(m_pCurrent->m_pCurrent + Offset + Size > m_pCurrent->m_pEnd)
37 return nullptr;
38
39 // get memory and move the pointer forward
40 char *pMem = m_pCurrent->m_pCurrent + Offset;
41 m_pCurrent->m_pCurrent += Offset + Size;
42 return pMem;
43}
44
45// creates a heap
46CHeap::CHeap()
47{
48 m_pCurrent = nullptr;
49 Reset();
50}
51
52CHeap::~CHeap()
53{
54 Clear();
55}
56
57void CHeap::Reset()
58{
59 Clear();
60 NewChunk(ChunkSize: CHUNK_SIZE);
61}
62
63// destroys the heap
64void CHeap::Clear()
65{
66 while(m_pCurrent)
67 {
68 CChunk *pNext = m_pCurrent->m_pNext;
69 free(ptr: m_pCurrent);
70 m_pCurrent = pNext;
71 }
72}
73
74//
75void *CHeap::Allocate(unsigned Size, unsigned Alignment)
76{
77 // try to allocate from current chunk
78 void *pMem = AllocateFromChunk(Size, Alignment);
79 if(!pMem)
80 {
81 // allocate new chunk and add it to the heap
82 NewChunk(ChunkSize: maximum<size_t>(a: CHUNK_SIZE, b: Size + Alignment));
83
84 // try to allocate again
85 pMem = AllocateFromChunk(Size, Alignment);
86 }
87
88 return pMem;
89}
90
91const char *CHeap::StoreString(const char *pSrc)
92{
93 const int Size = str_length(str: pSrc) + 1;
94 char *pMem = static_cast<char *>(Allocate(Size));
95 str_copy(dst: pMem, src: pSrc, dst_size: Size);
96 return pMem;
97}
98