String.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Util/String.h>
  6. #include <AnKi/Util/F16.h>
  7. #include <cmath> // For HUGE_VAL
  8. #include <climits> // For LLONG_MAX
  9. #include <cstdarg> // For var args
  10. #include <cstdlib> // For stdtod and strtol
  11. namespace anki {
  12. Error CString::toNumber(F64& out) const
  13. {
  14. checkInit();
  15. errno = 0;
  16. char* endPtr;
  17. out = std::strtod(m_ptr, &endPtr);
  18. if(errno || endPtr != m_ptr + getLength())
  19. {
  20. errno = 0;
  21. ANKI_UTIL_LOGE("Conversion failed: %s", m_ptr);
  22. return Error::USER_DATA;
  23. }
  24. return Error::NONE;
  25. }
  26. Error CString::toNumber(F32& out) const
  27. {
  28. F64 d;
  29. ANKI_CHECK(toNumber(d));
  30. out = F32(d);
  31. return Error::NONE;
  32. }
  33. Error CString::toNumber(F16& out) const
  34. {
  35. F64 d;
  36. ANKI_CHECK(toNumber(d));
  37. out = F16(d);
  38. return Error::NONE;
  39. }
  40. Error CString::toNumber(I64& out) const
  41. {
  42. checkInit();
  43. errno = 0;
  44. char* endPtr;
  45. static_assert(sizeof(long long) == sizeof(I64), "See file");
  46. out = std::strtoll(m_ptr, &endPtr, 10);
  47. if(errno || endPtr != m_ptr + getLength())
  48. {
  49. errno = 0;
  50. ANKI_UTIL_LOGE("Conversion failed: %s", m_ptr);
  51. return Error::USER_DATA;
  52. }
  53. return Error::NONE;
  54. }
  55. Error CString::toNumber(I8& out) const
  56. {
  57. I64 i64 = 0;
  58. ANKI_CHECK(toNumber(i64));
  59. if(i64 < MIN_I8 || i64 > MAX_I8)
  60. {
  61. ANKI_UTIL_LOGE("Conversion failed. Our of range: %s", m_ptr);
  62. return Error::USER_DATA;
  63. }
  64. out = I8(i64);
  65. return Error::NONE;
  66. }
  67. Error CString::toNumber(I32& out) const
  68. {
  69. I64 i64 = 0;
  70. ANKI_CHECK(toNumber(i64));
  71. if(i64 < MIN_I32 || i64 > MAX_I32)
  72. {
  73. ANKI_UTIL_LOGE("Conversion failed. Our of range: %s", m_ptr);
  74. return Error::USER_DATA;
  75. }
  76. out = I32(i64);
  77. return Error::NONE;
  78. }
  79. Error CString::toNumber(U64& out) const
  80. {
  81. checkInit();
  82. errno = 0;
  83. char* endPtr;
  84. static_assert(sizeof(unsigned long long) == sizeof(U64), "See file");
  85. out = std::strtoull(m_ptr, &endPtr, 10);
  86. if(errno || endPtr != m_ptr + getLength())
  87. {
  88. errno = 0;
  89. ANKI_UTIL_LOGE("Conversion failed: %s", m_ptr);
  90. return Error::USER_DATA;
  91. }
  92. return Error::NONE;
  93. }
  94. Error CString::toNumber(U32& out) const
  95. {
  96. U64 u64;
  97. ANKI_CHECK(toNumber(u64));
  98. if(u64 > MAX_U32)
  99. {
  100. ANKI_UTIL_LOGE("Conversion failed. Our of range: %s", m_ptr);
  101. return Error::USER_DATA;
  102. }
  103. out = U32(u64);
  104. return Error::NONE;
  105. }
  106. Error CString::toNumber(U8& out) const
  107. {
  108. U64 u64 = 0;
  109. ANKI_CHECK(toNumber(u64));
  110. if(u64 > MAX_U8)
  111. {
  112. ANKI_UTIL_LOGE("Conversion failed. Our of range: %s", m_ptr);
  113. return Error::USER_DATA;
  114. }
  115. out = U8(u64);
  116. return Error::NONE;
  117. }
  118. Error CString::toNumber(I16& out) const
  119. {
  120. I64 i64 = 0;
  121. ANKI_CHECK(toNumber(i64));
  122. if(i64 < MIN_I16 || i64 > MAX_I16)
  123. {
  124. ANKI_UTIL_LOGE("Conversion failed. Our of range: %s", m_ptr);
  125. return Error::USER_DATA;
  126. }
  127. out = I16(i64);
  128. return Error::NONE;
  129. }
  130. Error CString::toNumber(U16& out) const
  131. {
  132. U64 u64;
  133. ANKI_CHECK(toNumber(u64));
  134. if(u64 > MAX_U16)
  135. {
  136. ANKI_UTIL_LOGE("Conversion failed. Our of range: %s", m_ptr);
  137. return Error::USER_DATA;
  138. }
  139. out = U16(u64);
  140. return Error::NONE;
  141. }
  142. Error CString::toNumber(Bool& out) const
  143. {
  144. I32 i;
  145. ANKI_CHECK(toNumber(i));
  146. out = i != 0;
  147. return Error::NONE;
  148. }
  149. String& String::operator=(StringAuto&& b)
  150. {
  151. m_data = std::move(b.m_data);
  152. return *this;
  153. }
  154. void String::create(Allocator alloc, const CStringType& cstr)
  155. {
  156. auto len = cstr.getLength();
  157. auto size = len + 1;
  158. m_data.create(alloc, size);
  159. memcpy(&m_data[0], &cstr[0], sizeof(Char) * size);
  160. }
  161. void String::create(Allocator alloc, ConstIterator first, ConstIterator last)
  162. {
  163. ANKI_ASSERT(first != 0 && last != 0);
  164. auto length = last - first;
  165. m_data.create(alloc, length + 1);
  166. memcpy(&m_data[0], first, length);
  167. m_data[length] = '\0';
  168. }
  169. void String::create(Allocator alloc, Char c, PtrSize length)
  170. {
  171. ANKI_ASSERT(c != '\0');
  172. m_data.create(alloc, length + 1);
  173. memset(&m_data[0], c, length);
  174. m_data[length] = '\0';
  175. }
  176. void String::appendInternal(Allocator& alloc, const Char* str, PtrSize strLen)
  177. {
  178. ANKI_ASSERT(str != nullptr);
  179. ANKI_ASSERT(strLen > 0);
  180. auto size = m_data.getSize();
  181. // Fix empty string
  182. if(size == 0)
  183. {
  184. size = 1;
  185. }
  186. DynamicArray<Char, PtrSize> newData;
  187. newData.create(alloc, size + strLen);
  188. if(!m_data.isEmpty())
  189. {
  190. memcpy(&newData[0], &m_data[0], sizeof(Char) * size);
  191. }
  192. memcpy(&newData[size - 1], str, sizeof(Char) * strLen);
  193. newData[newData.getSize() - 1] = '\0';
  194. m_data.destroy(alloc);
  195. m_data = std::move(newData);
  196. }
  197. void String::sprintf(Allocator& alloc, const Char* fmt, va_list& args)
  198. {
  199. Array<Char, 512> buffer;
  200. va_list args2;
  201. va_copy(args2, args); // vsnprintf will alter "args". Copy it case we need to call vsnprintf in the else bellow
  202. I len = std::vsnprintf(&buffer[0], sizeof(buffer), fmt, args);
  203. if(len < 0)
  204. {
  205. ANKI_UTIL_LOGF("vsnprintf() failed");
  206. }
  207. else if(static_cast<PtrSize>(len) >= sizeof(buffer))
  208. {
  209. I size = len + 1;
  210. m_data.create(alloc, size);
  211. len = std::vsnprintf(&m_data[0], size, fmt, args2);
  212. ANKI_ASSERT((len + 1) == size);
  213. }
  214. else
  215. {
  216. // buffer was enough
  217. create(alloc, CString(&buffer[0]));
  218. }
  219. va_end(args2);
  220. }
  221. String& String::sprintf(Allocator alloc, const Char* fmt, ...)
  222. {
  223. ANKI_ASSERT(fmt);
  224. va_list args;
  225. va_start(args, fmt);
  226. sprintf(alloc, fmt, args);
  227. va_end(args);
  228. return *this;
  229. }
  230. String& String::replaceAll(Allocator alloc, CString from, CString to)
  231. {
  232. String tmp = {alloc, toCString()};
  233. const PtrSize fromLen = from.getLength();
  234. const PtrSize toLen = to.getLength();
  235. PtrSize pos = NPOS;
  236. while((pos = tmp.find(from)) != NPOS)
  237. {
  238. String tmp2;
  239. if(pos > 0)
  240. {
  241. tmp2.create(alloc, tmp.getBegin(), tmp.getBegin() + pos);
  242. }
  243. if(toLen > 0)
  244. {
  245. tmp2.append(alloc, to.getBegin(), to.getBegin() + toLen);
  246. }
  247. if(pos + fromLen < tmp.getLength())
  248. {
  249. tmp2.append(alloc, tmp.getBegin() + pos + fromLen, tmp.getEnd());
  250. }
  251. tmp.destroy(alloc);
  252. tmp = std::move(tmp2);
  253. }
  254. destroy(alloc);
  255. *this = std::move(tmp);
  256. return *this;
  257. }
  258. StringAuto& StringAuto::sprintf(const Char* fmt, ...)
  259. {
  260. va_list args;
  261. va_start(args, fmt);
  262. Base::sprintf(m_alloc, fmt, args);
  263. va_end(args);
  264. return *this;
  265. }
  266. } // end namespace anki