extract explicit mesh with topology information from implicit surfaces with boolean operations, and do surface/volume integrating on them.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

608 lines
20 KiB

8 months ago
#pragma once
#include <iostream>
#include <range/v3/iterator.hpp>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 26495)
#endif
template <class T, std::size_t N = 16>
class static_vector
{
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = T*;
using const_pointer = const T*;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
static_vector() noexcept : m_size{0} {}
explicit static_vector(size_type count) : m_size{count}
{
assert(count <= N);
std::uninitialized_value_construct(begin(), end());
}
static_vector(size_type count, const value_type& value) : m_size{count}
{
assert(count <= N);
std::uninitialized_fill(begin(), end(), value);
}
static_vector(const static_vector& other) : m_size{other.m_size}
{
std::uninitialized_copy(other.begin(), other.end(), begin());
}
static_vector(static_vector&& other) noexcept : m_size{other.m_size}
{
std::uninitialized_move(other.begin(), other.end(), begin());
other.clear();
}
static_vector(std::initializer_list<value_type> ilist) : m_size{static_cast<size_type>(ilist.size())}
{
assert(ilist.size() <= N);
std::uninitialized_copy(ilist.begin(), ilist.end(), begin());
}
template <typename Iter, typename = std::enable_if_t<ranges::input_iterator<Iter>>>
static_vector(Iter first, Iter last) : static_vector(first, last, typename std::iterator_traits<Iter>::iterator_category{})
{
}
~static_vector() { std::destroy(begin(), end()); }
static_vector& operator=(const static_vector& rhs)
{
if (this != &rhs) {
if (m_size > rhs.m_size) {
std::destroy(begin() + rhs.m_size, end());
std::copy(rhs.begin(), rhs.end(), begin());
} else {
if constexpr (std::is_trivially_copy_assignable_v<value_type>
&& std::is_trivially_copy_constructible_v<value_type>) {
std::memcpy(&m_storage, &rhs.m_storage, rhs.m_size * sizeof(value_type));
} else {
std::copy(rhs.begin(), rhs.begin() + m_size, begin());
std::uninitialized_copy(rhs.begin() + m_size, rhs.end(), end());
}
}
m_size = rhs.m_size;
}
return *this;
}
static_vector& operator=(static_vector&& rhs) noexcept
{
if (this != &rhs) {
if (m_size > rhs.m_size) {
std::destroy(begin() + rhs.m_size, end());
std::move(rhs.begin(), rhs.end(), begin());
} else {
if constexpr (std::is_trivially_move_assignable_v<value_type>
&& std::is_trivially_move_constructible_v<value_type>) {
std::memcpy(&m_storage, &rhs.m_storage, rhs.m_size * sizeof(value_type));
} else {
std::copy(rhs.begin(), rhs.begin() + m_size, begin());
std::uninitialized_move(rhs.begin() + m_size, rhs.end(), end());
}
}
m_size = rhs.m_size;
rhs.clear();
}
return *this;
}
static_vector& operator=(std::initializer_list<value_type> rhs)
{
assert(rhs.size() <= N);
const size_type rhs_size = static_cast<size_type>(rhs.size());
if (m_size > rhs_size) {
std::destroy(begin() + rhs_size, end());
std::copy(rhs.begin(), rhs.end(), begin());
} else {
if constexpr (std::is_trivially_copy_assignable_v<value_type>
&& std::is_trivially_copy_constructible_v<value_type>) {
std::memcpy(&m_storage, rhs.begin(), rhs_size * sizeof(value_type));
} else {
std::copy(rhs.begin(), rhs.begin() + m_size, begin());
std::uninitialized_copy(rhs.begin() + m_size, rhs.end(), end());
}
}
m_size = rhs_size;
return *this;
}
void assign(size_type count, const value_type& value)
{
assert(count <= N);
const pointer myfirst = begin();
const pointer mylast = end();
if (count > m_size) {
std::fill(myfirst, mylast, value);
std::uninitialized_fill_n(mylast, count - m_size, value);
} else {
const pointer newlast = myfirst + count;
std::fill(myfirst, newlast, value);
std::destroy(newlast, mylast);
}
m_size = count;
}
template <class Iter, typename = std::enable_if_t<ranges::input_iterator<Iter>>>
void assign(Iter first, Iter last)
{
assign_range(first, last, typename std::iterator_traits<Iter>::iterator_category{});
}
void assign(std::initializer_list<T> ilist) { assign_range(ilist.begin(), ilist.end(), std::random_access_iterator_tag{}); }
reference at(size_type pos)
{
if (pos >= size()) std::cerr << "Invalid static_vector<T, N> subscript: Referring index is out of range!" << std::endl;
return *(data() + pos);
}
const_reference at(size_type pos) const
{
if (pos >= size()) std::cerr << "Invalid static_vector<T, N> subscript: Referring index is out of range!" << std::endl;
return *(data() + pos);
}
reference operator[](size_type pos) noexcept
{
assert(pos < size());
return *(data() + pos);
}
const_reference operator[](size_type pos) const noexcept
{
assert(pos < size());
return *(data() + pos);
}
reference front() noexcept
{
assert(!empty());
return *data();
}
const_reference front() const noexcept
{
assert(!empty());
return *data();
}
reference back() noexcept
{
assert(!empty());
return *(data() + m_size - 1);
}
const_reference back() const noexcept
{
assert(!empty());
return *(data() + m_size - 1);
}
pointer data() noexcept { return reinterpret_cast<pointer>(&m_storage); }
const_pointer data() const noexcept { return reinterpret_cast<const_pointer>(&m_storage); }
iterator begin() noexcept { return data(); }
const_iterator begin() const noexcept { return data(); }
const_iterator cbegin() const noexcept { return begin(); }
iterator end() noexcept { return data() + m_size; }
const_iterator end() const noexcept { return data() + m_size; }
const_iterator cend() const noexcept { return end(); }
reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
const_reverse_iterator crbegin() const noexcept { return rbegin(); }
reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
const_reverse_iterator crend() const noexcept { return rend(); }
bool empty() const noexcept { return m_size == 0; }
size_type size() const noexcept { return m_size; }
size_type max_size() const noexcept { return N; }
size_type capacity() const noexcept { return N; }
void clear() noexcept
{
if constexpr (!std::is_trivially_destructible_v<T>) {
for (value_type& elem : *this) elem.~value_type();
}
m_size = 0;
}
iterator insert(const_iterator pos, const value_type& value) { return emplace(pos, value); }
iterator insert(const_iterator pos, value_type&& value) { return emplace(pos, std::move(value)); }
iterator insert(const_iterator pos, size_type count, const value_type& value)
{
assert(size() + count <= N);
iterator last = end();
assert(begin() <= pos && pos <= last);
const pointer posptr = const_cast<pointer>(pos);
const auto affected_elements = static_cast<size_type>(last - posptr);
if (affected_elements == 0)
;
else if (affected_elements < count) {
// [pos, last) --move--> [last, ...)
std::uninitialized_move(posptr, last, last);
std::destroy(posptr, last);
} else {
if constexpr (std::is_trivially_move_assignable_v<value_type>) {
if constexpr (std::is_trivially_move_constructible_v<value_type>)
// 1. + 2. [pos, last) --move--> [pos+count, last+count)
std::memmove(posptr + count, posptr, (last - posptr) * sizeof(value_type));
else {
// 1. [last-count, last) -> [last, last+count)
std::uninitialized_move(last - count, last, last);
// 2. [pos, last-count) --move--> [pos+count, last)
std::memmove(posptr + count, posptr, (last - posptr - count) * sizeof(value_type));
}
} else {
// 1. [last-count, last) -> [last, last+count)
std::uninitialized_move(last - count, last, last);
// 2. [pos, last-count) --move--> [pos+count, last)
for (auto cursor = last - count - 1; cursor >= pos; --cursor) *(cursor + count) = std::move(*cursor);
}
std::destroy(posptr, posptr + count);
}
std::uninitialized_fill(posptr, posptr + count, value);
m_size += count;
return posptr;
}
template <typename Iter, typename = std::enable_if_t<ranges::input_iterator<Iter>>>
iterator insert(const_iterator pos, Iter first, Iter last)
{
insert_range(pos, first, last, typename std::iterator_traits<Iter>::iterator_category{});
return const_cast<iterator>(pos);
}
iterator insert(const_iterator pos, std::initializer_list<value_type> ilist)
{
return insert(pos, ilist.begin(), ilist.end());
}
template <typename... Args>
iterator emplace(const_iterator pos, Args&&... args)
{
pointer posptr = const_cast<pointer>(pos);
assert(size() < max_size());
iterator last = end();
assert(begin() <= pos && pos <= last);
if (posptr != last) {
if constexpr (std::is_trivially_move_assignable_v<value_type>) {
if constexpr (std::is_trivially_move_constructible_v<value_type>)
// 1. + 2. [pos, last) --move--> [pos+1, last+1)
std::memmove(posptr + 1, posptr, (last - posptr) * sizeof(value_type));
else {
// 1. pos -> last
new (last) value_type{std::move(*(last - 1))};
// 2. [pos, last-1) --move--> [pos+1, last)
std::memmove(posptr + 1, posptr, (last - posptr - 1) * sizeof(value_type));
}
} else {
// 1. pos -> last
new (last) value_type{std::move(*(last - 1))};
// 2. [pos, last-1) --move--> [pos+1, last)
for (auto cursor = last - 2; cursor >= pos; --cursor) *(cursor + 1) = std::move(*cursor);
}
// 3. destroy
if constexpr (!std::is_trivially_destructible_v<value_type>) posptr->~value_type();
}
// 4. copy ctor at pos
new (posptr) value_type{std::forward<Args>(args)...};
++m_size;
return posptr;
}
iterator erase(const_iterator pos) noexcept(std::is_nothrow_move_assignable_v<value_type>)
{
const pointer posptr = const_cast<pointer>(pos);
const pointer mylast = end();
assert(begin() <= pos && pos < mylast);
std::move(posptr + 1, mylast, posptr);
if constexpr (!std::is_trivially_destructible_v<value_type>) (mylast - 1)->~value_type();
m_size--;
return posptr;
}
iterator erase(const_iterator first, const_iterator last) noexcept(std::is_nothrow_move_assignable_v<value_type>)
{
const pointer mylast = end();
assert(begin() <= first && first <= last && last <= mylast);
const pointer firstptr = const_cast<pointer>(first);
const pointer lastptr = const_cast<pointer>(last);
const size_type affected_elements = conver_size(static_cast<size_type>(last - first));
if (affected_elements > 0) {
const pointer newlast = std::move(lastptr, mylast, firstptr);
std::destroy(newlast, mylast);
m_size -= affected_elements;
}
return firstptr;
}
void push_back(const value_type& value)
{
assert(size() < max_size());
new (data() + m_size) value_type{value};
++m_size;
}
void push_back(T&& value)
{
assert(size() < max_size());
new (data() + m_size) value_type{std::move(value)};
++m_size;
}
template <typename... Args>
reference emplace_back(Args&&... args)
{
assert(size() < max_size());
pointer addr = data() + m_size;
new (addr) value_type{std::forward<Args>(args)...};
++m_size;
return *addr;
}
void pop_back()
{
assert(!empty());
if constexpr (!std::is_trivially_destructible_v<value_type>) back().~value_type();
--m_size;
}
void resize(size_type count)
{
7 months ago
assert(count <= max_size());
8 months ago
if (count > m_size)
std::uninitialized_default_construct(end(), begin() + count);
else
std::destroy(begin() + count, end());
m_size = count;
}
void resize(size_type count, const T& value)
{
7 months ago
assert(count <= max_size());
8 months ago
if (count > m_size)
std::uninitialized_fill(end(), begin() + count, value);
else
std::destroy(begin() + count, end());
m_size = count;
}
private:
template <typename Iter, typename = std::enable_if_t<ranges::input_iterator<Iter>>>
static_vector(Iter first, Iter last, std::input_iterator_tag)
{
for (; first != last; ++first) emplace_back(*first);
}
template <typename Iter, typename = std::enable_if_t<ranges::input_iterator<Iter>>>
static_vector(Iter first, Iter last, std::forward_iterator_tag)
{
auto mylast = std::uninitialized_copy(first, last, begin());
m_size = conver_size(static_cast<size_type>(mylast - begin()));
}
template <class Iter>
void assign_range(Iter first, Iter last, std::input_iterator_tag)
{ // assign input range [first, last)
const pointer myfirst = begin();
const pointer mylast = end();
pointer cursor = myfirst;
for (; first != last && cursor != mylast; ++first, ++cursor) *cursor = *first;
// Trim.
std::destroy(cursor, mylast);
m_size = cursor - myfirst;
// Append.
for (; first != last; ++first) emplace_back(*first);
}
template <class Iter>
void assign_range(Iter first, Iter last, std::forward_iterator_tag)
{ // assign forward range [first, last)
const auto newsize = conver_size(static_cast<size_type>(std::distance(first, last)));
assert(newsize <= N);
const pointer myfirst = begin();
const pointer mylast = end();
if (newsize > m_size) {
// performance note: traversing [first, _Mid) twice
const Iter mid = std::next(first, static_cast<difference_type>(m_size));
std::copy(first, mid, myfirst);
std::uninitialized_copy(mid, last, mylast);
} else {
const pointer newlast = myfirst + newsize;
std::copy(first, last, myfirst);
std::destroy(newlast, mylast);
}
m_size = newsize;
}
template <typename Iter>
void insert_range(const_iterator pos, Iter first, Iter last, std::input_iterator_tag)
{
assert(begin() <= pos && pos <= end());
if (first == last) return; // nothing to do, avoid invalidating iterators
pointer myfirst = begin();
const auto whereoff = static_cast<size_type>(pos - myfirst);
const auto oldsize = m_size;
for (; first != last; ++first) {
emplace_back(*first);
assert(m_size < max_size());
++m_size;
}
std::rotate(myfirst + whereoff, myfirst + oldsize, end());
}
template <typename S>
static constexpr size_type conver_size(const S& s) noexcept
{
assert(s <= N);
return static_cast<size_type>(s);
}
template <typename Iter>
void insert_range(const_iterator pos, Iter first, Iter last, std::forward_iterator_tag)
{
// insert forward range [first, last) at pos
const pointer posptr = const_cast<pointer>(pos);
const auto count = conver_size(static_cast<size_type>(std::distance(first, last)));
assert(count + m_size <= N);
assert(begin() <= pos && pos <= end());
const pointer oldlast = end();
// Attempt to provide the strong guarantee for EmplaceConstructible failure.
// If we encounter copy/move construction/assignment failure, provide the basic guarantee.
// (For one-at-back, this provides the strong guarantee.)
const auto affected_elements = static_cast<size_type>(oldlast - posptr);
if (count < affected_elements) { // some affected elements must be assigned
if constexpr (std::is_trivially_move_assignable_v<value_type>) {
if constexpr (std::is_trivially_move_constructible_v<value_type>)
std::memmove(posptr + count, posptr, affected_elements * sizeof(value_type));
else {
/*mylast = */ std::uninitialized_move(oldlast - count, oldlast, oldlast);
std::memmove(posptr + count, posptr, (affected_elements - count) * sizeof(value_type));
}
} else {
/*mylast = */ std::uninitialized_move(oldlast - count, oldlast, oldlast);
std::move(posptr, oldlast - count, posptr + count);
for (auto cursor = oldlast - count - 1; cursor >= posptr; --cursor) *(cursor + count) = std::move(*cursor);
}
std::destroy(posptr, posptr + count);
std::uninitialized_copy(first, last, posptr);
} else { // affected elements don't overlap before/after
const pointer relocated = posptr + count;
std::uninitialized_move(posptr, oldlast, relocated);
std::destroy(posptr, oldlast);
std::uninitialized_copy(first, last, posptr);
}
m_size += count;
}
std::aligned_storage_t<sizeof(T) * N, alignof(T)> m_storage;
size_type m_size;
};
template <typename T, std::size_t N>
bool operator==(const static_vector<T, N>& lhs, const static_vector<T, N>& rhs)
{
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template <typename T, std::size_t N>
bool operator<(const static_vector<T, N>& lhs, const static_vector<T, N>& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template <typename T, std::size_t N>
bool operator!=(const static_vector<T, N>& lhs, const static_vector<T, N>& rhs)
{
return !(lhs == rhs);
}
template <typename T, std::size_t N>
bool operator>(const static_vector<T, N>& lhs, const static_vector<T, N>& rhs)
{
return rhs < lhs;
}
template <typename T, std::size_t N>
bool operator<=(const static_vector<T, N>& lhs, const static_vector<T, N>& rhs)
{
return !(rhs < lhs);
}
template <typename T, std::size_t N>
bool operator>=(const static_vector<T, N>& lhs, const static_vector<T, N>& rhs)
{
return !(lhs < rhs);
}
namespace detail
{
template <size_t N>
struct static_vector_bind {
template <typename T>
using type = static_vector<T, N>;
};
} // namespace detail
#ifdef _MSC_VER
#pragma warning(pop)
#endif