SpUtility.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. #ifndef _SP_UTILITIES_H__
  2. #define _SP_UTILITIES_H__
  3. #pragma once
  4. #include <vector>
  5. #include <algorithm>
  6. #include <cctype>
  7. #include <iomanip>
  8. #include <sstream>
  9. #include <time.h>
  10. #include "toolkit.h"
  11. #include "ErrorCode.h"
  12. #include "SpBase.h"
  13. #include <winpr/synch.h>
  14. #ifndef ASSERT
  15. #include <assert.h>
  16. #define ASSERT assert
  17. #endif
  18. #define random(x) (rand() %x)
  19. inline static void InitializeRandomSeed(void)
  20. {
  21. srand((int)time(0));
  22. }
  23. inline static int GetRandomDigit(int greatEqual, int lowerThan)
  24. {
  25. int c = random(lowerThan);
  26. while (c < greatEqual) {
  27. c = random(lowerThan);
  28. }
  29. return c;
  30. }
  31. namespace SP {
  32. namespace Utility {
  33. inline bool IsStartWith(std::string const& s, std::string const& prefix)
  34. {
  35. return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
  36. }
  37. inline bool IsStartWith(std::string const& s, char prefixChar)
  38. {
  39. return !s.empty() && s[0] == prefixChar;
  40. }
  41. inline bool IsEndWith(std::string const& s, std::string const& suffix)
  42. {
  43. return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
  44. }
  45. inline bool IsEndWith(std::string const& s, char suffixChar)
  46. {
  47. return !s.empty() && s[s.size() - 1] == suffixChar;
  48. }
  49. inline bool IsContains(std::string const& s, std::string const& infix)
  50. {
  51. return s.find(infix) != std::string::npos;
  52. }
  53. inline bool IsNum(const std::string& value);
  54. inline char ToLowerCh(char c)
  55. {
  56. return static_cast<char>(std::tolower(c));
  57. }
  58. inline bool CheckIPv4(const std::string& value);
  59. inline void toLowerInPlace(std::string& s)
  60. {
  61. std::transform(s.begin(), s.end(), s.begin(), ToLowerCh);
  62. }
  63. inline std::string ToLower(std::string const& s)
  64. {
  65. std::string lc = s;
  66. toLowerInPlace(lc);
  67. return lc;
  68. }
  69. inline std::string ToUpper(const std::string str)
  70. {
  71. std::string dest;
  72. dest.resize(str.size());
  73. std::transform(str.begin(), str.end(), dest.begin(), ::toupper);
  74. return dest;
  75. }
  76. inline std::string ToTrim(std::string const& str)
  77. {
  78. static char const* whitespaceChars = "\n\r\t ";
  79. std::string::size_type start = str.find_first_not_of(whitespaceChars);
  80. std::string::size_type end = str.find_last_not_of(whitespaceChars);
  81. return start != std::string::npos ? str.substr(start, 1 + end - start) : std::string();
  82. }
  83. inline bool replaceInPlace(std::string& str, std::string const& replaceThis, std::string const& withThis)
  84. {
  85. bool replaced = false;
  86. std::size_t i = str.find(replaceThis);
  87. while (i != std::string::npos) {
  88. replaced = true;
  89. str = str.substr(0, i) + withThis + str.substr(i + replaceThis.size());
  90. if (i < str.size() - withThis.size())
  91. i = str.find(replaceThis, i + withThis.size());
  92. else
  93. i = std::string::npos;
  94. }
  95. return replaced;
  96. }
  97. template<typename T>
  98. std::string fpToString(T value, int precision) {
  99. std::ostringstream oss;
  100. oss << std::setprecision(precision)
  101. << std::fixed
  102. << value;
  103. std::string d = oss.str();
  104. std::size_t i = d.find_last_not_of('0');
  105. if (i != std::string::npos && i != d.size() - 1) {
  106. if (d[i] == '.')
  107. i++;
  108. d = d.substr(0, i + 1);
  109. }
  110. return d;
  111. }
  112. inline static std::vector<std::string> Split(std::string str, char splitElem)
  113. {
  114. std::vector<std::string> strs;
  115. std::string::size_type pos1, pos2;
  116. pos2 = str.find(splitElem);
  117. pos1 = 0;
  118. while (std::string::npos != pos2) {
  119. strs.push_back(str.substr(pos1, pos2 - pos1));
  120. pos1 = pos2 + 1;
  121. pos2 = str.find(splitElem, pos1);
  122. }
  123. strs.push_back(str.substr(pos1));
  124. return strs;
  125. }
  126. /** TODO: Migrate from LocalMediaplyer::AdvManage, which is functionally similar as the above one [Gifur@2025822]
  127. 两者实现还有些不一样,参考find_first_of的用法,分隔符号更多是separator的其中之一个字符就生效
  128. */
  129. inline static void split2(const std::string& src, const std::string& separator, std::vector<std::string>& dest)
  130. {
  131. std::string str = src;
  132. std::string substring;
  133. std::string::size_type start = 0, index;
  134. do
  135. {
  136. index = str.find_first_of(separator, start);
  137. if (index != std::string::npos)
  138. {
  139. substring = str.substr(start, index - start);
  140. dest.push_back(substring);
  141. start = str.find_first_not_of(separator, index);
  142. if (start == std::string::npos) return;
  143. }
  144. } while (index != std::string::npos);
  145. //the last token
  146. substring = str.substr(start);
  147. dest.push_back(substring);
  148. }
  149. inline std::string ExtractClassName(std::string const& className)
  150. {
  151. std::string strClassName = className;
  152. if(IsStartWith(strClassName, '&'))
  153. {
  154. std::size_t lastColons = strClassName.rfind("::");
  155. std::size_t nextLastColons = strClassName.rfind("::", lastColons - 1);
  156. if (nextLastColons == std::string::npos)
  157. nextLastColons = 1;
  158. strClassName = strClassName.substr(nextLastColons, lastColons - nextLastColons);
  159. }
  160. return strClassName;
  161. }
  162. inline bool IsValidUrl(const std::string& value);
  163. SPBASE_API std::string W2S(const std::wstring wstr);
  164. SPBASE_API std::wstring S2W(const std::string str);
  165. SPBASE_API std::string GBK2UTF8(const std::string str);
  166. SPBASE_API std::string UTF8ToGBK(const std::string str);
  167. }
  168. namespace Toolkit {
  169. class CConditionVar;
  170. class CMutex
  171. {
  172. public:
  173. CMutex() :_in(false)
  174. {
  175. toolkit_mutex_init(&_mutex);
  176. }
  177. ~CMutex() {
  178. if (_in) { Leave(); }
  179. toolkit_mutex_destroy(&_mutex);
  180. }
  181. void Enter() {
  182. toolkit_mutex_lock(&_mutex);
  183. _in = true;
  184. }
  185. void Leave() {
  186. toolkit_mutex_unlock(&_mutex);
  187. _in = false;
  188. }
  189. bool TryEnter() {
  190. if (0 == toolkit_mutex_trylock(&_mutex)) {
  191. _in = true;
  192. return true;
  193. }
  194. return false;
  195. }
  196. friend class CConditionVar;
  197. private:
  198. toolkit_mutex_t _mutex;
  199. bool _in;
  200. };
  201. class CUniqueLock
  202. {
  203. public:
  204. CUniqueLock(CMutex& m) : mutex_(m)
  205. {
  206. innerLock();
  207. }
  208. ~CUniqueLock()
  209. {
  210. if (owns_) {
  211. innerUnlock();
  212. }
  213. }
  214. private:
  215. void innerLock()
  216. {
  217. mutex_.Enter();
  218. owns_ = true;
  219. }
  220. void innerUnlock()
  221. {
  222. owns_ = false;
  223. mutex_.Leave();
  224. }
  225. CMutex& mutex_;
  226. bool owns_;
  227. };
  228. class CConditionVar
  229. {
  230. public:
  231. CConditionVar(void) {
  232. toolkit_cond_init(&_cond);
  233. }
  234. ~CConditionVar(void) {
  235. toolkit_cond_destroy(&_cond);
  236. }
  237. void Signal() {
  238. toolkit_cond_signal(&_cond);
  239. }
  240. void Broadcast() {
  241. toolkit_cond_broadcast(&_cond);
  242. }
  243. void Wait(toolkit_mutex_t* mutex_) {
  244. toolkit_cond_wait(&_cond, mutex_);
  245. }
  246. void Wait(CMutex* mutex_) {
  247. toolkit_cond_wait(&_cond, &(mutex_->_mutex));
  248. }
  249. bool WaitTimeout(toolkit_mutex_t* CMutex, uint64_t millisec) {
  250. int ret = -1;
  251. ret = toolkit_cond_timedwait(&_cond, CMutex, (uint64_t)(millisec * 1e6));
  252. return ret == 0;
  253. }
  254. bool WaitTimeout(CMutex* mutex_, uint64_t millisec) {
  255. int ret = -1;
  256. ret = toolkit_cond_timedwait(&_cond, &(mutex_->_mutex), (uint64_t)(millisec * 1e6));
  257. return ret == 0;
  258. }
  259. private:
  260. toolkit_cond_t _cond;
  261. };
  262. class CConditionVarPlus
  263. {
  264. public:
  265. CConditionVarPlus(void) :_active(false) {
  266. toolkit_mutex_init(&_mutex);
  267. toolkit_cond_init(&_cond);
  268. }
  269. ~CConditionVarPlus(void) {
  270. toolkit_cond_destroy(&_cond);
  271. toolkit_mutex_destroy(&_mutex);
  272. }
  273. void Signal() {
  274. //it is usually considered a best practice to perform
  275. //the "signal"/"Signal" operation before releasing CMutex m
  276. if (!_active) {
  277. uint8_t times_ = 0;
  278. while (!_active && times_ < 3) {
  279. Sleep(100);
  280. times_++;
  281. }
  282. }
  283. toolkit_mutex_lock(&_mutex);
  284. toolkit_cond_signal(&_cond);
  285. _active = false;
  286. toolkit_mutex_unlock(&_mutex);
  287. }
  288. void Broadcast() {
  289. if (!_active) {
  290. uint8_t times_ = 0;
  291. while (!_active && times_ < 3) {
  292. Sleep(100);
  293. times_++;
  294. }
  295. }
  296. toolkit_mutex_lock(&_mutex);
  297. toolkit_cond_broadcast(&_cond);
  298. _active = false;
  299. toolkit_mutex_unlock(&_mutex);
  300. }
  301. void Wait() {
  302. ASSERT(_active == false);
  303. toolkit_mutex_lock(&_mutex);
  304. _active = true;
  305. toolkit_cond_wait(&_cond, &_mutex);
  306. toolkit_mutex_unlock(&_mutex);
  307. }
  308. bool WaitTimeout(uint64_t millisec) {
  309. int ret = -1;
  310. ASSERT(_active == false);
  311. toolkit_mutex_lock(&_mutex);
  312. _active = true;
  313. ret = toolkit_cond_timedwait(&_cond, &_mutex, (uint64_t)(millisec * 1e6));
  314. toolkit_mutex_unlock(&_mutex);
  315. return ret == 0;
  316. }
  317. int TryWaitTimeout(uint64_t millisec) {
  318. int ret;
  319. if (0 == toolkit_mutex_trylock(&_mutex)) {
  320. _active = true;
  321. ret = toolkit_cond_timedwait(&_cond, &_mutex, (uint64_t)(millisec * 1e6));
  322. if (ret == TOOLKIT_ETIMEDOUT) {
  323. ret = Error_TimeOut;
  324. _active = false;
  325. }
  326. toolkit_mutex_unlock(&_mutex);
  327. }
  328. else {
  329. ret = Error_Duplication;
  330. }
  331. return ret;
  332. }
  333. private:
  334. toolkit_mutex_t _mutex;
  335. toolkit_cond_t _cond;
  336. bool _active;
  337. };
  338. class CSemaphore
  339. {
  340. public:
  341. CSemaphore(void)
  342. {
  343. toolkit_sem_init(&_sem, 0);
  344. }
  345. explicit CSemaphore(int init_value)
  346. {
  347. toolkit_sem_init(&_sem, init_value);
  348. }
  349. virtual ~CSemaphore()
  350. {
  351. toolkit_sem_destroy(&_sem);
  352. }
  353. void Signal()
  354. {
  355. toolkit_sem_post(&_sem);
  356. }
  357. void Wait()
  358. {
  359. toolkit_sem_wait(&_sem);
  360. }
  361. bool TryWait()
  362. {
  363. return toolkit_sem_trywait(&_sem) == 0;
  364. }
  365. private:
  366. toolkit_sem_t _sem;
  367. };
  368. }
  369. }
  370. #endif //_SP_UTILITIES_H__