Merge branch '138-toggle-free-look-with-hotkey' into 'main/atys-live'
[ryzomcore.git] / nel / src / misc / object_arena_allocator.cpp
blobb8aea9adacf0aba8618c6e5d0898da952c9ff840
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdmisc.h"
21 #include "nel/misc/object_arena_allocator.h"
22 #include "nel/misc/fixed_size_allocator.h"
24 #ifdef DEBUG_NEW
25 #define new DEBUG_NEW
26 #endif
28 namespace NLMISC
32 CObjectArenaAllocator *CObjectArenaAllocator::_DefaultAllocator = NULL;
35 // *****************************************************************************************************************
36 CObjectArenaAllocator::CObjectArenaAllocator(uint maxAllocSize, uint granularity /* = 4*/)
38 nlassert(granularity > 0);
39 nlassert(maxAllocSize > 0);
40 _MaxAllocSize = granularity * ((maxAllocSize + (granularity - 1)) / granularity);
41 _ObjectSizeToAllocator.resize(_MaxAllocSize / granularity, NULL);
42 _Granularity = granularity;
43 #ifdef NL_DEBUG
44 _AllocID = 0;
45 _WantBreakOnAlloc = false;
46 _BreakAllocID = 0;
47 #endif
50 // *****************************************************************************************************************
51 CObjectArenaAllocator::~CObjectArenaAllocator()
53 for(uint k = 0; k < _ObjectSizeToAllocator.size(); ++k)
55 delete _ObjectSizeToAllocator[k];
59 // *****************************************************************************************************************
60 void *CObjectArenaAllocator::alloc(uint size)
62 #ifdef NL_DEBUG
63 if (_WantBreakOnAlloc)
65 if (_AllocID == _BreakAllocID)
67 nlassert(0);
70 #endif
71 if (size >= _MaxAllocSize)
73 // use standard allocator
74 nlctassert(NL_DEFAULT_MEMORY_ALIGNMENT >= sizeof(uint));
75 uint8 *block = (uint8 *)aligned_malloc(NL_DEFAULT_MEMORY_ALIGNMENT + (ptrdiff_t)size, NL_DEFAULT_MEMORY_ALIGNMENT); //new uint8[size + sizeof(uint)]; // an additionnal uint is needed to store size of block
76 if (!block) throw std::bad_alloc();
77 #ifdef NL_DEBUG
78 _MemBlockToAllocID[block] = _AllocID;
79 ++_AllocID;
80 #endif
81 *(uint *) block = size;
82 return block + NL_DEFAULT_MEMORY_ALIGNMENT;
84 uint entry = ((size + (_Granularity - 1)) / _Granularity) ;
85 nlassert(entry < _ObjectSizeToAllocator.size());
86 if (!_ObjectSizeToAllocator[entry])
88 _ObjectSizeToAllocator[entry] = new CFixedSizeAllocator(entry * _Granularity + NL_DEFAULT_MEMORY_ALIGNMENT, _MaxAllocSize / size); // an additionnal uint is needed to store size of block
90 void *block = _ObjectSizeToAllocator[entry]->alloc();
91 if (!block) throw std::bad_alloc();
92 nlassert(((uintptr_t)block % NL_DEFAULT_MEMORY_ALIGNMENT) == 0);
93 #ifdef NL_DEBUG
94 _MemBlockToAllocID[block] = _AllocID;
95 ++_AllocID;
96 #endif
97 *(uint *)block = size;
98 return (void *)((uint8 *)block + NL_DEFAULT_MEMORY_ALIGNMENT);
101 // *****************************************************************************************************************
102 void CObjectArenaAllocator::freeBlock(void *block)
104 if (!block) return;
105 uint8 *realBlock = (uint8 *) block - NL_DEFAULT_MEMORY_ALIGNMENT; // sizeof(uint); // a uint is used at start of block to give its size
106 uint size = *(uint *) realBlock;
107 if (size >= _MaxAllocSize)
109 #ifdef NL_DEBUG
110 std::map<void *, uint>::iterator it = _MemBlockToAllocID.find(realBlock);
111 nlassert(it != _MemBlockToAllocID.end());
112 _MemBlockToAllocID.erase(it);
113 #endif
114 aligned_free(realBlock);
115 return;
117 uint entry = ((size + (_Granularity - 1)) / _Granularity);
118 nlassert(entry < _ObjectSizeToAllocator.size());
119 _ObjectSizeToAllocator[entry]->freeBlock(realBlock);
120 #ifdef NL_DEBUG
121 std::map<void *, uint>::iterator it = _MemBlockToAllocID.find(realBlock);
122 nlassert(it != _MemBlockToAllocID.end());
124 #ifdef NL_DEBUG
125 if (_WantBreakOnAlloc)
127 if (it->second == _BreakAllocID)
129 nlassert(0);
132 #endif
134 _MemBlockToAllocID.erase(it);
135 #endif
138 // *****************************************************************************************************************
139 uint CObjectArenaAllocator::getNumAllocatedBlocks() const
141 uint numObjs = 0;
142 for(uint k = 0; k < _ObjectSizeToAllocator.size(); ++k)
144 if (_ObjectSizeToAllocator[k]) numObjs += _ObjectSizeToAllocator[k]->getNumAllocatedBlocks();
146 return numObjs;
149 // *****************************************************************************************************************
150 CObjectArenaAllocator &CObjectArenaAllocator::getDefaultAllocator()
152 if (!_DefaultAllocator)
154 _DefaultAllocator = new CObjectArenaAllocator(32768);
156 return *_DefaultAllocator;
160 #ifdef NL_DEBUG
162 // *****************************************************************************************************************
163 void CObjectArenaAllocator::dumpUnreleasedBlocks()
165 for(std::map<void *, uint>::iterator it = _MemBlockToAllocID.begin(); it != _MemBlockToAllocID.end(); ++it)
167 nlinfo("block %u at adress %p remains", it->second, (static_cast<uint8 *>(it->first) + sizeof(uint)));
171 // *****************************************************************************************************************
172 void CObjectArenaAllocator::setBreakForAllocID(bool enabled, uint id)
174 _WantBreakOnAlloc = enabled;
175 _BreakAllocID = id;
178 #endif // NL_DEBUG
181 } // NLMISC