Skip to content

Commit 314caf9

Browse files
author
pfeatherstone
committed
Adding value + tests
1 parent 6f98b09 commit 314caf9

File tree

7 files changed

+7597
-41
lines changed

7 files changed

+7597
-41
lines changed

include/msgpack.h

Lines changed: 326 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,107 @@
11
#pragma once
22

33
#include <cstdint>
4+
#include <cstring>
5+
#include <type_traits>
46
#include <limits>
57
#include <utility>
6-
#include <type_traits>
8+
#include <algorithm>
9+
#include <string>
710
#include <string_view>
11+
#include <tuple>
812
#include <vector>
913
#include <map>
1014
#include <unordered_map>
11-
#include <tuple>
12-
#include <cstring>
15+
#include <variant>
1316
#if __cpp_lib_bit_cast
1417
#include <bit>
1518
#endif
1619
#include <endian.h>
1720
#include "msgpack_error.h"
1821

19-
2022
namespace msgpackcpp
2123
{
22-
/////////////////////////////////////////////////////////////////////////////////
23-
/// Helpers
24-
/////////////////////////////////////////////////////////////////////////////////
2524

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+
//----------------------------------------------------------------------------------------------------------------
4199

42100
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);
48102

49103
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);
61105

62106
/////////////////////////////////////////////////////////////////////////////////
63107
/// Unsigned integers
@@ -696,4 +740,248 @@ namespace msgpackcpp
696740
(deserialize(in, std::forward<decltype(args)>(args)),...);
697741
}, tpl);
698742
}
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+
699987
}

0 commit comments

Comments
 (0)