Dict.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Dict.cpp
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Westwood Studios Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2001 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: RTS3
  34. //
  35. // File name: Dict.cpp
  36. //
  37. // Created: Steven Johnson, November 2001
  38. //
  39. // Desc: General-purpose dictionary class
  40. //
  41. //-----------------------------------------------------------------------------
  42. ///////////////////////////////////////////////////////////////////////////////
  43. #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine
  44. #include "Common/Dict.h"
  45. #include "Common/GameMemory.h"
  46. // -----------------------------------------------------
  47. void Dict::DictPair::copyFrom(DictPair* that)
  48. {
  49. Dict::DataType curType = this->getType();
  50. Dict::DataType newType = that->getType();
  51. if (curType != newType)
  52. {
  53. clear();
  54. }
  55. switch(newType)
  56. {
  57. case DICT_BOOL:
  58. case DICT_INT:
  59. case DICT_REAL:
  60. *this = *that;
  61. break;
  62. case DICT_ASCIISTRING:
  63. this->m_key = that->m_key;
  64. *this->asAsciiString() = *that->asAsciiString();
  65. break;
  66. case DICT_UNICODESTRING:
  67. this->m_key = that->m_key;
  68. *this->asUnicodeString() = *that->asUnicodeString();
  69. break;
  70. }
  71. }
  72. // -----------------------------------------------------
  73. void Dict::DictPair::clear()
  74. {
  75. switch (getType())
  76. {
  77. case DICT_BOOL:
  78. case DICT_INT:
  79. case DICT_REAL:
  80. m_value = 0;
  81. break;
  82. case DICT_ASCIISTRING:
  83. asAsciiString()->clear();
  84. break;
  85. case DICT_UNICODESTRING:
  86. asUnicodeString()->clear();
  87. break;
  88. }
  89. }
  90. // -----------------------------------------------------
  91. void Dict::DictPair::setNameAndType(NameKeyType key, Dict::DataType type)
  92. {
  93. Dict::DataType curType = getType();
  94. if (curType != type)
  95. {
  96. clear();
  97. }
  98. m_key = createKey(key, type);
  99. }
  100. // -----------------------------------------------------
  101. #ifdef _DEBUG
  102. void Dict::validate() const
  103. {
  104. if (!m_data) return;
  105. DEBUG_ASSERTCRASH(m_data->m_refCount > 0, ("m_refCount is zero"));
  106. DEBUG_ASSERTCRASH(m_data->m_refCount < 32000, ("m_refCount is suspiciously large"));
  107. DEBUG_ASSERTCRASH(m_data->m_numPairsAllocated > 0, ("m_numPairsAllocated is zero"));
  108. DEBUG_ASSERTCRASH(m_data->m_numPairsUsed >= 0, ("m_numPairsUsed is neg"));
  109. DEBUG_ASSERTCRASH(m_data->m_numPairsAllocated >= m_data->m_numPairsUsed, ("m_numPairsAllocated too small"));
  110. DEBUG_ASSERTCRASH(m_data->m_numPairsAllocated < 1024, ("m_numPairsAllocated suspiciously large"));
  111. }
  112. #endif
  113. // -----------------------------------------------------
  114. Dict::DictPair* Dict::findPairByKey(NameKeyType key) const
  115. {
  116. DEBUG_ASSERTCRASH(key != NAMEKEY_INVALID, ("invalid namekey!"));
  117. DEBUG_ASSERTCRASH((UnsignedInt)key < (1L<<23), ("namekey too large!"));
  118. if (!m_data)
  119. return NULL;
  120. DictPair* base = m_data->peek();
  121. Int minIdx = 0;
  122. Int maxIdx = m_data->m_numPairsUsed;
  123. while (minIdx < maxIdx)
  124. {
  125. Int midIdx = (((minIdx + maxIdx) - 1) >> 1);
  126. DictPair* mid = base + midIdx;
  127. NameKeyType midKey = mid->getName();
  128. if (key > midKey)
  129. minIdx = midIdx + 1;
  130. else if (key < midKey)
  131. maxIdx = midIdx;
  132. else
  133. return mid;
  134. }
  135. return NULL;
  136. }
  137. // -----------------------------------------------------
  138. Dict::DictPair *Dict::ensureUnique(int numPairsNeeded, Bool preserveData, DictPair *pairToTranslate)
  139. {
  140. if (m_data &&
  141. m_data->m_refCount == 1 &&
  142. m_data->m_numPairsAllocated >= numPairsNeeded)
  143. {
  144. // no buffer manhandling is needed (it's already large enough, and unique to us)
  145. return pairToTranslate;
  146. }
  147. if (numPairsNeeded > MAX_LEN)
  148. throw ERROR_OUT_OF_MEMORY;
  149. Dict::DictPairData* newData = NULL;
  150. if (numPairsNeeded > 0)
  151. {
  152. int minBytes = sizeof(Dict::DictPairData) + numPairsNeeded*sizeof(Dict::DictPair);
  153. int actualBytes = TheDynamicMemoryAllocator->getActualAllocationSize(minBytes);
  154. // note: be certain to alloc with zero; we'll take advantage of the fact that all-zero
  155. // is a bit-pattern that happens to init all our pairs to legal values:
  156. // type BOOL, key INVALID, value FALSE.
  157. newData = (Dict::DictPairData*)TheDynamicMemoryAllocator->allocateBytes(actualBytes, "Dict::ensureUnique");
  158. newData->m_refCount = 1;
  159. newData->m_numPairsAllocated = (actualBytes - sizeof(Dict::DictPairData))/sizeof(Dict::DictPair);
  160. newData->m_numPairsUsed = 0;
  161. if (preserveData && m_data)
  162. {
  163. Dict::DictPair* src = m_data->peek();
  164. Dict::DictPair* dst = newData->peek();
  165. for (Int i = 0; i < m_data->m_numPairsUsed; ++i, ++src, ++dst)
  166. dst->copyFrom(src);
  167. newData->m_numPairsUsed = m_data->m_numPairsUsed;
  168. }
  169. }
  170. Int delta;
  171. if (pairToTranslate && m_data)
  172. delta = pairToTranslate - m_data->peek();
  173. releaseData();
  174. m_data = newData;
  175. if (pairToTranslate && m_data)
  176. pairToTranslate = m_data->peek() + delta;
  177. return pairToTranslate;
  178. }
  179. // -----------------------------------------------------
  180. void Dict::clear()
  181. {
  182. releaseData();
  183. m_data = NULL;
  184. }
  185. // -----------------------------------------------------
  186. void Dict::releaseData()
  187. {
  188. if (m_data)
  189. {
  190. if (--m_data->m_refCount == 0)
  191. {
  192. Dict::DictPair* src = m_data->peek();
  193. for (Int i = 0; i < m_data->m_numPairsUsed; ++i, ++src)
  194. src->clear();
  195. TheDynamicMemoryAllocator->freeBytes(m_data);
  196. }
  197. m_data = 0;
  198. }
  199. }
  200. // -----------------------------------------------------
  201. Dict::Dict(Int numPairsToPreAllocate) : m_data(0)
  202. {
  203. /*
  204. This class plays some skanky games, in the name of memory and code
  205. efficiency; it assumes all the data types will fit into a pointer.
  206. This is currently true, but if that assumption ever changes, all hell
  207. will break loose. So we do a quick check to assure this...
  208. */
  209. DEBUG_ASSERTCRASH(sizeof(Bool) <= sizeof(void*) &&
  210. sizeof(Int) <= sizeof(void*) &&
  211. sizeof(Real) <= sizeof(void*) &&
  212. sizeof(AsciiString) <= sizeof(void*) &&
  213. sizeof(UnicodeString) <= sizeof(void*), ("oops, this code needs attention"));
  214. if (numPairsToPreAllocate)
  215. ensureUnique(numPairsToPreAllocate, false, NULL); // will throw on error
  216. }
  217. // -----------------------------------------------------
  218. Dict& Dict::operator=(const Dict& src)
  219. {
  220. validate();
  221. if (&src != this)
  222. {
  223. releaseData();
  224. m_data = src.m_data;
  225. if (m_data)
  226. ++m_data->m_refCount;
  227. }
  228. validate();
  229. return *this;
  230. }
  231. // -----------------------------------------------------
  232. Dict::DataType Dict::getType(NameKeyType key) const
  233. {
  234. validate();
  235. DictPair* pair = findPairByKey(key);
  236. if (pair)
  237. return pair->getType();
  238. return DICT_NONE;
  239. }
  240. // -----------------------------------------------------
  241. Bool Dict::getBool(NameKeyType key, Bool *exists/*=NULL*/) const
  242. {
  243. validate();
  244. DictPair* pair = findPairByKey(key);
  245. if (pair && pair->getType() == DICT_BOOL)
  246. {
  247. if (exists) *exists = true;
  248. return *pair->asBool();
  249. }
  250. DEBUG_ASSERTCRASH(exists != NULL, ("dict key missing, or of wrong type\n")); // only assert if they didn't check result
  251. if (exists) *exists = false;
  252. return false;
  253. }
  254. // -----------------------------------------------------
  255. Int Dict::getInt(NameKeyType key, Bool *exists/*=NULL*/) const
  256. {
  257. validate();
  258. DictPair* pair = findPairByKey(key);
  259. if (pair && pair->getType() == DICT_INT)
  260. {
  261. if (exists) *exists = true;
  262. return *pair->asInt();
  263. }
  264. DEBUG_ASSERTCRASH(exists != NULL,("dict key missing, or of wrong type\n")); // only assert if they didn't check result
  265. if (exists) *exists = false;
  266. return 0;
  267. }
  268. // -----------------------------------------------------
  269. Real Dict::getReal(NameKeyType key, Bool *exists/*=NULL*/) const
  270. {
  271. validate();
  272. DictPair* pair = findPairByKey(key);
  273. if (pair && pair->getType() == DICT_REAL)
  274. {
  275. if (exists) *exists = true;
  276. return *pair->asReal();
  277. }
  278. DEBUG_ASSERTCRASH(exists != NULL,("dict key missing, or of wrong type\n")); // only assert if they didn't check result
  279. if (exists) *exists = false;
  280. return 0.0f;
  281. }
  282. // -----------------------------------------------------
  283. AsciiString Dict::getAsciiString(NameKeyType key, Bool *exists/*=NULL*/) const
  284. {
  285. validate();
  286. DictPair* pair = findPairByKey(key);
  287. if (pair && pair->getType() == DICT_ASCIISTRING)
  288. {
  289. if (exists) *exists = true;
  290. return *pair->asAsciiString();
  291. }
  292. DEBUG_ASSERTCRASH(exists != NULL,("dict key missing, or of wrong type\n")); // only assert if they didn't check result
  293. if (exists) *exists = false;
  294. return AsciiString::TheEmptyString;
  295. }
  296. // -----------------------------------------------------
  297. UnicodeString Dict::getUnicodeString(NameKeyType key, Bool *exists/*=NULL*/) const
  298. {
  299. validate();
  300. DictPair* pair = findPairByKey(key);
  301. if (pair && pair->getType() == DICT_UNICODESTRING)
  302. {
  303. if (exists) *exists = true;
  304. return *pair->asUnicodeString();
  305. }
  306. DEBUG_ASSERTCRASH(exists != NULL,("dict key missing, or of wrong type\n")); // only assert if they didn't check result
  307. if (exists) *exists = false;
  308. return UnicodeString::TheEmptyString;
  309. }
  310. // -----------------------------------------------------
  311. Bool Dict::getNthBool(Int n) const
  312. {
  313. validate();
  314. DEBUG_ASSERTCRASH(n >= 0 && n < getPairCount(), ("n out of range\n"));
  315. if (m_data)
  316. {
  317. DictPair* pair = &m_data->peek()[n];
  318. if (pair && pair->getType() == DICT_BOOL)
  319. return *pair->asBool();
  320. }
  321. DEBUG_CRASH(("dict key missing, or of wrong type\n"));
  322. return false;
  323. }
  324. // -----------------------------------------------------
  325. Int Dict::getNthInt(Int n) const
  326. {
  327. validate();
  328. DEBUG_ASSERTCRASH(n >= 0 && n < getPairCount(), ("n out of range\n"));
  329. if (m_data)
  330. {
  331. DictPair* pair = &m_data->peek()[n];
  332. if (pair && pair->getType() == DICT_INT)
  333. return *pair->asInt();
  334. }
  335. DEBUG_CRASH(("dict key missing, or of wrong type\n"));
  336. return 0;
  337. }
  338. // -----------------------------------------------------
  339. Real Dict::getNthReal(Int n) const
  340. {
  341. validate();
  342. DEBUG_ASSERTCRASH(n >= 0 && n < getPairCount(), ("n out of range\n"));
  343. if (m_data)
  344. {
  345. DictPair* pair = &m_data->peek()[n];
  346. if (pair && pair->getType() == DICT_REAL)
  347. return *pair->asReal();
  348. }
  349. DEBUG_CRASH(("dict key missing, or of wrong type\n"));
  350. return 0.0f;
  351. }
  352. // -----------------------------------------------------
  353. AsciiString Dict::getNthAsciiString(Int n) const
  354. {
  355. validate();
  356. DEBUG_ASSERTCRASH(n >= 0 && n < getPairCount(), ("n out of range\n"));
  357. if (m_data)
  358. {
  359. DictPair* pair = &m_data->peek()[n];
  360. if (pair && pair->getType() == DICT_ASCIISTRING)
  361. return *pair->asAsciiString();
  362. }
  363. DEBUG_CRASH(("dict key missing, or of wrong type\n"));
  364. return AsciiString::TheEmptyString;
  365. }
  366. // -----------------------------------------------------
  367. UnicodeString Dict::getNthUnicodeString(Int n) const
  368. {
  369. validate();
  370. DEBUG_ASSERTCRASH(n >= 0 && n < getPairCount(), ("n out of range\n"));
  371. if (m_data)
  372. {
  373. DictPair* pair = &m_data->peek()[n];
  374. if (pair && pair->getType() == DICT_UNICODESTRING)
  375. return *pair->asUnicodeString();
  376. }
  377. DEBUG_CRASH(("dict key missing, or of wrong type\n"));
  378. return UnicodeString::TheEmptyString;
  379. }
  380. // -----------------------------------------------------
  381. Dict::DictPair *Dict::setPrep(NameKeyType key, Dict::DataType type)
  382. {
  383. DictPair* pair = findPairByKey(key);
  384. Int pairsNeeded = getPairCount();
  385. if (!pair)
  386. ++pairsNeeded;
  387. pair = ensureUnique(pairsNeeded, true, pair);
  388. if (!pair)
  389. {
  390. pair = &m_data->peek()[m_data->m_numPairsUsed++];
  391. }
  392. pair->setNameAndType(key, type);
  393. DEBUG_ASSERTCRASH(pair, ("pair must not be null here"));
  394. return pair;
  395. }
  396. // -----------------------------------------------------
  397. void Dict::sortPairs()
  398. {
  399. if (!m_data)
  400. return;
  401. // yer basic shellsort.
  402. for (Int gap = m_data->m_numPairsUsed >> 1; gap > 0; gap >>= 1)
  403. {
  404. for (Int i = gap; i < m_data->m_numPairsUsed; i++)
  405. {
  406. for (Int j = i - gap; j >= 0; j -= gap)
  407. {
  408. DictPair* a = m_data->peek() + j;
  409. DictPair* b = m_data->peek() + j + gap;
  410. if (a->getName() > b->getName())
  411. {
  412. DictPair tmp = *a;
  413. *a = *b;
  414. *b = tmp;
  415. }
  416. else
  417. {
  418. break;
  419. }
  420. }
  421. }
  422. }
  423. }
  424. // -----------------------------------------------------
  425. void Dict::setBool(NameKeyType key, Bool value)
  426. {
  427. validate();
  428. DictPair* pair = setPrep(key, DICT_BOOL);
  429. *pair->asBool() = value;
  430. sortPairs();
  431. validate();
  432. }
  433. // -----------------------------------------------------
  434. void Dict::setInt(NameKeyType key, Int value)
  435. {
  436. validate();
  437. DictPair* pair = setPrep(key, DICT_INT);
  438. *pair->asInt() = value;
  439. sortPairs();
  440. validate();
  441. }
  442. // -----------------------------------------------------
  443. void Dict::setReal(NameKeyType key, Real value)
  444. {
  445. validate();
  446. DictPair* pair = setPrep(key, DICT_REAL);
  447. *pair->asReal() = value;
  448. sortPairs();
  449. validate();
  450. }
  451. // -----------------------------------------------------
  452. void Dict::setAsciiString(NameKeyType key, const AsciiString& value)
  453. {
  454. validate();
  455. DictPair* pair = setPrep(key, DICT_ASCIISTRING);
  456. *pair->asAsciiString() = value;
  457. sortPairs();
  458. validate();
  459. }
  460. // -----------------------------------------------------
  461. void Dict::setUnicodeString(NameKeyType key, const UnicodeString& value)
  462. {
  463. validate();
  464. DictPair* pair = setPrep(key, DICT_UNICODESTRING);
  465. *pair->asUnicodeString() = value;
  466. sortPairs();
  467. validate();
  468. }
  469. // -----------------------------------------------------
  470. Bool Dict::remove(NameKeyType key)
  471. {
  472. validate();
  473. DictPair* pair = findPairByKey(key);
  474. if (pair)
  475. {
  476. pair = ensureUnique(m_data->m_numPairsUsed, true, pair);
  477. pair->setNameAndType((NameKeyType)0x7fffffff, DICT_BOOL);
  478. sortPairs();
  479. --m_data->m_numPairsUsed;
  480. validate();
  481. return true;
  482. }
  483. DEBUG_CRASH(("dict key missing in remove\n"));
  484. return false;
  485. }
  486. // -----------------------------------------------------
  487. void Dict::copyPairFrom(const Dict& that, NameKeyType key)
  488. {
  489. this->validate();
  490. DictPair* thatPair = that.findPairByKey(key);
  491. if (thatPair)
  492. {
  493. DictPair* thisPair = this->setPrep(key, thatPair->getType());
  494. thisPair->copyFrom(thatPair);
  495. this->sortPairs();
  496. }
  497. else
  498. {
  499. if (this->findPairByKey(key))
  500. this->remove(key);
  501. }
  502. this->validate();
  503. }