• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NeonGE / geEngineSDK / 22732298543

05 Mar 2026 07:06PM UTC coverage: 57.834% (-0.08%) from 57.909%
22732298543

push

github

NeonGE
Make core classes final, modernize lambdas and destructors

Refactored several classes to be final and updated destructors to use override for safer inheritance. Switched event signal lambdas in main.cpp to non-capturing for improved safety and efficiency. Annotated ImGuiPlatform member with GE_NO_UNIQUE_ADDRESS for potential memory optimization. Used C++20 map contains in FileTracker for cleaner code. These changes enhance code safety, clarity, and performance.

Make classes final, clean up destructors, improve safety

Refactored several classes to be final and removed unnecessary virtual destructors, marking them override where appropriate. Updated event signal lambdas in main.cpp to be non-capturing for better performance and safety. Annotated ImGuiPlatform with GE_NO_UNIQUE_ADDRESS for potential memory optimizations. Switched to C++20 map contains in geFileTracker.h when available. In geFrameAlloc.cpp, allocation functions now safely return nullptr if m_freeBlock is null, improving robustness.

0 of 8 new or added lines in 4 files covered. (0.0%)

6 existing lines in 2 files now uncovered.

5607 of 9695 relevant lines covered (57.83%)

9096.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/sdk/geUtilities/src/geFrameAlloc.cpp
1
/*****************************************************************************/
2
/**
3
 * @file    geFrameAlloc.cpp
4
 * @author  Samuel Prince (samuel.prince.quezada@gmail.com)
5
 * @date    2016/03/06
6
 * @brief   Frame allocator
7
 *
8
 * Performs very fast allocations but can only free all of its memory at once.
9
 * Perfect for allocations that last just a single frame.
10
 *
11
 * @bug     No known bugs.
12
 */
13
/*****************************************************************************/
14

15
/*****************************************************************************/
16
/**
17
 * Includes
18
 */
19
/*****************************************************************************/
20
#include "gePrerequisitesUtilities.h"
21
#include "geFrameAlloc.h"
22
#include "geException.h"
23

