statemachines.H 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * statemachines.H
  3. *
  4. * Created on: Feb 1, 2013
  5. * Author: xaxaxa
  6. */
  7. /*
  8. This program is free software: you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation, either version 3 of the License, or
  11. (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. * */
  19. #ifndef STATEMACHINES_H_
  20. #define STATEMACHINES_H_
  21. #include <functional>
  22. #include <stdint.h>
  23. #include <string>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <stdexcept>
  28. #include <delegate.H>
  29. #include "basictypes.H"
  30. #ifndef likely
  31. #define likely(x) __builtin_expect((x),1)
  32. #define unlikely(x) __builtin_expect((x),0)
  33. #endif
  34. using namespace std;
  35. namespace CP
  36. {
  37. //streamReader C-style API/ABI; this is to avoid breaking the ABI when the
  38. //internal state machine structure changes
  39. //usage example:
  40. //streamReader* sr=(streamReader*)malloc(streamReader_getSize()+4096);
  41. //streamReader_init(sr, 4096);
  42. // ...
  43. //streamReader_deinit(sr);
  44. //it is safe to delete a streamReader from within your callback
  45. struct streamReader;
  46. int streamReader_getSize();
  47. void streamReader_init(streamReader* sr, void* buffer, int capacity);
  48. void streamReader_init(streamReader* sr, int capacity);
  49. void streamReader_deinit(streamReader* sr);
  50. tuple<uint8_t*, int> streamReader_beginPutData(streamReader* sr);
  51. void streamReader_endPutData(streamReader* sr, int len);
  52. void streamReader_readUntilString(streamReader* sr, const char* delim, int delimLen);
  53. void streamReader_readUntilChar(streamReader* sr, char delim);
  54. void streamReader_setCallback(streamReader* sr, const Delegate<void(uint8_t*, int, bool)>& cb);
  55. tuple<uint8_t*, int> streamReader_getBufferData(streamReader* sr);
  56. void streamReader_reset(streamReader* sr);
  57. void streamReader_skip(streamReader* sr, int i);
  58. //another streamReader implementation that remembers all data that has ever been fed into it;
  59. //mainly for socketd
  60. struct persistentStreamReader
  61. {
  62. uint8_t* buffer;
  63. int capacity;
  64. int len;
  65. int pos;
  66. int searchPos;
  67. int state; //0: none; 1: readUntilString; 2: readUntilChar
  68. //function<void(uint8_t*, int)> output;
  69. Delegate<void(uint8_t*, int)> output;
  70. const char* delim1;
  71. int delim1_len;
  72. char delim2;
  73. inline void clearBuffer() {
  74. searchPos = pos = len;
  75. //delayProcessing = false;
  76. }
  77. void resize(int nc) {
  78. uint8_t* tmp = (uint8_t*) realloc(buffer, nc);
  79. if (tmp == NULL) throw runtime_error(strerror(errno));
  80. buffer = tmp;
  81. capacity = nc;
  82. }
  83. void ensureCapacity(int c) {
  84. if (likely(c < capacity)) return;
  85. int nc = capacity;
  86. while (nc < c)
  87. nc *= 2;
  88. if (nc != capacity) resize(nc);
  89. }
  90. persistentStreamReader(int c = 4096) :
  91. capacity(c), len(0), pos(0), searchPos(0), state(0) {
  92. buffer = (uint8_t*) malloc(c);
  93. if (buffer == NULL) throw runtime_error(strerror(errno));
  94. }
  95. ~persistentStreamReader() {
  96. free(buffer);
  97. }
  98. void process() {
  99. if (len <= searchPos) return;
  100. switch (state) {
  101. case 0:
  102. break;
  103. case 1:
  104. {
  105. uint8_t* tmp = (uint8_t*) memmem(buffer + searchPos, len - searchPos, delim1,
  106. delim1_len);
  107. if (tmp == NULL) {
  108. //overlap the search so that delimitors that are cut in half at
  109. //the end of the buffer can be caught
  110. searchPos = len - delim1_len;
  111. } else {
  112. int oldPos = pos;
  113. pos = searchPos = (tmp - buffer) + delim1_len;
  114. state = 0;
  115. output(buffer + oldPos, tmp - buffer - oldPos);
  116. }
  117. break;
  118. }
  119. case 2:
  120. {
  121. uint8_t* tmp = (uint8_t*) memchr(buffer + searchPos, delim2, len - searchPos);
  122. if (tmp == NULL) {
  123. searchPos = len;
  124. } else {
  125. int oldPos = pos;
  126. pos = searchPos = (tmp - buffer) + 1;
  127. state = 0;
  128. output(buffer + oldPos, tmp - buffer - oldPos);
  129. }
  130. break;
  131. }
  132. }
  133. }
  134. void readUntilString(const char* delim, int len) {
  135. state = 1;
  136. delim1 = delim;
  137. delim1_len = len;
  138. //printf("%i\n",delim.length());
  139. process();
  140. }
  141. void readUntilChar(char delim) {
  142. state = 2;
  143. delim2 = delim;
  144. process();
  145. }
  146. uint8_t* beginPutData(int len) {
  147. ensureCapacity(this->len + len);
  148. return buffer + this->len;
  149. }
  150. void endPutData(int len) {
  151. this->len += len;
  152. if (len > 0) process();
  153. }
  154. inline tuple<uint8_t*, int> getBufferData() {
  155. return make_tuple(buffer + pos, len - pos);
  156. }
  157. inline tuple<uint8_t*, int> getHistory(bool includeUnprocessed = true) {
  158. return make_tuple(buffer, includeUnprocessed ? len : pos);
  159. }
  160. };
  161. //revised version of streamReader which does not use callbacks
  162. struct newStreamReader
  163. {
  164. struct item
  165. {
  166. String data;
  167. bool delimReached;
  168. };
  169. uint8_t* buffer;
  170. const char* delim1;
  171. int bufferCapacity;
  172. int bufferLen;
  173. int bufferPos;
  174. int state; //0: none; 1: readUntilString; 2: readUntilChar
  175. int delim1len;
  176. char delim2;
  177. bool repeat;
  178. inline void reset() {
  179. bufferPos = 0;
  180. bufferLen = 0;
  181. state = 0;
  182. repeat = false;
  183. //delayProcessing = false;
  184. }
  185. newStreamReader(void* buffer, int capacity) {
  186. this->buffer = (uint8_t*) buffer;
  187. bufferCapacity = capacity;
  188. reset();
  189. }
  190. newStreamReader(int capacity) {
  191. this->buffer = (uint8_t*) (this + 1);
  192. bufferCapacity = capacity;
  193. reset();
  194. }
  195. inline void readUntilString(const char* delim, int delimLen, bool repeat = false) {
  196. state = 1;
  197. delim1 = delim;
  198. delim1len = delimLen;
  199. this->repeat = repeat;
  200. }
  201. inline void readUntilChar(char delim, bool repeat = false) {
  202. state = 2;
  203. delim2 = delim;
  204. this->repeat = repeat;
  205. }
  206. inline String beginPutData() {
  207. //printf("%i %i\n",bufferLen, bufferCapacity - bufferLen);
  208. return {(char*) buffer + bufferLen, bufferCapacity - bufferLen};
  209. }
  210. //len <= length returned from beginPutData()
  211. inline void endPutData(int len) {
  212. bufferLen += len;
  213. }
  214. inline String getBufferData() {
  215. return {(char*)buffer + bufferPos, bufferLen - bufferPos};
  216. }
  217. inline void skip(int i) {
  218. bufferPos += i;
  219. }
  220. bool process(item& it) {
  221. if (bufferPos >= bufferLen) {
  222. bufferPos = bufferLen = 0;
  223. return false;
  224. }
  225. bool ret = false;
  226. switch (state) {
  227. case 0:
  228. return false;
  229. case 1:
  230. {
  231. uint8_t* buf = buffer;
  232. if (bufferLen - bufferPos < (int) delim1len) {
  233. if (unlikely(bufferPos==0)) return false;
  234. asdfg: memmove(buf, buf + bufferPos, bufferLen - bufferPos);
  235. bufferLen -= bufferPos;
  236. bufferPos = 0;
  237. return ret;
  238. }
  239. uint8_t* tmp = (uint8_t*) memmem(buf + bufferPos, bufferLen - bufferPos, delim1,
  240. delim1len);
  241. if (tmp == NULL) {
  242. it= { {(char*)buf + bufferPos, bufferLen - bufferPos - delim1len + 1}, false};
  243. bufferPos = bufferLen - delim1len + 1;
  244. ret=true;
  245. goto asdfg;
  246. } else {
  247. int oldPos = bufferPos;
  248. int newPos = tmp - buf;
  249. bufferPos = newPos + delim1len;
  250. if (bufferPos >= bufferLen) {
  251. bufferLen = bufferPos = 0;
  252. }
  253. if(!repeat)state = 0;
  254. it= { {(char*)buf + oldPos, newPos - oldPos}, true};
  255. return true;
  256. }
  257. }
  258. case 2:
  259. {
  260. uint8_t* buf = buffer;
  261. uint8_t* tmp = (uint8_t*) memchr(buf + bufferPos, delim2, bufferLen - bufferPos);
  262. int oldPos = bufferPos;
  263. if (tmp == NULL) {
  264. int oldLen = bufferLen;
  265. bufferLen = bufferPos = 0;
  266. it= { {(char*)buf + oldPos, oldLen - oldPos}, false};
  267. return true;
  268. } else {
  269. int newPos = tmp - buf;
  270. bufferPos = newPos + 1;
  271. if (bufferPos >= bufferLen) {
  272. bufferLen = bufferPos = 0;
  273. }
  274. if (!repeat) state = 0;
  275. it= { {(char*)buf + oldPos, newPos - oldPos}, true};
  276. return true;
  277. }
  278. }
  279. default: return false;
  280. }
  281. //if (delayedProcessing) goto reprocess;
  282. }
  283. };
  284. struct newPersistentStreamReader
  285. {
  286. struct item
  287. {
  288. String data;
  289. };
  290. uint8_t* buffer;
  291. const char* delim1;
  292. int capacity;
  293. int len;
  294. int pos;
  295. int searchPos;
  296. int state; //0: none; 1: readUntilString; 2: readUntilChar
  297. int delim1_len;
  298. char delim2;
  299. bool repeat;
  300. inline void clearBuffer() {
  301. searchPos = pos = len;
  302. }
  303. void resize(int nc) {
  304. uint8_t* tmp = (uint8_t*) realloc(buffer, nc);
  305. if (tmp == NULL) throw runtime_error(strerror(errno));
  306. buffer = tmp;
  307. capacity = nc;
  308. }
  309. void ensureCapacity(int c) {
  310. if (likely(c < capacity)) return;
  311. int nc = capacity;
  312. while (nc < c)
  313. nc *= 2;
  314. if (nc != capacity) resize(nc);
  315. }
  316. void reset() {
  317. len = pos = searchPos = state = 0;
  318. }
  319. newPersistentStreamReader(int c = 4096) :
  320. capacity(c), len(0), pos(0), searchPos(0), state(0) {
  321. buffer = (uint8_t*) malloc(c);
  322. if (buffer == NULL) throw runtime_error(strerror(errno));
  323. }
  324. ~newPersistentStreamReader() {
  325. free(buffer);
  326. }
  327. bool process(item& it) {
  328. if (len <= searchPos) return false;
  329. switch (state) {
  330. case 0:
  331. return false;
  332. case 1:
  333. {
  334. uint8_t* tmp = (uint8_t*) memmem(buffer + searchPos, len - searchPos, delim1,
  335. delim1_len);
  336. if (tmp == NULL) {
  337. //overlap the search so that delimitors that are cut in half at
  338. //the end of the buffer can be caught
  339. searchPos = len - delim1_len;
  340. return false;
  341. } else {
  342. int oldPos = pos;
  343. pos = searchPos = (tmp - buffer) + delim1_len;
  344. if (!repeat) state = 0;
  345. it= { {(char*)buffer + oldPos, int(tmp - buffer - oldPos)}};
  346. return true;
  347. }
  348. }
  349. case 2:
  350. {
  351. uint8_t* tmp = (uint8_t*) memchr(buffer + searchPos, delim2, len - searchPos);
  352. if (tmp == NULL) {
  353. searchPos = len;
  354. return false;
  355. } else {
  356. int oldPos = pos;
  357. pos = searchPos = (tmp - buffer) + 1;
  358. if (!repeat) state = 0;
  359. it= { {(char*)buffer + oldPos, int(tmp - buffer - oldPos)}};
  360. return true;
  361. }
  362. }
  363. default:
  364. return false;
  365. }
  366. }
  367. void readUntilString(const char* delim, int len, bool repeat = false) {
  368. state = 1;
  369. delim1 = delim;
  370. delim1_len = len;
  371. this->repeat = repeat;
  372. }
  373. void readUntilChar(char delim, bool repeat = false) {
  374. state = 2;
  375. delim2 = delim;
  376. this->repeat = repeat;
  377. }
  378. String beginPutData(int len) {
  379. ensureCapacity(this->len + len);
  380. return {(char*)buffer + this->len,this->capacity-this->len};
  381. }
  382. void endPutData(int len) {
  383. this->len += len;
  384. }
  385. inline String getBufferData() {
  386. return {(char*)buffer + pos, len - pos};
  387. }
  388. inline String getHistory(bool includeUnprocessed = true) {
  389. return {(char*)buffer, includeUnprocessed ? len : pos};
  390. }
  391. void clearHistory() {
  392. if (pos > 0) {
  393. memmove(buffer, buffer + pos, len - pos);
  394. len -= pos;
  395. searchPos -= pos;
  396. pos = 0;
  397. }
  398. }
  399. }
  400. ;
  401. }
  402. #endif /* STATEMACHINES_H_ */