unicode.hpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #pragma once
  2. #include <sol/string_view.hpp>
  3. #include <array>
  4. #include <cstring>
  5. namespace sol {
  6. // Everything here was lifted pretty much straight out of
  7. // ogonek, because fuck figuring it out=
  8. namespace unicode {
  9. enum class error_code {
  10. ok = 0,
  11. invalid_code_point,
  12. invalid_code_unit,
  13. invalid_leading_surrogate,
  14. invalid_trailing_surrogate,
  15. sequence_too_short,
  16. overlong_sequence,
  17. };
  18. inline const string_view& to_string(error_code ec) {
  19. static const string_view storage[7] = { "ok",
  20. "invalid code points",
  21. "invalid code unit",
  22. "invalid leading surrogate",
  23. "invalid trailing surrogate",
  24. "sequence too short",
  25. "overlong sequence" };
  26. return storage[static_cast<std::size_t>(ec)];
  27. }
  28. template <typename It>
  29. struct decoded_result {
  30. error_code error;
  31. char32_t codepoint;
  32. It next;
  33. };
  34. template <typename C>
  35. struct encoded_result {
  36. error_code error;
  37. std::size_t code_units_size;
  38. std::array<C, 4> code_units;
  39. };
  40. struct unicode_detail {
  41. // codepoint related
  42. static constexpr char32_t last_code_point = 0x10FFFF;
  43. static constexpr char32_t first_lead_surrogate = 0xD800;
  44. static constexpr char32_t last_lead_surrogate = 0xDBFF;
  45. static constexpr char32_t first_trail_surrogate = 0xDC00;
  46. static constexpr char32_t last_trail_surrogate = 0xDFFF;
  47. static constexpr char32_t first_surrogate = first_lead_surrogate;
  48. static constexpr char32_t last_surrogate = last_trail_surrogate;
  49. static constexpr bool is_lead_surrogate(char32_t u) {
  50. return u >= first_lead_surrogate && u <= last_lead_surrogate;
  51. }
  52. static constexpr bool is_trail_surrogate(char32_t u) {
  53. return u >= first_trail_surrogate && u <= last_trail_surrogate;
  54. }
  55. static constexpr bool is_surrogate(char32_t u) {
  56. return u >= first_surrogate && u <= last_surrogate;
  57. }
  58. // utf8 related
  59. static constexpr auto last_1byte_value = 0x7Fu;
  60. static constexpr auto last_2byte_value = 0x7FFu;
  61. static constexpr auto last_3byte_value = 0xFFFFu;
  62. static constexpr auto start_2byte_mask = 0x80u;
  63. static constexpr auto start_3byte_mask = 0xE0u;
  64. static constexpr auto start_4byte_mask = 0xF0u;
  65. static constexpr auto continuation_mask = 0xC0u;
  66. static constexpr auto continuation_signature = 0x80u;
  67. static constexpr bool is_invalid(unsigned char b) {
  68. return b == 0xC0 || b == 0xC1 || b > 0xF4;
  69. }
  70. static constexpr bool is_continuation(unsigned char b) {
  71. return (b & unicode_detail::continuation_mask) == unicode_detail::continuation_signature;
  72. }
  73. static constexpr bool is_overlong(char32_t u, std::size_t bytes) {
  74. return u <= unicode_detail::last_1byte_value || (u <= unicode_detail::last_2byte_value && bytes > 2)
  75. || (u <= unicode_detail::last_3byte_value && bytes > 3);
  76. }
  77. static constexpr int sequence_length(unsigned char b) {
  78. return (b & start_2byte_mask) == 0 ? 1
  79. : (b & start_3byte_mask) != start_3byte_mask ? 2
  80. : (b & start_4byte_mask) != start_4byte_mask ? 3
  81. : 4;
  82. }
  83. static constexpr char32_t decode(unsigned char b0, unsigned char b1) {
  84. return (static_cast<char32_t>((b0 & 0x1Fu) << 6u) | static_cast<char32_t>(b1 & 0x3Fu));
  85. }
  86. static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2) {
  87. return static_cast<char32_t>((b0 & 0x0Fu) << 12u) | static_cast<char32_t>((b1 & 0x3Fu) << 6u) | static_cast<char32_t>(b2 & 0x3Fu);
  88. }
  89. static constexpr char32_t decode(unsigned char b0, unsigned char b1, unsigned char b2, unsigned char b3) {
  90. return static_cast<char32_t>(static_cast<char32_t>((b0 & 0x07u) << 18u) | static_cast<char32_t>((b1 & 0x3F) << 12)
  91. | static_cast<char32_t>((b2 & 0x3Fu) << 6u) | static_cast<char32_t>(b3 & 0x3Fu));
  92. }
  93. // utf16 related
  94. static constexpr char32_t last_bmp_value = 0xFFFF;
  95. static constexpr char32_t normalizing_value = 0x10000;
  96. static constexpr int lead_surrogate_bitmask = 0xFFC00;
  97. static constexpr int trail_surrogate_bitmask = 0x3FF;
  98. static constexpr int lead_shifted_bits = 10;
  99. static constexpr char32_t replacement = 0xFFFD;
  100. static char32_t combine_surrogates(char16_t lead, char16_t trail) {
  101. auto hi = lead - first_lead_surrogate;
  102. auto lo = trail - first_trail_surrogate;
  103. return normalizing_value + ((hi << lead_shifted_bits) | lo);
  104. }
  105. };
  106. inline encoded_result<char> code_point_to_utf8(char32_t codepoint) {
  107. encoded_result<char> er;
  108. er.error = error_code::ok;
  109. if (codepoint <= unicode_detail::last_1byte_value) {
  110. er.code_units_size = 1;
  111. er.code_units = std::array<char, 4> { { static_cast<char>(codepoint) } };
  112. }
  113. else if (codepoint <= unicode_detail::last_2byte_value) {
  114. er.code_units_size = 2;
  115. er.code_units = std::array<char, 4> { {
  116. static_cast<char>(0xC0 | ((codepoint & 0x7C0) >> 6)),
  117. static_cast<char>(0x80 | (codepoint & 0x3F)),
  118. } };
  119. }
  120. else if (codepoint <= unicode_detail::last_3byte_value) {
  121. er.code_units_size = 3;
  122. er.code_units = std::array<char, 4> { {
  123. static_cast<char>(0xE0 | ((codepoint & 0xF000) >> 12)),
  124. static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)),
  125. static_cast<char>(0x80 | (codepoint & 0x3F)),
  126. } };
  127. }
  128. else {
  129. er.code_units_size = 4;
  130. er.code_units = std::array<char, 4> { {
  131. static_cast<char>(0xF0 | ((codepoint & 0x1C0000) >> 18)),
  132. static_cast<char>(0x80 | ((codepoint & 0x3F000) >> 12)),
  133. static_cast<char>(0x80 | ((codepoint & 0xFC0) >> 6)),
  134. static_cast<char>(0x80 | (codepoint & 0x3F)),
  135. } };
  136. }
  137. return er;
  138. }
  139. inline encoded_result<char16_t> code_point_to_utf16(char32_t codepoint) {
  140. encoded_result<char16_t> er;
  141. if (codepoint <= unicode_detail::last_bmp_value) {
  142. er.code_units_size = 1;
  143. er.code_units = std::array<char16_t, 4> { { static_cast<char16_t>(codepoint) } };
  144. er.error = error_code::ok;
  145. }
  146. else {
  147. auto normal = codepoint - unicode_detail::normalizing_value;
  148. auto lead = unicode_detail::first_lead_surrogate + ((normal & unicode_detail::lead_surrogate_bitmask) >> unicode_detail::lead_shifted_bits);
  149. auto trail = unicode_detail::first_trail_surrogate + (normal & unicode_detail::trail_surrogate_bitmask);
  150. er.code_units = std::array<char16_t, 4> { { static_cast<char16_t>(lead), static_cast<char16_t>(trail) } };
  151. er.code_units_size = 2;
  152. er.error = error_code::ok;
  153. }
  154. return er;
  155. }
  156. inline encoded_result<char32_t> code_point_to_utf32(char32_t codepoint) {
  157. encoded_result<char32_t> er;
  158. er.code_units_size = 1;
  159. er.code_units[0] = codepoint;
  160. er.error = error_code::ok;
  161. return er;
  162. }
  163. template <typename It>
  164. inline decoded_result<It> utf8_to_code_point(It it, It last) {
  165. decoded_result<It> dr;
  166. if (it == last) {
  167. dr.next = it;
  168. dr.error = error_code::sequence_too_short;
  169. return dr;
  170. }
  171. unsigned char b0 = static_cast<unsigned char>(*it);
  172. std::size_t length = static_cast<std::size_t>(unicode_detail::sequence_length(b0));
  173. if (length == 1) {
  174. dr.codepoint = static_cast<char32_t>(b0);
  175. dr.error = error_code::ok;
  176. ++it;
  177. dr.next = it;
  178. return dr;
  179. }
  180. if (unicode_detail::is_invalid(b0) || unicode_detail::is_continuation(b0)) {
  181. dr.error = error_code::invalid_code_unit;
  182. dr.next = it;
  183. return dr;
  184. }
  185. ++it;
  186. std::array<unsigned char, 4> b;
  187. b[0] = b0;
  188. for (std::size_t i = 1; i < length; ++i) {
  189. b[i] = static_cast<unsigned char>(*it);
  190. if (!unicode_detail::is_continuation(b[i])) {
  191. dr.error = error_code::invalid_code_unit;
  192. dr.next = it;
  193. return dr;
  194. }
  195. ++it;
  196. }
  197. char32_t decoded;
  198. switch (length) {
  199. case 2:
  200. decoded = unicode_detail::decode(b[0], b[1]);
  201. break;
  202. case 3:
  203. decoded = unicode_detail::decode(b[0], b[1], b[2]);
  204. break;
  205. default:
  206. decoded = unicode_detail::decode(b[0], b[1], b[2], b[3]);
  207. break;
  208. }
  209. if (unicode_detail::is_overlong(decoded, length)) {
  210. dr.error = error_code::overlong_sequence;
  211. return dr;
  212. }
  213. if (unicode_detail::is_surrogate(decoded) || decoded > unicode_detail::last_code_point) {
  214. dr.error = error_code::invalid_code_point;
  215. return dr;
  216. }
  217. // then everything is fine
  218. dr.codepoint = decoded;
  219. dr.error = error_code::ok;
  220. dr.next = it;
  221. return dr;
  222. }
  223. template <typename It>
  224. inline decoded_result<It> utf16_to_code_point(It it, It last) {
  225. decoded_result<It> dr;
  226. if (it == last) {
  227. dr.next = it;
  228. dr.error = error_code::sequence_too_short;
  229. return dr;
  230. }
  231. char16_t lead = static_cast<char16_t>(*it);
  232. if (!unicode_detail::is_surrogate(lead)) {
  233. ++it;
  234. dr.codepoint = static_cast<char32_t>(lead);
  235. dr.next = it;
  236. dr.error = error_code::ok;
  237. return dr;
  238. }
  239. if (!unicode_detail::is_lead_surrogate(lead)) {
  240. dr.error = error_code::invalid_leading_surrogate;
  241. dr.next = it;
  242. return dr;
  243. }
  244. ++it;
  245. auto trail = *it;
  246. if (!unicode_detail::is_trail_surrogate(trail)) {
  247. dr.error = error_code::invalid_trailing_surrogate;
  248. dr.next = it;
  249. return dr;
  250. }
  251. dr.codepoint = unicode_detail::combine_surrogates(lead, trail);
  252. dr.next = ++it;
  253. dr.error = error_code::ok;
  254. return dr;
  255. }
  256. template <typename It>
  257. inline decoded_result<It> utf32_to_code_point(It it, It last) {
  258. decoded_result<It> dr;
  259. if (it == last) {
  260. dr.next = it;
  261. dr.error = error_code::sequence_too_short;
  262. return dr;
  263. }
  264. dr.codepoint = static_cast<char32_t>(*it);
  265. dr.next = ++it;
  266. dr.error = error_code::ok;
  267. return dr;
  268. }
  269. } // namespace unicode
  270. } // namespace sol