/* * 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 #include "reflection.hpp" #include "util.h" namespace struct_pack::detail { namespace align { template constexpr std::size_t alignment_impl(); template constexpr std::size_t alignment_v = alignment_impl(); template constexpr std::size_t default_alignment_helper(std::index_sequence) { return (std::max)( {(is_compatible_v>> ? std::size_t{0} : align::alignment_v< remove_cvref_t>>)...}); } template constexpr std::size_t default_alignment() { if constexpr (!is_trivial_serializable::value && !is_trivial_view_v) { using type = decltype(get_types()); return default_alignment_helper( std::make_index_sequence>()); } else if constexpr (is_trivial_view_v) { return std::alignment_of_v; } else { return std::alignment_of_v; } } template constexpr std::size_t default_alignment_v = default_alignment(); template constexpr std::size_t alignment_impl(); template constexpr std::size_t pack_alignment_impl_helper(std::index_sequence) { return (std::max)( {(is_compatible_v>> ? std::size_t{0} : align::alignment_v< remove_cvref_t>>)...}); } template constexpr std::size_t pack_alignment_impl() { static_assert(std::is_class_v); static_assert(!is_trivial_view_v); constexpr auto ret = struct_pack::pack_alignment_v; static_assert(ret == 0 || ret == 1 || ret == 2 || ret == 4 || ret == 8 || ret == 16); if constexpr (ret == 0) { using type = decltype(get_types()); return pack_alignment_impl_helper( std::make_index_sequence>()); } else { return ret; } } template constexpr std::size_t pack_alignment_v = pack_alignment_impl(); template constexpr std::size_t alignment_impl() { if constexpr (struct_pack::detail::is_compatible_v) { return 0; } else if constexpr (struct_pack::alignment_v == 0 && struct_pack::pack_alignment_v == 0) { return default_alignment_v; } else if constexpr (struct_pack::alignment_v != 0) { if constexpr (is_trivial_serializable::value) { static_assert(default_alignment_v == alignment_v); } constexpr auto ret = struct_pack::alignment_v; 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::value) { return default_alignment_v; } else { return pack_alignment_v; } } } template struct calculate_trival_obj_size { constexpr void operator()(std::size_t &total); }; template struct calculate_padding_size_impl { constexpr void operator()( std::size_t &offset, std::array + 1> &padding_size) { if constexpr (is_compatible_v) { padding_size[I] = 0; } else if constexpr (is_trivial_view_v) { calculate_padding_size_impl{}(offset, padding_size); } else { if constexpr (align::alignment_v) { if (offset % align::alignment_v) { padding_size[I] = (std::min)( align::pack_alignment_v

- 1, align::alignment_v - offset % align::alignment_v); } else { padding_size[I] = 0; } } else { padding_size[I] = 0; } offset += padding_size[I]; if constexpr (is_trivial_serializable::value) offset += sizeof(T); else { for_each(offset); static_assert(is_trivial_serializable::value); } } } }; template constexpr auto calculate_padding_size() { std::array + 1> padding_size{}; std::size_t offset = 0; for_each(offset, padding_size); if constexpr (align::alignment_v > 0) { if (offset % align::alignment_v) { padding_size[struct_pack::members_count] = align::alignment_v - offset % align::alignment_v; return padding_size; } } padding_size[struct_pack::members_count] = 0; return padding_size; } template constexpr std::array + 1> padding_size = calculate_padding_size(); template constexpr std::size_t get_total_padding_size() { std::size_t sum = 0; for (auto &e : padding_size) { sum += e; } return sum; }; template constexpr std::size_t total_padding_size = get_total_padding_size(); template using calculate_trival_obj_size_wrapper = calculate_trival_obj_size; template constexpr void calculate_trival_obj_size::operator()( std::size_t &total) { if constexpr (I == 0) { total += total_padding_size

; } if constexpr (!is_compatible_v) { if constexpr (is_trivial_serializable::value) { total += sizeof(T); } else if constexpr (is_trivial_view_v) { total += sizeof(typename T::value_type); } else { static_assert(is_trivial_serializable::value); std::size_t offset = 0; for_each(offset); total += offset; } } } } // namespace align } // namespace struct_pack::detail