24
namespace geEngineSDK {
25
  byte*
26
  FrameAlloc::MemBlock::alloc(SIZE_T amount) {
×
27
    byte* freePtr = &m_data[m_freePtr];
×
28
    m_freePtr += amount;
×
29
    return freePtr;
×
30
  }
31

32
  void
33
  FrameAlloc::MemBlock::clear() {
×
34
    m_freePtr = 0;
×
35
  }
×
36

37
#if USING(GE_DEBUG_MODE)
38
  FrameAlloc::FrameAlloc(SIZE_T blockSize)
39
    : m_blockSize(blockSize),
40
      m_freeBlock(nullptr),
41
      m_nextBlockIdx(0),
42
      m_totalAllocBytes(0),
43
      m_lastFrame(nullptr)
44
  {}
45
#else
46
  FrameAlloc::FrameAlloc(SIZE_T blockSize)
×
47
    : m_blockSize(blockSize),
×
48
      m_freeBlock(nullptr),
×
49
      m_nextBlockIdx(0),
×
50
      m_totalAllocBytes(0),
×
51
      m_lastFrame(nullptr)
×
52
  {}
×
53
#endif
54

55
  FrameAlloc::~FrameAlloc() {
×
56
    for (auto& block : m_blocks) {
×
57
      deallocBlock(block);
×
58
    }
59
  }
×
60

61
  byte*
62
  FrameAlloc::alloc(SIZE_T amount) {
×
NEW
63
    if (!m_freeBlock) {
×
NEW
64
      return nullptr;
×
65
    }
66
    GE_DEBUG_ONLY(amount += sizeof(SIZE_T));
67

68
    SIZE_T freeMem = 0;
×
69
    freeMem = m_freeBlock->m_size - m_freeBlock->m_freePtr;
×
70

71
    if (amount > freeMem) {
×
72
      allocBlock(amount);
×
73
    }
74

75
    byte* data = m_freeBlock->alloc(amount);
×
76

77
#if USING(GE_DEBUG_MODE)
78
    m_totalAllocBytes += amount;
79

80
    SIZE_T* storedSize = reinterpret_cast<SIZE_T*>(data);
81
    *storedSize = amount;
82

83
    return data + sizeof(SIZE_T);
84
#else
85
    return data;
×
86
#endif
87
  }
88

89
  byte*
90
  FrameAlloc::allocAligned(SIZE_T amount, SIZE_T alignment) {
×
NEW
91
    if (!m_freeBlock) {
×
NEW
92
      return nullptr;
×
93
    }
94
    GE_DEBUG_ONLY(amount += sizeof(SIZE_T));
95

96
    SIZE_T freeMem = 0;
×
97
    SIZE_T freePtr = 0;
×
98
    freeMem = m_freeBlock->m_size - m_freeBlock->m_freePtr;
×
99
#if USING(GE_DEBUG_MODE)
100
    freePtr = m_freeBlock->m_freePtr + sizeof(SIZE_T);
101
#else
102
    freePtr = m_freeBlock->m_freePtr;
×
103
#endif
104

105
    SIZE_T alignOffset = (alignment - (freePtr & (alignment - 1))) & (alignment - 1);
×
106
    if ((amount + alignOffset) > freeMem) {
×
107
      //New blocks are allocated on a 16 byte boundary, ensure enough space is
108
      //allocated taking into account the requested alignment
109

110
#if USING(GE_DEBUG_MODE)
111
      alignOffset = (alignment - (sizeof(SIZE_T) & (alignment - 1))) & (alignment - 1);
112
#else
113
      if (16 < alignment) {
×
114
        alignOffset = alignment - 16;
×
115
      }
116
      else {
117
        alignOffset = 0;
×
118
      }
119
#endif
120
      allocBlock(amount + alignOffset);
×
121
    }
122

123
    amount += alignOffset;
×
124
    byte* data = m_freeBlock->alloc(amount);
×
125

126
#if USING(GE_DEBUG_MODE)
127
    m_totalAllocBytes += amount;
128

129
    auto storedSize = reinterpret_cast<SIZE_T*>(data + alignOffset);
130
    *storedSize = amount;
131

132
    return data + sizeof(SIZE_T) + alignOffset;
133
#else
134
    return data + alignOffset;
×
135
#endif
136
  }
137

138
  void
139
  FrameAlloc::free(byte* data) {
×
140
    //Dealloc is only used for debug and can be removed if needed.
141
    //All the actual deallocation happens in clear()
142
#if USING(GE_DEBUG_MODE)
143
    if (data) {
144
      data -= sizeof(SIZE_T);
145
      auto storedSize = reinterpret_cast<SIZE_T*>(data);
146
      m_totalAllocBytes -= *storedSize;
147
    }
148
#else
149
    GE_UNREFERENCED_PARAMETER(data);
150
#endif
151
  }
×
152

153
  void
154
  FrameAlloc::markFrame() {
×
155
    auto framePtr = reinterpret_cast<void**>(alloc(sizeof(void*)));
×
156
    *framePtr = m_lastFrame;
×
157
    m_lastFrame = framePtr;
×
158
  }
×
159

160
  void
161
  FrameAlloc::clear() {
×
162
    if (nullptr != m_lastFrame) {
×
163
      GE_ASSERT(m_blocks.size() > 0 && 0 < m_nextBlockIdx);
164

165
      free(reinterpret_cast<byte*>(m_lastFrame));
×
166

167
      auto framePtr = reinterpret_cast<byte*>(m_lastFrame);
×
168
      m_lastFrame = *reinterpret_cast<void**>(m_lastFrame);
×
169

170
      GE_DEBUG_ONLY(framePtr -= sizeof(SIZE_T));
171

172
      uint32 startBlockIdx = m_nextBlockIdx - 1;
×
173
      uint32 numFreedBlocks = 0;
×
174
      for (int32 i = int32(startBlockIdx); i >= 0; --i) {
×
175
        uint32 index = static_cast<uint32>(i);
×
176
        MemBlock* curBlock = m_blocks[index];
×
177
        byte* blockEnd = curBlock->m_data + curBlock->m_size;
×
178
        if (framePtr >= curBlock->m_data && framePtr < blockEnd) {
×
179
          byte* dataEnd = curBlock->m_data + curBlock->m_freePtr;
×
180
          auto sizeInBlock = static_cast<SIZE_T>(dataEnd - framePtr);
×
181
          GE_ASSERT(sizeInBlock <= curBlock->m_freePtr);
182

183
          curBlock->m_freePtr -= sizeInBlock;
×
184
          if (0 == curBlock->m_freePtr) {
×
185
            ++numFreedBlocks;
×
186

187
            //Reset block counter if we're gonna reallocate this one
188
            if (1 < numFreedBlocks) {
×
189
              m_nextBlockIdx = static_cast<uint32>(i);
×
190
            }
191
          }
192

193
          break;
×
194
        }
195
        else {
196
          curBlock->m_freePtr = 0;
×
197
          m_nextBlockIdx = static_cast<uint32>(i);
×
198
          ++numFreedBlocks;
×
199
        }
200
      }
201

202
      if (1 < numFreedBlocks) {
×
203
        SIZE_T totalBytes = 0;
×
204
        for (uint32 i = 0; i < numFreedBlocks; ++i) {
×
205
          MemBlock* curBlock = m_blocks[m_nextBlockIdx];
×
206
          totalBytes += curBlock->m_size;
×
207

208
          deallocBlock(curBlock);
×
209
          m_blocks.erase(m_blocks.begin() + m_nextBlockIdx);
×
210
        }
211

212
        uint32 oldNextBlockIdx = m_nextBlockIdx;
×
213
        allocBlock(totalBytes);
×
214

215
        /** Point to the first non-full block, or if none available then point
216
         the the block we just allocated */
217
        if (0 < oldNextBlockIdx) {
×
218
          m_freeBlock = m_blocks[oldNextBlockIdx - 1];
×
219
        }
220
      }
221
      else {
222
        m_freeBlock = m_blocks[m_nextBlockIdx - 1];
×
223
      }
224
    }
225
    else {
226
#if USING(GE_DEBUG_MODE)
227
      if (m_totalAllocBytes.load() > 0) {
228
        GE_EXCEPT(InvalidStateException,
229
                  "Not all frame allocated bytes were properly released.");
230
      }
231
#endif
232
      if (m_blocks.size() > 1) {
×
233
        //Merge all blocks into one
234
        SIZE_T totalBytes = 0;
×
235
        for (auto& block : m_blocks) {
×
236
          totalBytes += block->m_size;
×
237
          deallocBlock(block);
×
238
        }
239

240
        m_blocks.clear();
×
241
        m_nextBlockIdx = 0;
×
242

243
        allocBlock(totalBytes);
×
244
      }
245
      else if (!m_blocks.empty()) {
×
246
        m_blocks[0]->m_freePtr = 0;
×
247
      }
248
    }
249
  }
×
250

251
  FrameAlloc::MemBlock*
252
  FrameAlloc::allocBlock(SIZE_T wantedSize) {
×
253
    SIZE_T blockSize = m_blockSize;
×
254
    if (wantedSize > blockSize) {
×
255
      blockSize = wantedSize;
×
256
    }
257

258
    MemBlock* newBlock = nullptr;
×
259
    while (m_nextBlockIdx < m_blocks.size()) {
×
260
      MemBlock* curBlock = m_blocks[m_nextBlockIdx];
×
261
      if (blockSize <= curBlock->m_size) {
×
262
        newBlock = curBlock;
×
263
        ++m_nextBlockIdx;
×
264
        break;
×
265
      }
266
      else {
267
        //Found an empty block that doesn't fit our data, delete it
268
        deallocBlock(curBlock);
×
269
        m_blocks.erase(m_blocks.begin() + m_nextBlockIdx);
×
270
      }
271
    }
272

273
    if (nullptr == newBlock) {
×
274
      SIZE_T alignOffset = 16 - (sizeof(MemBlock) & (16 - 1));
×
275

276
      auto data = reinterpret_cast<byte*>(ge_alloc_aligned16(blockSize +
×
277
                                                              sizeof(MemBlock) +
×
278
                                                              alignOffset));
279
      newBlock = new (data) MemBlock(blockSize);
×
280
      data += sizeof(MemBlock) + alignOffset;
×
281
      newBlock->m_data = data;
×
282

283
      m_blocks.push_back(newBlock);
×
284
      ++m_nextBlockIdx;
×
285
    }
286

287
    //If previous block had some empty space it is lost until next "clear"
288
    m_freeBlock = newBlock;
×
289

290
    return newBlock;
×
291
  }
292

293
  void
294
  FrameAlloc::deallocBlock(MemBlock* block) {
×
295
    block->~MemBlock();
×
296
    ge_free_aligned16(block);
×
297
  }
×
298

299
  void
300
  FrameAlloc::setOwnerThread(ThreadId /*thread*/) {}
×
301

302
  GE_THREADLOCAL FrameAlloc* _globalFrameAlloc = nullptr;
303

304
  FrameAlloc&
305
  g_frameAlloc() {
×
306
    if (nullptr == _globalFrameAlloc) {
×
307
      //Note: This will leak memory but since it should exist throughout the
308
      //entirety of runtime it should only leak on shutdown when the OS will
309
      //free it anyway.
310
      _globalFrameAlloc = new FrameAlloc();
×
311
    }
312

313
    return *_globalFrameAlloc;
×
314
  }
315

316
  byte*
317
  ge_frame_alloc(SIZE_T numBytes) {
×
318
    return g_frameAlloc().alloc(numBytes);
×
319
  }
320

321
  byte*
322
  ge_frame_alloc_aligned(SIZE_T count, SIZE_T align) {
×
323
    return g_frameAlloc().allocAligned(count, align);
×
324
  }
325

326
  void
327
  ge_frame_free(void* data) {
×
328
    g_frameAlloc().free(reinterpret_cast<byte*>(data));
×
329
  }
×
330

331
  void
332
  ge_frame_free_aligned(void* data) {
×
333
    g_frameAlloc().free(reinterpret_cast<byte*>(data));
×
334
  }
×
335

336
  void
337
  ge_frame_mark() {
×
338
    g_frameAlloc().markFrame();
×
339
  }
×
340

341
  void
342
  ge_frame_clear() {
×
343
    g_frameAlloc().clear();
×
344
  }
×
345
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc