Skip to content

Commit

Permalink
[struct_pack] enhance serialize performance by uninitialized resize (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
poor-circle authored Nov 10, 2023
1 parent ae6abd1 commit 873d75f
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 5 deletions.
3 changes: 2 additions & 1 deletion include/ylt/coro_io/rate_limiter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ class abstract_smooth_rate_limiter : public rate_limiter {
do_set_rate(permits_per_second, stable_internal_micros);
}
std::chrono::steady_clock::time_point reserve_earliest_available(
int required_permits, std::chrono::steady_clock::time_point now_micros) {
int required_permits,
std::chrono::steady_clock::time_point now_micros) override {
resync(now_micros);
std::chrono::steady_clock::time_point return_value =
this->next_free_ticket_micros_;
Expand Down
1 change: 1 addition & 0 deletions include/ylt/coro_rpc/impl/coro_rpc_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,7 @@ class coro_rpc_client {
}

auto &header = *(coro_rpc_protocol::req_header *)buffer.data();
header = {};
header.magic = coro_rpc_protocol::magic_number;
header.function_id = func_id<func>();
#ifdef UNIT_TEST_INJECT
Expand Down
4 changes: 2 additions & 2 deletions include/ylt/struct_pack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ STRUCT_PACK_INLINE void serialize_to(Writer &writer, const Args &...args) {
auto data_offset = writer.size();
auto info = detail::get_serialize_runtime_info<conf>(args...);
auto total = data_offset + info.size();
writer.resize(total);
detail::resize(writer, total);
auto real_writer =
struct_pack::detail::memory_writer{(char *)writer.data() + data_offset};
struct_pack::detail::serialize_to<conf>(real_writer, info, args...);
Expand Down Expand Up @@ -189,7 +189,7 @@ void STRUCT_PACK_INLINE serialize_to_with_offset(Buffer &buffer,
static_assert(sizeof...(args) > 0);
auto info = detail::get_serialize_runtime_info<conf>(args...);
auto old_size = buffer.size();
buffer.resize(old_size + offset + info.size());
detail::resize(buffer, old_size + offset + info.size());
auto writer = struct_pack::detail::memory_writer{(char *)buffer.data() +
old_size + offset};
struct_pack::detail::serialize_to<conf>(writer, info, args...);
Expand Down
2 changes: 1 addition & 1 deletion include/ylt/struct_pack/type_trait.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace struct_pack::detail {
template <typename T>
constexpr bool struct_pack_byte =
std::is_same_v<char, T> || std::is_same_v<unsigned char, T> ||
std::is_same_v<std::byte, T>;
std::is_same_v<signed char, T> || std::is_same_v<std::byte, T>;

template <typename T>
#if __cpp_concepts < 201907L
Expand Down
133 changes: 133 additions & 0 deletions include/ylt/struct_pack/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
*/
#pragma once
#include <array>
#include <cstddef>
#include <string>
#include <type_traits>
#include <vector>

#include "marco.h"
namespace struct_pack::detail {
Expand Down Expand Up @@ -77,4 +81,133 @@ constexpr void STRUCT_PACK_INLINE compile_time_unique(
}
}
}

#if __cpp_lib_string_resize_and_overwrite >= 202110L
template <typename ch>
inline void resize(std::basic_string<ch> &str, std::size_t sz) {
str.resize_and_overwrite(sz, [](ch *, std::size_t sz) {
return sz;
});
}
#elif (defined(_MSC_VER) && _MSC_VER <= 1920)
// old msvc don't support visit private, discard it.

#else

template <typename Function, Function func_ptr>
class string_thief {
public:
friend void string_set_length_hacker(std::string &self, std::size_t sz) {
#if defined(_MSVC_STL_VERSION)
(self.*func_ptr)._Myval2._Mysize = sz;
#else
#if defined(_LIBCPP_VERSION)
(self.*func_ptr)(sz);
#else
#if (_GLIBCXX_USE_CXX11_ABI == 0) && defined(__GLIBCXX__)
(self.*func_ptr)()->_M_set_length_and_sharable(sz);
#else
#if defined(__GLIBCXX__)
(self.*func_ptr)(sz);
#endif
#endif
#endif
#endif
}
};

#if defined(__GLIBCXX__) // libstdc++
#if (_GLIBCXX_USE_CXX11_ABI == 0)
template class string_thief<decltype(&std::string::_M_rep),
&std::string::_M_rep>;
#else
template class string_thief<decltype(&std::string::_M_set_length),
&std::string::_M_set_length>;
#endif
#elif defined(_LIBCPP_VERSION)
template class string_thief<decltype(&std::string::__set_size),
&std::string::__set_size>;
#elif defined(_MSVC_STL_VERSION)
template class string_thief<decltype(&std::string::_Mypair),
&std::string::_Mypair>;
#endif

void string_set_length_hacker(std::string &, std::size_t);

template <typename ch>
inline void resize(std::basic_string<ch> &raw_str, std::size_t sz) {
std::string &str = *reinterpret_cast<std::string *>(&raw_str);
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \
defined(_MSVC_STL_VERSION)
if (sz > str.capacity()) {
str.reserve(sz);
}
string_set_length_hacker(str, sz);
str[sz] = '\0';
#else
raw_str.resize(sz);
#endif
}

#endif

#if (defined(_MSC_VER) && _MSC_VER <= 1920)
#else
void vector_set_length_hacker(std::vector<char> &self, std::size_t sz);

template <typename Function, Function func_ptr>
class vector_thief {
public:
friend void vector_set_length_hacker(std::vector<char> &self,
std::size_t sz) {
#if defined(_MSVC_STL_VERSION)
(self.*func_ptr)._Myval2._Mylast = self.data() + sz;
#else
#if defined(_LIBCPP_VERSION)
#if _LIBCPP_VERSION < 14000
((*(std::__vector_base<char, std::allocator<char>> *)(&self)).*func_ptr) =
self.data() + sz;
#else
(self.*func_ptr) = self.data() + sz;
#endif
#else
#if defined(__GLIBCXX__)
((*(std::_Vector_base<char, std::allocator<char>> *)(&self)).*func_ptr)
._M_finish = self.data() + sz;
#endif
#endif
#endif
}
};

#if defined(__GLIBCXX__) // libstdc++
template class vector_thief<decltype(&std::vector<char>::_M_impl),
&std::vector<char>::_M_impl>;
#elif defined(_LIBCPP_VERSION)
template class vector_thief<decltype(&std::vector<char>::__end_),
&std::vector<char>::__end_>;
#elif defined(_MSVC_STL_VERSION)
template class vector_thief<decltype(&std::vector<char>::_Mypair),
&std::vector<char>::_Mypair>;
#endif

template <typename ch>
inline void resize(std::vector<ch> &raw_vec, std::size_t sz) {
#if defined(__GLIBCXX__) || \
(defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_ASAN)) || \
defined(_MSVC_STL_VERSION)
std::vector<char> &vec = *reinterpret_cast<std::vector<char> *>(&raw_vec);
vec.reserve(sz);
vector_set_length_hacker(vec, sz);
#else
raw_vec.resize(sz);
#endif
}
#endif

template <typename T>
inline void resize(T &str, std::size_t sz) {
str.resize(sz);
}

} // namespace struct_pack::detail
5 changes: 4 additions & 1 deletion src/struct_pack/examples/basic_usage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ void basic_usage() {
// api 5. serialize with offset
{
auto buffer = struct_pack::serialize_with_offset(/* offset = */ 2, p);
assert(buffer[0] == '\0' && buffer[1] == '\0');
auto buffer2 = struct_pack::serialize(p);
bool result = std::string_view{buffer.data() + 2, buffer.size() - 2} ==
std::string_view{buffer2.data(), buffer2.size()};
assert(result);
}
// api 6. serialize varadic param
{
Expand Down

0 comments on commit 873d75f

Please sign in to comment.