Skip to content

Commit

Permalink
[struct_pack] enhance struct_pack::write/read/get_write_size
Browse files Browse the repository at this point in the history
  • Loading branch information
poor-circle committed Dec 28, 2023
1 parent 08d0c6d commit c9720a8
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 275 deletions.
1 change: 1 addition & 0 deletions include/ylt/struct_pack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "struct_pack/type_id.hpp"
#include "struct_pack/type_trait.hpp"
#include "struct_pack/unpacker.hpp"
#include "struct_pack/user_helper.hpp"
#include "struct_pack/varint.hpp"

#if __has_include(<expected>) && __cplusplus > 202002L
Expand Down
180 changes: 0 additions & 180 deletions include/ylt/struct_pack/endian_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,184 +270,4 @@ STRUCT_PACK_INLINE bool low_bytes_read_wrapper(reader_t& reader, T& elem) {
}
}
} // namespace detail
template <typename Writer, typename T>
STRUCT_PACK_INLINE void write(Writer& writer, const T& t) {
if constexpr (std::is_fundamental_v<T>) {
detail::write_wrapper<sizeof(T)>(writer, (const char*)&t);
}
else if constexpr (detail::array<T>) {
if constexpr (detail::is_little_endian_copyable<sizeof(t[0])> &&
std::is_fundamental_v<
std::remove_reference_t<decltype(t[0])>>) {
write_bytes_array(writer, (const char*)t.data(), sizeof(T));
}
else {
for (auto& e : t) write(writer, e);
}
}
else if constexpr (detail::string<T> || detail::container<T>) {
std::uint64_t len = t.size();
detail::write_wrapper<8>(writer, (char*)&len);
if constexpr (detail::continuous_container<T> &&
detail::is_little_endian_copyable<sizeof(t[0])> &&
std::is_fundamental_v<typename T::value_type>) {
write_bytes_array(writer, (const char*)t.data(), len * sizeof(t[0]));
}
else {
for (auto& e : t) write(writer, e);
}
}
else {
static_assert(!sizeof(T), "not support type");
}
}
template <typename Writer, typename T>
STRUCT_PACK_INLINE void write(Writer& writer, const T* t, std::size_t length) {
if constexpr (std::is_fundamental_v<T>) {
if constexpr (detail::is_little_endian_copyable<sizeof(T)>) {
write_bytes_array(writer, (const char*)t, sizeof(T) * length);
}
else {
for (std::size_t i = 0; i < length; ++i) write(writer, t[i]);
}
}
else {
static_assert(!sizeof(T), "not support type");
}
}
template <typename T>
STRUCT_PACK_INLINE constexpr std::size_t get_write_size(const T& t) {
if constexpr (std::is_fundamental_v<T>) {
return sizeof(T);
}
else if constexpr (detail::array<T>) {
if constexpr (std::is_fundamental_v<
std::remove_reference_t<decltype(t[0])>>) {
return sizeof(T);
}
else {
std::size_t ret = 0;
for (auto& e : t) ret += get_write_size(e);
return ret;
}
}
else if constexpr (detail::string<T> || detail::container<T>) {
std::size_t ret = 8;
if constexpr (detail::continuous_container<T> &&
detail::is_little_endian_copyable<sizeof(t[0])> &&
std::is_fundamental_v<typename T::value_type>) {
ret += t.size() * sizeof(t[0]);
}
else {
for (auto& e : t) ret += get_write_size(e);
}
return ret;
}
else {
static_assert(!sizeof(T), "not support type");
}
}
template <typename T>
STRUCT_PACK_INLINE constexpr std::size_t get_write_size(const T* t,
std::size_t length) {
return sizeof(T) * length;
}
template <typename Reader, typename T>
STRUCT_PACK_INLINE struct_pack::errc read(Reader& reader, T& t) {
if constexpr (std::is_fundamental_v<T>) {
if SP_UNLIKELY (!detail::read_wrapper<sizeof(T)>(reader, (char*)&t)) {
return struct_pack::errc::no_buffer_space;
}
else {
return {};
}
}
else if constexpr (detail::array<T>) {
if constexpr (std::is_fundamental_v<
std::remove_reference_t<decltype(t[0])>> &&
detail::is_little_endian_copyable<sizeof(t[0])>) {
if SP_UNLIKELY (!read_bytes_array(reader, (char*)t.data(), sizeof(T))) {
return struct_pack::errc::no_buffer_space;
}
else {
return {};
}
}
else {
struct_pack::errc ec;
for (auto& e : t) {
ec = read(reader, e);
if SP_UNLIKELY (ec != struct_pack::errc{}) {
return ec;
}
}
return struct_pack::errc{};
}
}
else if constexpr (detail::string<T> || detail::container<T>) {
std::uint64_t sz;
auto ec = read(reader, sz);
if SP_UNLIKELY (ec != struct_pack::errc{}) {
return ec;
}
if constexpr (detail::continuous_container<T> &&
std::is_fundamental_v<
std::remove_reference_t<decltype(t[0])>> &&
detail::is_little_endian_copyable<sizeof(t[0])> &&
checkable_reader_t<Reader>) {
if SP_UNLIKELY (sz > UINT64_MAX / sizeof(t[0]) || sz > SIZE_MAX) {
return struct_pack::errc::invalid_buffer;
}
std::size_t mem_size = sz * sizeof(t[0]);
if SP_UNLIKELY (!reader.check(mem_size)) {
return struct_pack::errc::no_buffer_space;
}
detail::resize(t, sz);
if SP_UNLIKELY (!read_bytes_array(reader, (char*)t.data(), mem_size)) {
return struct_pack::errc::no_buffer_space;
}
return struct_pack::errc{};
}
else {
t.clear();
for (std::size_t i = 0; i < sz; ++i) {
t.push_back(typename T::value_type{});
ec = read(reader, t.back());
if SP_UNLIKELY (ec != struct_pack::errc{}) {
return ec;
}
}
return struct_pack::errc{};
}
}
else {
static_assert(!sizeof(T), "not support type");
}
}
template <typename Reader, typename T>
struct_pack::errc read(Reader& reader, T* t, std::size_t length) {
if constexpr (std::is_fundamental_v<T>) {
if constexpr (detail::is_little_endian_copyable<sizeof(T)>) {
if SP_UNLIKELY (!read_bytes_array(reader, (char*)t, sizeof(T) * length)) {
return struct_pack::errc::no_buffer_space;
}
else {
return {};
}
}
else {
struct_pack::errc ec{};
for (std::size_t i = 0; i < length; ++i) {
ec = read(reader, t[i]);
if SP_UNLIKELY (ec != struct_pack::errc{}) {
return ec;
}
};
return ec;
}
}
else {
static_assert(!sizeof(T), "not support type");
}
}
}; // namespace struct_pack
91 changes: 51 additions & 40 deletions include/ylt/struct_pack/packer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ template <
#else
typename writer,
#endif
typename serialize_type>
typename serialize_type, bool force_optimize = false>
class packer {
constexpr inline static serialize_buffer_size useless_info{};

public:
packer(writer &writer_, const serialize_buffer_size &info)
: writer_(writer_), info(info) {
: writer_(writer_), info_(info) {
#if __cpp_concepts < 201907L
static_assert(writer_t<writer>,
"The writer type must satisfy requirements!");
#endif
}
packer(writer &writer_) : writer_(writer_), info_(useless_info) {
#if __cpp_concepts < 201907L
static_assert(writer_t<writer>,
"The writer type must satisfy requirements!");
Expand Down Expand Up @@ -70,7 +77,6 @@ class packer {
}
}

private:
template <typename T, typename... Args>
static constexpr uint32_t STRUCT_PACK_INLINE calculate_raw_hash() {
if constexpr (sizeof...(Args) == 0) {
Expand Down Expand Up @@ -100,10 +106,10 @@ class packer {
write_wrapper<sizeof(uint32_t)>(writer_, (char *)&hash_head);
}
if constexpr (hash_head % 2) { // has more metainfo
auto metainfo = info.metainfo();
auto metainfo = info_.metainfo();
write_wrapper<sizeof(char)>(writer_, (char *)&metainfo);
if constexpr (serialize_static_config<serialize_type>::has_compatible) {
std::size_t sz = info.size();
std::size_t sz = info_.size();
switch (metainfo & 0b11) {
case 1:
low_bytes_write_wrapper<2>(writer_, sz);
Expand Down Expand Up @@ -132,7 +138,6 @@ class packer {
}
}

private:
template <std::size_t size_type, uint64_t version,
std::uint64_t parent_tag = 0, typename First, typename... Args>
constexpr void STRUCT_PACK_INLINE serialize_many(const First &first_item,
Expand Down Expand Up @@ -302,50 +307,56 @@ class packer {
}
else if constexpr (map_container<type> || container<type>) {
auto size = item.size();

if constexpr (size_type == 1) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
#ifdef STRUCT_PACK_OPTIMIZE
else if constexpr (size_type == 2) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else if constexpr (size_type == 4) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else if constexpr (size_type == 8) {
if constexpr (sizeof(std::size_t) >= 8) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else {
static_assert(!sizeof(T), "illegal size_type");
}
}
else {
static_assert(!sizeof(item), "illegal size_type.");
}
#ifdef STRUCT_PACK_OPTIMIZE
constexpr bool struct_pack_optimize = true;
#else
else {
auto size = item.size();
switch ((info.metainfo() & 0b11000) >> 3) {
case 1:
low_bytes_write_wrapper<2>(writer_, size);
break;
case 2:
low_bytes_write_wrapper<4>(writer_, size);
break;
case 3:
constexpr bool struct_pack_optimize = false;
#endif
if constexpr (force_optimize || struct_pack_optimize) {
if constexpr (size_type == 2) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else if constexpr (size_type == 4) {
low_bytes_write_wrapper<size_type>(writer_, size);
}
else if constexpr (size_type == 8) {
if constexpr (sizeof(std::size_t) >= 8) {
low_bytes_write_wrapper<8>(writer_, size);
low_bytes_write_wrapper<size_type>(writer_, size);
}
else {
unreachable();
static_assert(!sizeof(T), "illegal size_type");
}
break;
default:
unreachable();
}
else {
static_assert(!sizeof(item), "illegal size_type.");
}
}
else {
switch ((info_.metainfo() & 0b11000) >> 3) {
case 1:
low_bytes_write_wrapper<2>(writer_, size);
break;
case 2:
low_bytes_write_wrapper<4>(writer_, size);
break;
case 3:
if constexpr (sizeof(std::size_t) >= 8) {
low_bytes_write_wrapper<8>(writer_, size);
}
else {
unreachable();
}
break;
default:
unreachable();
}
}
}
#endif
if constexpr (trivially_copyable_container<type> &&
is_little_endian_copyable<sizeof(
typename type::value_type)>) {
Expand Down Expand Up @@ -522,7 +533,7 @@ class packer {
template <typename T>
friend constexpr serialize_buffer_size get_needed_size(const T &t);
writer &writer_;
const serialize_buffer_size &info;
const serialize_buffer_size &info_;
};

template <uint64_t conf = sp_config::DEFAULT,
Expand Down
Loading

0 comments on commit c9720a8

Please sign in to comment.