OpenMoHAA 0.82.0
Loading...
Searching...
No Matches
container.h
1/*
2===========================================================================
3Copyright (C) 2025 the OpenMoHAA team
4
5This file is part of OpenMoHAA source code.
6
7OpenMoHAA source code is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 2 of the License,
10or (at your option) any later version.
11
12OpenMoHAA source code is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with OpenMoHAA source code; if not, write to the Free Software
19Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20===========================================================================
21*/
22
23// container.h: C++ Container
24
25#pragma once
26
27#if defined(GAME_DLL)
28//
29// game dll specific defines
30//
31# include "../fgame/g_local.h"
32
33# define CONTAINER_Error gi.Error
34# define CONTAINER_DPrintf gi.DPrintf
35# define CONTAINER_WDPrintf(text) gi.DPrintf(text)
36# define CONTAINER_Alloc gi.Malloc
37# define CONTAINER_Free gi.Free
38
39#elif defined(CGAME_DLL)
40//
41// cgame dll specific defines
42//
43# include "../cgame/cg_local.h"
44
45# define CONTAINER_Error cgi.Error
46# define CONTAINER_DPrintf cgi.DPrintf
47# define CONTAINER_WDPrintf(text) cgi.DPrintf(text)
48# define CONTAINER_Alloc cgi.Malloc
49# define CONTAINER_Free cgi.Free
50
51#elif defined(REF_DLL)
52
53# include "../renderercommon/tr_common.h"
54
55//
56// client specific defines
57//
58# define CONTAINER_Error Com_Error
59# define CONTAINER_DPrintf Com_DPrintf
60# define CONTAINER_WDPrintf(text) Com_DPrintf(text)
61# define CONTAINER_Alloc ri.Malloc
62# define CONTAINER_Free ri.Free
63
64#else
65
66# include "qcommon.h"
67
68//
69// client specific defines
70//
71# define CONTAINER_Error Com_Error
72# define CONTAINER_DPrintf Com_DPrintf
73# define CONTAINER_WDPrintf(text) Com_DPrintf(text)
74# define CONTAINER_Alloc Z_Malloc
75# define CONTAINER_Free Z_Free
76#endif
77
78#include <utility>
79#include <new>
80
81class Archiver;
82
83template<class Type>
84class Container
85{
86private:
87 Type *objlist;
88 int numobjects;
89 int maxobjects;
90
91private:
92 void Copy(const Container<Type>& container);
93
94public:
95 Container();
96
97 Container(const Container<Type>& container);
98 Container<Type>& operator=(const Container<Type>& container);
99
100 Container(Container<Type>&& container);
101 Container<Type>& operator=(Container<Type>&& container);
102
103 ~Container();
104
105 void Archive(Archiver& arc);
106 void Archive(Archiver& arc, void (*ArchiveFunc)(Archiver& arc, Type *obj));
107
108 int AddObject(const Type& obj);
109 int AddUniqueObject(const Type& obj);
110 void AddObjectAt(int index, const Type& obj);
111 Type *AddressOfObjectAt(int index);
112 void ClearObjectList(void);
113 void FreeObjectList(void);
114 int IndexOfObject(const Type& obj);
115 void InsertObjectAt(int index, const Type& obj);
116 int MaxObjects(void) const;
117 int NumObjects(void) const;
118 Type& ObjectAt(const size_t index) const;
119 bool ObjectInList(const Type& obj);
120 void RemoveObjectAt(int index);
121 void RemoveObject(const Type& obj);
122 void Reset(void);
123 void Resize(int maxelements);
124 void SetObjectAt(int index, const Type& obj);
125 void Sort(int (*compare)(const void *elem1, const void *elem2));
126 Type& operator[](const uintptr_t index) const;
127};
128
129template<class Type>
130Container<Type>::Container()
131{
132 objlist = NULL;
133 numobjects = 0;
134 maxobjects = 0;
135}
136
137template<class Type>
138Container<Type>::Container(const Container<Type>& container)
139{
140 objlist = NULL;
141
142 Copy(container);
143}
144
145template<class Type>
146Container<Type>& Container<Type>::operator=(const Container<Type>& container)
147{
148 Copy(container);
149
150 return *this;
151}
152
153template<class Type>
154Container<Type>::Container(Container<Type>&& container)
155{
156 objlist = container.objlist;
157 numobjects = container.numobjects;
158 maxobjects = container.maxobjects;
159 container.objlist = NULL;
160 container.numobjects = 0;
161 container.maxobjects = 0;
162}
163
164template<class Type>
165Container<Type>& Container<Type>::operator=(Container<Type>&& container)
166{
167 FreeObjectList();
168
169 objlist = container.objlist;
170 numobjects = container.numobjects;
171 maxobjects = container.maxobjects;
172 container.objlist = NULL;
173 container.numobjects = 0;
174 container.maxobjects = 0;
175
176 return *this;
177}
178
179template<class Type>
180Container<Type>::~Container()
181{
182 FreeObjectList();
183}
184
185template<class Type>
186int Container<Type>::AddObject(const Type& obj)
187{
188 if (!objlist) {
189 Resize(10);
190 }
191
192 if (numobjects >= maxobjects) {
193 Resize(numobjects * 2);
194 }
195
196 new (objlist + numobjects) Type(obj);
197 numobjects++;
198
199 return numobjects;
200}
201
202template<class Type>
203int Container<Type>::AddUniqueObject(const Type& obj)
204{
205 int index;
206
207 index = IndexOfObject(obj);
208
209 if (!index) {
210 index = AddObject(obj);
211 }
212
213 return index;
214}
215
216template<class Type>
217void Container<Type>::AddObjectAt(int index, const Type& obj)
218{
219 int i;
220
221 if (index > maxobjects) {
222 Resize(index);
223 }
224
225 if (index > numobjects) {
226 for (i = numobjects; i < index; i++) {
227 new (objlist + i) Type();
228 }
229
230 numobjects = index;
231 }
232
233 SetObjectAt(index, obj);
234}
235
236template<class Type>
237Type *Container<Type>::AddressOfObjectAt(int index)
238{
239 if (index > maxobjects) {
240 CONTAINER_Error(ERR_DROP, "Container::AddressOfObjectAt : index is greater than maxobjects");
241 }
242
243 if (index > numobjects) {
244 numobjects = index;
245 }
246
247 return &objlist[index - 1];
248}
249
250template<class Type>
251void Container<Type>::ClearObjectList(void)
252{
253 size_t i;
254
255 if (objlist && numobjects) {
256 for (i = 0; i < numobjects; ++i) {
257 objlist[i].~Type();
258 }
259
260 // don't free the object list, it can be reused later
261 numobjects = 0;
262 }
263}
264
265template<class Type>
266void Container<Type>::FreeObjectList(void)
267{
268 size_t i;
269
270 if (objlist) {
271 for (i = 0; i < numobjects; ++i) {
272 objlist[i].~Type();
273 }
274
275 CONTAINER_Free(objlist);
276 }
277
278 objlist = NULL;
279 numobjects = 0;
280 maxobjects = 0;
281}
282
283template<class Type>
284int Container<Type>::IndexOfObject(const Type& obj)
285{
286 int i;
287
288 if (!objlist) {
289 return 0;
290 }
291
292 for (i = 0; i < numobjects; i++) {
293 if (objlist[i] == obj) {
294 return i + 1;
295 }
296 }
297
298 return 0;
299}
300
301template<class Type>
302void Container<Type>::InsertObjectAt(int index, const Type& obj)
303{
304 size_t i;
305
306 if ((index <= 0) || (index > numobjects + 1)) {
307 CONTAINER_Error(ERR_DROP, "Container::InsertObjectAt : index out of range");
308 return;
309 }
310
311 numobjects++;
312 intptr_t arrayIndex = index - 1;
313
314 if (numobjects > maxobjects) {
315 maxobjects = numobjects;
316 if (!objlist) {
317 objlist = (Type *)CONTAINER_Alloc(sizeof(Type) * maxobjects);
318
319 for (i = 0; i < arrayIndex; ++i) {
320 new (objlist + i) Type();
321 }
322
323 new (objlist + arrayIndex) Type(obj);
324 } else {
325 Type *temp = objlist;
326 if (maxobjects < numobjects) {
327 maxobjects = numobjects;
328 }
329
330 objlist = (Type *)CONTAINER_Alloc(sizeof(Type) * maxobjects);
331
332 for (i = 0; i < arrayIndex; ++i) {
333 new (objlist + i) Type(std::move(temp[i]));
334 }
335
336 new (objlist + arrayIndex) Type(obj);
337 for (i = arrayIndex; i < numobjects - 1; ++i) {
338 new (objlist + i + 1) Type(std::move(temp[i]));
339 }
340
341 CONTAINER_Free(temp);
342 }
343 } else {
344 for (i = numobjects - 1; i > arrayIndex; i--) {
345 objlist[i] = std::move(objlist[i - 1]);
346 }
347 objlist[arrayIndex] = obj;
348 }
349}
350
351template<class Type>
352int Container<Type>::MaxObjects(void) const
353{
354 return maxobjects;
355}
356
357template<class Type>
358int Container<Type>::NumObjects(void) const
359{
360 return numobjects;
361}
362
363template<class Type>
364Type& Container<Type>::ObjectAt(const size_t index) const
365{
366 if ((index <= 0) || (index > numobjects)) {
367 CONTAINER_Error(ERR_DROP, "Container::ObjectAt : index out of range");
368 }
369
370 return objlist[index - 1];
371}
372
373template<class Type>
374bool Container<Type>::ObjectInList(const Type& obj)
375{
376 if (!IndexOfObject(obj)) {
377 return false;
378 }
379
380 return true;
381}
382
383template<class Type>
384void Container<Type>::RemoveObjectAt(int index)
385{
386 int i;
387
388 if (!objlist) {
389 return;
390 }
391
392 if ((index <= 0) || (index > numobjects)) {
393 return;
394 }
395
396 i = index - 1;
397 numobjects--;
398
399 for (i = index - 1; i < numobjects; i++) {
400 objlist[i] = std::move(objlist[i + 1]);
401 }
402
403 // Destroy the last object as it's now useless
404 objlist[numobjects].~Type();
405}
406
407template<class Type>
408void Container<Type>::RemoveObject(const Type& obj)
409{
410 int index;
411
412 index = IndexOfObject(obj);
413
414 assert(index);
415 if (!index) {
416 CONTAINER_WDPrintf("Container::RemoveObject : Object not in list\n");
417 return;
418 }
419
420 RemoveObjectAt(index);
421}
422
423template<class Type>
424void Container<Type>::Reset()
425{
426 objlist = NULL;
427 numobjects = 0;
428 maxobjects = 0;
429}
430
431template<class Type>
432void Container<Type>::Resize(int maxelements)
433{
434 Type *temp;
435 size_t i;
436
437 if (maxelements <= 0) {
438 FreeObjectList();
439 return;
440 }
441
442 if (!objlist) {
443 maxobjects = maxelements;
444 objlist = (Type *)CONTAINER_Alloc(sizeof(Type) * maxobjects);
445 } else {
446 temp = objlist;
447
448 maxobjects = maxelements;
449
450 if (maxobjects < numobjects) {
451 maxobjects = numobjects;
452 }
453
454 objlist = (Type *)CONTAINER_Alloc(sizeof(Type) * maxobjects);
455
456 for (i = 0; i < numobjects; i++) {
457 // move the older type
458 new (objlist + i) Type(std::move(temp[i]));
459
460 // destruct the older type
461 temp[i].~Type();
462 }
463
464 CONTAINER_Free(temp);
465 }
466}
467
468template<class Type>
469void Container<Type>::SetObjectAt(int index, const Type& obj)
470{
471 if (!objlist) {
472 return;
473 }
474
475 if ((index <= 0) || (index > numobjects)) {
476 CONTAINER_Error(ERR_DROP, "Container::SetObjectAt : index out of range");
477 }
478
479 objlist[index - 1] = obj;
480}
481
482template<class Type>
483void Container<Type>::Sort(int (*compare)(const void *elem1, const void *elem2))
484{
485 if (!objlist) {
486 return;
487 }
488
489 qsort((void *)objlist, (size_t)numobjects, sizeof(Type), compare);
490}
491
492template<class Type>
493Type& Container<Type>::operator[](const uintptr_t index) const
494{
495 return ObjectAt(index + 1);
496}
497
498template<class Type>
499void Container<Type>::Copy(const Container<Type>& container)
500{
501 int i;
502
503 if (&container == this) {
504 return;
505 }
506
507 FreeObjectList();
508
509 numobjects = container.numobjects;
510 maxobjects = container.maxobjects;
511 objlist = NULL;
512
513 if (container.objlist == NULL || !container.maxobjects) {
514 return;
515 }
516
517 Resize(maxobjects);
518
519 if (!container.numobjects) {
520 return;
521 }
522
523 for (i = 0; i < container.numobjects; i++) {
524 new(objlist + i) Type(container.objlist[i]);
525 }
526
527 return;
528}
529
530template<typename T>
531void *operator new(size_t count, Container<T>& container)
532{
533 (void)count;
534
535 assert(count == sizeof(T));
536 return &container.ObjectAt(container.AddObject());
537}
538
539template<typename T>
540void operator delete(void *ptr, Container<T>& container)
541{
542 container.RemoveObject((T *)ptr);
543}
Definition archive.h:86
Definition container.h:85