tchar.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. // Generic algorithms for manipulating null-terminated character sequences
  2. //
  3. // Platform: ISO C++ 98/11
  4. // $Id$
  5. //
  6. // (c) __vic 2008
  7. #ifndef __VIC_TCHAR_H
  8. #define __VIC_TCHAR_H
  9. #include<__vic/defs.h>
  10. #include<string> // for char_traits
  11. #include<cstring>
  12. #include<cwchar>
  13. #if !__cpp_lambdas
  14. #include<functional>
  15. #endif
  16. namespace __vic { namespace tchar {
  17. //----------------------------------------------------------------------------
  18. // String length (generic strlen)
  19. //----------------------------------------------------------------------------
  20. template<class charT>
  21. inline size_t length(const charT *st)
  22. {
  23. return std::char_traits<charT>::length(st);
  24. }
  25. //----------------------------------------------------------------------------
  26. //----------------------------------------------------------------------------
  27. // Check if string has no characters
  28. //----------------------------------------------------------------------------
  29. template<class charT>
  30. inline bool empty(const charT *s)
  31. {
  32. return !s || !*s;
  33. }
  34. //----------------------------------------------------------------------------
  35. //----------------------------------------------------------------------------
  36. // Find end of sequence (pointer to null-terminator)
  37. //----------------------------------------------------------------------------
  38. template<class charT>
  39. const charT *end(const charT *st)
  40. {
  41. while(*st != charT()) st++;
  42. return st;
  43. }
  44. //----------------------------------------------------------------------------
  45. template<>
  46. inline const char *end(const char *st)
  47. {
  48. return std::strchr(st, '\x0');
  49. }
  50. //----------------------------------------------------------------------------
  51. template<>
  52. inline const wchar_t *end(const wchar_t *st)
  53. {
  54. return std::wcschr(st, L'\x0');
  55. }
  56. //----------------------------------------------------------------------------
  57. template<class charT>
  58. inline charT *end(charT *st)
  59. {
  60. return const_cast<charT*>(end(const_cast<const charT *>(st)));
  61. }
  62. //----------------------------------------------------------------------------
  63. //----------------------------------------------------------------------------
  64. // Compare strings (generic strcmp, wcscmp)
  65. //----------------------------------------------------------------------------
  66. template<class charT>
  67. inline int compare(const charT *s1, const charT *s2)
  68. {
  69. for(; *s1 && *s2; ++s1, ++s2)
  70. if(*s1 != *s2) return *s1 < *s2 ? -1 : 1;
  71. if(!*s1 && *s2) return -1; // s1 < s2
  72. if( *s1 && !*s2) return 1; // s1 > s2
  73. return 0; // s1 == s2
  74. }
  75. //----------------------------------------------------------------------------
  76. template<>
  77. inline int compare(const char *s1, const char *s2)
  78. {
  79. return std::strcmp(s1, s2);
  80. }
  81. //----------------------------------------------------------------------------
  82. template<>
  83. inline int compare(const wchar_t *s1, const wchar_t *s2)
  84. {
  85. return std::wcscmp(s1, s2);
  86. }
  87. //----------------------------------------------------------------------------
  88. //----------------------------------------------------------------------------
  89. // Check if strings are equal
  90. //----------------------------------------------------------------------------
  91. template<class charT>
  92. inline bool equal(const charT *s1, const charT *s2)
  93. {
  94. return compare(s1, s2) == 0;
  95. }
  96. //----------------------------------------------------------------------------
  97. //----------------------------------------------------------------------------
  98. // Copy string (generic strcpy, wcscpy)
  99. //----------------------------------------------------------------------------
  100. template<class charT>
  101. inline charT *copy(charT *dest, const charT *src, size_t n)
  102. {
  103. std::memcpy(dest, src, n*sizeof(charT));
  104. return dest;
  105. }
  106. //----------------------------------------------------------------------------
  107. template<class charT>
  108. inline charT *copy(charT *dest, const charT *src)
  109. {
  110. return copy(dest, src, length(src) + 1);
  111. }
  112. //----------------------------------------------------------------------------
  113. template<>
  114. inline char *copy(char *dest, const char *src)
  115. {
  116. return std::strcpy(dest, src);
  117. }
  118. //----------------------------------------------------------------------------
  119. template<>
  120. inline wchar_t *copy(wchar_t *dest, const wchar_t *src)
  121. {
  122. return std::wcscpy(dest, src);
  123. }
  124. //----------------------------------------------------------------------------
  125. //----------------------------------------------------------------------------
  126. // Move the string in memory (generic memmove)
  127. //----------------------------------------------------------------------------
  128. template<class charT>
  129. inline charT *move(charT *dest, const charT *src)
  130. {
  131. std::memmove(dest, src, (length(src) + 1) * sizeof(charT));
  132. return dest;
  133. }
  134. //----------------------------------------------------------------------------
  135. //----------------------------------------------------------------------------
  136. // Add a one string to another (generic strcat)
  137. //----------------------------------------------------------------------------
  138. template<class charT>
  139. charT *concat(charT *dest, const charT *src)
  140. {
  141. return copy(end(dest), src);
  142. }
  143. //----------------------------------------------------------------------------
  144. template<>
  145. inline char *concat(char *dest, const char *src)
  146. {
  147. return std::strcat(dest, src);
  148. }
  149. //----------------------------------------------------------------------------
  150. template<>
  151. inline wchar_t *concat(wchar_t *dest, const wchar_t *src)
  152. {
  153. return std::wcscat(dest, src);
  154. }
  155. //----------------------------------------------------------------------------
  156. //----------------------------------------------------------------------------
  157. // Find first character in a string that satisfies a specified condition
  158. //----------------------------------------------------------------------------
  159. template<class charT, class Pred>
  160. const charT *find_if(const charT *st, Pred pred)
  161. {
  162. for(; *st; st++)
  163. if(pred(*st)) return st;
  164. return nullptr;
  165. }
  166. //----------------------------------------------------------------------------
  167. template<class charT, class Pred>
  168. inline charT *find_if(charT *st, Pred pred)
  169. {
  170. return const_cast<charT*>(find_if(const_cast<const charT *>(st), pred));
  171. }
  172. //----------------------------------------------------------------------------
  173. //----------------------------------------------------------------------------
  174. // Find first character in a string that not satisfies a specified condition
  175. //----------------------------------------------------------------------------
  176. template<class charT, class Pred>
  177. const charT *find_if_not(const charT *st, Pred pred)
  178. {
  179. for(; *st; st++)
  180. if(!pred(*st)) return st;
  181. return nullptr;
  182. }
  183. //----------------------------------------------------------------------------
  184. template<class charT, class Pred>
  185. inline charT *find_if_not(charT *st, Pred pred)
  186. {
  187. return const_cast<charT*>(find_if_not(const_cast<const charT *>(st), pred));
  188. }
  189. //----------------------------------------------------------------------------
  190. //----------------------------------------------------------------------------
  191. // Find last character in a string that satisfies a specified condition
  192. //----------------------------------------------------------------------------
  193. template<class charT, class Pred>
  194. const charT *rfind_if(const charT *st, Pred pred)
  195. {
  196. for(const charT *p = end(st) - 1; p >= st; p--)
  197. if(pred(*p)) return p;
  198. return nullptr;
  199. }
  200. //----------------------------------------------------------------------------
  201. template<class charT, class Pred>
  202. inline charT *rfind_if(charT *st, Pred pred)
  203. {
  204. return const_cast<charT*>(rfind_if(const_cast<const charT *>(st), pred));
  205. }
  206. //----------------------------------------------------------------------------
  207. //----------------------------------------------------------------------------
  208. // Find last character in a string that not satisfies a specified condition
  209. //----------------------------------------------------------------------------
  210. template<class charT, class Pred>
  211. const charT *rfind_if_not(const charT *st, Pred pred)
  212. {
  213. for(const charT *p = end(st) - 1; p >= st; p--)
  214. if(!pred(*p)) return p;
  215. return nullptr;
  216. }
  217. //----------------------------------------------------------------------------
  218. template<class charT, class Pred>
  219. inline charT *rfind_if_not(charT *st, Pred pred)
  220. {
  221. return const_cast<charT*>(rfind_if_not(const_cast<const charT *>(st), pred));
  222. }
  223. //----------------------------------------------------------------------------
  224. //----------------------------------------------------------------------------
  225. // Find a first occurrence of char in string (generic strchr)
  226. //----------------------------------------------------------------------------
  227. template<class charT>
  228. inline const charT *find(const charT *st, charT ch)
  229. {
  230. return find_if(st,
  231. #if __cpp_lambdas
  232. [ch](charT c) { return c == ch; }
  233. #else
  234. std::bind2nd(std::equal_to<charT>(), ch)
  235. #endif
  236. );
  237. }
  238. //----------------------------------------------------------------------------
  239. template<>
  240. inline const char *find(const char *st, char ch)
  241. {
  242. return std::strchr(st,ch);
  243. }
  244. //----------------------------------------------------------------------------
  245. template<>
  246. inline const wchar_t *find(const wchar_t *st, wchar_t ch)
  247. {
  248. return std::wcschr(st,ch);
  249. }
  250. //----------------------------------------------------------------------------
  251. template<class charT>
  252. inline charT *find(charT *st, charT ch)
  253. {
  254. return const_cast<charT*>(find(const_cast<const charT *>(st), ch));
  255. }
  256. //----------------------------------------------------------------------------
  257. //----------------------------------------------------------------------------
  258. // Find a first occurrence of substring in string (generic strstr)
  259. //----------------------------------------------------------------------------
  260. template<class charT>
  261. const charT *find(const charT *st, const charT *sub)
  262. {
  263. for(; *st; st++)
  264. {
  265. if(*st == *sub)
  266. {
  267. const charT *p = st, *q = sub;
  268. while(*p && *q && *p != *q) p++, q++;
  269. if(*q == charT()) return st;
  270. }
  271. }
  272. return nullptr;
  273. }
  274. //----------------------------------------------------------------------------
  275. template<>
  276. inline const char *find(const char *st, const char *sub)
  277. {
  278. return std::strstr(st,sub);
  279. }
  280. //----------------------------------------------------------------------------
  281. template<>
  282. inline const wchar_t *find(const wchar_t *st, const wchar_t *sub)
  283. {
  284. return std::wcsstr(st,sub);
  285. }
  286. //----------------------------------------------------------------------------
  287. template<class charT>
  288. inline charT *find(charT *st, const charT *sub)
  289. {
  290. return const_cast<charT*>(find(const_cast<const charT *>(st), sub));
  291. }
  292. //----------------------------------------------------------------------------
  293. //----------------------------------------------------------------------------
  294. // Find a last occurrence of ch in string or NULL (generic strrchr)
  295. //----------------------------------------------------------------------------
  296. template<class charT>
  297. inline const charT *rfind(const charT *st, charT ch)
  298. {
  299. return rfind_if(st,
  300. #if __cpp_lambdas
  301. [ch](charT c) { return c == ch; }
  302. #else
  303. std::bind2nd(std::equal_to<charT>(), ch)
  304. #endif
  305. );
  306. }
  307. //----------------------------------------------------------------------------
  308. template<>
  309. inline const char *rfind(const char *st, char ch)
  310. {
  311. return std::strrchr(st,ch);
  312. }
  313. //----------------------------------------------------------------------------
  314. template<>
  315. inline const wchar_t *rfind(const wchar_t *st, wchar_t ch)
  316. {
  317. return std::wcsrchr(st,ch);
  318. }
  319. //----------------------------------------------------------------------------
  320. template<class charT>
  321. inline charT *rfind(charT *st, charT ch)
  322. {
  323. return const_cast<charT*>(rfind(const_cast<const charT *>(st), ch));
  324. }
  325. //----------------------------------------------------------------------------
  326. //----------------------------------------------------------------------------
  327. // Find a first occurrence of any character from
  328. // specified set in string (generic strpbrk)
  329. //----------------------------------------------------------------------------
  330. template<class charT>
  331. const charT *find_first_of(const charT *st, const charT *set)
  332. {
  333. for(; *st; st++)
  334. for(const charT *p = set; *p; p++) if(*st == *p) return st;
  335. return nullptr;
  336. }
  337. //----------------------------------------------------------------------------
  338. template<>
  339. inline const char *find_first_of(const char *st, const char *set)
  340. {
  341. return std::strpbrk(st, set);
  342. }
  343. //----------------------------------------------------------------------------
  344. template<>
  345. inline const wchar_t *find_first_of(const wchar_t *st, const wchar_t *set)
  346. {
  347. return std::wcspbrk(st, set);
  348. }
  349. //----------------------------------------------------------------------------
  350. template<class charT>
  351. inline charT *find_first_of(charT *st, const charT *set)
  352. {
  353. return const_cast<charT*>(find_first_of(const_cast<const charT *>(st), set));
  354. }
  355. //----------------------------------------------------------------------------
  356. //----------------------------------------------------------------------------
  357. // Find a first character in a string that does NOT belong
  358. // to a set (generic strspn, that returns pointer instead of index)
  359. //----------------------------------------------------------------------------
  360. template<class charT>
  361. const charT *find_first_not_of(const charT *st, const charT *set)
  362. {
  363. for(; *st; st++)
  364. for(const charT *p = set; *p; p++) if(*st != *p) return st;
  365. return nullptr;
  366. }
  367. //----------------------------------------------------------------------------
  368. template<>
  369. inline const char *find_first_not_of(const char *st, const char *set)
  370. {
  371. return st + std::strspn(st, set);
  372. }
  373. //----------------------------------------------------------------------------
  374. template<>
  375. inline const wchar_t *find_first_not_of(const wchar_t *st, const wchar_t *set)
  376. {
  377. return st + std::wcsspn(st, set);
  378. }
  379. //----------------------------------------------------------------------------
  380. template<class charT>
  381. inline charT *find_first_not_of(charT *st, const charT *set)
  382. {
  383. return const_cast<charT*>(find_first_not_of(const_cast<const charT *>(st), set));
  384. }
  385. //----------------------------------------------------------------------------
  386. //----------------------------------------------------------------------------
  387. // Find a last occurrence of any character from specified set in string
  388. //----------------------------------------------------------------------------
  389. template<class charT>
  390. const charT *find_last_of(const charT *st, const charT *set)
  391. {
  392. const charT *p = end(st) - 1;
  393. while(p >= st && !find(set, *p)) p--;
  394. return p >= st ? p : nullptr;
  395. }
  396. //----------------------------------------------------------------------------
  397. template<class charT>
  398. inline charT *find_last_of(charT *st, const charT *set)
  399. {
  400. return const_cast<charT*>(find_last_of(const_cast<const charT *>(st), set));
  401. }
  402. //----------------------------------------------------------------------------
  403. //----------------------------------------------------------------------------
  404. // Find a last character in a string that does NOT belong to a set
  405. //----------------------------------------------------------------------------
  406. template<class charT>
  407. const charT *find_last_not_of(const charT *st, const charT *set)
  408. {
  409. const charT *p = end(st) - 1;
  410. while(p >= st && find(set, *p)) p--;
  411. return p >= st ? p : nullptr;
  412. }
  413. //----------------------------------------------------------------------------
  414. template<class charT>
  415. inline charT *find_last_not_of(charT *st, const charT *set)
  416. {
  417. return const_cast<charT*>(find_last_not_of(const_cast<const charT *>(st), set));
  418. }
  419. //----------------------------------------------------------------------------
  420. //----------------------------------------------------------------------------
  421. // Skip all occurrences of the specified character at the begin of the string
  422. //----------------------------------------------------------------------------
  423. template<class charT>
  424. const charT *skip(const charT *p, charT ch)
  425. {
  426. while(*p && *p == ch) p++;
  427. return p;
  428. }
  429. //----------------------------------------------------------------------------
  430. template<class charT>
  431. charT *skip(charT *p, charT ch)
  432. {
  433. return const_cast<charT*>(skip(const_cast<const charT *>(p), ch));
  434. }
  435. //----------------------------------------------------------------------------
  436. }} // namespace
  437. #endif // header guard