PageRenderTime 58ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/script/C4ValueMap.cpp

https://bitbucket.org/randrian/openclonk2
C++ | 472 lines | 306 code | 77 blank | 89 comment | 66 complexity | 33780e39ae884641657872df58f91fed MD5 | raw file
Possible License(s): WTFPL, 0BSD, LGPL-2.1, CC-BY-3.0
  1. /*
  2. * OpenClonk, http://www.openclonk.org
  3. *
  4. * Copyright (c) 2001-2002, 2004-2006 Peter Wortmann
  5. * Copyright (c) 2004-2006 Sven Eberhardt
  6. * Copyright (c) 2005, 2008 G?nther Brammer
  7. * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
  8. *
  9. * Portions might be copyrighted by other authors who have contributed
  10. * to OpenClonk.
  11. *
  12. * Permission to use, copy, modify, and/or distribute this software for any
  13. * purpose with or without fee is hereby granted, provided that the above
  14. * copyright notice and this permission notice appear in all copies.
  15. * See isc_license.txt for full license and disclaimer.
  16. *
  17. * "Clonk" is a registered trademark of Matthes Bender.
  18. * See clonk_trademark_license.txt for full license.
  19. */
  20. #include "C4Include.h"
  21. #include "C4ValueMap.h"
  22. // *** C4ValueMapData ***
  23. C4ValueMapData::C4ValueMapData()
  24. : pData(0), pNames(0), bTempNameList(false), pNext(0)
  25. {
  26. }
  27. C4ValueMapData::C4ValueMapData(const C4ValueMapData &DataToCopy)
  28. : pData(0), pNames(0), bTempNameList(false), pNext(0)
  29. {
  30. SetNameList(DataToCopy.pNames);
  31. if (pNames) for(int32_t i = 0; i < pNames->iSize; i++)
  32. pData[i].Set(DataToCopy.pData[i]);
  33. }
  34. C4ValueMapData &C4ValueMapData::operator = (const C4ValueMapData &DataToCopy)
  35. {
  36. SetNameList(DataToCopy.pNames);
  37. if (pNames) for(int32_t i = 0; i < pNames->iSize; i++)
  38. pData[i].Set(DataToCopy.pData[i]);
  39. return *this;
  40. }
  41. bool C4ValueMapData::operator == (const C4ValueMapData &Data) const
  42. {
  43. if(pNames != Data.pNames) return false;
  44. if(pNames)
  45. for(int i = 0; i < pNames->iSize; i++)
  46. if(pData[i] != Data.pData[i])
  47. return false;
  48. return true;
  49. }
  50. C4ValueMapData::~C4ValueMapData()
  51. {
  52. Reset();
  53. }
  54. void C4ValueMapData::Reset()
  55. {
  56. // unreg from name list (if using one)
  57. if(pNames) UnRegister();
  58. pNames = 0;
  59. // free data
  60. delete[] pData;
  61. pData = 0;
  62. }
  63. void C4ValueMapData::ResetContent()
  64. {
  65. if(pNames)
  66. // Realloc list (will destroy all data)
  67. ReAllocList();
  68. else
  69. {
  70. delete[] pData;
  71. pData = 0;
  72. }
  73. }
  74. void C4ValueMapData::SetNameList(C4ValueMapNames *pnNames)
  75. {
  76. if(pNames == pnNames) return;
  77. if(pNames)
  78. {
  79. // save name array from old name list
  80. char **pOldNames = pNames->pNames;
  81. int32_t iOldSize = pNames->iSize;
  82. // unreg from old name list
  83. // (manually, because Data::UnRegister() would destroy content)
  84. C4ValueMapNames *pNames = this->pNames;
  85. pNames->UnRegister(this);
  86. // register at new name list
  87. pnNames->Register(this);
  88. // call OnNameListChanged to copy data and realloc data array
  89. OnNameListChanged(const_cast<const char **>(pOldNames), iOldSize);
  90. // delete old names list, if it is temporary
  91. if(bTempNameList)
  92. delete pNames;
  93. bTempNameList = false;
  94. // ok
  95. }
  96. else
  97. {
  98. // simply register...
  99. Register(pnNames);
  100. }
  101. }
  102. void C4ValueMapData::Register(C4ValueMapNames *pnNames)
  103. {
  104. // UnReg from old?
  105. if(pNames) UnRegister();
  106. if (pnNames) pnNames->Register(this);
  107. pNames = pnNames;
  108. // alloc data array
  109. ReAllocList();
  110. }
  111. void C4ValueMapData::UnRegister()
  112. {
  113. if(!pNames) return;
  114. // safe pointer
  115. C4ValueMapNames *pNames = this->pNames;
  116. // unreg
  117. pNames->UnRegister(this);
  118. // delete name list (if it is temporary)
  119. if(bTempNameList)
  120. delete pNames;
  121. bTempNameList = false;
  122. // delete data array
  123. delete[] pData;
  124. pData = 0;
  125. }
  126. C4ValueMapNames *C4ValueMapData::CreateTempNameList()
  127. {
  128. // create new list
  129. C4ValueMapNames *pTempNames = new C4ValueMapNames();
  130. // register (this func will unreg if necessary, too)
  131. Register(pTempNames);
  132. // error?
  133. if(pNames != pTempNames)
  134. {
  135. delete pTempNames;
  136. return 0;
  137. }
  138. // set flag
  139. bTempNameList = true;
  140. return pTempNames;
  141. }
  142. void C4ValueMapData::ReAllocList()
  143. {
  144. if(!pNames)
  145. {
  146. Reset();
  147. return;
  148. }
  149. // delete old array
  150. delete[] pData;
  151. // create new one
  152. pData = new C4Value [pNames->iSize] ();
  153. // ok...
  154. }
  155. void C4ValueMapData::OnNameListChanged(const char **pOldNames, int32_t iOldSize)
  156. {
  157. if(!pNames)
  158. {
  159. Reset();
  160. return;
  161. }
  162. // this function does not use ReAllocList because the old values
  163. // have to be hold.
  164. // save pointer on old data
  165. C4Value *pOldData = pData;
  166. // create new data list
  167. pData = new C4Value [pNames->iSize] ();
  168. // (try to) copy data
  169. int32_t i, j;
  170. for(i = 0; i < iOldSize; i++)
  171. {
  172. //FIXME: This optimization is ugly.
  173. if(i < pNames->iSize && SEqual(pNames->pNames[i], pOldNames[i]))
  174. {
  175. pOldData[i].Move(&pData[i]);
  176. }
  177. else for(j = 0; j < pNames->iSize; j++)
  178. {
  179. if(SEqual(pNames->pNames[j], pOldNames[i]))
  180. {
  181. pOldData[i].Move(&pData[j]);
  182. break; // in hope this will only break the last for...
  183. }
  184. }
  185. }
  186. // delete old data array
  187. delete[] pOldData;
  188. }
  189. C4Value *C4ValueMapData::GetItem(int32_t iNr)
  190. {
  191. // the list is nothing without name list...
  192. if(!pNames) return 0;
  193. if(iNr >= pNames->iSize) return 0;
  194. return &pData[iNr];
  195. }
  196. C4Value *C4ValueMapData::GetItem(const char *strName)
  197. {
  198. if(!pNames) return 0;
  199. int32_t iNr = pNames->GetItemNr(strName);
  200. if(iNr == -1) return 0;
  201. return &pData[iNr];
  202. }
  203. int32_t C4ValueMapData::GetAnzItems()
  204. {
  205. if(!pNames) return 0;
  206. return pNames->iSize;
  207. }
  208. void C4ValueMapData::DenumeratePointers()
  209. {
  210. if(!pNames) return;
  211. for(int32_t i = 0; i < pNames->iSize; i++)
  212. pData[i].DenumeratePointer();
  213. }
  214. void C4ValueMapData::CompileFunc(StdCompiler *pComp)
  215. {
  216. bool fCompiler = pComp->isCompiler();
  217. if(fCompiler) Reset();
  218. // Compile item count
  219. int32_t iValueCnt;
  220. if(!fCompiler) iValueCnt = pNames ? pNames->iSize : 0;
  221. pComp->Value(mkDefaultAdapt(iValueCnt, 0));
  222. // nuthing 2do for no items
  223. if (!iValueCnt) return;
  224. // Seperator (';')
  225. pComp->Seperator(StdCompiler::SEP_SEP2);
  226. // Data
  227. char **ppNames = !fCompiler ? pNames->pNames : new char * [iValueCnt];
  228. if (fCompiler) for(int32_t i = 0; i < iValueCnt; i++) ppNames[i] = 0;
  229. C4Value *pValues = !fCompiler ? pData : new C4Value [iValueCnt];
  230. // Compile
  231. try
  232. {
  233. for(int32_t i = 0; i < iValueCnt; i++)
  234. {
  235. // Seperate
  236. if(i) pComp->Seperator();
  237. // Name
  238. StdStrBuf Name;
  239. if(!fCompiler) Name.Ref(ppNames[i]);
  240. pComp->Value(mkParAdapt(Name, StdCompiler::RCT_Idtf));
  241. if(fCompiler) ppNames[i] = Name.GrabPointer();
  242. // Seperator ('=')
  243. pComp->Seperator(StdCompiler::SEP_SET);
  244. // Value
  245. pComp->Value(pValues[i]);
  246. }
  247. }
  248. catch (...)
  249. {
  250. // make sure no mem is leaked on compiler error in name list
  251. if (fCompiler)
  252. {
  253. for(int32_t i = 0; i < iValueCnt; i++) if (ppNames[i]) free(ppNames[i]);
  254. delete [] ppNames;
  255. delete [] pValues;
  256. }
  257. throw;
  258. }
  259. // Set
  260. if(fCompiler)
  261. {
  262. C4ValueMapNames *pOldNames = pNames;
  263. // Set
  264. CreateTempNameList();
  265. pNames->SetNameArray(const_cast<const char **>(ppNames), iValueCnt);
  266. for(int32_t i = 0; i < iValueCnt; i++) delete ppNames[i];
  267. delete [] ppNames; delete [] pData;
  268. pData = pValues;
  269. // Assign old name list
  270. if(pOldNames) SetNameList(pOldNames);
  271. }
  272. }
  273. // *** C4ValueMapNames ***
  274. C4ValueMapNames::C4ValueMapNames()
  275. : pNames(0), iSize(0), pFirst(0)
  276. {
  277. }
  278. C4ValueMapNames::C4ValueMapNames(C4ValueMapNames& NamesToCopy)
  279. : pNames(0), iSize(0), pFirst(0)
  280. {
  281. ChangeNameList(const_cast<const char **>(NamesToCopy.pNames), NamesToCopy.iSize);
  282. }
  283. C4ValueMapNames& C4ValueMapNames::operator = (C4ValueMapNames &NamesToCopy)
  284. {
  285. ChangeNameList(const_cast<const char **>(NamesToCopy.pNames), NamesToCopy.iSize);
  286. return *this;
  287. }
  288. C4ValueMapNames::~C4ValueMapNames()
  289. {
  290. Reset();
  291. }
  292. void C4ValueMapNames::Reset()
  293. {
  294. // unreg all data lists
  295. while(pFirst) UnRegister(pFirst);
  296. // free name list
  297. for(int32_t i = 0; i < iSize; i++)
  298. delete[] pNames[i];
  299. delete[] pNames;
  300. pNames = NULL;
  301. iSize = 0;
  302. }
  303. void C4ValueMapNames::Register(C4ValueMapData *pData)
  304. {
  305. // add to begin of list
  306. pData->pNext = pFirst;
  307. pFirst = pData;
  308. // set name list
  309. pData->pNames = this;
  310. }
  311. void C4ValueMapNames::UnRegister(C4ValueMapData *pData)
  312. {
  313. // find in list
  314. C4ValueMapData *pAktData = pFirst, *pLastData = 0;
  315. while(pAktData && pAktData != pData)
  316. {
  317. pLastData = pAktData;
  318. pAktData = pAktData->pNext;
  319. }
  320. if(!pAktData)
  321. // isn't registred here...
  322. return;
  323. // unreg
  324. if(pLastData)
  325. pLastData->pNext = pData->pNext;
  326. else
  327. pFirst = pData->pNext;
  328. pData->pNext = 0;
  329. pData->pNames = 0;
  330. }
  331. void C4ValueMapNames::ChangeNameList(const char **pnNames, int32_t nSize)
  332. {
  333. // safe old name list
  334. char **pOldNames = pNames;
  335. int32_t iOldSize = iSize;
  336. // create new lists
  337. pNames = new char *[nSize];
  338. // copy names
  339. int32_t i;
  340. for(i = 0; i < nSize; i++)
  341. {
  342. pNames[i] = new char [SLen(pnNames[i]) + 1];
  343. SCopy(pnNames[i], pNames[i], SLen(pnNames[i]) + 1);
  344. }
  345. // set new size
  346. iSize = nSize;
  347. // call OnNameListChanged list for all "child" lists
  348. C4ValueMapData *pAktData = pFirst;
  349. while(pAktData)
  350. {
  351. pAktData->OnNameListChanged(const_cast<const char **>(pOldNames), iOldSize);
  352. pAktData = pAktData->pNext;
  353. }
  354. // delete old list
  355. for(i = 0; i < iOldSize; i++)
  356. delete[] pOldNames[i];
  357. delete[] pOldNames;
  358. // ok.
  359. }
  360. void C4ValueMapNames::SetNameArray(const char **pnNames, int32_t nSize)
  361. {
  362. // simply pass it through...
  363. ChangeNameList(pnNames, nSize);
  364. }
  365. int32_t C4ValueMapNames::AddName(const char *pnName)
  366. {
  367. // name already existing?
  368. int32_t iNr;
  369. if((iNr=GetItemNr(pnName)) != -1)
  370. return iNr;
  371. // create new dummy lists
  372. const char **pDummyNames = new const char *[iSize + 1];
  373. // copy all data from old list
  374. // (danger! if ChangeNameList would now delete them before
  375. // creating the new list, this would cause cruel errors...)
  376. int32_t i;
  377. for(i = 0; i < iSize; i++)
  378. {
  379. pDummyNames[i] = pNames[i];
  380. }
  381. pDummyNames[i] = pnName;
  382. // change list
  383. ChangeNameList(pDummyNames, iSize + 1);
  384. // delete dummy arrays
  385. delete[] pDummyNames;
  386. // return index to new element (simply last element)
  387. return iSize-1;
  388. }
  389. int32_t C4ValueMapNames::GetItemNr(const char *strName)
  390. {
  391. for(int32_t i = 0; i < iSize; i++)
  392. if(SEqual(pNames[i], strName))
  393. return i;
  394. return -1;
  395. }