General Purpose library for Freestanding C++ and POSIX systems
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

896 rader
24 KiB

4 år sedan
4 år sedan
4 år sedan
4 år sedan
  1. #pragma once
  2. #include <gp/algorithms/repeat.hpp>
  3. #include <gp/math/boolean/bitops.hpp>
  4. #include <gp/functional/optional.hpp>
  5. #include <gp/utils/pair.hpp>
  6. #include <gp/functional/variant.hpp>
  7. #include <gp/containers/vector.hpp>
  8. // TODO: Rewrite in a more ORM-like way
  9. // TODO: Implement some bignum for support
  10. namespace gp {
  11. enum class cbor_type : uint8_t {
  12. uint = 0,
  13. nint = 1,
  14. bstr = 2,
  15. tstr = 3,
  16. list = 4,
  17. hmap = 5,
  18. tags = 6,
  19. oths = 7
  20. };
  21. enum class cbor_oths : uint8_t {
  22. value_false = 20,
  23. value_true = 21,
  24. value_null = 22,
  25. value_undefined = 23,
  26. byte = 24,
  27. word = 25,
  28. dword = 26,
  29. qword = 27,
  30. terminator = 31
  31. };
  32. enum class cbor_tags {
  33. datetime = 0,
  34. unix_time = 1,
  35. ubignum = 2,
  36. nbignum = 3,
  37. decimal = 4,
  38. bigfloat = 5,
  39. cose_encrypt0 = 16,
  40. cose_mac0 = 17,
  41. cose_sign1 = 18,
  42. expected_base64url = 21,
  43. expected_base64 = 22,
  44. expected_base16 = 23,
  45. encoded_cbor = 24,
  46. url = 32,
  47. base64url = 33,
  48. base64 = 34,
  49. regexp = 35,
  50. mime = 36,
  51. cose_encrypt = 96,
  52. cose_mac = 97,
  53. cose_sign = 98,
  54. signature = 55799
  55. };
  56. struct cbor_number final {
  57. bool sign;
  58. uint64_t value;
  59. bool is_negative() {
  60. return sign;
  61. }
  62. cbor_number(int64_t v)
  63. : sign{v < 0}
  64. , value{uint64_t((sign ? -1 : 1) * v)}
  65. {}
  66. cbor_number(bool s, uint64_t v)
  67. : sign{s}
  68. , value{v}
  69. {}
  70. };
  71. struct ieee754_hf final {
  72. uint16_t sign : 1;
  73. uint16_t exponent : 5;
  74. uint16_t mantissa : 10;
  75. // TODO: support for denormalized values and NaNs
  76. operator float() {
  77. auto a = (uint32_t)((sign<<16) | ((exponent+0x1C000)<<13) | (mantissa<<13));
  78. return *(float*)&a;
  79. }
  80. operator double() {
  81. return (float)*this;
  82. }
  83. };
  84. template<typename T>
  85. vector<char>& push_as_cbor(vector<char>&, T);
  86. template<typename T>
  87. vector<char>& push_as_cbor(vector<char>&, T&);
  88. inline vector<char>& push_integer_with_header_as_cbor(vector<char>& src, uint8_t header, uint64_t value) {
  89. auto norm_v = (value<0) ? -value : value;
  90. if(norm_v <= 23) {
  91. src.push_back(header+norm_v);
  92. } else if(norm_v < (1ll<<8ll)) {
  93. src.push_back(header+24);
  94. src.push_back(norm_v);
  95. } else if(norm_v < (1ll<<16ll)) {
  96. endian_wrapper<uint16_t, endian::big> wrapper = norm_v;
  97. src.push_back(header+25);
  98. for(auto byte : wrapper.bytes) {
  99. src.push_back(byte);
  100. }
  101. } else if(norm_v < (1ll<<32ll)) {
  102. endian_wrapper<uint32_t, endian::big> wrapper = norm_v;
  103. src.push_back(header+26);
  104. for(auto byte : wrapper.bytes) {
  105. src.push_back(byte);
  106. }
  107. } else {
  108. endian_wrapper<uint64_t, endian::big> wrapper = norm_v;
  109. src.push_back(header+27);
  110. for(auto byte : wrapper.bytes) {
  111. src.push_back(byte);
  112. }
  113. }
  114. return src;
  115. }
  116. /**
  117. * @brief Pushes an integer as CBOR on the vector
  118. *
  119. * @param src the vector on which the push happens
  120. * @param value the value to push, can be signed
  121. * @return vector<char>& the same reference that was received for the source
  122. */
  123. template<>
  124. vector<char>& push_as_cbor<int64_t>(vector<char>& src, int64_t& value) {
  125. uint8_t sign = (value<0) ? 0b00100000 : 0;
  126. auto norm_v = (value<0) ? -value : value;
  127. return push_integer_with_header_as_cbor(src, sign, norm_v);
  128. }
  129. /**
  130. * @brief Pushes an unsigned integer as CBOR on the vector
  131. *
  132. * @param src the vector on which the push happens
  133. * @param value the value to push, cannot be signed
  134. * @return vector<char>& the same reference that was received for the source
  135. */
  136. template<>
  137. vector<char>& push_as_cbor<uint64_t>(vector<char>& src, uint64_t& value) {
  138. return push_integer_with_header_as_cbor(src, 0, value);
  139. }
  140. template<>
  141. vector<char>& push_as_cbor<std::nullptr_t>(vector<char>& src, std::nullptr_t) {
  142. src.push_back(0b11110110);
  143. return src;
  144. }
  145. struct cbor_undefined{};
  146. template<>
  147. vector<char>& push_as_cbor<cbor_undefined>(vector<char>& src, cbor_undefined) {
  148. src.push_back(0b11110111);
  149. return src;
  150. }
  151. template<>
  152. vector<char>& push_as_cbor<bool>(vector<char>& src, bool value) {
  153. src.push_back(0b11110100+(value ? 1 : 0));
  154. return src;
  155. }
  156. template<>
  157. vector<char>& push_as_cbor<gp::buffer<char>>(vector<char>& src, gp::buffer<char> value) {
  158. push_integer_with_header_as_cbor(src, (uint8_t)0b01000000, value.size());
  159. for(auto byte : value) {
  160. src.push_back(byte);
  161. }
  162. return src;
  163. }
  164. struct cbor_array_initiator {
  165. size_t size;
  166. };
  167. struct cbor_associative_array_initiator {
  168. size_t size;
  169. };
  170. template<>
  171. vector<char>& push_as_cbor<cbor_array_initiator>(vector<char>& src, cbor_array_initiator value) {
  172. return push_integer_with_header_as_cbor(src, (uint8_t)0b10000000, value.size);
  173. }
  174. template<>
  175. vector<char>& push_as_cbor<cbor_associative_array_initiator>(vector<char>& src, cbor_associative_array_initiator value) {
  176. return push_integer_with_header_as_cbor(src, (uint8_t)0b10100000, value.size);
  177. }
  178. template<typename First, typename Second>
  179. vector<char>& push_as_cbor(vector<char>& src, gp::pair<First, Second>& value) {
  180. push_as_cbor<First>(src,value.first);
  181. return push_as_cbor<Second>(src,value.second);
  182. }
  183. struct cbor_tag_initiator {
  184. union {
  185. size_t as_integer;
  186. cbor_tags tag;
  187. };
  188. };
  189. template<>
  190. vector<char>& push_as_cbor<cbor_tag_initiator>(vector<char>& src, cbor_tag_initiator value) {
  191. return push_integer_with_header_as_cbor(src, (uint8_t)0b11000000, value.as_integer);
  192. }
  193. using parsing_state = gp::buffer<char>;
  194. template<typename T>
  195. gp::pair<gp::optional<T>, parsing_state> read_cbor(parsing_state state);
  196. inline gp::pair<gp::optional<uint64_t>, parsing_state> pull_arbitrary_integer_from_cbor(parsing_state state) {
  197. auto local = (uint8_t)0b00011111 & (uint8_t)*state.begin();
  198. if(local <= 23) {
  199. return {*state.begin(), {state.begin()+1, state.end()}};
  200. } else {
  201. switch((cbor_oths)local) {
  202. case cbor_oths::byte: {
  203. if(state.size() < 2) return {nullopt, state};
  204. return {*(state.begin()+1), {state.begin()+2, state.end()}};
  205. }
  206. case cbor_oths::word: {
  207. if(state.size() < 3) return {nullopt, state};
  208. return {
  209. uint16_t(*(state.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, endian::big>>().begin().data)),
  210. {state.begin()+3, state.end()}
  211. };
  212. }
  213. case cbor_oths::dword: {
  214. if(state.size() < 5) return {nullopt, state};
  215. return {
  216. uint32_t(*(state.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, endian::big>>().begin().data)),
  217. {state.begin()+5, state.end()}
  218. };
  219. }
  220. case cbor_oths::qword: {
  221. if(state.size() < 9) return {nullopt, state};
  222. return {
  223. uint64_t(*(state.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, endian::big>>().begin().data)),
  224. {state.begin()+9, state.end()}
  225. };
  226. }
  227. default: {
  228. return {nullopt, state};
  229. }
  230. }
  231. }
  232. }
  233. template<>
  234. gp::pair<gp::optional<int64_t>, parsing_state> read_cbor<int64_t>(parsing_state state) {
  235. if(state.size()) return {nullopt, state};
  236. auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5);
  237. int64_t sign = type == cbor_type::nint ? -1 : 1;
  238. switch(type) {
  239. case cbor_type::uint:
  240. case cbor_type::nint:
  241. {
  242. auto[value, new_state] = pull_arbitrary_integer_from_cbor(state);
  243. if(value.has_value()) return {value.value() * sign, new_state};
  244. break;
  245. }
  246. default:
  247. break;
  248. }
  249. return {nullopt, state};
  250. }
  251. template<>
  252. gp::pair<gp::optional<uint64_t>, parsing_state> read_cbor<uint64_t>(parsing_state state) {
  253. if(state.size()) return {nullopt, state};
  254. auto type = cbor_type(((uint8_t)0b11100000 & (uint8_t)*state.begin()) >> 5);
  255. switch(type) {
  256. case cbor_type::uint:
  257. {
  258. auto[value, new_state] = pull_arbitrary_integer_from_cbor(state);
  259. if(value.has_value()) return {value.value(), new_state};
  260. break;
  261. }
  262. default:
  263. break;
  264. }
  265. return {nullopt, state};
  266. }
  267. struct cbor_floating_point final {
  268. using backing = gp::fixed_variant<
  269. ieee754_hf,
  270. float,
  271. double
  272. >;
  273. backing contents;
  274. cbor_floating_point(backing& p)
  275. : contents{p}{}
  276. cbor_floating_point(ieee754_hf p)
  277. : contents{p}{}
  278. cbor_floating_point(float p)
  279. : contents{p}{}
  280. cbor_floating_point(double p)
  281. : contents{p}{}
  282. operator ieee754_hf() {
  283. return contents.value<ieee754_hf>();
  284. }
  285. operator float() {
  286. switch(contents.type()) {
  287. case backing::alt<ieee754_hf>():
  288. return contents.value<ieee754_hf>();
  289. case backing::alt<float>():
  290. return contents.value<float>();
  291. default:
  292. gp_config::assertion(false,"this code should never be reached");
  293. return std::numeric_limits<float>::quiet_NaN();
  294. }
  295. }
  296. operator double() {
  297. switch(contents.type()) {
  298. case backing::alt<ieee754_hf>():
  299. return contents.value<ieee754_hf>();
  300. case backing::alt<float>():
  301. return contents.value<float>();
  302. case backing::alt<double>():
  303. return contents.value<double>();
  304. default:
  305. gp_config::assertion(false,"this code should never be reached");
  306. return std::numeric_limits<double>::quiet_NaN();
  307. }
  308. }
  309. };
  310. struct undefined_t final {};
  311. template<typename T>
  312. using cbor_composite = gp::fixed_variant<
  313. gp::undefined_t,
  314. cbor_number,
  315. gp::vector<std::byte>,
  316. bool,
  317. gp::vector<T>,
  318. gp::vector<gp::pair<T, T>>,
  319. gp::nullopt_t,
  320. cbor_floating_point
  321. >;
  322. class cbor_value {
  323. cbor_composite<cbor_value> contents;
  324. gp::reference_wrapper<allocator> alloc;
  325. public:
  326. cbor_value(allocator& alloc_v)
  327. : contents()
  328. , alloc(alloc_v)
  329. {}
  330. cbor_value(cbor_number number, allocator& alloc_v)
  331. : contents(number)
  332. , alloc(alloc_v)
  333. {}
  334. cbor_value(cbor_composite<cbor_value> val, allocator& alloc_v)
  335. : contents(val)
  336. , alloc(alloc_v)
  337. {}
  338. cbor_value(const cbor_value& oth)
  339. : contents(oth.contents)
  340. , alloc(oth.alloc)
  341. {}
  342. cbor_value(cbor_value&& oth)
  343. : contents(gp::move(oth.contents))
  344. , alloc(gp::move(oth.alloc))
  345. {}
  346. cbor_value& operator=(cbor_value& value) {
  347. contents = value.contents;
  348. alloc = value.alloc;
  349. return *this;
  350. }
  351. cbor_value& operator=(cbor_value&& value) {
  352. gp::swap(contents, value.contents);
  353. gp::swap(alloc, value.alloc);
  354. return *this;
  355. }
  356. cbor_value& operator=(cbor_composite<cbor_value>& value) {
  357. contents = value;
  358. return *this;
  359. }
  360. template<typename T>
  361. cbor_value& operator=(T& value) {
  362. contents = value;
  363. return *this;
  364. }
  365. template<typename T>
  366. cbor_value& operator=(T&& value) {
  367. contents = gp::move(value);
  368. return *this;
  369. }
  370. auto new_array() {
  371. return gp::vector<cbor_value>{alloc};
  372. }
  373. auto new_object() {
  374. return gp::vector<gp::pair<cbor_value, cbor_value>>{alloc};
  375. }
  376. static gp::pair<uint64_t, gp::buffer<std::byte>::associated_iterator> decode_integer(gp::buffer<std::byte> src) {
  377. #define ERROR return {0, src.begin()}
  378. auto local = (uint8_t)0b00011111 & (uint8_t)src[0];
  379. if(local <= 23) {
  380. return {local, src.begin()+1};
  381. } else {
  382. switch((cbor_oths)local) {
  383. case cbor_oths::byte: {
  384. if(src.size()<2) ERROR;
  385. return {
  386. (uint8_t)*(src.begin()+1),
  387. src.begin()+2
  388. };
  389. }
  390. case cbor_oths::word: {
  391. if(src.size()<3) ERROR;
  392. return {
  393. uint16_t(*(src.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, endian::big>>().begin().data)),
  394. src.begin()+3
  395. };
  396. }
  397. case cbor_oths::dword: {
  398. if(src.size()<5) ERROR;
  399. return {
  400. uint32_t(*(src.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, endian::big>>().begin().data)),
  401. src.begin()+5
  402. };
  403. }
  404. case cbor_oths::qword: {
  405. if(src.size()<9) ERROR;
  406. return {
  407. uint64_t(*(src.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, endian::big>>().begin().data)),
  408. src.begin()+9
  409. };
  410. }
  411. default: {
  412. ERROR;
  413. }
  414. }
  415. }
  416. #undef ERROR
  417. }
  418. template<typename U>
  419. bool is_a() {
  420. if constexpr (
  421. std::is_same_v<U, uint8_t>
  422. || std::is_same_v<U, uint16_t>
  423. || std::is_same_v<U, uint32_t>
  424. || std::is_same_v<U, uint64_t>
  425. || std::is_same_v<U, int8_t>
  426. || std::is_same_v<U, int16_t>
  427. || std::is_same_v<U, int32_t>
  428. || std::is_same_v<U, int64_t>
  429. ) {
  430. if(contents.is_a<cbor_number>())
  431. {
  432. auto& v = contents.value<cbor_number>();
  433. if(!std::is_signed_v<U> && v.is_negative()) return false;
  434. if(
  435. std::numeric_limits<int64_t>::max()<v.value
  436. && (
  437. !std::is_same_v<U, uint64_t>
  438. || v.is_negative()
  439. )
  440. ) return false;
  441. int64_t signed_v = (v.is_negative() ? -1 : 1 ) * v.value;
  442. if(
  443. std::numeric_limits<U>::min() <= signed_v
  444. && std::numeric_limits<U>::max() >= signed_v
  445. ) return true;
  446. return false;
  447. } else return false;
  448. } else if constexpr (
  449. std::is_same_v<U, ieee754_hf>
  450. || std::is_same_v<U, float>
  451. || std::is_same_v<U, double>
  452. ) {
  453. auto& v = contents.value<cbor_floating_point>();
  454. switch(v.contents.type()) {
  455. case cbor_floating_point::backing::alt<ieee754_hf>():
  456. return std::is_same_v<U, ieee754_hf>;
  457. case cbor_floating_point::backing::alt<float>():
  458. return std::is_same_v<U, float> || std::is_same_v<U, ieee754_hf>;
  459. case cbor_floating_point::backing::alt<double>():
  460. return std::is_same_v<U, double> || std::is_same_v<U, float> || std::is_same_v<U, ieee754_hf>;
  461. default:
  462. return false;
  463. }
  464. } else {
  465. return contents.is_a<U>();
  466. }
  467. }
  468. template<typename U>
  469. U get_value() {
  470. gp_config::assertion(is_a<U>(), "can't convert value legally");
  471. if constexpr (
  472. std::is_same_v<U, uint8_t>
  473. || std::is_same_v<U, uint16_t>
  474. || std::is_same_v<U, uint32_t>
  475. || std::is_same_v<U, uint64_t>
  476. || std::is_same_v<U, int8_t>
  477. || std::is_same_v<U, int16_t>
  478. || std::is_same_v<U, int32_t>
  479. || std::is_same_v<U, int64_t>
  480. ) {
  481. auto& v = contents.value<cbor_number>();
  482. return (v.is_negative() ? -1 : 1 ) * v.value;
  483. } else if constexpr (
  484. std::is_same_v<U, ieee754_hf>
  485. || std::is_same_v<U, float>
  486. || std::is_same_v<U, double>
  487. ) {
  488. auto& v = contents.value<cbor_floating_point>();
  489. return v;
  490. } else {
  491. return contents.value<U>();
  492. }
  493. }
  494. static gp::pair<cbor_value, gp::buffer<std::byte>::associated_iterator> decode(allocator& alloc, gp::buffer<std::byte> src) {
  495. #define ERROR return {cbor_value{alloc}, src.begin()}
  496. if(src.size()==0) ERROR;
  497. auto discriminant = (cbor_type)(((uint8_t)*src.begin()) >> 5);
  498. auto local = uint8_t(((uint8_t)*src.begin()) & 0b00011111);
  499. switch(discriminant) {
  500. case cbor_type::uint:
  501. case cbor_type::nint: {
  502. auto nb = decode_integer(src);
  503. return {cbor_value{cbor_number{(bool)discriminant, nb.first}, alloc}, nb.second};
  504. }
  505. case cbor_type::bstr: {
  506. gp::vector<std::byte> str{alloc};
  507. if(local == 31) {
  508. auto sub = src.slice_end(src.size() - 1);
  509. if(!sub.size()) ERROR;
  510. while((uint8_t)sub[0] && 0b00011111 != 31) {
  511. auto len = decode_integer(sub);
  512. if(len.second == sub.begin()) ERROR;
  513. str.reserve(str.size() + len.first);
  514. auto end = (len.second + len.first);
  515. if(len.first + (len.second - src.begin()) > src.size()) ERROR;
  516. for(auto it = len.second; it != end; it++) {
  517. str.push_back(*it);
  518. }
  519. sub = sub.slice_end(sub.size() - (len.first + (len.second - sub.begin())));
  520. }
  521. return {cbor_value{str, alloc}, sub.begin()+1};
  522. } else if(auto len = decode_integer(src); len.second != src.begin()) {
  523. str.reserve(len.first);
  524. auto end = (len.second + len.first);
  525. if(len.first + (len.second - src.begin()) > src.size()) ERROR;
  526. for(auto it = len.second; it != end; it++) {
  527. str.push_back(*it);
  528. }
  529. return {cbor_value{str, alloc}, end};
  530. }
  531. ERROR;
  532. }
  533. case cbor_type::tstr: {
  534. ERROR;
  535. }
  536. case cbor_type::list: {
  537. gp::vector<cbor_value> list{alloc};
  538. if(local == 31) {
  539. // TODO: Add the indefinite length version
  540. } else if(auto len = decode_integer(src); len.second != src.begin()) {
  541. auto sub = src.slice_end(src.size()-(len.second - src.begin()));
  542. while(len.first--) {
  543. auto tmp = decode(alloc, sub);
  544. if(tmp.second == sub.begin()) ERROR;
  545. list.push_back(tmp.first);
  546. sub = sub.slice_end(sub.size() - (tmp.second - sub.begin()));
  547. }
  548. return {cbor_value{list, alloc}, sub.begin()};
  549. }
  550. ERROR;
  551. }
  552. case cbor_type::hmap: {
  553. gp::vector<gp::pair<cbor_value, cbor_value>> list{alloc};
  554. if(local == 31) {
  555. // TODO: Add the indefinite length version
  556. } else if(auto len = decode_integer(src); len.second != src.begin()) {
  557. auto sub = src.slice_end(src.size()-(len.second - src.begin()));
  558. while(len.first--) {
  559. auto tmpl = decode(alloc, sub);
  560. if(tmpl.second == sub.begin()) ERROR;
  561. sub = sub.slice_end(sub.size() - (tmpl.second - sub.begin()));
  562. auto tmpr = decode(alloc, sub);
  563. if(tmpr.second == sub.begin()) ERROR;
  564. list.push_back(gp::make_pair(
  565. tmpl.first,
  566. tmpr.first
  567. ));
  568. sub = sub.slice_end(sub.size() - (tmpr.second - sub.begin()));
  569. }
  570. return {cbor_value{list, alloc}, sub.begin()};
  571. }
  572. ERROR;
  573. }
  574. case cbor_type::tags: {
  575. // TODO: add tag decoding methods
  576. }
  577. case cbor_type::oths: {
  578. switch((cbor_oths)local) {
  579. case cbor_oths::value_false: {
  580. return {
  581. cbor_value{
  582. cbor_composite<cbor_value>(false),
  583. alloc
  584. },
  585. src.begin()+1
  586. };
  587. }
  588. case cbor_oths::value_true: {
  589. return {
  590. cbor_value{
  591. cbor_composite<cbor_value>(true),
  592. alloc
  593. },
  594. src.begin()+1
  595. };
  596. }
  597. case cbor_oths::value_null: {
  598. return {
  599. cbor_value{
  600. cbor_composite<cbor_value>(nullopt),
  601. alloc
  602. },
  603. src.begin()+1
  604. };
  605. }
  606. case cbor_oths::value_undefined: {
  607. return {
  608. cbor_value{
  609. cbor_composite<cbor_value>(undefined_t{}),
  610. alloc
  611. },
  612. src.begin()+1
  613. };
  614. }
  615. case cbor_oths::word: {
  616. if(src.size()<3) ERROR;
  617. return {
  618. cbor_value{
  619. cbor_floating_point{ieee754_hf(*(src.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, endian::big>>().begin().data))},
  620. alloc
  621. },
  622. src.begin()+3
  623. };
  624. }
  625. case cbor_oths::dword: {
  626. if(src.size()<5) ERROR;
  627. return {
  628. cbor_value{
  629. cbor_floating_point{float(*(src.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, endian::big>>().begin().data))},
  630. alloc
  631. },
  632. src.begin()+5
  633. };
  634. }
  635. case cbor_oths::qword: {
  636. if(src.size()<9) ERROR;
  637. return {
  638. cbor_value{
  639. cbor_floating_point{double(*(src.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, endian::big>>().begin().data))},
  640. alloc
  641. },
  642. src.begin()+9
  643. };
  644. }
  645. default: {
  646. ERROR;
  647. }
  648. }
  649. }
  650. }
  651. ERROR;
  652. #undef ERROR
  653. }
  654. static auto encode_float(buffer<std::byte> dest, cbor_floating_point& value) {
  655. switch(value.contents.type()) {
  656. case cbor_floating_point::backing::alt<ieee754_hf>():{
  657. if(dest.size() < 3) return dest.begin();
  658. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::word);
  659. (dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, gp::endian::big>>())[0] = value.contents.value<ieee754_hf>();
  660. return dest.begin()+3;
  661. }
  662. case cbor_floating_point::backing::alt<float>():{
  663. if(dest.size() < 5) return dest.begin();
  664. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::dword);
  665. (dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, gp::endian::big>>())[0] = value.contents.value<float>();
  666. return dest.begin()+5;
  667. }
  668. case cbor_floating_point::backing::alt<double>():{
  669. if(dest.size() < 9) return dest.begin();
  670. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::qword);
  671. (dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, gp::endian::big>>())[0] = value.contents.value<double>();
  672. return dest.begin()+9;
  673. }
  674. default: return dest.begin();
  675. }
  676. }
  677. static auto encode_length(buffer<std::byte> dest, cbor_type major, uint64_t value) {
  678. auto num = value;
  679. if(value <= 23) {
  680. if(dest.size() < 1) return dest.begin();
  681. dest[0] = std::byte(((uint8_t)major << 5u) + value);
  682. return dest.begin()+1;
  683. } else if(value <= 255) {
  684. if(dest.size() < 2) return dest.begin();
  685. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::byte);
  686. dest[1] = std::byte(value);
  687. return dest.begin() + 2;
  688. } else if(value <= 65535) {
  689. if(dest.size() < 3) return dest.begin();
  690. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::word);
  691. (dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, gp::endian::big>>())[0] = num;
  692. return dest.begin()+3;
  693. } else if(value <= 4294967295) {
  694. if(dest.size() < 5) return dest.begin();
  695. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::dword);
  696. (dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, gp::endian::big>>())[0] = num;
  697. return dest.begin()+5;
  698. } else {
  699. if(dest.size() < 9) return dest.begin();
  700. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::qword);
  701. (dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, gp::endian::big>>())[0] = num;
  702. return dest.begin()+9;
  703. }
  704. }
  705. auto encode(buffer<std::byte> dest) {
  706. switch(contents.type()) {
  707. case cbor_composite<cbor_value>::alt<undefined_t>(): {
  708. if(dest.size() < 1) return dest.begin();
  709. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_undefined);
  710. return dest.begin()+1;
  711. }
  712. case cbor_composite<cbor_value>::alt<cbor_number>(): {
  713. auto& ref = contents.value<cbor_number>();
  714. return encode_length(
  715. dest,
  716. ref.is_negative() ? cbor_type::nint : cbor_type::uint,
  717. ref.value
  718. );
  719. }
  720. case cbor_composite<cbor_value>::alt<gp::vector<std::byte>>(): {
  721. auto& ref = contents.value<gp::vector<std::byte>>();
  722. auto it = encode_length(
  723. dest,
  724. cbor_type::bstr,
  725. ref.size()
  726. );
  727. if(it == dest.begin()) return it;
  728. for(auto a : ref) {
  729. *(it++) = a;
  730. }
  731. return it;
  732. }
  733. case cbor_composite<cbor_value>::alt<bool>(): {
  734. if(dest.size() < 1) return dest.begin();
  735. if(contents.value<bool>())
  736. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_true);
  737. else
  738. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_false);
  739. return dest.begin()+1;
  740. }
  741. case cbor_composite<cbor_value>::alt<gp::vector<cbor_value>>(): {
  742. auto& ary = contents.value<gp::vector<cbor_value>>();
  743. auto it_begin = encode_length(dest, cbor_type::list, ary.size());
  744. if(it_begin == dest.begin()) return dest.begin();
  745. for(auto& elem : ary) {
  746. auto slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  747. auto it = elem.encode(slice);
  748. if(it == it_begin)
  749. return dest.begin();
  750. it_begin = it;
  751. }
  752. return it_begin;
  753. }
  754. case cbor_composite<cbor_value>::alt<gp::vector<gp::pair<cbor_value, cbor_value>>>(): {
  755. auto& ary = contents.value<gp::vector<gp::pair<cbor_value,cbor_value>>>();
  756. auto it_begin = encode_length(dest, cbor_type::hmap, ary.size());
  757. if(it_begin == dest.begin()) return dest.begin();
  758. for(auto& elem : ary) {
  759. auto slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  760. auto it = elem.first.encode(slice);
  761. if(it == it_begin) return dest.begin();
  762. it_begin = it;
  763. slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  764. it = elem.second.encode(slice);
  765. if(it == it_begin) return dest.begin();
  766. it_begin = it;
  767. }
  768. return it_begin;
  769. }
  770. case cbor_composite<cbor_value>::alt<gp::nullopt_t>(): {
  771. if(dest.size() < 1) return dest.begin();
  772. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_null);
  773. return dest.begin()+1;
  774. }
  775. case cbor_composite<cbor_value>::alt<cbor_floating_point>(): {
  776. return encode_float(dest, contents.value<cbor_floating_point>());
  777. }
  778. default: return dest.begin();
  779. }
  780. }
  781. };
  782. }