String.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. // Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include "anki/util/DArray.h"
  7. #include "anki/util/Array.h"
  8. #include "anki/util/NonCopyable.h"
  9. #include <cstring>
  10. #include <cmath> // For HUGE_VAL
  11. #include <climits> // For LLONG_MAX
  12. #include <cstdarg> // For var args
  13. namespace anki {
  14. // Forward
  15. class String;
  16. /// @addtogroup util_private
  17. /// @{
  18. namespace detail {
  19. template<typename TNumber>
  20. constexpr const char* toStringFormat()
  21. {
  22. return nullptr;
  23. }
  24. #define ANKI_DEPLOY_TO_STRING(type_, string_) \
  25. template<> \
  26. constexpr const char* toStringFormat<type_>() \
  27. { \
  28. return string_; \
  29. }
  30. ANKI_DEPLOY_TO_STRING(I8, "%d")
  31. ANKI_DEPLOY_TO_STRING(I16, "%d")
  32. ANKI_DEPLOY_TO_STRING(I32, "%d")
  33. ANKI_DEPLOY_TO_STRING(I64, "%lld")
  34. ANKI_DEPLOY_TO_STRING(U8, "%u")
  35. ANKI_DEPLOY_TO_STRING(U16, "%u")
  36. ANKI_DEPLOY_TO_STRING(U32, "%u")
  37. ANKI_DEPLOY_TO_STRING(U64, "%llu")
  38. ANKI_DEPLOY_TO_STRING(F32, "%f")
  39. ANKI_DEPLOY_TO_STRING(F64, "%f")
  40. #undef ANKI_DEPLOY_TO_STRING
  41. } // end namespace detail
  42. /// @}
  43. /// @addtogroup util_containers
  44. /// @{
  45. /// A wrapper on top of C strings. Used mainly for safety.
  46. class CString
  47. {
  48. public:
  49. using Char = char;
  50. static const PtrSize NPOS = MAX_PTR_SIZE;
  51. CString() = default;
  52. CString(const Char* ptr)
  53. : m_ptr(ptr)
  54. {
  55. checkInit();
  56. }
  57. /// Copy constructor.
  58. CString(const CString& b)
  59. : m_ptr(b.m_ptr)
  60. {
  61. checkInit();
  62. }
  63. /// Copy.
  64. CString& operator=(const CString& b)
  65. {
  66. m_ptr = b.m_ptr;
  67. return *this;
  68. }
  69. /// Return true if the string is initialized.
  70. operator Bool() const
  71. {
  72. return !isEmpty();
  73. }
  74. /// Return char at the specified position.
  75. const Char& operator[](U pos) const
  76. {
  77. checkInit();
  78. ANKI_ASSERT(pos <= getLength());
  79. return m_ptr[pos];
  80. }
  81. const Char* begin() const
  82. {
  83. checkInit();
  84. return &m_ptr[0];
  85. }
  86. const Char* end() const
  87. {
  88. checkInit();
  89. return &m_ptr[getLength()];
  90. }
  91. /// Return true if the string is not initialized.
  92. Bool isEmpty() const
  93. {
  94. return m_ptr == nullptr || getLength() == 0;
  95. }
  96. Bool operator==(const CString& b) const
  97. {
  98. if(m_ptr == nullptr || b.m_ptr == nullptr)
  99. {
  100. return m_ptr == b.m_ptr;
  101. }
  102. else
  103. {
  104. return std::strcmp(m_ptr, b.m_ptr) == 0;
  105. }
  106. }
  107. Bool operator!=(const CString& b) const
  108. {
  109. return !((*this) == b);
  110. }
  111. Bool operator<(const CString& b) const
  112. {
  113. if(m_ptr == nullptr || b.m_ptr == nullptr)
  114. {
  115. return false;
  116. }
  117. else
  118. {
  119. return std::strcmp(m_ptr, b.m_ptr) < 0;
  120. }
  121. }
  122. Bool operator<=(const CString& b) const
  123. {
  124. if(m_ptr == nullptr || b.m_ptr == nullptr)
  125. {
  126. return m_ptr == b.m_ptr;
  127. }
  128. else
  129. {
  130. return std::strcmp(m_ptr, b.m_ptr) <= 0;
  131. }
  132. }
  133. Bool operator>(const CString& b) const
  134. {
  135. if(m_ptr == nullptr || b.m_ptr == nullptr)
  136. {
  137. return false;
  138. }
  139. else
  140. {
  141. return std::strcmp(m_ptr, b.m_ptr) > 0;
  142. }
  143. }
  144. Bool operator>=(const CString& b) const
  145. {
  146. if(m_ptr == nullptr || b.m_ptr == nullptr)
  147. {
  148. return m_ptr == b.m_ptr;
  149. }
  150. else
  151. {
  152. return std::strcmp(m_ptr, b.m_ptr) >= 0;
  153. }
  154. }
  155. /// Get the underlying C string.
  156. const char* get() const
  157. {
  158. checkInit();
  159. return m_ptr;
  160. }
  161. /// Get the string length.
  162. U getLength() const
  163. {
  164. checkInit();
  165. return std::strlen(m_ptr);
  166. }
  167. PtrSize find(const CString& cstr, PtrSize position = 0) const
  168. {
  169. checkInit();
  170. ANKI_ASSERT(position < getLength());
  171. const Char* out = std::strstr(m_ptr, &cstr[0]);
  172. return (out == nullptr) ? NPOS : (out - m_ptr);
  173. }
  174. /// Convert to F64.
  175. ANKI_USE_RESULT Error toF64(F64& out) const
  176. {
  177. checkInit();
  178. Error err = ErrorCode::NONE;
  179. out = std::strtod(m_ptr, nullptr);
  180. if(out == HUGE_VAL)
  181. {
  182. ANKI_LOGE("Conversion failed");
  183. err = ErrorCode::USER_DATA;
  184. }
  185. return err;
  186. }
  187. /// Convert to F32.
  188. ANKI_USE_RESULT Error toF32(F32& out) const
  189. {
  190. F64 d;
  191. Error err = toF64(d);
  192. if(!err)
  193. {
  194. out = d;
  195. }
  196. return err;
  197. }
  198. /// Convert to I64.
  199. ANKI_USE_RESULT Error toI64(I64& out) const
  200. {
  201. checkInit();
  202. Error err = ErrorCode::NONE;
  203. out = std::strtoll(m_ptr, nullptr, 10);
  204. if(out == LLONG_MAX || out == LLONG_MIN)
  205. {
  206. ANKI_LOGE("Conversion failed");
  207. err = ErrorCode::USER_DATA;
  208. }
  209. return err;
  210. }
  211. private:
  212. const Char* m_ptr = nullptr;
  213. void checkInit() const
  214. {
  215. ANKI_ASSERT(m_ptr != nullptr);
  216. }
  217. };
  218. /// The base class for strings.
  219. class String: public NonCopyable
  220. {
  221. public:
  222. using Char = char; ///< Character type
  223. using CStringType = CString;
  224. using Iterator = Char*;
  225. using ConstIterator = const Char*;
  226. static const PtrSize NPOS = MAX_PTR_SIZE;
  227. /// Default constructor.
  228. String()
  229. {}
  230. /// Move constructor.
  231. String(String&& b)
  232. {
  233. move(b);
  234. }
  235. /// Requires manual destruction.
  236. ~String()
  237. {}
  238. /// Initialize using a const string.
  239. template<typename TAllocator>
  240. void create(TAllocator alloc, const CStringType& cstr);
  241. /// Initialize using a range. Copies the range of [first, last)
  242. template<typename TAllocator>
  243. void create(TAllocator alloc,
  244. ConstIterator first, ConstIterator last);
  245. /// Initialize using a character.
  246. template<typename TAllocator>
  247. void create(TAllocator alloc, Char c, PtrSize length);
  248. /// Copy one string to this one.
  249. template<typename TAllocator>
  250. void create(TAllocator alloc, const String& b)
  251. {
  252. create(alloc, b.toCString());
  253. }
  254. /// Destroy the string.
  255. template<typename TAllocator>
  256. void destroy(TAllocator alloc)
  257. {
  258. m_data.destroy(alloc);
  259. }
  260. /// Move one string to this one.
  261. String& operator=(String&& b)
  262. {
  263. move(b);
  264. return *this;
  265. }
  266. /// Return char at the specified position.
  267. const Char& operator[](U pos) const
  268. {
  269. checkInit();
  270. return m_data[pos];
  271. }
  272. /// Return char at the specified position as a modifiable reference.
  273. Char& operator[](U pos)
  274. {
  275. checkInit();
  276. return m_data[pos];
  277. }
  278. Iterator begin()
  279. {
  280. checkInit();
  281. return &m_data[0];
  282. }
  283. ConstIterator begin() const
  284. {
  285. checkInit();
  286. return &m_data[0];
  287. }
  288. Iterator end()
  289. {
  290. checkInit();
  291. return &m_data[m_data.getSize() - 1];
  292. }
  293. ConstIterator end() const
  294. {
  295. checkInit();
  296. return &m_data[m_data.getSize() - 1];
  297. }
  298. /// Return true if strings are equal
  299. Bool operator==(const String& b) const
  300. {
  301. checkInit();
  302. b.checkInit();
  303. return std::strcmp(&m_data[0], &b.m_data[0]) == 0;
  304. }
  305. /// Return true if strings are not equal
  306. Bool operator!=(const String& b) const
  307. {
  308. return !(*this == b);
  309. }
  310. /// Return true if this is less than b
  311. Bool operator<(const String& b) const
  312. {
  313. checkInit();
  314. b.checkInit();
  315. return std::strcmp(&m_data[0], &b.m_data[0]) < 0;
  316. }
  317. /// Return true if this is less or equal to b
  318. Bool operator<=(const String& b) const
  319. {
  320. checkInit();
  321. b.checkInit();
  322. return std::strcmp(&m_data[0], &b.m_data[0]) <= 0;
  323. }
  324. /// Return true if this is greater than b
  325. Bool operator>(const String& b) const
  326. {
  327. checkInit();
  328. b.checkInit();
  329. return std::strcmp(&m_data[0], &b.m_data[0]) > 0;
  330. }
  331. /// Return true if this is greater or equal to b
  332. Bool operator>=(const String& b) const
  333. {
  334. checkInit();
  335. b.checkInit();
  336. return std::strcmp(&m_data[0], &b.m_data[0]) >= 0;
  337. }
  338. /// Return true if strings are equal
  339. Bool operator==(const CStringType& cstr) const
  340. {
  341. checkInit();
  342. return std::strcmp(&m_data[0], cstr.get()) == 0;
  343. }
  344. /// Return true if strings are not equal
  345. Bool operator!=(const CStringType& cstr) const
  346. {
  347. return !(*this == cstr);
  348. }
  349. /// Return true if this is less than cstr.
  350. Bool operator<(const CStringType& cstr) const
  351. {
  352. checkInit();
  353. return std::strcmp(&m_data[0], cstr.get()) < 0;
  354. }
  355. /// Return true if this is less or equal to cstr.
  356. Bool operator<=(const CStringType& cstr) const
  357. {
  358. checkInit();
  359. return std::strcmp(&m_data[0], cstr.get()) <= 0;
  360. }
  361. /// Return true if this is greater than cstr.
  362. Bool operator>(const CStringType& cstr) const
  363. {
  364. checkInit();
  365. return std::strcmp(&m_data[0], cstr.get()) > 0;
  366. }
  367. /// Return true if this is greater or equal to cstr.
  368. Bool operator>=(const CStringType& cstr) const
  369. {
  370. checkInit();
  371. return std::strcmp(&m_data[0], cstr.get()) >= 0;
  372. }
  373. /// Return the string's length. It doesn't count the terminating character.
  374. PtrSize getLength() const
  375. {
  376. auto size = m_data.getSize();
  377. auto out = (size != 0) ? (size - 1) : 0;
  378. ANKI_ASSERT(std::strlen(&m_data[0]) == out);
  379. return out;
  380. }
  381. /// Return the CString.
  382. CStringType toCString() const
  383. {
  384. checkInit();
  385. return CStringType(&m_data[0]);
  386. }
  387. /// Append another string to this one.
  388. template<typename TAllocator>
  389. void append(TAllocator alloc, const String& b)
  390. {
  391. if(!b.isEmpty())
  392. {
  393. appendInternal(alloc, &b.m_data[0], b.m_data.getSize());
  394. }
  395. }
  396. /// Append a const string to this one.
  397. template<typename TAllocator>
  398. void append(TAllocator alloc, const CStringType& cstr)
  399. {
  400. if(!cstr.isEmpty())
  401. {
  402. appendInternal(alloc, &cstr[0], cstr.getLength() + 1);
  403. }
  404. }
  405. /// Create formated string.
  406. template<typename TAllocator>
  407. void sprintf(TAllocator alloc, CString fmt, ...);
  408. /// Return true if it's empty.
  409. Bool isEmpty() const
  410. {
  411. return m_data.isEmpty();
  412. }
  413. /// Find a substring of this string.
  414. /// @param[in] cstr The substring to search.
  415. /// @param position Position of the first character in the string to be
  416. /// considered in the search.
  417. /// @return A valid position if the string is found or NPOS if not found.
  418. PtrSize find(const CStringType& cstr, PtrSize position = 0) const
  419. {
  420. checkInit();
  421. return toCString().find(cstr, position);
  422. }
  423. /// Find a substring of this string.
  424. /// @param[in] str The substring to search.
  425. /// @param position Position of the first character in the string to be
  426. /// considered in the search.
  427. /// @return A valid position if the string is found or NPOS if not found.
  428. PtrSize find(const String& str, PtrSize position) const
  429. {
  430. str.checkInit();
  431. return find(str.toCString(), position);
  432. }
  433. /// Convert a number to a string.
  434. template<typename TAllocator, typename TNumber>
  435. void toString(TAllocator alloc, TNumber number);
  436. /// Convert to F64.
  437. ANKI_USE_RESULT Error toF64(F64& out) const
  438. {
  439. return toCString().toF64(out);
  440. }
  441. /// Convert to I64.
  442. ANKI_USE_RESULT Error toI64(I64& out) const
  443. {
  444. return toCString().toI64(out);
  445. }
  446. protected:
  447. DArray<Char> m_data;
  448. void checkInit() const
  449. {
  450. ANKI_ASSERT(m_data.getSize() > 1);
  451. }
  452. /// Append to this string.
  453. template<typename TAllocator>
  454. void appendInternal(TAllocator alloc, const Char* str, PtrSize strSize);
  455. void move(String& b)
  456. {
  457. ANKI_ASSERT(this != &b);
  458. m_data = std::move(b.m_data);
  459. }
  460. };
  461. /// String with automatic cleanup.
  462. class StringAuto: public String
  463. {
  464. public:
  465. using Base = String;
  466. /// Create with allocator.
  467. template<typename TAllocator>
  468. StringAuto(TAllocator alloc)
  469. : Base()
  470. , m_alloc(alloc)
  471. {}
  472. /// Move constructor.
  473. StringAuto(StringAuto&& b)
  474. : Base()
  475. {
  476. move(b);
  477. }
  478. /// Automatic destruction.
  479. ~StringAuto()
  480. {
  481. Base::destroy(m_alloc);
  482. }
  483. /// Initialize using a const string.
  484. void create(const CStringType& cstr)
  485. {
  486. Base::create(m_alloc, cstr);
  487. }
  488. /// Initialize using a range. Copies the range of [first, last)
  489. void create(ConstIterator first, ConstIterator last)
  490. {
  491. Base::create(m_alloc, first, last);
  492. }
  493. /// Initialize using a character.
  494. void create(Char c, PtrSize length)
  495. {
  496. Base::create(m_alloc, c, length);
  497. }
  498. /// Copy one string to this one.
  499. void create(const String& b)
  500. {
  501. Base::create(m_alloc, b.toCString());
  502. }
  503. /// Move one string to this one.
  504. StringAuto& operator=(StringAuto&& b)
  505. {
  506. move(b);
  507. return *this;
  508. }
  509. /// Append another string to this one.
  510. void append(const String& b)
  511. {
  512. Base::append(m_alloc, b);
  513. }
  514. /// Append a const string to this one.
  515. void append(const CStringType& cstr)
  516. {
  517. Base::append(m_alloc, cstr);
  518. }
  519. /// Create formated string.
  520. template<typename... TArgs>
  521. void sprintf(CString fmt, TArgs... args)
  522. {
  523. Base::sprintf(m_alloc, fmt, args...);
  524. }
  525. /// Convert a number to a string.
  526. template<typename TNumber>
  527. void toString(TNumber number)
  528. {
  529. Base::toString(m_alloc, number);
  530. }
  531. private:
  532. GenericMemoryPoolAllocator<Char> m_alloc;
  533. void move(StringAuto& b)
  534. {
  535. Base::move(b);
  536. m_alloc = std::move(b.m_alloc);
  537. }
  538. };
  539. /// @}
  540. } // end namespace anki
  541. #include "anki/util/String.inl.h"