|
1 | 1 | #pragma once |
2 | 2 |
|
3 | 3 | #include <cstdint> |
| 4 | +#include <cstring> |
| 5 | +#include <type_traits> |
4 | 6 | #include <limits> |
5 | 7 | #include <utility> |
6 | | -#include <type_traits> |
| 8 | +#include <algorithm> |
| 9 | +#include <string> |
7 | 10 | #include <string_view> |
| 11 | +#include <tuple> |
8 | 12 | #include <vector> |
9 | 13 | #include <map> |
10 | 14 | #include <unordered_map> |
11 | | -#include <tuple> |
12 | | -#include <cstring> |
| 15 | +#include <variant> |
13 | 16 | #if __cpp_lib_bit_cast |
14 | 17 | #include <bit> |
15 | 18 | #endif |
16 | 19 | #include <endian.h> |
17 | 20 | #include "msgpack_error.h" |
18 | 21 |
|
19 | | - |
20 | 22 | namespace msgpackcpp |
21 | 23 | { |
22 | | - ///////////////////////////////////////////////////////////////////////////////// |
23 | | - /// Helpers |
24 | | - ///////////////////////////////////////////////////////////////////////////////// |
25 | 24 |
|
26 | | -#if __cpp_lib_bit_cast |
27 | | - using std::bit_cast; |
28 | | -#else |
29 | | - template<class To, class From> |
30 | | - To bit_cast(const From& src) noexcept |
31 | | - { |
32 | | - To dst; |
33 | | - std::memcpy(&dst, &src, sizeof(To)); |
34 | | - return dst; |
35 | | - } |
36 | | -#endif |
37 | | - |
38 | | - ///////////////////////////////////////////////////////////////////////////////// |
39 | | - /// BOOL |
40 | | - ///////////////////////////////////////////////////////////////////////////////// |
| 25 | +//---------------------------------------------------------------------------------------------------------------- |
| 26 | + |
| 27 | + class value |
| 28 | + { |
| 29 | + private: |
| 30 | + std::variant<std::nullptr_t, |
| 31 | + bool, |
| 32 | + int64_t, |
| 33 | + uint64_t, |
| 34 | + double, |
| 35 | + std::string, |
| 36 | + std::vector<value>, |
| 37 | + std::map<std::string, value>> val; |
| 38 | + |
| 39 | + public: |
| 40 | + value() = default; |
| 41 | + value(const value& ori) = default; |
| 42 | + value(value&& ori) = default; |
| 43 | + value& operator=(const value& ori) = default; |
| 44 | + value& operator=(value&& ori) = default; |
| 45 | + |
| 46 | + value(std::nullptr_t); |
| 47 | + value(bool v); |
| 48 | + |
| 49 | + template<class Int, std::enable_if_t<std::is_integral_v<Int> && std::is_signed_v<Int>, bool> = true> |
| 50 | + value(Int v); |
| 51 | + |
| 52 | + template<class UInt, std::enable_if_t<std::is_integral_v<UInt> && std::is_unsigned_v<UInt>, bool> = true> |
| 53 | + value(UInt v); |
| 54 | + |
| 55 | + template<class Real, std::enable_if_t<std::is_floating_point_v<Real>, bool> = true> |
| 56 | + value(Real v); |
| 57 | + |
| 58 | + value(const char* v); |
| 59 | + value(std::string_view v); |
| 60 | + value(std::string v); |
| 61 | + value(std::vector<value> v); |
| 62 | + value(std::map<std::string, value> v); |
| 63 | + value(std::initializer_list<value> v); |
| 64 | + |
| 65 | + size_t size() const noexcept; |
| 66 | + |
| 67 | + bool is_null() const noexcept; |
| 68 | + bool is_bool() const noexcept; |
| 69 | + bool is_int() const noexcept; |
| 70 | + bool is_real() const noexcept; |
| 71 | + bool is_str() const noexcept; |
| 72 | + bool is_array() const noexcept; |
| 73 | + bool is_object() const noexcept; |
| 74 | + |
| 75 | + auto as_bool() const -> bool; |
| 76 | + auto as_bool() -> bool&; |
| 77 | + auto as_int64() const -> int64_t; |
| 78 | + auto as_int64() -> int64_t&; |
| 79 | + auto as_uint64() const -> uint64_t; |
| 80 | + auto as_uint64() -> uint64_t&; |
| 81 | + auto as_real() const -> double; |
| 82 | + auto as_real() -> double&; |
| 83 | + auto as_str() const -> const std::string&; |
| 84 | + auto as_str() -> std::string&; |
| 85 | + auto as_array() const -> const std::vector<value>&; |
| 86 | + auto as_array() -> std::vector<value>&; |
| 87 | + auto as_object() const -> const std::map<std::string, value>&; |
| 88 | + auto as_object() -> std::map<std::string, value>&; |
| 89 | + |
| 90 | + const value& at(const std::string& key) const; |
| 91 | + value& at(const std::string& key); |
| 92 | + value& operator[](const std::string& key); |
| 93 | + |
| 94 | + const value& operator[](size_t array_index) const; |
| 95 | + value& operator[](size_t array_index); |
| 96 | + }; |
| 97 | + |
| 98 | +//---------------------------------------------------------------------------------------------------------------- |
41 | 99 |
|
42 | 100 | template<class Stream> |
43 | | - inline void serialize(Stream& out, bool v) |
44 | | - { |
45 | | - const uint8_t format = v ? 0xc3 : 0xc2; |
46 | | - out((const char*)&format, 1); |
47 | | - } |
| 101 | + void serialize(Stream& out, bool v); |
48 | 102 |
|
49 | 103 | template<class Source> |
50 | | - inline void deserialize(Source& in, bool& v) |
51 | | - { |
52 | | - uint8_t tmp{}; |
53 | | - in((char*)&tmp, 1); |
54 | | - if (tmp == 0xc2) |
55 | | - v = false; |
56 | | - else if (tmp == 0xc3) |
57 | | - v = true; |
58 | | - else |
59 | | - throw std::system_error(BAD_FORMAT); |
60 | | - } |
| 104 | + void deserialize(Source& in, bool& v); |
61 | 105 |
|
62 | 106 | ///////////////////////////////////////////////////////////////////////////////// |
63 | 107 | /// Unsigned integers |
@@ -696,4 +740,248 @@ namespace msgpackcpp |
696 | 740 | (deserialize(in, std::forward<decltype(args)>(args)),...); |
697 | 741 | }, tpl); |
698 | 742 | } |
| 743 | + |
| 744 | +//---------------------------------------------------------------------------------------------------------------- |
| 745 | +//---------------------------------------------------------------------------------------------------------------- |
| 746 | +// DEFINITIONS |
| 747 | +//---------------------------------------------------------------------------------------------------------------- |
| 748 | +//---------------------------------------------------------------------------------------------------------------- |
| 749 | + |
| 750 | + namespace details |
| 751 | + { |
| 752 | + |
| 753 | +//---------------------------------------------------------------------------------------------------------------- |
| 754 | + |
| 755 | + template<class... Ts> |
| 756 | + struct overloaded : Ts... { using Ts::operator()...; }; |
| 757 | + template<class... Ts> |
| 758 | + overloaded(Ts...) -> overloaded<Ts...>; |
| 759 | + |
| 760 | +//---------------------------------------------------------------------------------------------------------------- |
| 761 | + |
| 762 | +#if __cpp_lib_bit_cast |
| 763 | + using std::bit_cast; |
| 764 | +#else |
| 765 | + template<class To, class From> |
| 766 | + To bit_cast(const From& src) noexcept |
| 767 | + { |
| 768 | + To dst; |
| 769 | + std::memcpy(&dst, &src, sizeof(To)); |
| 770 | + return dst; |
| 771 | + } |
| 772 | +#endif |
| 773 | + |
| 774 | +//---------------------------------------------------------------------------------------------------------------- |
| 775 | + |
| 776 | + constexpr uint16_t byte_swap16(uint16_t v) |
| 777 | + { |
| 778 | + return static_cast<uint16_t>(((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8)); |
| 779 | + } |
| 780 | + |
| 781 | + constexpr uint64_t byte_swap32(uint32_t v) |
| 782 | + { |
| 783 | + return static_cast<uint32_t>(((v & 0x000000FFu) << 24) | |
| 784 | + ((v & 0x0000FF00u) << 8) | |
| 785 | + ((v & 0x00FF0000u) >> 8) | |
| 786 | + ((v & 0xFF000000u) >> 24)); |
| 787 | + } |
| 788 | + |
| 789 | + constexpr uint64_t byte_swap64(uint64_t v) |
| 790 | + { |
| 791 | + return static_cast<uint64_t>(((v & 0x00000000000000FFULL) << 56) | |
| 792 | + ((v & 0x000000000000FF00ULL) << 40) | |
| 793 | + ((v & 0x0000000000FF0000ULL) << 24) | |
| 794 | + ((v & 0x00000000FF000000ULL) << 8) | |
| 795 | + ((v & 0x000000FF00000000ULL) >> 8) | |
| 796 | + ((v & 0x0000FF0000000000ULL) >> 24) | |
| 797 | + ((v & 0x00FF000000000000ULL) >> 40) | |
| 798 | + ((v & 0xFF00000000000000ULL) >> 56)); |
| 799 | + } |
| 800 | + |
| 801 | + static_assert(byte_swap16(0x1234) == 0x3412, "bad swap"); |
| 802 | + static_assert(byte_swap32(0x12345678) == 0x78563412, "bad swap"); |
| 803 | + static_assert(byte_swap64(0x123456789abcdef1) == 0xf1debc9a78563412, "bad swap"); |
| 804 | + |
| 805 | + inline bool is_little_endian() |
| 806 | + { |
| 807 | + constexpr uint32_t v{0x01020304}; |
| 808 | + const auto* ptr{reinterpret_cast<const unsigned char*>(&v)}; |
| 809 | + return ptr[0] == 0x04; |
| 810 | + } |
| 811 | + |
| 812 | +//---------------------------------------------------------------------------------------------------------------- |
| 813 | + |
| 814 | + inline uint16_t host_to_b16(uint16_t v) { return is_little_endian() ? byte_swap16(v) : v; } |
| 815 | + inline uint32_t host_to_b32(uint32_t v) { return is_little_endian() ? byte_swap32(v) : v; } |
| 816 | + inline uint64_t host_to_b64(uint64_t v) { return is_little_endian() ? byte_swap64(v) : v; } |
| 817 | + |
| 818 | +//---------------------------------------------------------------------------------------------------------------- |
| 819 | + |
| 820 | + } |
| 821 | + |
| 822 | +//---------------------------------------------------------------------------------------------------------------- |
| 823 | + |
| 824 | + inline value::value(std::nullptr_t) : val{nullptr} {} |
| 825 | + inline value::value(bool v) : val{v} {} |
| 826 | + inline value::value(const char* v) : val(std::string(v)) {} |
| 827 | + inline value::value(std::string_view v) : val(std::string(v)) {} |
| 828 | + inline value::value(std::string v) : val{std::move(v)} {} |
| 829 | + inline value::value(std::vector<value> v) : val{std::move(v)} {} |
| 830 | + inline value::value(std::map<std::string, value> v) : val{std::move(v)} {} |
| 831 | + |
| 832 | + template<class Int, std::enable_if_t<std::is_integral_v<Int> && std::is_signed_v<Int>, bool>> |
| 833 | + inline value::value(Int v) : val{static_cast<int64_t>(v)} {} |
| 834 | + |
| 835 | + template<class UInt, std::enable_if_t<std::is_integral_v<UInt> && std::is_unsigned_v<UInt>, bool>> |
| 836 | + inline value::value(UInt v) : val{static_cast<uint64_t>(v)} {} |
| 837 | + |
| 838 | + template<class Real, std::enable_if_t<std::is_floating_point_v<Real>, bool>> |
| 839 | + inline value::value(Real v) : val{static_cast<double>(v)} {} |
| 840 | + |
| 841 | + inline value::value(std::initializer_list<value> v) |
| 842 | + { |
| 843 | + const bool is_object = std::all_of(begin(v), end(v), [](const auto& el) { |
| 844 | + return el.is_array() && el.size() == 2 && el[0].is_str(); |
| 845 | + }); |
| 846 | + |
| 847 | + if (is_object) |
| 848 | + { |
| 849 | + auto& map = val.emplace<std::map<std::string, value>>(); |
| 850 | + for (const auto& el : v) |
| 851 | + map.emplace(el[0].as_str(), el[1]); |
| 852 | + } |
| 853 | + else |
| 854 | + val.emplace<std::vector<value>>(v); |
| 855 | + } |
| 856 | + |
| 857 | +//---------------------------------------------------------------------------------------------------------------- |
| 858 | + |
| 859 | + inline size_t value::size() const noexcept |
| 860 | + { |
| 861 | + return std::visit(details::overloaded{ |
| 862 | + [&](const std::vector<value>& v) {return v.size();}, |
| 863 | + [&](const std::map<std::string, value>& v) {return v.size();}, |
| 864 | + [&](std::nullptr_t) {return (size_t)0;}, |
| 865 | + [&](const auto&) {return (size_t)1;} |
| 866 | + }, val); |
| 867 | + } |
| 868 | + |
| 869 | +//---------------------------------------------------------------------------------------------------------------- |
| 870 | + |
| 871 | + inline bool value::is_null() const noexcept {return std::holds_alternative<std::nullptr_t>(val);} |
| 872 | + inline bool value::is_bool() const noexcept {return std::holds_alternative<bool>(val);} |
| 873 | + inline bool value::is_int() const noexcept {return std::holds_alternative<int64_t>(val) || std::holds_alternative<uint64_t>(val);} |
| 874 | + inline bool value::is_real() const noexcept {return std::holds_alternative<double>(val);} |
| 875 | + inline bool value::is_str() const noexcept {return std::holds_alternative<std::string>(val);} |
| 876 | + inline bool value::is_array() const noexcept {return std::holds_alternative<std::vector<value>>(val);} |
| 877 | + inline bool value::is_object() const noexcept {return std::holds_alternative<std::map<std::string, value>>(val);} |
| 878 | + |
| 879 | +//---------------------------------------------------------------------------------------------------------------- |
| 880 | + |
| 881 | + inline auto value::as_bool() const -> bool {return std::get<bool>(val);} |
| 882 | + inline auto value::as_bool() -> bool& {return std::get<bool>(val);} |
| 883 | + inline auto value::as_int64() const -> int64_t {return std::get<int64_t>(val);} |
| 884 | + inline auto value::as_int64() -> int64_t& {return std::get<int64_t>(val);} |
| 885 | + inline auto value::as_uint64() const -> uint64_t {return std::get<uint64_t>(val);} |
| 886 | + inline auto value::as_uint64() -> uint64_t& {return std::get<uint64_t>(val);} |
| 887 | + inline auto value::as_real() const -> double {return std::get<double>(val);} |
| 888 | + inline auto value::as_real() -> double& {return std::get<double>(val);} |
| 889 | + inline auto value::as_str() const -> const std::string& {return std::get<std::string>(val);} |
| 890 | + inline auto value::as_str() -> std::string& {return std::get<std::string>(val);} |
| 891 | + inline auto value::as_array() const -> const std::vector<value>& {return std::get<std::vector<value>>(val);} |
| 892 | + inline auto value::as_array() -> std::vector<value>& {return std::get<std::vector<value>>(val);} |
| 893 | + inline auto value::as_object() const -> const std::map<std::string, value>& {return std::get<std::map<std::string, value>>(val);} |
| 894 | + inline auto value::as_object() -> std::map<std::string, value>& {return std::get<std::map<std::string, value>>(val);} |
| 895 | + |
| 896 | +//---------------------------------------------------------------------------------------------------------------- |
| 897 | + |
| 898 | + inline const value& value::at(const std::string& key) const { return std::get<std::map<std::string, value>>(val).at(key); } |
| 899 | + inline value& value::at(const std::string& key) { return std::get<std::map<std::string, value>>(val).at(key); } |
| 900 | + |
| 901 | + inline value& value::operator[](const std::string& key) |
| 902 | + { |
| 903 | + if (!std::holds_alternative<std::map<std::string, value>>(val)) |
| 904 | + val.emplace<std::map<std::string, value>>(); |
| 905 | + return std::get<std::map<std::string, value>>(val)[key]; |
| 906 | + } |
| 907 | + |
| 908 | +//---------------------------------------------------------------------------------------------------------------- |
| 909 | + |
| 910 | + inline const value& value::operator[](size_t array_index) const { return std::get<std::vector<value>>(val)[array_index]; } |
| 911 | + inline value& value::operator[](size_t array_index) { return std::get<std::vector<value>>(val)[array_index]; } |
| 912 | + |
| 913 | +//---------------------------------------------------------------------------------------------------------------- |
| 914 | + |
| 915 | + enum msgpack_identifier : uint8_t |
| 916 | + { |
| 917 | + MSGPACK_FALSE = 0xc2, |
| 918 | + MSGPACK_TRUE = 0xc3 |
| 919 | + }; |
| 920 | + |
| 921 | + template<class Stream> |
| 922 | + inline void serialize(Stream& out, bool v) |
| 923 | + { |
| 924 | + const uint8_t format = v ? MSGPACK_TRUE : MSGPACK_FALSE; |
| 925 | + out((const char*)&format, 1); |
| 926 | + } |
| 927 | + |
| 928 | + template<class Source> |
| 929 | + inline void deserialize(Source& in, bool& v) |
| 930 | + { |
| 931 | + uint8_t tmp{}; |
| 932 | + in((char*)&tmp, 1); |
| 933 | + if (tmp == MSGPACK_FALSE) v = false; |
| 934 | + else if (tmp == MSGPACK_TRUE) v = true; |
| 935 | + else throw std::system_error(BAD_FORMAT); |
| 936 | + } |
| 937 | + |
| 938 | +//---------------------------------------------------------------------------------------------------------------- |
| 939 | + |
| 940 | + template<class Stream, class UInt, std::enable_if_t<std::is_integral_v<UInt> && std::is_unsigned_v<UInt>, bool>> |
| 941 | + inline void serialize(Stream& out, UInt v) |
| 942 | + { |
| 943 | + using namespace details; |
| 944 | + |
| 945 | + if (v <= 0x7f) |
| 946 | + { |
| 947 | + // positive fixint (7-bit positive integer) |
| 948 | + const uint8_t v8 = static_cast<uint8_t>(v); |
| 949 | + out((const char*)&v8, 1); |
| 950 | + } |
| 951 | + else if (v <= std::numeric_limits<uint8_t>::max()) |
| 952 | + { |
| 953 | + // unsigned 8 |
| 954 | + constexpr uint8_t format = 0xcc; |
| 955 | + const uint8_t v8 = static_cast<uint8_t>(v); |
| 956 | + out((const char*)&format, 1); |
| 957 | + out((const char*)&v8, 1); |
| 958 | + } |
| 959 | + else if (v <= std::numeric_limits<uint16_t>::max()) |
| 960 | + { |
| 961 | + // unsigned 16 |
| 962 | + constexpr uint8_t format = 0xcd; |
| 963 | + const uint16_t v16 = htobe16(static_cast<uint16_t>(v)); |
| 964 | + out((const char*)&format, 1); |
| 965 | + out((const char*)&v16, 2); |
| 966 | + } |
| 967 | + else if (v <= std::numeric_limits<uint32_t>::max()) |
| 968 | + { |
| 969 | + // unsigned 32 |
| 970 | + constexpr uint8_t format = 0xce; |
| 971 | + const uint32_t v32 = htobe32(static_cast<uint32_t>(v)); |
| 972 | + out((const char*)&format, 1); |
| 973 | + out((const char*)&v32, 4); |
| 974 | + } |
| 975 | + else |
| 976 | + { |
| 977 | + // unsigned 64 |
| 978 | + constexpr uint8_t format = 0xcf; |
| 979 | + const uint64_t v64 = htobe64(static_cast<uint64_t>(v)); |
| 980 | + out((const char*)&format, 1); |
| 981 | + out((const char*)&v64, 8); |
| 982 | + } |
| 983 | + } |
| 984 | + |
| 985 | +//---------------------------------------------------------------------------------------------------------------- |
| 986 | + |
699 | 987 | } |
0 commit comments