string.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. /**
  2. * @file string.h
  3. * Furi string primitive
  4. */
  5. #pragma once
  6. #include <stdbool.h>
  7. #include <stdint.h>
  8. #include <stddef.h>
  9. #include <stdarg.h>
  10. #include <m-core.h>
  11. #ifdef __cplusplus
  12. extern "C" {
  13. #endif
  14. /**
  15. * @brief Furi string failure constant.
  16. */
  17. #define FURI_STRING_FAILURE ((size_t)-1)
  18. /**
  19. * @brief Furi string primitive.
  20. */
  21. typedef struct FuriString FuriString;
  22. //---------------------------------------------------------------------------
  23. // Constructors
  24. //---------------------------------------------------------------------------
  25. /**
  26. * @brief Allocate new FuriString.
  27. * @return FuriString*
  28. */
  29. FuriString* furi_string_alloc();
  30. /**
  31. * @brief Allocate new FuriString and set it to string.
  32. * Allocate & Set the string a to the string.
  33. * @param source
  34. * @return FuriString*
  35. */
  36. FuriString* furi_string_alloc_set(const FuriString* source);
  37. /**
  38. * @brief Allocate new FuriString and set it to C string.
  39. * Allocate & Set the string a to the C string.
  40. * @param cstr_source
  41. * @return FuriString*
  42. */
  43. FuriString* furi_string_alloc_set_str(const char cstr_source[]);
  44. /**
  45. * @brief Allocate new FuriString and printf to it.
  46. * Initialize and set a string to the given formatted value.
  47. * @param format
  48. * @param ...
  49. * @return FuriString*
  50. */
  51. FuriString* furi_string_alloc_printf(const char format[], ...)
  52. _ATTRIBUTE((__format__(__printf__, 1, 2)));
  53. /**
  54. * @brief Allocate new FuriString and printf to it.
  55. * Initialize and set a string to the given formatted value.
  56. * @param format
  57. * @param args
  58. * @return FuriString*
  59. */
  60. FuriString* furi_string_alloc_vprintf(const char format[], va_list args);
  61. /**
  62. * @brief Allocate new FuriString and move source string content to it.
  63. * Allocate the string, set it to the other one, and destroy the other one.
  64. * @param source
  65. * @return FuriString*
  66. */
  67. FuriString* furi_string_alloc_move(FuriString* source);
  68. //---------------------------------------------------------------------------
  69. // Destructors
  70. //---------------------------------------------------------------------------
  71. /**
  72. * @brief Free FuriString.
  73. * @param string
  74. */
  75. void furi_string_free(FuriString* string);
  76. //---------------------------------------------------------------------------
  77. // String memory management
  78. //---------------------------------------------------------------------------
  79. /**
  80. * @brief Reserve memory for string.
  81. * Modify the string capacity to be able to handle at least 'alloc' characters (including final null char).
  82. * @param string
  83. * @param size
  84. */
  85. void furi_string_reserve(FuriString* string, size_t size);
  86. /**
  87. * @brief Reset string.
  88. * Make the string empty.
  89. * @param s
  90. */
  91. void furi_string_reset(FuriString* string);
  92. /**
  93. * @brief Swap two strings.
  94. * Swap the two strings string_1 and string_2.
  95. * @param string_1
  96. * @param string_2
  97. */
  98. void furi_string_swap(FuriString* string_1, FuriString* string_2);
  99. /**
  100. * @brief Move string_2 content to string_1.
  101. * Set the string to the other one, and destroy the other one.
  102. * @param string_1
  103. * @param string_2
  104. */
  105. void furi_string_move(FuriString* string_1, FuriString* string_2);
  106. /**
  107. * @brief Compute a hash for the string.
  108. * @param string
  109. * @return size_t
  110. */
  111. size_t furi_string_hash(const FuriString* string);
  112. /**
  113. * @brief Get string size (usually length, but not for UTF-8)
  114. * @param string
  115. * @return size_t
  116. */
  117. size_t furi_string_size(const FuriString* string);
  118. /**
  119. * @brief Check that string is empty or not
  120. * @param string
  121. * @return bool
  122. */
  123. bool furi_string_empty(const FuriString* string);
  124. //---------------------------------------------------------------------------
  125. // Getters
  126. //---------------------------------------------------------------------------
  127. /**
  128. * @brief Get the character at the given index.
  129. * Return the selected character of the string.
  130. * @param string
  131. * @param index
  132. * @return char
  133. */
  134. char furi_string_get_char(const FuriString* string, size_t index);
  135. /**
  136. * @brief Return the string view a classic C string.
  137. * @param string
  138. * @return const char*
  139. */
  140. const char* furi_string_get_cstr(const FuriString* string);
  141. //---------------------------------------------------------------------------
  142. // Setters
  143. //---------------------------------------------------------------------------
  144. /**
  145. * @brief Set the string to the other string.
  146. * Set the string to the source string.
  147. * @param string
  148. * @param source
  149. */
  150. void furi_string_set(FuriString* string, FuriString* source);
  151. /**
  152. * @brief Set the string to the other C string.
  153. * Set the string to the source C string.
  154. * @param string
  155. * @param source
  156. */
  157. void furi_string_set_str(FuriString* string, const char source[]);
  158. /**
  159. * @brief Set the string to the n first characters of the C string.
  160. * @param string
  161. * @param source
  162. * @param length
  163. */
  164. void furi_string_set_strn(FuriString* string, const char source[], size_t length);
  165. /**
  166. * @brief Set the character at the given index.
  167. * @param string
  168. * @param index
  169. * @param c
  170. */
  171. void furi_string_set_char(FuriString* string, size_t index, const char c);
  172. /**
  173. * @brief Set the string to the n first characters of other one.
  174. * @param string
  175. * @param source
  176. * @param offset
  177. * @param length
  178. */
  179. void furi_string_set_n(FuriString* string, const FuriString* source, size_t offset, size_t length);
  180. /**
  181. * @brief Format in the string the given printf format
  182. * @param string
  183. * @param format
  184. * @param ...
  185. * @return int
  186. */
  187. int furi_string_printf(FuriString* string, const char format[], ...)
  188. _ATTRIBUTE((__format__(__printf__, 2, 3)));
  189. /**
  190. * @brief Format in the string the given printf format
  191. * @param string
  192. * @param format
  193. * @param args
  194. * @return int
  195. */
  196. int furi_string_vprintf(FuriString* string, const char format[], va_list args);
  197. //---------------------------------------------------------------------------
  198. // Appending
  199. //---------------------------------------------------------------------------
  200. /**
  201. * @brief Append a character to the string.
  202. * @param string
  203. * @param c
  204. */
  205. void furi_string_push_back(FuriString* string, char c);
  206. /**
  207. * @brief Append a string to the string.
  208. * Concatenate the string with the other string.
  209. * @param string_1
  210. * @param string_2
  211. */
  212. void furi_string_cat(FuriString* string_1, const FuriString* string_2);
  213. /**
  214. * @brief Append a C string to the string.
  215. * Concatenate the string with the C string.
  216. * @param string_1
  217. * @param cstring_2
  218. */
  219. void furi_string_cat_str(FuriString* string_1, const char cstring_2[]);
  220. /**
  221. * @brief Append to the string the formatted string of the given printf format.
  222. * @param string
  223. * @param format
  224. * @param ...
  225. * @return int
  226. */
  227. int furi_string_cat_printf(FuriString* string, const char format[], ...)
  228. _ATTRIBUTE((__format__(__printf__, 2, 3)));
  229. /**
  230. * @brief Append to the string the formatted string of the given printf format.
  231. * @param string
  232. * @param format
  233. * @param args
  234. * @return int
  235. */
  236. int furi_string_cat_vprintf(FuriString* string, const char format[], va_list args);
  237. //---------------------------------------------------------------------------
  238. // Comparators
  239. //---------------------------------------------------------------------------
  240. /**
  241. * @brief Compare two strings and return the sort order.
  242. * @param string_1
  243. * @param string_2
  244. * @return int
  245. */
  246. int furi_string_cmp(const FuriString* string_1, const FuriString* string_2);
  247. /**
  248. * @brief Compare string with C string and return the sort order.
  249. * @param string_1
  250. * @param cstring_2
  251. * @return int
  252. */
  253. int furi_string_cmp_str(const FuriString* string_1, const char cstring_2[]);
  254. /**
  255. * @brief Compare two strings (case insensitive according to the current locale) and return the sort order.
  256. * Note: doesn't work with UTF-8 strings.
  257. * @param string_1
  258. * @param string_2
  259. * @return int
  260. */
  261. int furi_string_cmpi(const FuriString* string_1, const FuriString* string_2);
  262. /**
  263. * @brief Compare string with C string (case insensitive according to the current locale) and return the sort order.
  264. * Note: doesn't work with UTF-8 strings.
  265. * @param string_1
  266. * @param cstring_2
  267. * @return int
  268. */
  269. int furi_string_cmpi_str(const FuriString* string_1, const char cstring_2[]);
  270. //---------------------------------------------------------------------------
  271. // Search
  272. //---------------------------------------------------------------------------
  273. /**
  274. * @brief Search the first occurrence of the needle in the string from the position start.
  275. * Return STRING_FAILURE if not found.
  276. * By default, start is zero.
  277. * @param string
  278. * @param needle
  279. * @param start
  280. * @return size_t
  281. */
  282. size_t furi_string_search(const FuriString* string, const FuriString* needle, size_t start);
  283. /**
  284. * @brief Search the first occurrence of the needle in the string from the position start.
  285. * Return STRING_FAILURE if not found.
  286. * @param string
  287. * @param needle
  288. * @param start
  289. * @return size_t
  290. */
  291. size_t furi_string_search_str(const FuriString* string, const char needle[], size_t start);
  292. /**
  293. * @brief Search for the position of the character c from the position start (include) in the string.
  294. * Return STRING_FAILURE if not found.
  295. * By default, start is zero.
  296. * @param string
  297. * @param c
  298. * @param start
  299. * @return size_t
  300. */
  301. size_t furi_string_search_char(const FuriString* string, char c, size_t start);
  302. /**
  303. * @brief Reverse search for the position of the character c from the position start (include) in the string.
  304. * Return STRING_FAILURE if not found.
  305. * By default, start is zero.
  306. * @param string
  307. * @param c
  308. * @param start
  309. * @return size_t
  310. */
  311. size_t furi_string_search_rchar(const FuriString* string, char c, size_t start);
  312. //---------------------------------------------------------------------------
  313. // Equality
  314. //---------------------------------------------------------------------------
  315. /**
  316. * @brief Test if two strings are equal.
  317. * @param string_1
  318. * @param string_2
  319. * @return bool
  320. */
  321. bool furi_string_equal(const FuriString* string_1, const FuriString* string_2);
  322. /**
  323. * @brief Test if the string is equal to the C string.
  324. * @param string_1
  325. * @param cstring_2
  326. * @return bool
  327. */
  328. bool furi_string_equal_str(const FuriString* string_1, const char cstring_2[]);
  329. //---------------------------------------------------------------------------
  330. // Replace
  331. //---------------------------------------------------------------------------
  332. /**
  333. * @brief Replace in the string the sub-string at position 'pos' for 'len' bytes into the C string 'replace'.
  334. * @param string
  335. * @param pos
  336. * @param len
  337. * @param replace
  338. */
  339. void furi_string_replace_at(FuriString* string, size_t pos, size_t len, const char replace[]);
  340. /**
  341. * @brief Replace a string 'needle' to string 'replace' in a string from 'start' position.
  342. * By default, start is zero.
  343. * Return STRING_FAILURE if 'needle' not found or replace position.
  344. * @param string
  345. * @param needle
  346. * @param replace
  347. * @param start
  348. * @return size_t
  349. */
  350. size_t
  351. furi_string_replace(FuriString* string, FuriString* needle, FuriString* replace, size_t start);
  352. /**
  353. * @brief Replace a C string 'needle' to C string 'replace' in a string from 'start' position.
  354. * By default, start is zero.
  355. * Return STRING_FAILURE if 'needle' not found or replace position.
  356. * @param string
  357. * @param needle
  358. * @param replace
  359. * @param start
  360. * @return size_t
  361. */
  362. size_t furi_string_replace_str(
  363. FuriString* string,
  364. const char needle[],
  365. const char replace[],
  366. size_t start);
  367. /**
  368. * @brief Replace all occurrences of 'needle' string into 'replace' string.
  369. * @param string
  370. * @param needle
  371. * @param replace
  372. */
  373. void furi_string_replace_all(
  374. FuriString* string,
  375. const FuriString* needle,
  376. const FuriString* replace);
  377. /**
  378. * @brief Replace all occurrences of 'needle' C string into 'replace' C string.
  379. * @param string
  380. * @param needle
  381. * @param replace
  382. */
  383. void furi_string_replace_all_str(FuriString* string, const char needle[], const char replace[]);
  384. //---------------------------------------------------------------------------
  385. // Start / End tests
  386. //---------------------------------------------------------------------------
  387. /**
  388. * @brief Test if the string starts with the given string.
  389. * @param string
  390. * @param start
  391. * @return bool
  392. */
  393. bool furi_string_start_with(const FuriString* string, const FuriString* start);
  394. /**
  395. * @brief Test if the string starts with the given C string.
  396. * @param string
  397. * @param start
  398. * @return bool
  399. */
  400. bool furi_string_start_with_str(const FuriString* string, const char start[]);
  401. /**
  402. * @brief Test if the string ends with the given string.
  403. * @param string
  404. * @param end
  405. * @return bool
  406. */
  407. bool furi_string_end_with(const FuriString* string, const FuriString* end);
  408. /**
  409. * @brief Test if the string ends with the given C string.
  410. * @param string
  411. * @param end
  412. * @return bool
  413. */
  414. bool furi_string_end_with_str(const FuriString* string, const char end[]);
  415. //---------------------------------------------------------------------------
  416. // Trim
  417. //---------------------------------------------------------------------------
  418. /**
  419. * @brief Trim the string left to the first 'index' bytes.
  420. * @param string
  421. * @param index
  422. */
  423. void furi_string_left(FuriString* string, size_t index);
  424. /**
  425. * @brief Trim the string right from the 'index' position to the last position.
  426. * @param string
  427. * @param index
  428. */
  429. void furi_string_right(FuriString* string, size_t index);
  430. /**
  431. * @brief Trim the string from position index to size bytes.
  432. * See also furi_string_set_n.
  433. * @param string
  434. * @param index
  435. * @param size
  436. */
  437. void furi_string_mid(FuriString* string, size_t index, size_t size);
  438. /**
  439. * @brief Trim a string from the given set of characters (default is " \n\r\t").
  440. * @param string
  441. * @param chars
  442. */
  443. void furi_string_trim(FuriString* string, const char chars[]);
  444. //---------------------------------------------------------------------------
  445. // UTF8
  446. //---------------------------------------------------------------------------
  447. /**
  448. * @brief An unicode value.
  449. */
  450. typedef unsigned int FuriStringUnicodeValue;
  451. /**
  452. * @brief Compute the length in UTF8 characters in the string.
  453. * @param string
  454. * @return size_t
  455. */
  456. size_t furi_string_utf8_length(FuriString* string);
  457. /**
  458. * @brief Push unicode into string, encoding it in UTF8.
  459. * @param string
  460. * @param unicode
  461. */
  462. void furi_string_utf8_push(FuriString* string, FuriStringUnicodeValue unicode);
  463. /**
  464. * @brief State of the UTF8 decoding machine state.
  465. */
  466. typedef enum {
  467. FuriStringUTF8StateStarting,
  468. FuriStringUTF8StateDecoding1,
  469. FuriStringUTF8StateDecoding2,
  470. FuriStringUTF8StateDecoding3,
  471. FuriStringUTF8StateError
  472. } FuriStringUTF8State;
  473. /**
  474. * @brief Main generic UTF8 decoder.
  475. * It takes a character, and the previous state and the previous value of the unicode value.
  476. * It updates the state and the decoded unicode value.
  477. * A decoded unicode encoded value is valid only when the state is FuriStringUTF8StateStarting.
  478. * @param c
  479. * @param state
  480. * @param unicode
  481. */
  482. void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnicodeValue* unicode);
  483. //---------------------------------------------------------------------------
  484. // Lasciate ogne speranza, voi ch’entrate
  485. //---------------------------------------------------------------------------
  486. /**
  487. *
  488. * Select either the string function or the str function depending on
  489. * the b operand to the function.
  490. * func1 is the string function / func2 is the str function.
  491. */
  492. /**
  493. * @brief Select for 1 argument
  494. */
  495. #define FURI_STRING_SELECT1(func1, func2, a) \
  496. _Generic((a), char* : func2, const char* : func2, FuriString* : func1, const FuriString* : func1)(a)
  497. /**
  498. * @brief Select for 2 arguments
  499. */
  500. #define FURI_STRING_SELECT2(func1, func2, a, b) \
  501. _Generic((b), char* : func2, const char* : func2, FuriString* : func1, const FuriString* : func1)(a, b)
  502. /**
  503. * @brief Select for 3 arguments
  504. */
  505. #define FURI_STRING_SELECT3(func1, func2, a, b, c) \
  506. _Generic((b), char* : func2, const char* : func2, FuriString* : func1, const FuriString* : func1)(a, b, c)
  507. /**
  508. * @brief Select for 4 arguments
  509. */
  510. #define FURI_STRING_SELECT4(func1, func2, a, b, c, d) \
  511. _Generic((b), char* : func2, const char* : func2, FuriString* : func1, const FuriString* : func1)(a, b, c, d)
  512. /**
  513. * @brief Allocate new FuriString and set it content to string (or C string).
  514. * ([c]string)
  515. */
  516. #define furi_string_alloc_set(a) \
  517. FURI_STRING_SELECT1(furi_string_alloc_set, furi_string_alloc_set_str, a)
  518. /**
  519. * @brief Set the string content to string (or C string).
  520. * (string, [c]string)
  521. */
  522. #define furi_string_set(a, b) FURI_STRING_SELECT2(furi_string_set, furi_string_set_str, a, b)
  523. /**
  524. * @brief Compare string with string (or C string) and return the sort order.
  525. * Note: doesn't work with UTF-8 strings.
  526. * (string, [c]string)
  527. */
  528. #define furi_string_cmp(a, b) FURI_STRING_SELECT2(furi_string_cmp, furi_string_cmp_str, a, b)
  529. /**
  530. * @brief Compare string with string (or C string) (case insensitive according to the current locale) and return the sort order.
  531. * Note: doesn't work with UTF-8 strings.
  532. * (string, [c]string)
  533. */
  534. #define furi_string_cmpi(a, b) FURI_STRING_SELECT2(furi_string_cmpi, furi_string_cmpi_str, a, b)
  535. /**
  536. * @brief Test if the string is equal to the string (or C string).
  537. * (string, [c]string)
  538. */
  539. #define furi_string_equal(a, b) FURI_STRING_SELECT2(furi_string_equal, furi_string_equal_str, a, b)
  540. /**
  541. * @brief Replace all occurrences of string into string (or C string to another C string) in a string.
  542. * (string, [c]string, [c]string)
  543. */
  544. #define furi_string_replace_all(a, b, c) \
  545. FURI_STRING_SELECT3(furi_string_replace_all, furi_string_replace_all_str, a, b, c)
  546. /**
  547. * @brief Search for a string (or C string) in a string
  548. * (string, [c]string[, start=0])
  549. */
  550. #define furi_string_search(v, ...) \
  551. M_APPLY( \
  552. FURI_STRING_SELECT3, \
  553. furi_string_search, \
  554. furi_string_search_str, \
  555. v, \
  556. M_IF_DEFAULT1(0, __VA_ARGS__))
  557. /**
  558. * @brief Search for a C string in a string
  559. * (string, cstring[, start=0])
  560. */
  561. #define furi_string_search_str(v, ...) \
  562. M_APPLY(furi_string_search_str, v, M_IF_DEFAULT1(0, __VA_ARGS__))
  563. /**
  564. * @brief Test if the string starts with the given string (or C string).
  565. * (string, [c]string)
  566. */
  567. #define furi_string_start_with(a, b) \
  568. FURI_STRING_SELECT2(furi_string_start_with, furi_string_start_with_str, a, b)
  569. /**
  570. * @brief Test if the string ends with the given string (or C string).
  571. * (string, [c]string)
  572. */
  573. #define furi_string_end_with(a, b) \
  574. FURI_STRING_SELECT2(furi_string_end_with, furi_string_end_with_str, a, b)
  575. /**
  576. * @brief Append a string (or C string) to the string.
  577. * (string, [c]string)
  578. */
  579. #define furi_string_cat(a, b) FURI_STRING_SELECT2(furi_string_cat, furi_string_cat_str, a, b)
  580. /**
  581. * @brief Trim a string from the given set of characters (default is " \n\r\t").
  582. * (string[, set=" \n\r\t"])
  583. */
  584. #define furi_string_trim(...) M_APPLY(furi_string_trim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__))
  585. /**
  586. * @brief Search for a character in a string.
  587. * (string, character[, start=0])
  588. */
  589. #define furi_string_search_char(v, ...) \
  590. M_APPLY(furi_string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__))
  591. /**
  592. * @brief Reverse Search for a character in a string.
  593. * (string, character[, start=0])
  594. */
  595. #define furi_string_search_rchar(v, ...) \
  596. M_APPLY(furi_string_search_rchar, v, M_IF_DEFAULT1(0, __VA_ARGS__))
  597. /**
  598. * @brief Replace a string to another string (or C string to another C string) in a string.
  599. * (string, [c]string, [c]string[, start=0])
  600. */
  601. #define furi_string_replace(a, b, ...) \
  602. M_APPLY( \
  603. FURI_STRING_SELECT4, \
  604. furi_string_replace, \
  605. furi_string_replace_str, \
  606. a, \
  607. b, \
  608. M_IF_DEFAULT1(0, __VA_ARGS__))
  609. /**
  610. * @brief Replace a C string to another C string in a string.
  611. * (string, cstring, cstring[, start=0])
  612. */
  613. #define furi_string_replace_str(a, b, ...) \
  614. M_APPLY(furi_string_replace_str, a, b, M_IF_DEFAULT1(0, __VA_ARGS__))
  615. /**
  616. * @brief INIT OPLIST for FuriString.
  617. */
  618. #define F_STR_INIT(a) ((a) = furi_string_alloc())
  619. /**
  620. * @brief INIT SET OPLIST for FuriString.
  621. */
  622. #define F_STR_INIT_SET(a, b) ((a) = furi_string_alloc_set(b))
  623. /**
  624. * @brief INIT MOVE OPLIST for FuriString.
  625. */
  626. #define F_STR_INIT_MOVE(a, b) ((a) = furi_string_alloc_move(b))
  627. /**
  628. * @brief OPLIST for FuriString.
  629. */
  630. #define FURI_STRING_OPLIST \
  631. (INIT(F_STR_INIT), \
  632. INIT_SET(F_STR_INIT_SET), \
  633. SET(furi_string_set), \
  634. INIT_MOVE(F_STR_INIT_MOVE), \
  635. MOVE(furi_string_move), \
  636. SWAP(furi_string_swap), \
  637. RESET(furi_string_reset), \
  638. EMPTY_P(furi_string_empty), \
  639. CLEAR(furi_string_free), \
  640. HASH(furi_string_hash), \
  641. EQUAL(furi_string_equal), \
  642. CMP(furi_string_cmp), \
  643. TYPE(FuriString*))
  644. #ifdef __cplusplus
  645. }
  646. #endif