From 70a08acb19d6b31e3c13d4eb659d6c7d9073a13a Mon Sep 17 00:00:00 2001 From: Zhicheng Wang <1627343141@qq.com> Date: Thu, 9 Oct 2025 17:04:28 +0800 Subject: [PATCH] fix error occured by creating primitives; minor change to primitive process framework --- application/main.cpp | 30 +- .../src/implicit_surface_network_solver.cpp | 4 +- .../interface/base/primitive.hpp | 12 +- .../interface/data/data_type.hpp | 17 +- .../interface/primitive/simple/cylinder.hpp | 18 +- .../interface/primitive/simple/sphere.hpp | 14 +- primitive_process/src/base/primitive.cpp | 48 +-- primitive_process/src/data/data_center.cpp | 12 +- .../src/primitive/simple/cylinder.cpp | 62 --- .../src/primitive/simple/sphere.cpp | 31 -- shared_module/container/span.hpp | 389 ++++++++++++++++++ 11 files changed, 473 insertions(+), 164 deletions(-) delete mode 100644 primitive_process/src/primitive/simple/cylinder.cpp delete mode 100644 primitive_process/src/primitive/simple/sphere.cpp create mode 100644 shared_module/container/span.hpp diff --git a/application/main.cpp b/application/main.cpp index 286ac37..a3ab2a3 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -17,25 +17,25 @@ int main() auto node_iter1 = blobtree_add_primitive_node(runtime_blobtree, cylinder); auto node_iter2 = blobtree_add_primitive_node(runtime_blobtree, sphere1); auto node_iter3 = blobtree_add_operation_node(runtime_blobtree, node_iter1, node_iter2, INTERSECTION_OP); - auto baked_blobtree = bake_blobtree(runtime_blobtree); - destroy_blobtree(runtime_blobtree); + // auto baked_blobtree = bake_blobtree(runtime_blobtree); + // destroy_blobtree(runtime_blobtree); - std::cout << "blobtree created..." << std::endl; + // std::cout << "blobtree created..." << std::endl; - s_settings settings{}; - settings.resolution = 21; - settings.scene_aabb_margin = 1e-5; - settings.restricted_primitive_bounding_test = true; - auto solver = create_solver(baked_blobtree, settings); + // s_settings settings{}; + // settings.resolution = 21; + // settings.scene_aabb_margin = 1e-5; + // settings.restricted_primitive_bounding_test = true; + // auto solver = create_solver(baked_blobtree, settings); - auto result = generate_polymesh(solver); - print_statistics(solver); + // auto result = generate_polymesh(solver); + // print_statistics(solver); - destroy_solver(solver); - destroy_baked_blobtree(baked_blobtree); - destroy_primitive(sphere1); - destroy_primitive(cylinder); - destroy_primitive_data_center(primitive_data_center); + // destroy_solver(solver); + // destroy_baked_blobtree(baked_blobtree); + // destroy_primitive(sphere1); + // destroy_primitive(cylinder); + // destroy_primitive_data_center(primitive_data_center); return 0; } \ No newline at end of file diff --git a/frontend/src/implicit_surface_network_solver.cpp b/frontend/src/implicit_surface_network_solver.cpp index 7e0a34e..ba8049d 100644 --- a/frontend/src/implicit_surface_network_solver.cpp +++ b/frontend/src/implicit_surface_network_solver.cpp @@ -8,11 +8,13 @@ void implicit_network_solver::generate_polymesh(stl_vector_mp& { // generate polymesh m_timers.push_timer("generate_polymesh"); + flat_hash_map_mp temp{}; build_implicit_network_by_blobtree(m_settings, *m_blobtree, output_vertices, output_polygon_faces, - output_vertex_counts_of_face); + output_vertex_counts_of_face, + temp); m_timers.pop_timer("generate_polymesh"); } diff --git a/primitive_process/interface/base/primitive.hpp b/primitive_process/interface/base/primitive.hpp index a5ab2ac..505e307 100644 --- a/primitive_process/interface/base/primitive.hpp +++ b/primitive_process/interface/base/primitive.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -48,12 +49,13 @@ static inline sign_t operator&(sign_t a, sign_t b) struct subface; EXTERN_C struct PE_API primitive { - virtual void initialize(primitive_data_center_t &) = 0; - virtual void destroy() = 0; + void initialize(primitive_data_center_t &); + void destroy(); - virtual primitive_type get_type() const = 0; - virtual stl_vector_mp> get_subfaces() const = 0; - virtual stl_vector_mp get_subface_types() const = 0; + virtual primitive_type get_type() const = 0; + virtual span> get_subfaces() const = 0; + virtual stl_vector_mp get_subface_types() const = 0; + virtual stl_vector_mp get_subface_init_model_matrices() const = 0; // sign_t judge_sign_by_subface_sdf(const std::vector &) const; // sign_t judge_sign_by_subface_sdf_sign(const std::vector &) const; diff --git a/primitive_process/interface/data/data_type.hpp b/primitive_process/interface/data/data_type.hpp index 98317a0..a62cc1e 100644 --- a/primitive_process/interface/data/data_type.hpp +++ b/primitive_process/interface/data/data_type.hpp @@ -18,8 +18,11 @@ struct paired_model_matrix { using paired_model_matrix_ptr_t = pointer_wrapper; -const paired_model_matrix identity_model_matrix{internal::transform_block::Identity(), internal::transform_block::Identity()}; -const auto plane_to_z_pos_1_model_matrix = []() { +namespace hidden +{ +static inline paired_model_matrix identity_model_matrix{internal::transform_block::Identity(), + internal::transform_block::Identity()}; +static inline auto plane_to_z_pos_1_model_matrix = []() { paired_model_matrix res{}; Eigen::Matrix3d::Identity(); res.world_to_local.linear().col(0) = Eigen::Vector3d{0, 0, 1}; @@ -30,7 +33,7 @@ const auto plane_to_z_pos_1_model_matrix = []() { res.local_to_world.translation() = Eigen::Vector3d{0, 0, 1}; return res; }(); -const auto plane_to_z_model_matrix = []() { +static inline auto plane_to_z_model_matrix = []() { paired_model_matrix res{}; Eigen::Matrix3d::Identity(); res.world_to_local.linear().col(0) = Eigen::Vector3d{0, 0, 1}; @@ -40,7 +43,7 @@ const auto plane_to_z_model_matrix = []() { res.local_to_world = res.world_to_local; return res; }(); -const auto plane_to_z_neg_1_model_matrix = []() { +static inline auto plane_to_z_neg_1_model_matrix = []() { paired_model_matrix res{}; res.world_to_local.linear().col(0) = Eigen::Vector3d{0, 0, 1}; res.world_to_local.linear().col(1) = Eigen::Vector3d{0, 1, 0}; @@ -50,6 +53,12 @@ const auto plane_to_z_neg_1_model_matrix = []() { res.local_to_world.translation() = Eigen::Vector3d{0, 0, -1}; return res; }(); +} // namespace hidden + +const auto identity_model_matrix_ptr = make_pointer_wrapper(hidden::identity_model_matrix); +const auto plane_to_z_pos_1_model_matrix_ptr = make_pointer_wrapper(hidden::plane_to_z_pos_1_model_matrix); +const auto plane_to_z_model_matrix_ptr = make_pointer_wrapper(hidden::plane_to_z_model_matrix); +const auto plane_to_z_neg_1_model_matrix_ptr = make_pointer_wrapper(hidden::plane_to_z_neg_1_model_matrix); template using primitive_data_iterator = typename hive_mp::iterator; diff --git a/primitive_process/interface/primitive/simple/cylinder.hpp b/primitive_process/interface/primitive/simple/cylinder.hpp index aeb87d8..fa3ffde 100644 --- a/primitive_process/interface/primitive/simple/cylinder.hpp +++ b/primitive_process/interface/primitive/simple/cylinder.hpp @@ -7,16 +7,11 @@ namespace internal { struct cylinder_t final : public primitive { - void initialize(primitive_data_center_t &) override; - void destroy() override; - primitive_type get_type() const override { return PRIMITIVE_TYPE_CYLINDER; }; - stl_vector_mp> get_subfaces() const override + span> get_subfaces() const override { - return {static_pointer_cast(cylinder_face), - static_pointer_cast(bottom_plane), - static_pointer_cast(top_plane)}; + return {const_cast *>(subfaces.data()), subfaces.size()}; } stl_vector_mp get_subface_types() const override @@ -24,8 +19,11 @@ struct cylinder_t final : public primitive { return {surface_type::cylinder, surface_type::plane, surface_type::plane}; } - marked_subface_ptr_t cylinder_face{}; - marked_subface_ptr_t bottom_plane{}; - marked_subface_ptr_t top_plane{}; + stl_vector_mp get_subface_init_model_matrices() const override + { + return {plane_to_z_model_matrix_ptr, identity_model_matrix_ptr, plane_to_z_pos_1_model_matrix_ptr}; + } + + std::array, 3> subfaces{}; }; } // namespace internal \ No newline at end of file diff --git a/primitive_process/interface/primitive/simple/sphere.hpp b/primitive_process/interface/primitive/simple/sphere.hpp index d508d01..e3e5aec 100644 --- a/primitive_process/interface/primitive/simple/sphere.hpp +++ b/primitive_process/interface/primitive/simple/sphere.hpp @@ -6,18 +6,20 @@ namespace internal { struct sphere_t final : primitive { - void initialize(primitive_data_center_t &) override; - void destroy() override; - primitive_type get_type() const override { return PRIMITIVE_TYPE_SPHERE; }; - stl_vector_mp> get_subfaces() const override + span> get_subfaces() const override { - return {static_pointer_cast(sphere_face)}; + return {const_cast *>(&sphere_face), 1}; } stl_vector_mp get_subface_types() const override { return {surface_type::sphere}; } - marked_subface_ptr_t sphere_face{}; + stl_vector_mp get_subface_init_model_matrices() const override + { + return {identity_model_matrix_ptr}; + } + + marked_subface_ptr_t sphere_face{}; }; } // namespace internal \ No newline at end of file diff --git a/primitive_process/src/base/primitive.cpp b/primitive_process/src/base/primitive.cpp index 6a5d6e9..94b9514 100644 --- a/primitive_process/src/base/primitive.cpp +++ b/primitive_process/src/base/primitive.cpp @@ -2,30 +2,6 @@ #include #include -#include "data/data_type.hpp" - -// sign_t primitive::judge_sign_by_subface_sdf(const std::vector &sdf_values) const -// { -// auto subfaces = get_subface(); - -// sign_t res{sign_by_subface(sdf_values[0] > 0) * sign_by_subface(subfaces[0].is_marked())}; -// for (size_t i = 1; i < get_subface_count(); ++i) { -// res = res & (sign_by_subface(sdf_values[i] > 0) * sign_by_subface(subfaces[i].is_marked())); -// } - -// return res; -// } - -// sign_t primitive::judge_sign_by_subface_sdf_sign(const std::vector &sdf_signs) const -// { -// auto subfaces = get_subface(); - -// sign_t res{sdf_signs[0] * sign_by_subface(subfaces[0].is_marked())}; -// for (size_t i = 1; i < get_subface_count(); ++i) { res = res & (sdf_signs[i] * sign_by_subface(subfaces[i].is_marked())); -// } - -// return res; -// } dynamic_bitset_mp<> primitive::judge_sign_by_subface_sign(stl_vector_mp> subface_signs) const { @@ -42,6 +18,30 @@ dynamic_bitset_mp<> primitive::judge_sign_by_subface_sign(stl_vector_mpdata_center; + assert(data_center); + + for (size_t i = 0; i < subfaces.size(); ++i) data_center->release_surface(subface_types[i], subfaces[i]); +} + void primitive::apply_transform(internal::transform_type type, Eigen::Vector4d param) { auto subfaces = get_subfaces(); diff --git a/primitive_process/src/data/data_center.cpp b/primitive_process/src/data/data_center.cpp index a125d26..98597bf 100644 --- a/primitive_process/src/data/data_center.cpp +++ b/primitive_process/src/data/data_center.cpp @@ -3,9 +3,9 @@ // before dtor, always keep identity transformation block primitive_data_center_t::primitive_data_center_t() noexcept { - this->transform_blocks.acquire(internal::identity_model_matrix); - this->transform_blocks.acquire(internal::plane_to_z_pos_1_model_matrix); - this->transform_blocks.acquire(internal::plane_to_z_neg_1_model_matrix); + this->transform_blocks.acquire(internal::identity_model_matrix_ptr); + this->transform_blocks.acquire(internal::plane_to_z_pos_1_model_matrix_ptr); + this->transform_blocks.acquire(internal::plane_to_z_neg_1_model_matrix_ptr); // set hashed refcount hive container to individual surface containers this->surfaces[static_cast(surface_type::plane)].emplace(); @@ -15,9 +15,9 @@ primitive_data_center_t::primitive_data_center_t() noexcept primitive_data_center_t::~primitive_data_center_t() noexcept { - this->transform_blocks.release(internal::identity_model_matrix); - this->transform_blocks.release(internal::plane_to_z_pos_1_model_matrix); - this->transform_blocks.release(internal::plane_to_z_neg_1_model_matrix); + this->transform_blocks.release(internal::identity_model_matrix_ptr); + this->transform_blocks.release(internal::plane_to_z_pos_1_model_matrix_ptr); + this->transform_blocks.release(internal::plane_to_z_neg_1_model_matrix_ptr); } auto primitive_data_center_t::require_transform_block(const internal::paired_model_matrix& matrix) diff --git a/primitive_process/src/primitive/simple/cylinder.cpp b/primitive_process/src/primitive/simple/cylinder.cpp deleted file mode 100644 index 03272e9..0000000 --- a/primitive_process/src/primitive/simple/cylinder.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include - -namespace internal -{ -void cylinder_t::initialize(primitive_data_center_t &data_center) -{ - auto bottom_plane_mat = data_center.require_transform_block(internal::plane_to_z_model_matrix); - auto cylinder_mat = data_center.require_transform_block(internal::identity_model_matrix); - auto top_plane_mat = data_center.require_transform_block(internal::plane_to_z_pos_1_model_matrix); - primitive::initialize(data_center, {cylinder_mat, bottom_plane_mat, top_plane_mat}); -} - -void cylinder_t::destroy() -{ - primitive_data_center_t &data_center = bottom_plane->data_center; - - data_center.release_surface(surface_type::cylinder, static_pointer_cast(cylinder_face)); - data_center.release_surface(surface_type::plane, static_pointer_cast(bottom_plane)); - data_center.release_surface(surface_type::plane, static_pointer_cast(top_plane)); -} - -// void cylinder_t::initialize(primitive_data_center_t &data_center, -// const std::vector> &new_model_matrices) -// { -// std::array old_ptrs{cylinder_face.get_ptr(), bottom_plane.get_ptr(), top_plane.get_ptr()}; -// std::array old_model_matrices{nullptr, nullptr, nullptr}; -// for (size_t i = 0; i < 3; ++i) { -// if (old_ptrs[i] != nullptr) old_model_matrices[i] = old_ptrs[i]->model_matrices; -// } - -// { -// auto [iter, is_new] = data_center.cylinders.acquire(cylinder_paired_model_matrix{new_model_matrices[0].first}); -// cylinder_face.set_ptr(iter.operator->()); -// cylinder_face.set_mark(new_model_matrices[0].second); -// if (is_new) cylinder_face.get_ptr()->data_center = &data_center; -// } - -// { -// auto [iter, is_new] = data_center.planes.acquire(plane_paired_model_matrix{new_model_matrices[1].first}); -// bottom_plane.set_ptr(iter.operator->()); -// bottom_plane.set_mark(new_model_matrices[1].second); -// if (is_new) bottom_plane.get_ptr()->data_center = &data_center; -// } - -// { -// auto [iter, is_new] = data_center.planes.acquire(plane_paired_model_matrix{new_model_matrices[2].first}); -// top_plane.set_ptr(iter.operator->()); -// top_plane.set_mark(new_model_matrices[2].second); -// if (is_new) top_plane.get_ptr()->data_center = &data_center; -// } - -// // deferred release to avoid acquiring the same just-released subface -// { -// if (old_ptrs[0] != nullptr) -// data_center.cylinders.release(cylinder_paired_model_matrix{old_model_matrices[0]}); -// if (old_ptrs[1] != nullptr) -// data_center.planes.release(plane_paired_model_matrix{old_model_matrices[1]}); -// if (old_ptrs[2] != nullptr) -// data_center.planes.release(plane_paired_model_matrix{old_model_matrices[2]}); -// } -// } -} // namespace internal \ No newline at end of file diff --git a/primitive_process/src/primitive/simple/sphere.cpp b/primitive_process/src/primitive/simple/sphere.cpp deleted file mode 100644 index 0c5f4a5..0000000 --- a/primitive_process/src/primitive/simple/sphere.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -namespace internal -{ -void sphere_t::initialize(primitive_data_center_t &data_center) -{ - primitive::initialize(data_center, {data_center.require_transform_block(internal::identity_model_matrix)}); -} - -void sphere_t::destroy() -{ - primitive_data_center_t& data_center = sphere_face->data_center; - data_center.release_surface(surface_type::sphere, static_pointer_cast(sphere_face)); -} - -// void sphere_t::initialize(primitive_data_center_t &data_center, -// const std::vector> &new_model_matrices) -// { -// auto old_ptr = sphere_face.get_ptr(); -// paired_model_matrix *old_model_matrices{nullptr}; -// if (old_ptr != nullptr) old_model_matrices = old_ptr->model_matrices; - -// auto [iter, is_new] = data_center.spheres.acquire(new_model_matrices[0].first); -// sphere_face.set_ptr(iter.operator->()); -// sphere_face.set_mark(new_model_matrices[0].second); -// if (is_new) sphere_face.get_ptr()->data_center = &data_center; - -// // deferred release to avoid acquiring the same just-released subface -// if (old_ptr != nullptr) data_center.spheres.release(old_model_matrices); -// } -} // namespace internal \ No newline at end of file diff --git a/shared_module/container/span.hpp b/shared_module/container/span.hpp new file mode 100644 index 0000000..b6e1726 --- /dev/null +++ b/shared_module/container/span.hpp @@ -0,0 +1,389 @@ +#pragma once + +#include +#include +#include +#include + +inline constexpr std::size_t dynamic_extent = std::numeric_limits::max(); + +template +class span; + +namespace detail +{ + +template +struct span_storage { + constexpr span_storage() noexcept = default; + + constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept : ptr(p_ptr) {} + + E* ptr = nullptr; + static constexpr std::size_t size = S; +}; + +template +struct span_storage { + constexpr span_storage() noexcept = default; + + constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept : ptr(p_ptr), size(p_size) {} + + E* ptr = nullptr; + std::size_t size = 0; +}; + +using std::void_t; + +template +using uncvref_t = typename std::remove_cv_t>; + +template +struct is_span : std::false_type { +}; + +template +struct is_span> : std::true_type { +}; + +template +static constexpr auto is_span_v = is_span::value; + +template +struct is_std_array : std::false_type { +}; + +template +struct is_std_array> : std::true_type { +}; + +template +static constexpr auto is_std_array_v = is_std_array::value; + +template +struct has_size_and_data : std::false_type { +}; + +template +struct has_size_and_data())), decltype(std::data(std::declval()))>> + : std::true_type { +}; + +template +static constexpr auto has_size_and_data_v = has_size_and_data::value; + +template > +struct is_container { + static constexpr bool value = !is_span_v && !is_std_array_v && !std::is_array_v && has_size_and_data_v; +}; + +template +static constexpr auto is_container_v = is_container::value; + +template +using remove_pointer_t = std::remove_pointer_t; + +template +struct is_container_element_type_compatible : std::false_type { +}; + +template +struct is_container_element_type_compatible< + T, + E, + typename std::enable_if< + !std::is_same_v()))>, void> + && std::is_convertible_v()))> (*)[], E (*)[]>>::type> + : std::true_type { +}; + +template +static constexpr auto is_container_element_type_compatible_v = is_container_element_type_compatible::value; + +template +struct is_complete : std::false_type { +}; + +template +struct is_complete : std::true_type { +}; + +template +static constexpr auto is_complete_v = is_complete::value; + +} // namespace detail + +template +class span +{ + static_assert(std::is_object_v, + "A span's ElementType must be an object type (not a " + "reference type or void)"); + static_assert(detail::is_complete_v, + "A span's ElementType must be a complete type (not a forward " + "declaration)"); + static_assert(!std::is_abstract_v, "A span's ElementType cannot be an abstract class type"); + + using storage_type = detail::span_storage; + +public: + // constants and types + using element_type = ElementType; + using value_type = std::remove_cv_t; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using pointer = element_type*; + using const_pointer = const element_type*; + using reference = element_type&; + using const_reference = const element_type&; + using iterator = pointer; + using reverse_iterator = std::reverse_iterator; + + static constexpr size_type extent = Extent; + + // [span.cons], span constructors, copy, assignment, and destructor + template = 0> + constexpr span() noexcept + { + } + + constexpr span(pointer ptr, size_type count) : storage_(ptr, count) { assert(extent == dynamic_extent || count == extent); } + + constexpr span(pointer first_elem, pointer last_elem) : storage_(first_elem, last_elem - first_elem) + { + assert(extent == dynamic_extent || last_elem - first_elem == static_cast(extent)); + } + + template >> + constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N) + { + } + + template &, ElementType>>> + constexpr span(std::array& arr) noexcept : storage_(arr.data(), N) + { + } + + template < + typename T, + std::size_t N, + std::size_t E = Extent, + typename = std::enable_if_t<(E == dynamic_extent || N == E) + && detail::is_container_element_type_compatible_v&, ElementType>>> + constexpr span(const std::array& arr) noexcept : storage_(arr.data(), N) + { + } + + template + && detail::is_container_element_type_compatible_v>> + constexpr span(Container& cont) : storage_(std::data(cont), std::size(cont)) + { + } + + template + && detail::is_container_element_type_compatible_v>> + constexpr span(const Container& cont) : storage_(std::data(cont), std::size(cont)) + { + } + + constexpr span(const span& other) noexcept = default; + + template >> + constexpr span(const span& other) noexcept : storage_(other.data(), other.size()) + { + } + + ~span() noexcept = default; + + constexpr span& operator=(const span& other) noexcept = default; + + // [span.sub], span subviews + template + constexpr span first() const + { + assert(Count <= size()); + return {data(), Count}; + } + + template + constexpr span last() const + { + assert(Count <= size()); + return {data() + (size() - Count), Count}; + } + + template + using subspan_return_t = + span; + + template + constexpr subspan_return_t subspan() const + { + assert(Offset <= size() && (Count == dynamic_extent || Offset + Count <= size())); + return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset}; + } + + constexpr span first(size_type count) const + { + assert(count <= size()); + return {data(), count}; + } + + constexpr span last(size_type count) const + { + assert(count <= size()); + return {data() + (size() - count), count}; + } + + constexpr span subspan(size_type offset, size_type count = dynamic_extent) const + { + assert(offset <= size() && (count == dynamic_extent || offset + count <= size())); + return {data() + offset, count == dynamic_extent ? size() - offset : count}; + } + + // [span.obs], span observers + constexpr size_type size() const noexcept { return storage_.size; } + + constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); } + + [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } + + // [span.elem], span element access + constexpr reference operator[](size_type idx) const + { + assert(idx < size()); + return *(data() + idx); + } + + constexpr reference front() const + { + assert(!empty()); + return *data(); + } + + constexpr reference back() const + { + assert(!empty()); + return *(data() + (size() - 1)); + } + + constexpr pointer data() const noexcept { return storage_.ptr; } + + // [span.iterators], span iterator support + constexpr iterator begin() const noexcept { return data(); } + + constexpr iterator end() const noexcept { return data() + size(); } + + constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } + + constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } + +private: + storage_type storage_{}; +}; + +/* Deduction Guides */ +template +span(T (&)[N]) -> span; + +template +span(std::array&) -> span; + +template +span(const std::array&) -> span; + +template +span(Container&) -> span()))>>; + +template +span(const Container&) -> span; + +template +constexpr span make_span(span s) noexcept +{ + return s; +} + +template +constexpr span make_span(T (&arr)[N]) noexcept +{ + return {arr}; +} + +template +constexpr span make_span(std::array& arr) noexcept +{ + return {arr}; +} + +template +constexpr span make_span(const std::array& arr) noexcept +{ + return {arr}; +} + +template +constexpr span()))>> make_span(Container& cont) +{ + return {cont}; +} + +template +constexpr span make_span(const Container& cont) +{ + return {cont}; +} + +template +span as_bytes( + span s) noexcept +{ + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +template >> +span as_writable_bytes( + span s) noexcept +{ + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +template +constexpr auto get(span s) -> decltype(s[N]) +{ + return s[N]; +} + +namespace std +{ +template +class tuple_size<::span> : public integral_constant +{ +}; + +template +class tuple_size<::span>; // not defined + +template +class tuple_element> +{ +public: + static_assert(Extent != ::dynamic_extent && I < Extent, ""); + using type = ElementType; +}; + +} // end namespace std \ No newline at end of file