Skip to content

Commit

Permalink
[struct_pack] refactor code (#464)
Browse files Browse the repository at this point in the history
  • Loading branch information
poor-circle authored Sep 21, 2023
1 parent daedb6a commit d32b0ee
Show file tree
Hide file tree
Showing 18 changed files with 3,289 additions and 3,101 deletions.
15 changes: 14 additions & 1 deletion include/ylt/struct_pack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,21 @@
#include <type_traits>
#include <utility>

#include "struct_pack/alignment.hpp"
#include "struct_pack/calculate_size.hpp"
#include "struct_pack/compatible.hpp"
#include "struct_pack/derived_helper.hpp"
#include "struct_pack/derived_marco.hpp"
#include "struct_pack/struct_pack_impl.hpp"
#include "struct_pack/error_code.hpp"
#include "struct_pack/md5_constexpr.hpp"
#include "struct_pack/packer.hpp"
#include "struct_pack/reflection.hpp"
#include "struct_pack/trivial_view.hpp"
#include "struct_pack/type_calculate.hpp"
#include "struct_pack/type_id.hpp"
#include "struct_pack/type_trait.hpp"
#include "struct_pack/unpacker.hpp"
#include "struct_pack/varint.hpp"

#if __has_include(<expected>) && __cplusplus > 202002L
#include <expected>
Expand Down
212 changes: 212 additions & 0 deletions include/ylt/struct_pack/alignment.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/*
* Copyright (c) 2023, Alibaba Group Holding Limited;
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

#include <algorithm>

#include "reflection.hpp"
#include "util.h"

namespace struct_pack::detail {
namespace align {

template <typename T>
constexpr std::size_t alignment_impl();

template <typename T>
constexpr std::size_t alignment_v = alignment_impl<T>();

template <typename type, std::size_t... I>
constexpr std::size_t default_alignment_helper(std::index_sequence<I...>) {
return (std::max)(
{(is_compatible_v<remove_cvref_t<std::tuple_element_t<I, type>>>
? std::size_t{0}
: align::alignment_v<
remove_cvref_t<std::tuple_element_t<I, type>>>)...});
}

template <typename T>
constexpr std::size_t default_alignment() {
if constexpr (!is_trivial_serializable<T>::value && !is_trivial_view_v<T>) {
using type = decltype(get_types<T>());
return default_alignment_helper<type>(
std::make_index_sequence<std::tuple_size_v<type>>());
}
else if constexpr (is_trivial_view_v<T>) {
return std::alignment_of_v<typename T::value_type>;
}
else {
return std::alignment_of_v<T>;
}
}
template <typename T>
constexpr std::size_t default_alignment_v = default_alignment<T>();

template <typename T>
constexpr std::size_t alignment_impl();

template <typename type, std::size_t... I>
constexpr std::size_t pack_alignment_impl_helper(std::index_sequence<I...>) {
return (std::max)(
{(is_compatible_v<remove_cvref_t<std::tuple_element_t<I, type>>>
? std::size_t{0}
: align::alignment_v<
remove_cvref_t<std::tuple_element_t<I, type>>>)...});
}

template <typename T>
constexpr std::size_t pack_alignment_impl() {
static_assert(std::is_class_v<T>);
static_assert(!is_trivial_view_v<T>);
constexpr auto ret = struct_pack::pack_alignment_v<T>;
static_assert(ret == 0 || ret == 1 || ret == 2 || ret == 4 || ret == 8 ||
ret == 16);
if constexpr (ret == 0) {
using type = decltype(get_types<T>());
return pack_alignment_impl_helper<type>(
std::make_index_sequence<std::tuple_size_v<type>>());
}
else {
return ret;
}
}

template <typename T>
constexpr std::size_t pack_alignment_v = pack_alignment_impl<T>();

template <typename T>
constexpr std::size_t alignment_impl() {
if constexpr (struct_pack::alignment_v<T> == 0 &&
struct_pack::pack_alignment_v<T> == 0) {
return default_alignment_v<T>;
}
else if constexpr (struct_pack::alignment_v<T> != 0) {
if constexpr (is_trivial_serializable<T>::value) {
static_assert(default_alignment_v<T> == alignment_v<T>);
}
constexpr auto ret = struct_pack::alignment_v<T>;
static_assert(
[](std::size_t align) constexpr {
while (align % 2 == 0) {
align /= 2;
}
return align == 1;
}(ret),
"alignment should be power of 2");
return ret;
}
else {
if constexpr (is_trivial_serializable<T>::value) {
return default_alignment_v<T>;
}
else {
return pack_alignment_v<T>;
}
}
}
template <typename P, typename T, std::size_t I>
struct calculate_trival_obj_size {
constexpr void operator()(std::size_t &total);
};

template <typename P, typename T, std::size_t I>
struct calculate_padding_size_impl {
constexpr void operator()(
std::size_t &offset,
std::array<std::size_t, struct_pack::members_count<P> + 1>
&padding_size) {
if constexpr (is_compatible_v<T>) {
padding_size[I] = 0;
}
else if constexpr (is_trivial_view_v<T>) {
calculate_padding_size_impl<P, typename T::value_type, I>{}(offset,
padding_size);
}
else {
if (offset % align::alignment_v<T>) {
padding_size[I] =
(std::min)(align::pack_alignment_v<P> - 1,
align::alignment_v<T> - offset % align::alignment_v<T>);
}
else {
padding_size[I] = 0;
}
offset += padding_size[I];
if constexpr (is_trivial_serializable<T>::value)
offset += sizeof(T);
else {
for_each<T, calculate_trival_obj_size>(offset);
static_assert(is_trivial_serializable<T, true>::value);
}
}
}
};

template <typename T>
constexpr auto calculate_padding_size() {
std::array<std::size_t, struct_pack::members_count<T> + 1> padding_size{};
std::size_t offset = 0;
for_each<T, calculate_padding_size_impl>(offset, padding_size);
if (offset % align::alignment_v<T>) {
padding_size[struct_pack::members_count<T>] =
align::alignment_v<T> - offset % align::alignment_v<T>;
}
else {
padding_size[struct_pack::members_count<T>] = 0;
}
return padding_size;
}
template <typename T>
constexpr std::array<std::size_t, struct_pack::members_count<T> + 1>
padding_size = calculate_padding_size<T>();
template <typename T>
constexpr std::size_t get_total_padding_size() {
std::size_t sum = 0;
for (auto &e : padding_size<T>) {
sum += e;
}
return sum;
};
template <typename T>
constexpr std::size_t total_padding_size = get_total_padding_size<T>();

template <typename P, typename T, std::size_t I>
using calculate_trival_obj_size_wrapper = calculate_trival_obj_size<P, T, I>;

template <typename P, typename T, std::size_t I>
constexpr void calculate_trival_obj_size<P, T, I>::operator()(
std::size_t &total) {
if constexpr (I == 0) {
total += total_padding_size<P>;
}
if constexpr (!is_compatible_v<T>) {
if constexpr (is_trivial_serializable<T>::value) {
total += sizeof(T);
}
else if constexpr (is_trivial_view_v<T>) {
total += sizeof(typename T::value_type);
}
else {
static_assert(is_trivial_serializable<T, true>::value);
std::size_t offset = 0;
for_each<T, calculate_trival_obj_size_wrapper>(offset);
total += offset;
}
}
}

} // namespace align
} // namespace struct_pack::detail
Loading

0 comments on commit d32b0ee

Please sign in to comment.