OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4IDList.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* At static list of C4IDs */
19 
20 #include "C4Include.h"
21 #include "object/C4IDList.h"
22 
23 #include "object/C4Def.h"
24 #include "object/C4DefList.h"
26 #include "graphics/C4Draw.h"
27 
29 {
30  // prepare list
31  pNext=nullptr;
32 }
33 
35 {
36  // empty the list
37  Clear();
38 }
39 
41 {
42  // kill all chunks
43  C4IDListChunk *pChunk=pNext,*pChunk2;
44  while (pChunk)
45  {
46  pChunk2=pChunk->pNext; pChunk->pNext=nullptr;
47  delete pChunk; pChunk=pChunk2;
48  }
49  pNext=nullptr;
50 }
51 
53 {
54  Default();
55 }
56 
58 {
59  Default();
60  *this = rCopy;
61 }
62 
64 {
65  // clear previous list
66  Clear();
67  // copy primary
68  memcpy(this, &rCopy, sizeof(C4IDList));
69  // copy all chunks
70  C4IDListChunk *pTo=this;
71  for (C4IDListChunk *pFrom=rCopy.pNext; pFrom; pFrom=pFrom->pNext)
72  {
73  C4IDListChunk *pNew = new C4IDListChunk(*pFrom);
74  pTo->pNext=pNew; pTo=pNew;
75  }
76  // finalize
77  pTo->pNext=nullptr;
78  return *this;
79 }
80 
82 {
83  // destruction is done in chunk
84 }
85 
86 void C4IDList::Clear()
87 {
88  // inherited
90  // reset count
91  Count=0;
92 }
93 
94 bool C4IDList::IsClear() const
95 {
96  return !Count;
97 }
98 
99 C4ID C4IDList::GetID(size_t index, int32_t *ipCount) const
100 {
101  // outside list?
102  if (!Inside<size_t>(index+1,1u,Count)) return C4ID::None;
103  // get chunk to query
104  const C4IDListChunk *pQueryChunk=this;
105  while (index>=C4IDListChunkSize) { pQueryChunk=pQueryChunk->pNext; index-=C4IDListChunkSize; }
106  // query it
107  if (ipCount) *ipCount=pQueryChunk->Count[index];
108  return pQueryChunk->id[index];
109 }
110 
111 int32_t C4IDList::GetCount(size_t index) const
112 {
113  // outside list?
114  if (!Inside<size_t>(index+1,1u,Count)) return 0;
115  // get chunk to query
116  const C4IDListChunk *pQueryChunk=this;
117  while (index>=C4IDListChunkSize) { pQueryChunk=pQueryChunk->pNext; index-=C4IDListChunkSize; }
118  // query it
119  return pQueryChunk->Count[index];
120 }
121 
122 bool C4IDList::SetCount(size_t index, int32_t iCount)
123 {
124  // outside list?
125  if (!Inside<size_t>(index+1,1u,Count)) return false;
126  // get chunk to set in
127  C4IDListChunk *pQueryChunk=this;
128  while (index>=C4IDListChunkSize) { pQueryChunk=pQueryChunk->pNext; index-=C4IDListChunkSize; }
129  // set it
130  pQueryChunk->Count[index]=iCount;
131  // success
132  return true;
133 }
134 
135 int32_t C4IDList::GetIDCount(C4ID c_id, int32_t iZeroDefVal) const
136 {
137  // find id
138  const C4IDListChunk *pQueryChunk=this;
139  size_t cnt=Count,cntl=0;
140  while (cnt--)
141  {
142  if (pQueryChunk->id[cntl]==c_id)
143  {
144  int32_t iCount=pQueryChunk->Count[cntl];
145  return iCount ? iCount : iZeroDefVal;
146  }
147  if (++cntl==C4IDListChunkSize)
148  {
149  pQueryChunk=pQueryChunk->pNext;
150  cntl=0;
151  }
152  }
153  // none found
154  return 0;
155 }
156 
157 bool C4IDList::SetIDCount(C4ID c_id, int32_t iCount, bool fAddNewID)
158 {
159  // find id
160  C4IDListChunk *pQueryChunk=this;
161  size_t cnt=Count,cntl=0;
162  while (cnt--)
163  {
164  if (pQueryChunk->id[cntl]==c_id)
165  {
166  pQueryChunk->Count[cntl]=iCount; return true;
167  }
168  if (++cntl==C4IDListChunkSize)
169  {
170  pQueryChunk=pQueryChunk->pNext;
171  cntl=0;
172  }
173  }
174  // none found: add new
175  if (fAddNewID)
176  {
177  // if end was reached, add new chunk
178  if (!pQueryChunk)
179  {
180  C4IDListChunk *pLast=this;
181  while (pLast->pNext) pLast=pLast->pNext;
182  pQueryChunk=new C4IDListChunk();
183  pLast->pNext=pQueryChunk;
184  }
185  // set id
186  pQueryChunk->id[cntl]=c_id;
187  pQueryChunk->Count[cntl]=iCount;
188  // count id!
189  ++Count;
190  // success
191  return true;
192  }
193  // failure
194  return false;
195 }
196 
198 {
199  return Count;
200 }
201 
202 int32_t C4IDList::GetIndex(C4ID c_id) const
203 {
204  // find id in list
205  const C4IDListChunk *pQueryChunk=this;
206  size_t cnt=Count,cntl=0;
207  while (cnt--)
208  {
209  if (pQueryChunk->id[cntl]==c_id) return Count-cnt-1;
210  if (++cntl==C4IDListChunkSize)
211  {
212  pQueryChunk=pQueryChunk->pNext;
213  cntl=0;
214  }
215  }
216  // not found
217  return -1;
218 }
219 
220 bool C4IDList::IncreaseIDCount(C4ID c_id, bool fAddNewID, int32_t IncreaseBy, bool fRemoveEmpty)
221 {
222  // find id in list
223  C4IDListChunk *pQueryChunk=this;
224  size_t cnt=Count,cntl=0;
225  while (cnt--)
226  {
227  if (pQueryChunk->id[cntl]==c_id)
228  {
229  // increase count
230  pQueryChunk->Count[cntl]+=IncreaseBy;
231  // check count
232  if (fRemoveEmpty && !pQueryChunk->Count[cntl]) DeleteItem(Count-cnt-1);
233  // success
234  return true;
235  }
236  if (++cntl==C4IDListChunkSize)
237  {
238  pQueryChunk=pQueryChunk->pNext;
239  cntl=0;
240  }
241  }
242  // add desired?
243  if (!fAddNewID) return true;
244  // add it
245  // if end was reached, add new chunk
246  if (!pQueryChunk)
247  {
248  C4IDListChunk *pLast=this;
249  while (pLast->pNext) pLast=pLast->pNext;
250  pQueryChunk=new C4IDListChunk();
251  pLast->pNext=pQueryChunk;
252  }
253  // set id
254  pQueryChunk->id[cntl]=c_id;
255  pQueryChunk->Count[cntl]=IncreaseBy;
256  ++Count;
257  // success
258  return true;
259 }
260 
261 
262 // Access by category-sorted index
263 C4ID C4IDList::GetID(C4DefList &rDefs, int32_t dwCategory, int32_t index, int32_t *ipCount) const
264 {
265  int32_t cindex=-1;
266  C4Def *cDef;
267  if (ipCount) *ipCount=0;
268  // find id
269  const C4IDListChunk *pQueryChunk=this;
270  size_t cnt=Count,cntl=0;
271  while (cnt--)
272  {
273  if ((dwCategory==C4D_All) || ( (cDef=rDefs.ID2Def(pQueryChunk->id[cntl])) && (cDef->Category & dwCategory) ) )
274  {
275  cindex++;
276  if (cindex==index) { if (ipCount) *ipCount=pQueryChunk->Count[cntl]; return pQueryChunk->id[cntl]; }
277  }
278  if (++cntl==C4IDListChunkSize)
279  {
280  pQueryChunk=pQueryChunk->pNext;
281  cntl=0;
282  }
283  }
284  return C4ID::None;
285 }
286 
287 int32_t C4IDList::GetCount(C4DefList &rDefs, int32_t dwCategory, int32_t index) const
288 {
289  int32_t cindex=-1;
290  C4Def *cDef;
291  const C4IDListChunk *pQueryChunk=this;
292  size_t cnt=Count,cntl=0;
293  while (cnt--)
294  {
295  if ((dwCategory==C4D_All) || ( (cDef=rDefs.ID2Def(pQueryChunk->id[cntl])) && (cDef->Category & dwCategory) ) )
296  {
297  cindex++;
298  if (cindex==index) return pQueryChunk->Count[cntl];
299  }
300  if (++cntl==C4IDListChunkSize)
301  {
302  pQueryChunk=pQueryChunk->pNext;
303  cntl=0;
304  }
305  }
306  return 0;
307 }
308 
309 bool C4IDList::SetCount(C4DefList &rDefs, int32_t dwCategory, int32_t index, int32_t iCount)
310 {
311  int32_t cindex=-1;
312  C4Def *cDef;
313  C4IDListChunk *pQueryChunk=this;
314  size_t cnt=Count,cntl=0;
315  while (cnt--)
316  {
317  if ((dwCategory==C4D_All) || ( (cDef=rDefs.ID2Def(pQueryChunk->id[cntl])) && (cDef->Category & dwCategory) ) )
318  {
319  cindex++;
320  if (cindex==index) { pQueryChunk->Count[cntl]=iCount; return true; }
321  }
322  if (++cntl==C4IDListChunkSize)
323  {
324  pQueryChunk=pQueryChunk->pNext;
325  cntl=0;
326  }
327  }
328  return false;
329 }
330 
331 int32_t C4IDList::GetNumberOfIDs(C4DefList &rDefs, int32_t dwCategory) const
332 {
333  int32_t idnum=0;
334  C4Def *cDef;
335  const C4IDListChunk *pQueryChunk=this;
336  size_t cnt=Count,cntl=0;
337  while (cnt--)
338  {
339  if ((dwCategory==C4D_All) || ( (cDef=rDefs.ID2Def(pQueryChunk->id[cntl])) && (cDef->Category & dwCategory) ) )
340  idnum++;
341  if (++cntl==C4IDListChunkSize)
342  {
343  pQueryChunk=pQueryChunk->pNext;
344  cntl=0;
345  }
346  }
347  return idnum;
348 }
349 // IDList merge
350 
352 {
353  C4IDListChunk *pQueryChunk=&rList;
354  size_t cnt=rList.Count,cntl=0;
355  while (cnt--)
356  {
357  IncreaseIDCount(pQueryChunk->id[cntl], true, pQueryChunk->Count[cntl]);
358  if (++cntl==C4IDListChunkSize)
359  {
360  pQueryChunk=pQueryChunk->pNext;
361  cntl=0;
362  }
363  }
364  return true;
365 }
366 
367 bool C4IDList::ConsolidateValids(C4DefList &rDefs, int32_t dwCategory)
368 {
369  bool fIDsRemoved=false;
370  C4IDListChunk *pQueryChunk=this;
371  size_t cnt=Count,cntl=0;
372  C4Def* pDef;
373  while (cnt--)
374  {
375  // ID does not resolve to a valid def or category is specified and def does not match category
376  if (!(pDef = rDefs.ID2Def(pQueryChunk->id[cntl])) || (dwCategory && !(pDef->Category & dwCategory)))
377  {
378  // delete it
379  DeleteItem(Count-cnt-1);
380  // handle this list index again!
381  --cntl;
382  // something was done
383  fIDsRemoved=true;
384  }
385  if (++cntl==C4IDListChunkSize)
386  {
387  pQueryChunk=pQueryChunk->pNext;
388  cntl=0;
389  }
390  }
391  return fIDsRemoved;
392 }
393 
394 void C4IDList::Draw(C4Facet &cgo, int32_t iSelection,
395  C4DefList &rDefs, DWORD dwCategory,
396  bool fCounts, int32_t iAlign) const
397 {
398 
399  int32_t sections = cgo.GetSectionCount();
400  int32_t idnum = GetNumberOfIDs(rDefs,dwCategory);
401  int32_t firstid = Clamp<int32_t>(iSelection-sections/2,0,std::max<int32_t>(idnum-sections,0));
402  int32_t idcount;
403  C4ID c_id;
404  C4Facet cgo2;
405  char buf[10];
406  for (int32_t cnt=0; (cnt<sections) && (c_id=GetID(rDefs,dwCategory,firstid+cnt,&idcount)); cnt++)
407  {
408  cgo2 = cgo.TruncateSection(iAlign);
409  rDefs.Draw(c_id,cgo2,(firstid+cnt==iSelection),0);
410  sprintf(buf,"%dx",idcount);
411  if (fCounts) pDraw->TextOut(buf, ::GraphicsResource.FontRegular, 1.0, cgo2.Surface,cgo2.X+cgo2.Wdt-1, cgo2.Y + cgo2.Hgt - 1 - ::GraphicsResource.FontRegular.GetLineHeight(),C4Draw::DEFAULT_MESSAGE_COLOR,ARight);
412  }
413 
414 }
415 
416 void C4IDList::Default()
417 {
418  Clear();
419 }
420 
421 // Clear index entry and shift all entries behind down by one.
422 
423 bool C4IDList::DeleteItem(size_t iIndex)
424 {
425  // invalid index
426  if (!Inside<size_t>(iIndex+1,1u,Count)) return false;
427  // get chunk to delete of
428  size_t index=iIndex;
429  C4IDListChunk *pQueryChunk=this;
430  while (index>=C4IDListChunkSize) { pQueryChunk=pQueryChunk->pNext; index-=C4IDListChunkSize; }
431  // shift down all entries behind
432  size_t cnt=--Count-iIndex,cntl=index,cntl2=cntl;
433  C4IDListChunk *pNextChunk=pQueryChunk;
434  while (cnt--)
435  {
436  // check for list overlap
437  if (++cntl2==C4IDListChunkSize)
438  {
439  pNextChunk=pQueryChunk->pNext;
440  cntl2=0;
441  }
442  // move down
443  pQueryChunk->id[cntl]=pNextChunk->id[cntl2];
444  pQueryChunk->Count[cntl]=pNextChunk->Count[cntl2];
445  // next item
446  pQueryChunk=pNextChunk; cntl=cntl2;
447  }
448  // done
449  return true;
450 }
451 
452 bool C4IDList::operator==(const C4IDList& rhs) const
453 {
454  // compare counts
455  if (Count != rhs.Count) return false;
456  // compare all chunks
457  const C4IDListChunk *pChunk1 = this;
458  const C4IDListChunk *pChunk2 = &rhs;
459  int32_t cnt=Count;
460  while (pChunk1 && pChunk2)
461  {
462  if (memcmp(pChunk1->id, pChunk2->id, sizeof(C4ID)*std::min<int32_t>(cnt, C4IDListChunkSize)) ) return false;
463  if (memcmp(pChunk1->Count, pChunk2->Count, sizeof(int32_t)*std::min<int32_t>(cnt, C4IDListChunkSize)) ) return false;
464  pChunk1=pChunk1->pNext; pChunk2=pChunk2->pNext;
465  cnt-=C4IDListChunkSize;
466  }
467  // equal!
468  return true;
469 }
470 
471 void C4IDList::CompileFunc(StdCompiler *pComp, bool fValues)
472 {
473  // Get compiler characteristics
474  bool deserializing = pComp->isDeserializer();
475  bool fNaming = pComp->hasNaming();
476  // Compiling: Clear existing data first
477  if (deserializing) Clear();
478  // Start
479  C4IDListChunk *pChunk = this;
480  size_t iNr = 0, iCNr = 0;
481  // Without naming: Compile Count
482  int32_t iCount = Count;
483  if (!fNaming) pComp->Value(iCount);
484  Count = iCount;
485  // Read
486  for (;;)
487  {
488  // Prepare compiling of single mapping
489  if (!deserializing)
490  {
491  // End of list?
492  if (iNr >= Count) break;
493  // End of chunk?
494  if (iCNr >= C4IDListChunkSize)
495  {
496  pChunk = pChunk->pNext;
497  iCNr = 0;
498  }
499  }
500  else
501  {
502  // End of list?
503  if (!fNaming) if (iNr >= Count) break;
504  // End of chunk?
505  if (iCNr >= C4IDListChunkSize)
506  {
507  pChunk = pChunk->pNext = new C4IDListChunk();
508  iCNr = 0;
509  }
510  }
511  // Separator (';')
512  if (iNr > 0) if (!pComp->Separator(StdCompiler::SEP_SEP2)) break;
513  // ID
514  pComp->Value(mkDefaultAdapt(pChunk->id[iCNr], C4ID::None));
515  // ID not valid? Note that C4ID::None is invalid.
516  if (pChunk->id[iCNr] == C4ID::None) break;
517  // Value: Skip this part if requested
518  if (fValues)
519  {
520  // Separator ('=')
521  if (pComp->Separator(StdCompiler::SEP_SET))
522  // Count
523  pComp->Value(mkDefaultAdapt(pChunk->Count[iCNr], 0));
524  }
525  else if (deserializing)
526  pChunk->Count[iCNr] = 0;
527  // Goto next entry
528  iNr++; iCNr++;
529  // Save back count
530  if (deserializing && fNaming) Count = iNr;
531  }
532 }
C4IDList & operator=(const C4IDList &rCopy)
Definition: stub-handle.cpp:65
C4Def * ID2Def(C4ID id)
void Draw(C4Facet &cgo, int32_t iSelection, C4DefList &rDefs, DWORD dwCategory, bool fCounts=true, int32_t iAlign=0) const
Definition: C4IDList.cpp:394
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:129
int32_t GetIDCount(C4ID c_id, int32_t iZeroDefVal=0) const
Definition: stub-handle.cpp:67
void Clear()
Definition: stub-handle.cpp:64
virtual bool hasNaming()
Definition: StdCompiler.h:68
bool ConsolidateValids(C4DefList &rDefs, int32_t dwCategory=0)
Definition: C4IDList.cpp:367
int GetLineHeight() const
Definition: C4FontLoader.h:132
C4Facet TruncateSection(int32_t iAlign=C4FCT_Left)
Definition: C4Facet.cpp:250
float Y
Definition: C4Facet.h:120
int32_t Count[C4IDListChunkSize]
Definition: C4IDList.h:34
#define sprintf
Definition: Standard.h:171
int32_t GetCount(size_t index) const
Definition: C4IDList.cpp:111
bool TextOut(const char *szText, CStdFont &rFont, float fZoom, C4Surface *sfcDest, float iTx, float iTy, DWORD dwFCol=0xffffffff, BYTE byForm=ALeft, bool fDoMarkup=true)
Definition: C4Draw.cpp:570
int32_t GetSectionCount()
Definition: C4Facet.cpp:46
const int ARight
Definition: C4Surface.h:43
bool SetCount(size_t index, int32_t iCount)
Definition: C4IDList.cpp:122
bool IsClear() const
Definition: C4IDList.cpp:94
C4IDListChunk * pNext
Definition: C4IDList.h:36
bool Add(C4IDList &rList)
Definition: C4IDList.cpp:351
C4GraphicsResource GraphicsResource
void Default()
Definition: stub-handle.cpp:63
bool IncreaseIDCount(C4ID c_id, bool fAddNewID=true, int32_t IncreaseBy=1, bool fRemoveEmpty=false)
Definition: C4IDList.cpp:220
static const C4ID None
Definition: C4Id.h:42
void Clear()
Definition: C4IDList.cpp:40
const int32_t C4D_All
Definition: C4Def.h:41
Definition: C4Def.h:100
C4Draw * pDraw
Definition: C4Draw.cpp:45
void CompileFunc(StdCompiler *pComp, bool fValues=true)
Definition: stub-handle.cpp:69
void Value(const T &rStruct)
Definition: StdCompiler.h:171
Definition: C4Id.h:28
const size_t C4IDListChunkSize
Definition: C4IDList.h:28
C4ID id[C4IDListChunkSize]
Definition: C4IDList.h:33
virtual bool isDeserializer()
Definition: StdCompiler.h:63
void Draw(C4ID id, C4Facet &cgo, bool fSelected, int32_t iColor)
Definition: C4DefList.cpp:393
float Hgt
Definition: C4Facet.h:120
bool operator==(const C4IDList &rhs) const
Definition: stub-handle.cpp:66
bool SetIDCount(C4ID c_id, int32_t iCount, bool fAddNewID=false)
Definition: stub-handle.cpp:68
int32_t Category
Definition: C4Def.h:119
bool DeleteItem(size_t iIndex)
Definition: C4IDList.cpp:423
size_t Count
Definition: C4IDList.h:55
StdDefaultAdapt< T, D > mkDefaultAdapt(T &&rValue, const D &rDefault)
Definition: StdAdaptors.h:65
C4Surface * Surface
Definition: C4Facet.h:119
C4ID GetID(size_t index, int32_t *ipCount=nullptr) const
Definition: C4IDList.cpp:99
uint32_t DWORD
int32_t GetNumberOfIDs() const
Definition: C4IDList.cpp:197
float Wdt
Definition: C4Facet.h:120
float X
Definition: C4Facet.h:120
int32_t GetIndex(C4ID c_id) const
Definition: C4IDList.cpp:202