General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

644 rivejä
18 KiB

4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
4 vuotta sitten
  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. struct cbor_floating_point final {
  85. using backing = gp::fixed_variant<
  86. ieee754_hf,
  87. float,
  88. double
  89. >;
  90. backing contents;
  91. cbor_floating_point(backing& p)
  92. : contents{p}{}
  93. cbor_floating_point(ieee754_hf p)
  94. : contents{p}{}
  95. cbor_floating_point(float p)
  96. : contents{p}{}
  97. cbor_floating_point(double p)
  98. : contents{p}{}
  99. operator ieee754_hf() {
  100. return contents.value<ieee754_hf>();
  101. }
  102. operator float() {
  103. switch(contents.type()) {
  104. case backing::alt<ieee754_hf>():
  105. return contents.value<ieee754_hf>();
  106. case backing::alt<float>():
  107. return contents.value<float>();
  108. default:
  109. gp_config::assertion(false,"this code should never be reached");
  110. return std::numeric_limits<float>::quiet_NaN();
  111. }
  112. }
  113. operator double() {
  114. switch(contents.type()) {
  115. case backing::alt<ieee754_hf>():
  116. return contents.value<ieee754_hf>();
  117. case backing::alt<float>():
  118. return contents.value<float>();
  119. case backing::alt<double>():
  120. return contents.value<double>();
  121. default:
  122. gp_config::assertion(false,"this code should never be reached");
  123. return std::numeric_limits<double>::quiet_NaN();
  124. }
  125. }
  126. };
  127. struct undefined_t final {};
  128. template<typename T>
  129. using cbor_composite = gp::fixed_variant<
  130. gp::undefined_t,
  131. cbor_number,
  132. gp::vector<std::byte>,
  133. bool,
  134. gp::vector<T>,
  135. gp::vector<gp::pair<T, T>>,
  136. gp::nullopt_t,
  137. cbor_floating_point
  138. >;
  139. class cbor_value {
  140. cbor_composite<cbor_value> contents;
  141. gp::reference_wrapper<allocator> alloc;
  142. public:
  143. cbor_value(allocator& alloc_v)
  144. : contents()
  145. , alloc(alloc_v)
  146. {}
  147. cbor_value(cbor_number number, allocator& alloc_v)
  148. : contents(number)
  149. , alloc(alloc_v)
  150. {}
  151. cbor_value(cbor_composite<cbor_value> val, allocator& alloc_v)
  152. : contents(val)
  153. , alloc(alloc_v)
  154. {}
  155. cbor_value(const cbor_value& oth)
  156. : contents(oth.contents)
  157. , alloc(oth.alloc)
  158. {}
  159. cbor_value(cbor_value&& oth)
  160. : contents(gp::move(oth.contents))
  161. , alloc(gp::move(oth.alloc))
  162. {}
  163. cbor_value& operator=(cbor_value& value) {
  164. contents = value.contents;
  165. alloc = value.alloc;
  166. return *this;
  167. }
  168. cbor_value& operator=(cbor_value&& value) {
  169. gp::swap(contents, value.contents);
  170. gp::swap(alloc, value.alloc);
  171. return *this;
  172. }
  173. cbor_value& operator=(cbor_composite<cbor_value>& value) {
  174. contents = value;
  175. return *this;
  176. }
  177. template<typename T>
  178. cbor_value& operator=(T& value) {
  179. contents = value;
  180. return *this;
  181. }
  182. template<typename T>
  183. cbor_value& operator=(T&& value) {
  184. contents = gp::move(value);
  185. return *this;
  186. }
  187. auto new_array() {
  188. return gp::vector<cbor_value>{alloc};
  189. }
  190. auto new_object() {
  191. return gp::vector<gp::pair<cbor_value, cbor_value>>{alloc};
  192. }
  193. static gp::pair<uint64_t, gp::buffer<std::byte>::associated_iterator> decode_integer(gp::buffer<std::byte> src) {
  194. #define ERROR return {0, src.begin()}
  195. auto local = (uint8_t)0b00011111 & (uint8_t)src[0];
  196. if(local <= 23) {
  197. return {local, src.begin()+1};
  198. } else {
  199. switch((cbor_oths)local) {
  200. case cbor_oths::byte: {
  201. if(src.size()<2) ERROR;
  202. return {
  203. (uint8_t)*(src.begin()+1),
  204. src.begin()+2
  205. };
  206. }
  207. case cbor_oths::word: {
  208. if(src.size()<3) ERROR;
  209. return {
  210. uint16_t(*(src.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, endian::big>>().begin().data)),
  211. src.begin()+3
  212. };
  213. }
  214. case cbor_oths::dword: {
  215. if(src.size()<5) ERROR;
  216. return {
  217. uint32_t(*(src.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, endian::big>>().begin().data)),
  218. src.begin()+5
  219. };
  220. }
  221. case cbor_oths::qword: {
  222. if(src.size()<9) ERROR;
  223. return {
  224. uint64_t(*(src.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, endian::big>>().begin().data)),
  225. src.begin()+9
  226. };
  227. }
  228. default: {
  229. ERROR;
  230. }
  231. }
  232. }
  233. #undef ERROR
  234. }
  235. template<typename U>
  236. bool is_a() {
  237. if constexpr (
  238. std::is_same_v<U, uint8_t>
  239. || std::is_same_v<U, uint16_t>
  240. || std::is_same_v<U, uint32_t>
  241. || std::is_same_v<U, uint64_t>
  242. || std::is_same_v<U, int8_t>
  243. || std::is_same_v<U, int16_t>
  244. || std::is_same_v<U, int32_t>
  245. || std::is_same_v<U, int64_t>
  246. ) {
  247. if(contents.is_a<cbor_number>())
  248. {
  249. auto& v = contents.value<cbor_number>();
  250. if(!std::is_signed_v<U> && v.is_negative()) return false;
  251. if(
  252. std::numeric_limits<int64_t>::max()<v.value
  253. && (
  254. !std::is_same_v<U, uint64_t>
  255. || v.is_negative()
  256. )
  257. ) return false;
  258. int64_t signed_v = (v.is_negative() ? -1 : 1 ) * v.value;
  259. if(
  260. std::numeric_limits<U>::min() <= signed_v
  261. && std::numeric_limits<U>::max() >= signed_v
  262. ) return true;
  263. return false;
  264. } else return false;
  265. } else if constexpr (
  266. std::is_same_v<U, ieee754_hf>
  267. || std::is_same_v<U, float>
  268. || std::is_same_v<U, double>
  269. ) {
  270. auto& v = contents.value<cbor_floating_point>();
  271. switch(v.contents.type()) {
  272. case cbor_floating_point::backing::alt<ieee754_hf>():
  273. return std::is_same_v<U, ieee754_hf>;
  274. case cbor_floating_point::backing::alt<float>():
  275. return std::is_same_v<U, float> || std::is_same_v<U, ieee754_hf>;
  276. case cbor_floating_point::backing::alt<double>():
  277. return std::is_same_v<U, double> || std::is_same_v<U, float> || std::is_same_v<U, ieee754_hf>;
  278. default:
  279. return false;
  280. }
  281. } else {
  282. return contents.is_a<U>();
  283. }
  284. }
  285. template<typename U>
  286. U get_value() {
  287. gp_config::assertion(is_a<U>(), "can't convert value legally");
  288. if constexpr (
  289. std::is_same_v<U, uint8_t>
  290. || std::is_same_v<U, uint16_t>
  291. || std::is_same_v<U, uint32_t>
  292. || std::is_same_v<U, uint64_t>
  293. || std::is_same_v<U, int8_t>
  294. || std::is_same_v<U, int16_t>
  295. || std::is_same_v<U, int32_t>
  296. || std::is_same_v<U, int64_t>
  297. ) {
  298. auto& v = contents.value<cbor_number>();
  299. return (v.is_negative() ? -1 : 1 ) * v.value;
  300. } else if constexpr (
  301. std::is_same_v<U, ieee754_hf>
  302. || std::is_same_v<U, float>
  303. || std::is_same_v<U, double>
  304. ) {
  305. auto& v = contents.value<cbor_floating_point>();
  306. return v;
  307. } else {
  308. return contents.value<U>();
  309. }
  310. }
  311. static gp::pair<cbor_value, gp::buffer<std::byte>::associated_iterator> decode(allocator& alloc, gp::buffer<std::byte> src) {
  312. #define ERROR return {cbor_value{alloc}, src.begin()}
  313. if(src.size()==0) ERROR;
  314. auto discriminant = (cbor_type)(((uint8_t)*src.begin()) >> 5);
  315. auto local = uint8_t(((uint8_t)*src.begin()) & 0b00011111);
  316. switch(discriminant) {
  317. case cbor_type::uint:
  318. case cbor_type::nint: {
  319. auto nb = decode_integer(src);
  320. return {cbor_value{cbor_number{(bool)discriminant, nb.first}, alloc}, nb.second};
  321. }
  322. case cbor_type::bstr: {
  323. gp::vector<std::byte> str{alloc};
  324. if(local == 31) {
  325. auto sub = src.slice_end(src.size() - 1);
  326. if(!sub.size()) ERROR;
  327. while((uint8_t)sub[0] && 0b00011111 != 31) {
  328. auto len = decode_integer(sub);
  329. if(len.second == sub.begin()) ERROR;
  330. str.reserve(str.size() + len.first);
  331. auto end = (len.second + len.first);
  332. if(len.first + (len.second - src.begin()) > src.size()) ERROR;
  333. for(auto it = len.second; it != end; it++) {
  334. str.push_back(*it);
  335. }
  336. sub = sub.slice_end(sub.size() - (len.first + (len.second - sub.begin())));
  337. }
  338. return {cbor_value{str, alloc}, sub.begin()+1};
  339. } else if(auto len = decode_integer(src); len.second != src.begin()) {
  340. str.reserve(len.first);
  341. auto end = (len.second + len.first);
  342. if(len.first + (len.second - src.begin()) > src.size()) ERROR;
  343. for(auto it = len.second; it != end; it++) {
  344. str.push_back(*it);
  345. }
  346. return {cbor_value{str, alloc}, end};
  347. }
  348. ERROR;
  349. }
  350. case cbor_type::tstr: {
  351. ERROR;
  352. }
  353. case cbor_type::list: {
  354. gp::vector<cbor_value> list{alloc};
  355. if(local == 31) {
  356. // TODO: Add the indefinite length version
  357. } else if(auto len = decode_integer(src); len.second != src.begin()) {
  358. auto sub = src.slice_end(src.size()-(len.second - src.begin()));
  359. while(len.first--) {
  360. auto tmp = decode(alloc, sub);
  361. if(tmp.second == sub.begin()) ERROR;
  362. list.push_back(tmp.first);
  363. sub = sub.slice_end(sub.size() - (tmp.second - sub.begin()));
  364. }
  365. return {cbor_value{list, alloc}, sub.begin()};
  366. }
  367. ERROR;
  368. }
  369. case cbor_type::hmap: {
  370. gp::vector<gp::pair<cbor_value, cbor_value>> list{alloc};
  371. if(local == 31) {
  372. // TODO: Add the indefinite length version
  373. } else if(auto len = decode_integer(src); len.second != src.begin()) {
  374. auto sub = src.slice_end(src.size()-(len.second - src.begin()));
  375. while(len.first--) {
  376. auto tmpl = decode(alloc, sub);
  377. if(tmpl.second == sub.begin()) ERROR;
  378. sub = sub.slice_end(sub.size() - (tmpl.second - sub.begin()));
  379. auto tmpr = decode(alloc, sub);
  380. if(tmpr.second == sub.begin()) ERROR;
  381. list.push_back(gp::make_pair(
  382. tmpl.first,
  383. tmpr.first
  384. ));
  385. sub = sub.slice_end(sub.size() - (tmpr.second - sub.begin()));
  386. }
  387. return {cbor_value{list, alloc}, sub.begin()};
  388. }
  389. ERROR;
  390. }
  391. case cbor_type::tags: {
  392. // TODO: add tag decoding methods
  393. }
  394. case cbor_type::oths: {
  395. switch((cbor_oths)local) {
  396. case cbor_oths::value_false: {
  397. return {
  398. cbor_value{
  399. cbor_composite<cbor_value>(false),
  400. alloc
  401. },
  402. src.begin()+1
  403. };
  404. }
  405. case cbor_oths::value_true: {
  406. return {
  407. cbor_value{
  408. cbor_composite<cbor_value>(true),
  409. alloc
  410. },
  411. src.begin()+1
  412. };
  413. }
  414. case cbor_oths::value_null: {
  415. return {
  416. cbor_value{
  417. cbor_composite<cbor_value>(nullopt),
  418. alloc
  419. },
  420. src.begin()+1
  421. };
  422. }
  423. case cbor_oths::value_undefined: {
  424. return {
  425. cbor_value{
  426. cbor_composite<cbor_value>(undefined_t{}),
  427. alloc
  428. },
  429. src.begin()+1
  430. };
  431. }
  432. case cbor_oths::word: {
  433. if(src.size()<3) ERROR;
  434. return {
  435. cbor_value{
  436. cbor_floating_point{ieee754_hf(*(src.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, endian::big>>().begin().data))},
  437. alloc
  438. },
  439. src.begin()+3
  440. };
  441. }
  442. case cbor_oths::dword: {
  443. if(src.size()<5) ERROR;
  444. return {
  445. cbor_value{
  446. cbor_floating_point{float(*(src.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, endian::big>>().begin().data))},
  447. alloc
  448. },
  449. src.begin()+5
  450. };
  451. }
  452. case cbor_oths::qword: {
  453. if(src.size()<9) ERROR;
  454. return {
  455. cbor_value{
  456. cbor_floating_point{double(*(src.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, endian::big>>().begin().data))},
  457. alloc
  458. },
  459. src.begin()+9
  460. };
  461. }
  462. default: {
  463. ERROR;
  464. }
  465. }
  466. }
  467. }
  468. ERROR;
  469. #undef ERROR
  470. }
  471. static auto encode_float(buffer<std::byte> dest, cbor_floating_point& value) {
  472. switch(value.contents.type()) {
  473. case cbor_floating_point::backing::alt<ieee754_hf>():{
  474. if(dest.size() < 3) return dest.begin();
  475. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::word);
  476. (dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<ieee754_hf, gp::endian::big>>())[0] = value.contents.value<ieee754_hf>();
  477. return dest.begin()+3;
  478. }
  479. case cbor_floating_point::backing::alt<float>():{
  480. if(dest.size() < 5) return dest.begin();
  481. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::dword);
  482. (dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<float, gp::endian::big>>())[0] = value.contents.value<float>();
  483. return dest.begin()+5;
  484. }
  485. case cbor_floating_point::backing::alt<double>():{
  486. if(dest.size() < 9) return dest.begin();
  487. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::qword);
  488. (dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<double, gp::endian::big>>())[0] = value.contents.value<double>();
  489. return dest.begin()+9;
  490. }
  491. default: return dest.begin();
  492. }
  493. }
  494. static auto encode_length(buffer<std::byte> dest, cbor_type major, uint64_t value) {
  495. auto num = value;
  496. if(value <= 23) {
  497. if(dest.size() < 1) return dest.begin();
  498. dest[0] = std::byte(((uint8_t)major << 5u) + value);
  499. return dest.begin()+1;
  500. } else if(value <= 255) {
  501. if(dest.size() < 2) return dest.begin();
  502. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::byte);
  503. dest[1] = std::byte(value);
  504. return dest.begin() + 2;
  505. } else if(value <= 65535) {
  506. if(dest.size() < 3) return dest.begin();
  507. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::word);
  508. (dest.slice_start(3).slice_end(2).cast<gp::endian_wrapper<uint16_t, gp::endian::big>>())[0] = num;
  509. return dest.begin()+3;
  510. } else if(value <= 4294967295) {
  511. if(dest.size() < 5) return dest.begin();
  512. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::dword);
  513. (dest.slice_start(5).slice_end(4).cast<gp::endian_wrapper<uint32_t, gp::endian::big>>())[0] = num;
  514. return dest.begin()+5;
  515. } else {
  516. if(dest.size() < 9) return dest.begin();
  517. dest[0] = std::byte(((uint8_t)major << 5u) + (uint8_t)cbor_oths::qword);
  518. (dest.slice_start(9).slice_end(8).cast<gp::endian_wrapper<uint64_t, gp::endian::big>>())[0] = num;
  519. return dest.begin()+9;
  520. }
  521. }
  522. auto encode(buffer<std::byte> dest) {
  523. switch(contents.type()) {
  524. case cbor_composite<cbor_value>::alt<undefined_t>(): {
  525. if(dest.size() < 1) return dest.begin();
  526. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_undefined);
  527. return dest.begin()+1;
  528. }
  529. case cbor_composite<cbor_value>::alt<cbor_number>(): {
  530. auto& ref = contents.value<cbor_number>();
  531. return encode_length(
  532. dest,
  533. ref.is_negative() ? cbor_type::nint : cbor_type::uint,
  534. ref.value
  535. );
  536. }
  537. case cbor_composite<cbor_value>::alt<gp::vector<std::byte>>(): {
  538. auto& ref = contents.value<gp::vector<std::byte>>();
  539. auto it = encode_length(
  540. dest,
  541. cbor_type::bstr,
  542. ref.size()
  543. );
  544. if(it == dest.begin()) return it;
  545. for(auto a : ref) {
  546. *(it++) = a;
  547. }
  548. return it;
  549. }
  550. case cbor_composite<cbor_value>::alt<bool>(): {
  551. if(dest.size() < 1) return dest.begin();
  552. if(contents.value<bool>())
  553. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_true);
  554. else
  555. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_false);
  556. return dest.begin()+1;
  557. }
  558. case cbor_composite<cbor_value>::alt<gp::vector<cbor_value>>(): {
  559. auto& ary = contents.value<gp::vector<cbor_value>>();
  560. auto it_begin = encode_length(dest, cbor_type::list, ary.size());
  561. if(it_begin == dest.begin()) return dest.begin();
  562. for(auto& elem : ary) {
  563. auto slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  564. auto it = elem.encode(slice);
  565. if(it == it_begin)
  566. return dest.begin();
  567. it_begin = it;
  568. }
  569. return it_begin;
  570. }
  571. case cbor_composite<cbor_value>::alt<gp::vector<gp::pair<cbor_value, cbor_value>>>(): {
  572. auto& ary = contents.value<gp::vector<gp::pair<cbor_value,cbor_value>>>();
  573. auto it_begin = encode_length(dest, cbor_type::hmap, ary.size());
  574. if(it_begin == dest.begin()) return dest.begin();
  575. for(auto& elem : ary) {
  576. auto slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  577. auto it = elem.first.encode(slice);
  578. if(it == it_begin) return dest.begin();
  579. it_begin = it;
  580. slice = dest.slice_end(dest.size() - (it_begin - dest.begin()));
  581. it = elem.second.encode(slice);
  582. if(it == it_begin) return dest.begin();
  583. it_begin = it;
  584. }
  585. return it_begin;
  586. }
  587. case cbor_composite<cbor_value>::alt<gp::nullopt_t>(): {
  588. if(dest.size() < 1) return dest.begin();
  589. dest[0] = std::byte(((uint8_t)cbor_type::oths << 5u) + (uint8_t)cbor_oths::value_null);
  590. return dest.begin()+1;
  591. }
  592. case cbor_composite<cbor_value>::alt<cbor_floating_point>(): {
  593. return encode_float(dest, contents.value<cbor_floating_point>());
  594. }
  595. default: return dest.begin();
  596. }
  597. }
  598. };
  599. }