irrString.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. // Copyright (C) 2002-2005 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine" and the "irrXML" project.
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
  4. #ifndef __IRR_STRING_H_INCLUDED__
  5. #define __IRR_STRING_H_INCLUDED__
  6. #include "irrTypes.h"
  7. namespace irr
  8. {
  9. namespace core
  10. {
  11. //! Very simple string class with some useful features.
  12. /** string<c8> and string<wchar_t> work both with unicode AND ascii,
  13. so you can assign unicode to string<c8> and ascii to string<wchar_t>
  14. (and the other way round) if your ever would want to.
  15. Note that the conversation between both is not done using an encoding.
  16. Known bugs:
  17. Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the
  18. methods make_upper, make_lower and equals_ignore_case.
  19. */
  20. template <class T>
  21. class string
  22. {
  23. public:
  24. //! Default constructor
  25. string()
  26. : array(0), allocated(1), used(1)
  27. {
  28. array = new T[1];
  29. array[0] = 0x0;
  30. }
  31. //! Constructor
  32. string(const string<T>& other)
  33. : array(0), allocated(0), used(0)
  34. {
  35. *this = other;
  36. }
  37. //! Constructs a string from an int
  38. string(int number)
  39. : array(0), allocated(0), used(0)
  40. {
  41. // store if negative and make positive
  42. bool negative = false;
  43. if (number < 0)
  44. {
  45. number *= -1;
  46. negative = true;
  47. }
  48. // temporary buffer for 16 numbers
  49. c8 tmpbuf[16];
  50. tmpbuf[15] = 0;
  51. s32 idx = 15;
  52. // special case '0'
  53. if (!number)
  54. {
  55. tmpbuf[14] = '0';
  56. *this = &tmpbuf[14];
  57. return;
  58. }
  59. // add numbers
  60. while(number && idx)
  61. {
  62. idx--;
  63. tmpbuf[idx] = (c8)('0' + (number % 10));
  64. number = number / 10;
  65. }
  66. // add sign
  67. if (negative)
  68. {
  69. idx--;
  70. tmpbuf[idx] = '-';
  71. }
  72. *this = &tmpbuf[idx];
  73. }
  74. //! Constructor for copying a string from a pointer with a given lenght
  75. template <class B>
  76. string(const B* c, s32 lenght)
  77. : array(0), allocated(0), used(0)
  78. {
  79. if (!c)
  80. return;
  81. allocated = used = lenght+1;
  82. array = new T[used];
  83. for (s32 l = 0; l<lenght; ++l)
  84. array[l] = (T)c[l];
  85. array[lenght] = 0;
  86. }
  87. //! Constructor for unicode and ascii strings
  88. template <class B>
  89. string(const B* c)
  90. : array(0), allocated(0), used(0)
  91. {
  92. *this = c;
  93. }
  94. //! destructor
  95. ~string()
  96. {
  97. delete [] array;
  98. }
  99. //! Assignment operator
  100. string<T>& operator=(const string<T>& other)
  101. {
  102. if (this == &other)
  103. return *this;
  104. delete [] array;
  105. allocated = used = other.size()+1;
  106. array = new T[used];
  107. const T* p = other.c_str();
  108. for (s32 i=0; i<used; ++i, ++p)
  109. array[i] = *p;
  110. return *this;
  111. }
  112. //! Assignment operator for strings, ascii and unicode
  113. template <class B>
  114. string<T>& operator=(const B* c)
  115. {
  116. if (!c)
  117. {
  118. if (!array)
  119. {
  120. array = new T[1];
  121. allocated = 1;
  122. used = 1;
  123. }
  124. array[0] = 0x0;
  125. return *this;
  126. }
  127. if ((void*)c == (void*)array)
  128. return *this;
  129. s32 len = 0;
  130. const B* p = c;
  131. while(*p)
  132. {
  133. ++len;
  134. ++p;
  135. }
  136. // we'll take the old string for a while, because the new string could be
  137. // a part of the current string.
  138. T* oldArray = array;
  139. allocated = used = len+1;
  140. array = new T[used];
  141. for (s32 l = 0; l<len+1; ++l)
  142. array[l] = (T)c[l];
  143. delete [] oldArray;
  144. return *this;
  145. }
  146. //! Add operator for other strings
  147. string<T> operator+(const string<T>& other)
  148. {
  149. string<T> str(*this);
  150. str.append(other);
  151. return str;
  152. }
  153. //! Add operator for strings, ascii and unicode
  154. template <class B>
  155. string<T> operator+(const B* c)
  156. {
  157. string<T> str(*this);
  158. str.append(c);
  159. return str;
  160. }
  161. //! Direct access operator
  162. T& operator [](const s32 index) const
  163. {
  164. _IRR_DEBUG_BREAK_IF(index>=used) // bad index
  165. return array[index];
  166. }
  167. //! Comparison operator
  168. bool operator ==(const T* str) const
  169. {
  170. int i;
  171. for(i=0; array[i] && str[i]; ++i)
  172. if (array[i] != str[i])
  173. return false;
  174. return !array[i] && !str[i];
  175. }
  176. //! Comparison operator
  177. bool operator ==(const string<T>& other) const
  178. {
  179. for(s32 i=0; array[i] && other.array[i]; ++i)
  180. if (array[i] != other.array[i])
  181. return false;
  182. return used == other.used;
  183. }
  184. //! Is smaller operator
  185. bool operator <(const string<T>& other) const
  186. {
  187. for(s32 i=0; array[i] && other.array[i]; ++i)
  188. if (array[i] != other.array[i])
  189. return (array[i] < other.array[i]);
  190. return used < other.used;
  191. }
  192. //! Equals not operator
  193. bool operator !=(const string<T>& other) const
  194. {
  195. return !(*this == other);
  196. }
  197. //! Returns length of string
  198. /** \return Returns length of the string in characters. */
  199. s32 size() const
  200. {
  201. return used-1;
  202. }
  203. //! Returns character string
  204. /** \return Returns pointer to C-style zero terminated string. */
  205. const T* c_str() const
  206. {
  207. return array;
  208. }
  209. //! Makes the string lower case.
  210. void make_lower()
  211. {
  212. const T A = (T)'A';
  213. const T Z = (T)'Z';
  214. const T diff = (T)'a' - A;
  215. for (s32 i=0; i<used; ++i)
  216. {
  217. if (array[i]>=A && array[i]<=Z)
  218. array[i] += diff;
  219. }
  220. }
  221. //! Makes the string upper case.
  222. void make_upper()
  223. {
  224. const T a = (T)'a';
  225. const T z = (T)'z';
  226. const T diff = (T)'A' - a;
  227. for (s32 i=0; i<used; ++i)
  228. {
  229. if (array[i]>=a && array[i]<=z)
  230. array[i] += diff;
  231. }
  232. }
  233. //! Compares the string ignoring case.
  234. /** \param other: Other string to compare.
  235. \return Returns true if the string are equal ignoring case. */
  236. bool equals_ignore_case(const string<T>& other) const
  237. {
  238. for(s32 i=0; array[i] && other[i]; ++i)
  239. if (toLower(array[i]) != toLower(other[i]))
  240. return false;
  241. return used == other.used;
  242. }
  243. //! compares the first n characters of the strings
  244. bool equalsn(const string<T>& other, int len)
  245. {
  246. int i;
  247. for(i=0; array[i] && other[i] && i < len; ++i)
  248. if (array[i] != other[i])
  249. return false;
  250. // if one (or both) of the strings was smaller then they
  251. // are only equal if they have the same lenght
  252. return (i == len) || (used == other.used);
  253. }
  254. //! compares the first n characters of the strings
  255. bool equalsn(const T* str, int len)
  256. {
  257. int i;
  258. for(i=0; array[i] && str[i] && i < len; ++i)
  259. if (array[i] != str[i])
  260. return false;
  261. // if one (or both) of the strings was smaller then they
  262. // are only equal if they have the same lenght
  263. return (i == len) || (array[i] == 0 && str[i] == 0);
  264. }
  265. //! Appends a character to this string
  266. /** \param character: Character to append. */
  267. void append(T character)
  268. {
  269. if (used + 1 > allocated)
  270. reallocate((s32)used + 1);
  271. used += 1;
  272. array[used-2] = character;
  273. array[used-1] = 0;
  274. }
  275. //! Appends a string to this string
  276. /** \param other: String to append. */
  277. void append(const string<T>& other)
  278. {
  279. --used;
  280. s32 len = other.size();
  281. if (used + len + 1 > allocated)
  282. reallocate((s32)used + (s32)len + 1);
  283. for (s32 l=0; l<len+1; ++l)
  284. array[l+used] = other[l];
  285. used = used + len + 1;
  286. }
  287. //! Appends a string of the length l to this string.
  288. /** \param other: other String to append to this string.
  289. \param length: How much characters of the other string to add to this one. */
  290. void append(const string<T>& other, s32 length)
  291. {
  292. s32 len = other.size();
  293. if (len < length)
  294. {
  295. append(other);
  296. return;
  297. }
  298. len = length;
  299. --used;
  300. if (used + len > allocated)
  301. reallocate((s32)used + (s32)len);
  302. for (s32 l=0; l<len; ++l)
  303. array[l+used] = other[l];
  304. used = used + len;
  305. }
  306. //! Reserves some memory.
  307. /** \param count: Amount of characters to reserve. */
  308. void reserve(s32 count)
  309. {
  310. if (count < allocated)
  311. return;
  312. reallocate(count);
  313. }
  314. //! finds first occurrence of character in string
  315. /** \param c: Character to search for.
  316. \return Returns position where the character has been found,
  317. or -1 if not found. */
  318. s32 findFirst(T c) const
  319. {
  320. for (s32 i=0; i<used; ++i)
  321. if (array[i] == c)
  322. return i;
  323. return -1;
  324. }
  325. //! finds first occurrence of a character of a list in string
  326. /** \param c: List of strings to find. For example if the method
  327. should find the first occurance of 'a' or 'b', this parameter should be "ab".
  328. \param count: Amount of characters in the list. Ususally,
  329. this should be strlen(ofParameter1)
  330. \return Returns position where one of the character has been found,
  331. or -1 if not found. */
  332. s32 findFirstChar(T* c, int count) const
  333. {
  334. for (s32 i=0; i<used; ++i)
  335. for (int j=0; j<count; ++j)
  336. if (array[i] == c[j])
  337. return i;
  338. return -1;
  339. }
  340. //! Finds first position of a character not in a given list.
  341. /** \param c: List of characters not to find. For example if the method
  342. should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
  343. \param count: Amount of characters in the list. Ususally,
  344. this should be strlen(ofParameter1)
  345. \return Returns position where the character has been found,
  346. or -1 if not found. */
  347. template <class B>
  348. s32 findFirstCharNotInList(B* c, int count) const
  349. {
  350. for (int i=0; i<used; ++i)
  351. {
  352. int j;
  353. for (j=0; j<count; ++j)
  354. if (array[i] == c[j])
  355. break;
  356. if (j==count)
  357. return i;
  358. }
  359. return -1;
  360. }
  361. //! Finds last position of a character not in a given list.
  362. /** \param c: List of characters not to find. For example if the method
  363. should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
  364. \param count: Amount of characters in the list. Ususally,
  365. this should be strlen(ofParameter1)
  366. \return Returns position where the character has been found,
  367. or -1 if not found. */
  368. template <class B>
  369. s32 findLastCharNotInList(B* c, int count) const
  370. {
  371. for (int i=used-2; i>=0; --i)
  372. {
  373. int j;
  374. for (j=0; j<count; ++j)
  375. if (array[i] == c[j])
  376. break;
  377. if (j==count)
  378. return i;
  379. }
  380. return -1;
  381. }
  382. //! finds next occurrence of character in string
  383. /** \param c: Character to search for.
  384. \param startPos: Position in string to start searching.
  385. \return Returns position where the character has been found,
  386. or -1 if not found. */
  387. s32 findNext(T c, s32 startPos) const
  388. {
  389. for (s32 i=startPos; i<used; ++i)
  390. if (array[i] == c)
  391. return i;
  392. return -1;
  393. }
  394. //! finds last occurrence of character in string
  395. //! \param c: Character to search for.
  396. //! \return Returns position where the character has been found,
  397. //! or -1 if not found.
  398. s32 findLast(T c) const
  399. {
  400. for (s32 i=used-1; i>=0; --i)
  401. if (array[i] == c)
  402. return i;
  403. return -1;
  404. }
  405. //! Returns a substring
  406. //! \param begin: Start of substring.
  407. //! \param length: Length of substring.
  408. string<T> subString(s32 begin, s32 length)
  409. {
  410. if (length <= 0)
  411. return string<T>("");
  412. string<T> o;
  413. o.reserve(length+1);
  414. for (s32 i=0; i<length; ++i)
  415. o.array[i] = array[i+begin];
  416. o.array[length] = 0;
  417. o.used = o.allocated;
  418. return o;
  419. }
  420. void operator += (T c)
  421. {
  422. append(c);
  423. }
  424. void operator += (const string<T>& other)
  425. {
  426. append(other);
  427. }
  428. void operator += (int i)
  429. {
  430. append(string<T>(i));
  431. }
  432. //! replaces all characters of a special type with another one
  433. void replace(T toReplace, T replaceWith)
  434. {
  435. for (s32 i=0; i<used; ++i)
  436. if (array[i] == toReplace)
  437. array[i] = replaceWith;
  438. }
  439. //! trims the string.
  440. /** Removes whitespace from begin and end of the string. */
  441. void trim()
  442. {
  443. const char whitespace[] = " \t\n";
  444. const int whitespacecount = 3;
  445. // find start and end of real string without whitespace
  446. int begin = findFirstCharNotInList(whitespace, whitespacecount);
  447. if (begin == -1)
  448. return;
  449. int end = findLastCharNotInList(whitespace, whitespacecount);
  450. if (end == -1)
  451. return;
  452. *this = subString(begin, (end +1) - begin);
  453. }
  454. //! Erases a character from the string. May be slow, because all elements
  455. //! following after the erased element have to be copied.
  456. //! \param index: Index of element to be erased.
  457. void erase(int index)
  458. {
  459. _IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
  460. for (int i=index+1; i<used; ++i)
  461. array[i-1] = array[i];
  462. --used;
  463. }
  464. private:
  465. //! Returns a character converted to lower case
  466. T toLower(const T& t) const
  467. {
  468. if (t>=(T)'A' && t<=(T)'Z')
  469. return t + ((T)'a' - (T)'A');
  470. else
  471. return t;
  472. }
  473. //! Reallocate the array, make it bigger or smaler
  474. void reallocate(s32 new_size)
  475. {
  476. T* old_array = array;
  477. array = new T[new_size];
  478. allocated = new_size;
  479. s32 amount = used < new_size ? used : new_size;
  480. for (s32 i=0; i<amount; ++i)
  481. array[i] = old_array[i];
  482. delete [] old_array;
  483. }
  484. //--- member variables
  485. T* array;
  486. s32 allocated;
  487. s32 used;
  488. };
  489. //! Typedef for character strings
  490. typedef string<irr::c8> stringc;
  491. //! Typedef for wide character strings
  492. typedef string<wchar_t> stringw;
  493. } // end namespace core
  494. } // end namespace irr
  495. #endif