-
Notifications
You must be signed in to change notification settings - Fork 235
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[struct_pack][feat] add derived class into struct_pack type system (#463
- Loading branch information
1 parent
aca25a3
commit daedb6a
Showing
12 changed files
with
1,172 additions
and
619 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
/* | ||
* 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 <cassert> | ||
#include <cstdint> | ||
#include <memory> | ||
#include <tuple> | ||
|
||
#include "error_code.hpp" | ||
#include "marco.h" | ||
#include "size_info.hpp" | ||
#include "util.h" | ||
namespace struct_pack { | ||
|
||
template <typename... Args> | ||
STRUCT_PACK_INLINE constexpr std::uint32_t get_type_code(); | ||
namespace detail { | ||
struct MD5_pair { | ||
uint32_t md5; | ||
uint32_t index; | ||
constexpr friend bool operator<(const MD5_pair &l, const MD5_pair &r) { | ||
return l.md5 < r.md5; | ||
} | ||
constexpr friend bool operator>(const MD5_pair &l, const MD5_pair &r) { | ||
return l.md5 > r.md5; | ||
} | ||
constexpr friend bool operator==(const MD5_pair &l, const MD5_pair &r) { | ||
return l.md5 == r.md5; | ||
} | ||
}; | ||
|
||
template <typename T> | ||
constexpr uint32_t get_types_code(); | ||
|
||
template <typename DerivedClasses> | ||
struct MD5_set { | ||
static constexpr int size = std::tuple_size_v<DerivedClasses>; | ||
static_assert(size <= 256); | ||
|
||
private: | ||
template <std::size_t... Index> | ||
static constexpr std::array<MD5_pair, size> calculate_md5( | ||
std::index_sequence<Index...>) { | ||
std::array<MD5_pair, size> md5{}; | ||
((md5[Index] = | ||
MD5_pair{ | ||
get_types_code<std::tuple_element_t<Index, DerivedClasses>>(), | ||
Index}), | ||
...); | ||
compile_time_sort(md5); | ||
return md5; | ||
} | ||
static constexpr std::size_t has_hash_collision_impl() { | ||
for (std::size_t i = 1; i < size; ++i) { | ||
if (value[i - 1] == value[i]) { | ||
return value[i].index; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
public: | ||
static constexpr std::array<MD5_pair, size> value = | ||
calculate_md5(std::make_index_sequence<size>()); | ||
static constexpr std::size_t has_hash_collision = has_hash_collision_impl(); | ||
}; | ||
|
||
template <typename BaseClass, typename DerivedClasses> | ||
struct public_base_class_checker { | ||
static_assert(std::tuple_size_v<DerivedClasses> <= 256); | ||
|
||
private: | ||
template <std::size_t... Index> | ||
static constexpr bool calculate_md5(std::index_sequence<Index...>) { | ||
return (std::is_base_of_v<BaseClass, | ||
std::tuple_element_t<Index, DerivedClasses>> && | ||
...); | ||
} | ||
|
||
public: | ||
static constexpr bool value = public_base_class_checker::calculate_md5( | ||
std::make_index_sequence<std::tuple_size_v<DerivedClasses>>()); | ||
}; | ||
|
||
template <typename DerivedClasses> | ||
struct deserialize_derived_class_helper { | ||
template <size_t index, typename BaseClass, typename unpack> | ||
static STRUCT_PACK_INLINE constexpr struct_pack::errc run( | ||
std::unique_ptr<BaseClass> &base, unpack &unpacker) { | ||
if constexpr (index >= std::tuple_size_v<DerivedClasses>) { | ||
unreachable(); | ||
return struct_pack::errc{}; | ||
} | ||
else { | ||
using derived_class = std::tuple_element_t<index, DerivedClasses>; | ||
base = std::make_unique<derived_class>(); | ||
return unpacker.deserialize(*(derived_class *)base.get()); | ||
} | ||
} | ||
}; | ||
|
||
template <typename T> | ||
constexpr size_info inline calculate_one_size(const T &item); | ||
|
||
template <typename DerivedClasses> | ||
struct calculate_one_size_derived_class_helper { | ||
template <size_t index, typename BaseClass> | ||
static STRUCT_PACK_INLINE constexpr size_info run(BaseClass *base) { | ||
if constexpr (index >= std::tuple_size_v<DerivedClasses>) { | ||
unreachable(); | ||
} | ||
else { | ||
using derived_class = std::tuple_element_t<index, DerivedClasses>; | ||
#ifdef STRUCT_PACK_RTTI_ENABLED | ||
assert(dynamic_cast<derived_class *>(base)); | ||
#endif | ||
return calculate_one_size(*(derived_class *)base); | ||
} | ||
} | ||
}; | ||
|
||
template <typename DerivedClasses, typename size_type, typename version> | ||
struct serialize_one_derived_class_helper { | ||
template <size_t index, typename packer, typename BaseClass> | ||
static STRUCT_PACK_INLINE constexpr void run(packer *self, BaseClass *base) { | ||
if constexpr (index >= std::tuple_size_v<DerivedClasses>) { | ||
unreachable(); | ||
} | ||
else { | ||
using derived_class = std::tuple_element_t<index, DerivedClasses>; | ||
#ifdef STRUCT_PACK_RTTI_ENABLED | ||
assert(dynamic_cast<derived_class *>(base)); | ||
#endif | ||
self->template serialize_one<size_type::value, version::value>( | ||
*(derived_class *)base); | ||
} | ||
} | ||
}; | ||
|
||
template <typename DerivedClasses, typename size_type, typename version, | ||
typename NotSkip> | ||
struct deserialize_one_derived_class_helper { | ||
template <size_t index, typename unpacker, typename Pointer> | ||
static STRUCT_PACK_INLINE constexpr struct_pack::errc run(unpacker *self, | ||
Pointer &base) { | ||
if constexpr (index >= std::tuple_size_v<DerivedClasses>) { | ||
unreachable(); | ||
} | ||
else { | ||
using derived_class = std::tuple_element_t<index, DerivedClasses>; | ||
base = std::make_unique<derived_class>(); | ||
return self->template deserialize_one<size_type::value, version::value, | ||
NotSkip::value>( | ||
*(derived_class *)base.get()); | ||
} | ||
} | ||
}; | ||
|
||
template <typename DerivedClasses, typename size_type, typename version> | ||
struct deserialize_one_compatible_in_derived_class_helper { | ||
template <size_t index, typename unpacker, typename Pointer> | ||
static STRUCT_PACK_INLINE constexpr struct_pack::errc run(unpacker *self, | ||
Pointer &base) { | ||
if constexpr (index >= std::tuple_size_v<DerivedClasses>) { | ||
unreachable(); | ||
} | ||
else { | ||
using derived_class = std::tuple_element_t<index, DerivedClasses>; | ||
#ifdef STRUCT_PACK_RTTI_ENABLED | ||
assert(dynamic_cast<derived_class *>(base.get())); | ||
#endif | ||
return self->template deserialize_one<size_type::value, version::value>( | ||
*(derived_class *)base.get()); | ||
} | ||
} | ||
}; | ||
|
||
template <typename Base> | ||
using derived_class_set_t = decltype(struct_pack_derived_decl((Base *)nullptr)); | ||
|
||
template <typename Base> | ||
constexpr std::size_t search_type_by_md5(uint32_t id, bool &ok) { | ||
constexpr auto &MD5s = MD5_set<derived_class_set_t<Base>>::value; | ||
auto result = std::lower_bound(MD5s.begin(), MD5s.end(), MD5_pair{id, 0}); | ||
ok = (result != MD5s.end() && result->md5 == id); | ||
return result->index; | ||
} | ||
|
||
template <typename T> | ||
std::uint32_t get_struct_pack_id_impl() { | ||
if constexpr (std::is_abstract_v<T>) { | ||
struct_pack::detail::unreachable(); | ||
} | ||
else { | ||
return struct_pack::get_type_code<T>(); | ||
} | ||
} | ||
|
||
template <typename Base, typename... Derives> | ||
constexpr auto derived_decl_impl() { | ||
if constexpr (std::is_abstract_v<Base>) { | ||
return struct_pack::detail::declval<std::tuple<Derives...>>(); | ||
} | ||
else { | ||
return struct_pack::detail::declval<std::tuple<Base, Derives...>>(); | ||
} | ||
} | ||
} // namespace detail | ||
} // namespace struct_pack |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
#include "foreach_macro.h" | ||
|
||
#pragma once | ||
#define GET_STRUCT_PACK_ID_IMPL(type) \ | ||
inline uint32_t type::get_struct_pack_id() const { \ | ||
return struct_pack::detail::get_struct_pack_id_impl<type>(); \ | ||
} | ||
|
||
#define GET_STRUCT_PACK_ID_IMPL_FOR_LOOP(idx, type) \ | ||
inline uint32_t type::get_struct_pack_id() const { \ | ||
return struct_pack::detail::get_struct_pack_id_impl<type>(); \ | ||
} | ||
|
||
#define STRUCT_PACK_DERIVED_IMPL(base, ...) \ | ||
\ | ||
inline decltype(struct_pack::detail::derived_decl_impl<base, __VA_ARGS__>()) \ | ||
struct_pack_derived_decl(base*); | ||
|
||
#define STRUCT_PACK_DERIVED_DECL(base, ...) \ | ||
STRUCT_PACK_EXPAND_EACH(, GET_STRUCT_PACK_ID_IMPL_FOR_LOOP, base, \ | ||
__VA_ARGS__) \ | ||
STRUCT_PACK_DERIVED_IMPL(base, __VA_ARGS__)\ |
Oops, something went wrong.