From 85dc7a4197ffeca4f4602fbfe735cd83a04d9819 Mon Sep 17 00:00:00 2001 From: Philip Trettner <Philip.Trettner@rwth-aachen.de> Date: Fri, 2 Oct 2020 08:45:31 +0200 Subject: [PATCH] some include renaming, added raw attributes --- src/polymesh/algorithms/cache-optimization.hh | 2 +- src/polymesh/algorithms/components.hh | 2 +- src/polymesh/algorithms/interpolation.hh | 2 +- src/polymesh/algorithms/normalize.hh | 2 +- src/polymesh/algorithms/topology.hh | 2 +- src/polymesh/algorithms/tracing.hh | 2 +- src/polymesh/attributes.hh | 11 +- src/polymesh/attributes/flags.hh | 2 +- src/polymesh/attributes/partitioning.hh | 2 +- src/polymesh/attributes/raw_attribute.hh | 275 ++++++++++++++++++ src/polymesh/detail/topology_iterator.hh | 2 +- src/polymesh/detail/unique_array.hh | 2 +- src/polymesh/formats/obj.hh | 2 +- src/polymesh/formats/off.hh | 2 +- src/polymesh/formats/ply.hh | 2 +- src/polymesh/formats/stl.hh | 2 +- src/polymesh/impl/impl_attributes.hh | 6 +- src/polymesh/impl/impl_cursors.hh | 2 +- src/polymesh/impl/impl_low_level_api_base.hh | 2 +- .../impl/impl_low_level_api_mutable.hh | 2 +- src/polymesh/impl/impl_mesh.hh | 2 +- src/polymesh/impl/impl_primitive.hh | 2 +- src/polymesh/impl/impl_ranges.hh | 2 +- src/polymesh/objects/cone.hh | 2 +- src/polymesh/objects/cube.hh | 2 +- src/polymesh/objects/cylinder.hh | 2 +- src/polymesh/objects/quad.hh | 2 +- src/polymesh/objects/uv_sphere.hh | 2 +- src/polymesh/span.hh | 80 +++++ src/polymesh/tmp.hh | 45 +++ 30 files changed, 437 insertions(+), 30 deletions(-) create mode 100644 src/polymesh/attributes/raw_attribute.hh create mode 100644 src/polymesh/span.hh diff --git a/src/polymesh/algorithms/cache-optimization.hh b/src/polymesh/algorithms/cache-optimization.hh index 9e9f04c..fa6e599 100644 --- a/src/polymesh/algorithms/cache-optimization.hh +++ b/src/polymesh/algorithms/cache-optimization.hh @@ -2,7 +2,7 @@ #include <vector> -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/algorithms/components.hh b/src/polymesh/algorithms/components.hh index 03aa1c2..57e984c 100644 --- a/src/polymesh/algorithms/components.hh +++ b/src/polymesh/algorithms/components.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> #include "../detail/primitive_set.hh" #include "../detail/topology_iterator.hh" diff --git a/src/polymesh/algorithms/interpolation.hh b/src/polymesh/algorithms/interpolation.hh index 6263237..e41d691 100644 --- a/src/polymesh/algorithms/interpolation.hh +++ b/src/polymesh/algorithms/interpolation.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/algorithms/normalize.hh b/src/polymesh/algorithms/normalize.hh index 970d524..da713a8 100644 --- a/src/polymesh/algorithms/normalize.hh +++ b/src/polymesh/algorithms/normalize.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> #include "../fields.hh" namespace polymesh diff --git a/src/polymesh/algorithms/topology.hh b/src/polymesh/algorithms/topology.hh index 9be358b..6d3c53b 100644 --- a/src/polymesh/algorithms/topology.hh +++ b/src/polymesh/algorithms/topology.hh @@ -2,7 +2,7 @@ #include <vector> -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/algorithms/tracing.hh b/src/polymesh/algorithms/tracing.hh index d757a17..66c74c7 100644 --- a/src/polymesh/algorithms/tracing.hh +++ b/src/polymesh/algorithms/tracing.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> #include "../fields.hh" namespace polymesh diff --git a/src/polymesh/attributes.hh b/src/polymesh/attributes.hh index cf3635e..d30c5b8 100644 --- a/src/polymesh/attributes.hh +++ b/src/polymesh/attributes.hh @@ -73,6 +73,8 @@ public: int size() const; int capacity() const; + size_t byte_size() const override { return size() * sizeof(AttrT); } + size_t allocated_byte_size() const override { return capacity() * sizeof(AttrT); } attribute_iterator<primitive_attribute> begin() { return {0, size(), *this}; } attribute_iterator<primitive_attribute const&> begin() const { return {0, size(), *this}; } @@ -146,8 +148,6 @@ protected: protected: void resize_from(int old_size) override; void clear_with_default() override; - size_t byte_size() const override { return size() * sizeof(AttrT); } - size_t allocated_byte_size() const override { return capacity() * sizeof(AttrT); } void apply_remapping(std::vector<int> const& map) override; void apply_transpositions(std::vector<std::pair<int, int>> const& ts) override; @@ -231,6 +231,13 @@ struct halfedge_attribute final : primitive_attribute<halfedge_tag, AttrT> friend struct smart_collection; }; +/** + * creates a new attribute from a primitive collection. + * + * Usage: + * + * auto pos = attribute(m.vertices(), tg::pos3::zero); + */ template <class AttrT, class Collection> auto attribute(Collection const& c, AttrT const& defaultValue = {}) -> decltype(c.make_attribute(defaultValue)) { diff --git a/src/polymesh/attributes/flags.hh b/src/polymesh/attributes/flags.hh index ea87558..8f182ff 100644 --- a/src/polymesh/attributes/flags.hh +++ b/src/polymesh/attributes/flags.hh @@ -1,6 +1,6 @@ #pragma once -#include "../attributes.hh" +#include <polymesh/attributes.hh> namespace polymesh { diff --git a/src/polymesh/attributes/partitioning.hh b/src/polymesh/attributes/partitioning.hh index e389472..0b67448 100644 --- a/src/polymesh/attributes/partitioning.hh +++ b/src/polymesh/attributes/partitioning.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/attributes/raw_attribute.hh b/src/polymesh/attributes/raw_attribute.hh new file mode 100644 index 0000000..ca5a124 --- /dev/null +++ b/src/polymesh/attributes/raw_attribute.hh @@ -0,0 +1,275 @@ +#pragma once + +#include <cstring> + +#include <polymesh/Mesh.hh> +#include <polymesh/attributes.hh> +#include <polymesh/span.hh> + +namespace polymesh +{ +/** + * Raw attributes are attributes that store a fixed (but runtime determined) number of bytes per primitive + * The number of bytes per primitive is called stride + * + * NOTE: they are always zero-initialized + * + * TODO: iteration + * TODO: smart range + */ +template <class tag> +struct raw_primitive_attribute : primitive_attribute_base<tag> +{ + template <class A> + using attribute = typename primitive<tag>::template attribute<A>; + using index_t = typename primitive<tag>::index; + using handle_t = typename primitive<tag>::handle; + using tag_t = tag; + + // data access +public: + span<std::byte> operator[](handle_t h) + { + POLYMESH_ASSERT(this->mMesh == h.mesh && "Handle belongs to a different mesh"); + POLYMESH_ASSERT(0 <= h.idx.value && h.idx.value < this->size() && "out of bounds"); + return {this->mData.get() + h.idx.value * mStride, mStride}; + } + span<std::byte const> operator[](handle_t h) const + { + POLYMESH_ASSERT(this->mMesh == h.mesh && "Handle belongs to a different mesh"); + POLYMESH_ASSERT(0 <= h.idx.value && h.idx.value < this->size() && "out of bounds"); + return {this->mData.get() + h.idx.value * mStride, mStride}; + } + span<std::byte> operator[](index_t h) + { + POLYMESH_ASSERT(h.is_valid()); + return {this->mData.get() + h.value * mStride, mStride}; + } + span<std::byte const> operator[](index_t h) const + { + POLYMESH_ASSERT(h.is_valid()); + return {this->mData.get() + h.value * mStride, mStride}; + } + + span<std::byte> operator()(handle_t h) + { + POLYMESH_ASSERT(this->mMesh == h.mesh && "Handle belongs to a different mesh"); + POLYMESH_ASSERT(0 <= h.idx.value && h.idx.value < this->size() && "out of bounds"); + return {this->mData.get() + h.idx.value * mStride, mStride}; + } + span<std::byte const> operator()(handle_t h) const + { + POLYMESH_ASSERT(this->mMesh == h.mesh && "Handle belongs to a different mesh"); + POLYMESH_ASSERT(0 <= h.idx.value && h.idx.value < this->size() && "out of bounds"); + return {this->mData.get() + h.idx.value * mStride, mStride}; + } + span<std::byte> operator()(index_t h) + { + POLYMESH_ASSERT(h.is_valid()); + return {this->mData.get() + h.value * mStride, mStride}; + } + + span<std::byte const> operator()(index_t h) const + { + POLYMESH_ASSERT(h.is_valid()); + return {this->mData.get() + h.value * mStride, mStride}; + } + + std::byte* data() { return mData.get(); } + std::byte const* data() const { return mData.get(); } + + int size() const { return primitive<tag>::all_size(*this->mMesh); } + int stride() const { return mStride; } + int capacity() const { return primitive<tag>::capacity(*this->mMesh); } + size_t byte_size() const override { return size() * mStride; } + size_t allocated_byte_size() const override { return capacity() * mStride; } + + /// true iff this attribute is still attached to a mesh + /// do not use the attribute if not valid + bool is_valid() const { return this->mMesh != nullptr; } + + // methods +public: + /// sets all attribute values to zero + void clear() + { + if (byte_size() > 0) + std::memset(this->mData.get(), 0, byte_size()); + } + + /// Saves ALL data into a vector (includes possibly removed ones) + std::vector<std::byte> to_raw_vector() const + { + auto r = std::vector<std::byte>(byte_size()); + if (r.size() > 0) + std::memcpy(r.data(), this->mData.get(), byte_size()); + return r; + } + + /// returns a new attribute where all elements were bitcast to the given type + /// NOTE: requires trivially copyable T with sizeof(T) == stride() + template <class T> + auto to() const -> attribute<T> + { + static_assert(std::is_trivially_copyable_v<T>, "only works for trivially copyable types"); + POLYMESH_ASSERT(sizeof(T) == mStride && "stride must match exactly with type size"); + auto a = attribute<T>(this->mesh()); + if (byte_size() > 0) + std::memcpy(a.data(), this->mData.get(), byte_size()); + return a; + } + + // public ctor +public: + raw_primitive_attribute() = default; + raw_primitive_attribute(Mesh const& mesh, int stride) : primitive_attribute_base<tag>(&mesh), mStride(stride) + { + POLYMESH_ASSERT(mStride > 0 && "only positive stride supported"); + + // register + this->register_attr(); + + // alloc data (zero-init) + this->mData.reset(new std::byte[this->capacity() * mStride]()); + } + + // members +protected: + unique_array<std::byte> mData; + size_t mStride = 0; ///< number of bytes per element + +protected: + void resize_from(int old_size) override + { + // mesh is already resized, thus capacity() and size() return new values + // old_size is size before resize + + auto new_capacity = this->capacity(); + auto shared_size = std::min(this->size(), old_size); + POLYMESH_ASSERT(shared_size <= new_capacity && "size cannot exceed capacity"); + + // alloc new data + auto new_data = new_capacity > 0 ? new std::byte[new_capacity * mStride]() : nullptr; + + // copy shared region to new data + if (shared_size > 0) + std::memcpy(new_data, this->mData.get(), shared_size * mStride); + + // replace old data + this->mData.reset(new_data); + } + void clear_with_default() override { std::memset(this->mData.get(), 0, byte_size()); } + + void apply_remapping(std::vector<int> const& map) override + { + // TODO: could be made faster by special casing a few stride sizes + for (auto i = 0u; i < map.size(); ++i) + std::memcpy(&this->mData[i], &this->mData[map[i]], mStride); + } + void apply_transpositions(std::vector<std::pair<int, int>> const& ts) override + { + for (auto t : ts) + for (auto i = 0u; i < mStride; ++i) + swap(this->mData[t.first * mStride + i], this->mData[t.second * mStride + i]); + } + + template <class MeshT> + friend struct low_level_attribute_api; + + // move & copy +public: + raw_primitive_attribute(raw_primitive_attribute const& rhs) noexcept // copy + : primitive_attribute_base<tag>(rhs.mMesh), mStride(rhs.mStride) + { + // register attr + this->register_attr(); + + // alloc data + this->mData.reset(new std::byte[this->capacity() * mStride]()); + + // copy valid data + std::memcpy(this->mData.get(), rhs.mData.get(), rhs.byte_size()); + } + raw_primitive_attribute(raw_primitive_attribute&& rhs) noexcept // move + : primitive_attribute_base<tag>(rhs.mMesh), mStride(rhs.mStride) + { + // take data from rhs + this->mData = std::move(rhs.mData); + + // deregister rhs + rhs.deregister_attr(); + + // register lhs + this->register_attr(); + } + raw_primitive_attribute& operator=(raw_primitive_attribute const& rhs) noexcept // copy assign + { + if (this == &rhs) // prevent self-copy + return *this; + + // save old capacity for no-realloc path + auto old_capacity_bytes = is_valid() ? this->capacity() * mStride : 0; + + // deregister from old mesh + this->deregister_attr(); + + // register into new mesh + this->mMesh = rhs.mMesh; + this->mStride = rhs.mStride; + this->register_attr(); + + // realloc if new capacity + auto new_capacity_bytes = this->capacity() * mStride; + if (old_capacity_bytes != new_capacity_bytes) + { + if (new_capacity_bytes == 0) + this->mData.reset(); + else + this->mData.reset(new std::byte[new_capacity_bytes]()); + } + + // copy valid AND defaulted data + std::memcpy(this->mData.get(), rhs.mData.get(), new_capacity_bytes); + + return *this; + } + raw_primitive_attribute& operator=(raw_primitive_attribute&& rhs) noexcept // move assign + { + if (this == &rhs) // prevent self-move + return *this; + + // deregister from old mesh + this->deregister_attr(); + + // register into new mesh + this->mMesh = rhs.mMesh; + this->register_attr(); + + // take data of rhs + this->mStride = rhs.mStride; + this->mData = std::move(rhs.mData); + + // deregister rhs + rhs.deregister_attr(); + + return *this; + } +}; + +struct raw_vertex_attribute final : raw_primitive_attribute<vertex_tag> +{ + using raw_primitive_attribute<vertex_tag>::raw_primitive_attribute; +}; +struct raw_face_attribute final : raw_primitive_attribute<face_tag> +{ + using raw_primitive_attribute<face_tag>::raw_primitive_attribute; +}; +struct raw_edge_attribute final : raw_primitive_attribute<edge_tag> +{ + using raw_primitive_attribute<edge_tag>::raw_primitive_attribute; +}; +struct raw_halfedge_attribute final : raw_primitive_attribute<halfedge_tag> +{ + using raw_primitive_attribute<halfedge_tag>::raw_primitive_attribute; +}; +} diff --git a/src/polymesh/detail/topology_iterator.hh b/src/polymesh/detail/topology_iterator.hh index 7dbeb6b..90bafd0 100644 --- a/src/polymesh/detail/topology_iterator.hh +++ b/src/polymesh/detail/topology_iterator.hh @@ -2,7 +2,7 @@ #include <queue> -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> #include "primitive_set.hh" /// CAUTION: these iterators do NOT work like normal iterators where you can make copies! diff --git a/src/polymesh/detail/unique_array.hh b/src/polymesh/detail/unique_array.hh index ff82441..1d316b8 100644 --- a/src/polymesh/detail/unique_array.hh +++ b/src/polymesh/detail/unique_array.hh @@ -11,7 +11,7 @@ struct unique_array using element_type = T; unique_array() = default; - explicit unique_array(int size) { ptr = new T[size]; } + explicit unique_array(int size) { ptr = new T[size](); } ~unique_array() { delete[] ptr; diff --git a/src/polymesh/formats/obj.hh b/src/polymesh/formats/obj.hh index d61ecbe..eb56a42 100644 --- a/src/polymesh/formats/obj.hh +++ b/src/polymesh/formats/obj.hh @@ -3,7 +3,7 @@ #include <iosfwd> #include <string> -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/formats/off.hh b/src/polymesh/formats/off.hh index 7847a86..18ea1a4 100644 --- a/src/polymesh/formats/off.hh +++ b/src/polymesh/formats/off.hh @@ -4,7 +4,7 @@ #include <iosfwd> #include <string> -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/formats/ply.hh b/src/polymesh/formats/ply.hh index 9f890e2..76b0b1b 100644 --- a/src/polymesh/formats/ply.hh +++ b/src/polymesh/formats/ply.hh @@ -3,7 +3,7 @@ #include <iosfwd> #include <string> -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/formats/stl.hh b/src/polymesh/formats/stl.hh index 347318a..0c5a364 100644 --- a/src/polymesh/formats/stl.hh +++ b/src/polymesh/formats/stl.hh @@ -4,7 +4,7 @@ #include <iosfwd> #include <string> -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/impl/impl_attributes.hh b/src/polymesh/impl/impl_attributes.hh index e17c5d5..b8aa5a8 100644 --- a/src/polymesh/impl/impl_attributes.hh +++ b/src/polymesh/impl/impl_attributes.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { @@ -189,7 +189,7 @@ primitive_attribute<tag, AttrT>& primitive_attribute<tag, AttrT>::operator=(prim if (new_capacity == 0) this->mData.reset(); else - this->mData.reset(new AttrT[new_capacity]); + this->mData.reset(new AttrT[new_capacity]()); } // copy ALL data (valid and defaulted) @@ -234,7 +234,7 @@ void primitive_attribute<tag, AttrT>::resize_from(int old_size) POLYMESH_ASSERT(shared_size <= new_capacity && "size cannot exceed capacity"); // alloc new data - auto new_data = new_capacity > 0 ? new AttrT[new_capacity] : nullptr; + auto new_data = new_capacity > 0 ? new AttrT[new_capacity]() : nullptr; // copy shared region to new data std::copy_n(this->mData.get(), shared_size, new_data); diff --git a/src/polymesh/impl/impl_cursors.hh b/src/polymesh/impl/impl_cursors.hh index 541efe5..78ee003 100644 --- a/src/polymesh/impl/impl_cursors.hh +++ b/src/polymesh/impl/impl_cursors.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/impl/impl_low_level_api_base.hh b/src/polymesh/impl/impl_low_level_api_base.hh index 7bdd5f9..a9665a0 100644 --- a/src/polymesh/impl/impl_low_level_api_base.hh +++ b/src/polymesh/impl/impl_low_level_api_base.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/impl/impl_low_level_api_mutable.hh b/src/polymesh/impl/impl_low_level_api_mutable.hh index 369c928..b0987e3 100644 --- a/src/polymesh/impl/impl_low_level_api_mutable.hh +++ b/src/polymesh/impl/impl_low_level_api_mutable.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/impl/impl_mesh.hh b/src/polymesh/impl/impl_mesh.hh index 892f15a..5af5703 100644 --- a/src/polymesh/impl/impl_mesh.hh +++ b/src/polymesh/impl/impl_mesh.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> #include "../assert.hh" #include "../detail/split_vector.hh" diff --git a/src/polymesh/impl/impl_primitive.hh b/src/polymesh/impl/impl_primitive.hh index 17d3e04..6aec17e 100644 --- a/src/polymesh/impl/impl_primitive.hh +++ b/src/polymesh/impl/impl_primitive.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/impl/impl_ranges.hh b/src/polymesh/impl/impl_ranges.hh index e834348..5725bce 100644 --- a/src/polymesh/impl/impl_ranges.hh +++ b/src/polymesh/impl/impl_ranges.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/objects/cone.hh b/src/polymesh/objects/cone.hh index 4e17284..c2244ee 100644 --- a/src/polymesh/objects/cone.hh +++ b/src/polymesh/objects/cone.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh::objects { diff --git a/src/polymesh/objects/cube.hh b/src/polymesh/objects/cube.hh index 5389783..5d0c1e0 100644 --- a/src/polymesh/objects/cube.hh +++ b/src/polymesh/objects/cube.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> #include "../fields.hh" namespace polymesh diff --git a/src/polymesh/objects/cylinder.hh b/src/polymesh/objects/cylinder.hh index 7e576b6..86dfa33 100644 --- a/src/polymesh/objects/cylinder.hh +++ b/src/polymesh/objects/cylinder.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh::objects { diff --git a/src/polymesh/objects/quad.hh b/src/polymesh/objects/quad.hh index 229eeab..85433cb 100644 --- a/src/polymesh/objects/quad.hh +++ b/src/polymesh/objects/quad.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh { diff --git a/src/polymesh/objects/uv_sphere.hh b/src/polymesh/objects/uv_sphere.hh index a44b2d9..fbbea26 100644 --- a/src/polymesh/objects/uv_sphere.hh +++ b/src/polymesh/objects/uv_sphere.hh @@ -1,6 +1,6 @@ #pragma once -#include "../Mesh.hh" +#include <polymesh/Mesh.hh> namespace polymesh::objects { diff --git a/src/polymesh/span.hh b/src/polymesh/span.hh new file mode 100644 index 0000000..db18e1a --- /dev/null +++ b/src/polymesh/span.hh @@ -0,0 +1,80 @@ +#pragma once + +#include <cstddef> +#include <type_traits> + +#include <polymesh/assert.hh> +#include <polymesh/tmp.hh> + +namespace polymesh +{ +// a non-owning view of a contiguous array of Ts +// can be read and write (span<const T> vs span<T>) +// is trivially copyable (and cheap) +// NOTE: is range-checked via POLYMESH_ASSERT +template <class T> +struct span +{ + // ctors +public: + constexpr span() = default; + constexpr span(T* data, size_t size) : _data(data), _size(size) {} + constexpr span(T* d_begin, T* d_end) : _data(d_begin), _size(d_end - d_begin) {} + template <size_t N> + constexpr span(T (&data)[N]) : _data(data), _size(N) + { + } + template <class Container, std::enable_if_t<tmp::is_contiguous_range<Container, T>, int> = 0> + constexpr span(Container&& c) : _data(c.data()), _size(c.size()) + { + } + + // container +public: + constexpr T* begin() const { return _data; } + constexpr T* end() const { return _data + _size; } + + constexpr T* data() const { return _data; } + constexpr size_t size() const { return _size; } + constexpr bool empty() const { return _size == 0; } + + constexpr T& operator[](size_t i) const + { + POLYMESH_ASSERT(i < _size); + return _data[i]; + } + + constexpr T& front() const + { + POLYMESH_ASSERT(_size > 0); + return _data[0]; + } + constexpr T& back() const + { + POLYMESH_ASSERT(_size > 0); + return _data[_size - 1]; + } + + // subviews +public: + constexpr span first(size_t n) const + { + POLYMESH_ASSERT(n <= _size); + return {_data, n}; + } + constexpr span last(size_t n) const + { + POLYMESH_ASSERT(n <= _size); + return {_data + (_size - n), n}; + } + constexpr span subspan(size_t offset, size_t count) const + { + POLYMESH_ASSERT(offset + count <= _size); + return {_data + offset, count}; + } + +private: + T* _data = nullptr; + size_t _size = 0; +}; +} diff --git a/src/polymesh/tmp.hh b/src/polymesh/tmp.hh index 527247d..7801d2c 100644 --- a/src/polymesh/tmp.hh +++ b/src/polymesh/tmp.hh @@ -1,5 +1,6 @@ #pragma once +#include <cstddef> #include <utility> namespace polymesh @@ -99,5 +100,49 @@ struct constant_rational } }; +namespace detail +{ +template <class Container, class ElementT> +auto contiguous_range_test(Container* c) -> decltype(static_cast<ElementT*>(c->data()), static_cast<size_t>(c->size()), 0); +template <class Container, class ElementT> +char contiguous_range_test(...); + +template <class Container, class ElementT, class = void> +struct is_range_t : std::false_type +{ +}; +template <class ElementT, size_t N> +struct is_range_t<ElementT[N], ElementT> : std::true_type +{ +}; +template <class ElementT, size_t N> +struct is_range_t<ElementT[N], ElementT const> : std::true_type +{ +}; +template <class ElementT, size_t N> +struct is_range_t<ElementT (&)[N], ElementT> : std::true_type +{ +}; +template <class ElementT, size_t N> +struct is_range_t<ElementT (&)[N], ElementT const> : std::true_type +{ +}; +template <class Container, class ElementT> +struct is_range_t<Container, + ElementT, + std::void_t< // + decltype(static_cast<ElementT&>(*std::declval<Container>().begin())), // + decltype(std::declval<Container>().end()) // + >> : std::true_type +{ +}; +} + +template <class Container, class ElementT> +static constexpr bool is_contiguous_range = sizeof(detail::contiguous_range_test<Container, ElementT>(nullptr)) == sizeof(int); + +template <class Container, class ElementT> +static constexpr bool is_range = detail::is_range_t<Container, ElementT>::value; + } // namespace tmp } // namespace polymesh -- GitLab