split winding_base_t into two types, so that we can switch out the backing storage

default winding_t for the main polylib to use heap-based, exact-memory-usage-only, winding
This commit is contained in:
Jonathan 2022-08-02 06:09:20 -04:00
parent da4c45d62f
commit 53adb9fed5
7 changed files with 560 additions and 82 deletions

View File

@ -74,7 +74,13 @@ int32_t entdict_t::get_int(const std::string_view &key) const
int32_t entdict_t::get_vector(const std::string_view &key, qvec3d &vec) const
{
const std::string &value = get(key);
std::string value = get(key);
// FIXME: this fixes ASan triggering on some entities...
if (*(value.data() + value.size()) != 0) {
*(value.data() + value.size()) = 0;
}
vec = {};
return sscanf(value.data(), "%lf %lf %lf", &vec[0], &vec[1], &vec[2]);
}

View File

@ -35,26 +35,402 @@ inline bool PointInWindingEdges(const winding_edges_t &wi, const qvec3d &point)
return true;
}
// Polygonal winding; uses stack allocation for the first N
#if 0
// Hybrid storage; uses stack allocation for the first N
// points, and uses a dynamic vector for storage after that.
template<size_t N>
struct winding_base_t
struct winding_storage_hybrid_t
{
// default constructor does nothing
inline winding_storage_hybrid_t();
// construct winding with initial size; may allocate
// memory, and sets size, but does not initialize any
// of them.
inline winding_storage_hybrid_t(const size_t &initial_size) : count(initial_size);
// construct winding from range.
// iterators must have operator+ and operator-.
template<typename Iter, std::enable_if_t<is_iterator_v<Iter>, int> = 0>
inline winding_storage_hybrid_t(Iter begin, Iter end) : winding_storage_hybrid_t(end - begin);
// initializer list constructor
inline winding_storage_hybrid_t(std::initializer_list<qvec3d> l) : winding_storage_hybrid_t(l.begin(), l.end());
// copy constructor; uses optimized method of copying
// data over.
inline winding_storage_hybrid_t(const winding_storage_hybrid_t &copy) : winding_storage_hybrid_t(copy.size());
// move constructor
inline winding_storage_hybrid_t(winding_storage_hybrid_t &&move) noexcept : count(move.count);
// assignment copy
inline winding_storage_hybrid_t &operator=(const winding_storage_hybrid_t &copy);
// assignment move
inline winding_storage_hybrid_t &operator=(winding_storage_hybrid_t &&move) noexcept;
inline bool empty() const;
inline explicit operator bool() const;
inline const size_t &size() const;
inline qvec3d &at(const size_t &index);
inline const qvec3d &at(const size_t &index) const;
// un-bounds-checked
inline qvec3d &operator[](const size_t &index);
inline const qvec3d &operator[](const size_t &index) const;
const const_iterator begin() const;
const const_iterator end() const;
iterator begin();
iterator end();
template<typename... Args>
qvec3d &emplace_back(Args &&...vec);
void resize(const size_t &new_size);
void clear();
};
#endif
// Stack storage; uses stack allocation. Throws if it can't insert
// a new member.
template<size_t N>
struct winding_storage_stack_t
{
protected:
using array_type = std::array<qvec3d, N>;
array_type array;
public:
size_t count = 0;
// default constructor does nothing
inline winding_storage_stack_t() { }
// construct winding with initial size; may allocate
// memory, and sets size, but does not initialize any
// of them.
inline winding_storage_stack_t(const size_t &initial_size) : count(initial_size)
{
if (initial_size > N) {
throw std::bad_alloc();
}
}
// construct winding from range.
// iterators must have operator+ and operator-.
template<typename Iter, std::enable_if_t<is_iterator_v<Iter>, int> = 0>
inline winding_storage_stack_t(Iter begin, Iter end) : winding_storage_stack_t(end - begin)
{
std::copy_n(begin, count, array.begin());
}
// copy constructor; uses optimized method of copying
// data over.
inline winding_storage_stack_t(const winding_storage_stack_t &copy) : winding_storage_stack_t(copy.size())
{
std::copy_n(copy.array.begin(), copy.count, array.begin());
}
// move constructor
inline winding_storage_stack_t(winding_storage_stack_t &&move) noexcept : count(move.count)
{
count = move.count;
std::copy_n(move.array.begin(), move.count, array.begin());
move.count = 0;
}
// assignment copy
inline winding_storage_stack_t &operator=(const winding_storage_stack_t &copy)
{
count = copy.count;
// copy array range
std::copy_n(copy.array.begin(), copy.count, array.begin());
return *this;
}
// assignment move
inline winding_storage_stack_t &operator=(winding_storage_stack_t &&move) noexcept
{
count = move.count;
// blit over array data
std::copy_n(move.array.begin(), move.count, array.begin());
move.count = 0;
return *this;
}
inline const size_t &size() const { return count; }
inline qvec3d &at(const size_t &index)
{
#ifdef _DEBUG
if (index >= count)
throw std::invalid_argument("index");
#endif
return array[index];
}
inline const qvec3d &at(const size_t &index) const
{
#ifdef _DEBUG
if (index >= count)
throw std::invalid_argument("index");
#endif
return array[index];
}
// un-bounds-checked
inline qvec3d &operator[](const size_t &index)
{
return array[index];
}
// un-bounds-checked
inline const qvec3d &operator[](const size_t &index) const
{
return array[index];
}
using const_iterator = typename array_type::const_iterator;
inline const const_iterator begin() const
{
return array.begin();
}
inline const const_iterator end() const
{
return array.begin() + count;
}
using iterator = typename array_type::iterator;
inline iterator begin()
{
return array.begin();
}
inline iterator end()
{
return array.begin() + count;
}
inline qvec3d &emplace_back(const qvec3d &vec)
{
count++;
if (count > N) {
throw std::bad_alloc();
}
return (array[count - 1] = vec);
}
inline void resize(const size_t &new_size)
{
if (new_size > N) {
throw std::bad_alloc();
}
count = new_size;
}
inline void clear()
{
count = 0;
}
};
// Stack storage; uses a solid heap allocation. Throws if it can't insert
// a new member.
struct winding_storage_heap_t
{
protected:
qvec3d *heap = nullptr;
public:
size_t count = 0;
// default constructor does nothing
inline winding_storage_heap_t() { }
// destructor
~winding_storage_heap_t() { free(heap); heap = nullptr; }
// construct winding with initial size; may allocate
// memory, and sets size, but does not initialize any
// of them.
inline winding_storage_heap_t(const size_t &initial_size) : count(initial_size)
{
if (initial_size) {
heap = reinterpret_cast<qvec3d *>(malloc(sizeof(qvec3d) * initial_size));
}
}
// construct winding from range.
// iterators must have operator+ and operator-.
template<typename Iter, std::enable_if_t<is_iterator_v<Iter>, int> = 0>
inline winding_storage_heap_t(Iter begin, Iter end) : winding_storage_heap_t(end - begin)
{
std::copy_n(begin, count, heap);
}
// copy constructor; uses optimized method of copying
// data over.
inline winding_storage_heap_t(const winding_storage_heap_t &copy) : winding_storage_heap_t(copy.size())
{
std::copy_n(copy.heap, copy.count, heap);
}
// move constructor
inline winding_storage_heap_t(winding_storage_heap_t &&move) noexcept : count(move.count)
{
// take ownership of heap pointer
heap = move.heap;
count = move.count;
move.heap = nullptr;
move.count = 0;
}
// assignment copy
inline winding_storage_heap_t &operator=(const winding_storage_heap_t &copy)
{
resize(copy.count);
// copy array range
std::copy_n(copy.heap, copy.count, heap);
return *this;
}
// assignment move
inline winding_storage_heap_t &operator=(winding_storage_heap_t &&move) noexcept
{
// take ownership of heap pointer
heap = move.heap;
count = move.count;
move.heap = nullptr;
move.count = 0;
return *this;
}
inline const size_t &size() const { return count; }
inline qvec3d &at(const size_t &index)
{
#ifdef _DEBUG
if (index >= count)
throw std::invalid_argument("index");
#endif
return heap[index];
}
inline const qvec3d &at(const size_t &index) const
{
#ifdef _DEBUG
if (index >= count)
throw std::invalid_argument("index");
#endif
return heap[index];
}
// un-bounds-checked
inline qvec3d &operator[](const size_t &index)
{
return heap[index];
}
// un-bounds-checked
inline const qvec3d &operator[](const size_t &index) const
{
return heap[index];
}
inline const auto begin() const
{
return heap;
}
inline const auto end() const
{
return heap + count;
}
inline auto begin()
{
return heap;
}
inline auto end()
{
return heap + count;
}
inline qvec3d &emplace_back(const qvec3d &vec)
{
resize(count + 1);
return (heap[count - 1] = vec);
}
inline void resize(const size_t &new_size)
{
count = new_size;
if (new_size == 0) {
free(heap);
heap = nullptr;
} else {
heap = reinterpret_cast<qvec3d *>(realloc(heap, new_size * sizeof(qvec3d)));
}
}
inline void clear()
{
count = 0;
}
};
// Hybrid storage; uses stack allocation for the first N
// points, and uses a dynamic vector for storage after that.
template<size_t N>
struct winding_storage_hybrid_t
{
protected:
using array_type = std::array<qvec3d, N>;
using vector_type = std::vector<qvec3d>;
using variant_type = std::variant<array_type, vector_type>;
size_t count = 0;
array_type array;
vector_type vector;
public:
size_t count = 0;
template<bool is_const>
class iterator_base
{
friend struct winding_base_t;
friend struct winding_storage_hybrid_t;
using container_type = typename std::conditional_t<is_const, const winding_base_t *, winding_base_t *>;
using container_type = typename std::conditional_t<is_const, const winding_storage_hybrid_t *, winding_storage_hybrid_t *>;
size_t index;
container_type w;
@ -138,12 +514,12 @@ public:
};
// default constructor does nothing
inline winding_base_t() { }
inline winding_storage_hybrid_t() { }
// construct winding with initial size; may allocate
// memory, and sets size, but does not initialize any
// of them.
inline winding_base_t(const size_t &initial_size) : count(initial_size)
inline winding_storage_hybrid_t(const size_t &initial_size) : count(initial_size)
{
if (count > N) {
vector.reserve(count);
@ -154,7 +530,7 @@ public:
// construct winding from range.
// iterators must have operator+ and operator-.
template<typename Iter, std::enable_if_t<is_iterator_v<Iter>, int> = 0>
inline winding_base_t(Iter begin, Iter end) : winding_base_t(end - begin)
inline winding_storage_hybrid_t(Iter begin, Iter end) : winding_storage_hybrid_t(end - begin)
{
// copy the array range
std::copy_n(begin, min(count, N), array.begin());
@ -165,12 +541,9 @@ public:
}
}
// initializer list constructor
inline winding_base_t(std::initializer_list<qvec3d> l) : winding_base_t(l.begin(), l.end()) { }
// copy constructor; uses optimized method of copying
// data over.
inline winding_base_t(const winding_base_t &copy) : winding_base_t(copy.size())
inline winding_storage_hybrid_t(const winding_storage_hybrid_t &copy) : winding_storage_hybrid_t(copy.size())
{
// copy array range
memcpy(&array.front(), &copy.array.front(), min(count, N) * sizeof(qvec3d));
@ -182,7 +555,7 @@ public:
}
// move constructor
inline winding_base_t(winding_base_t &&move) noexcept : count(move.count)
inline winding_storage_hybrid_t(winding_storage_hybrid_t &&move) noexcept : count(move.count)
{
count = move.count;
@ -198,7 +571,7 @@ public:
}
// assignment copy
inline winding_base_t &operator=(const winding_base_t &copy)
inline winding_storage_hybrid_t &operator=(const winding_storage_hybrid_t &copy)
{
count = copy.count;
@ -216,7 +589,7 @@ public:
}
// assignment move
inline winding_base_t &operator=(winding_base_t &&move) noexcept
inline winding_storage_hybrid_t &operator=(winding_storage_hybrid_t &&move) noexcept
{
count = move.count;
@ -233,12 +606,10 @@ public:
return *this;
}
inline bool empty() const { return count == 0; }
inline explicit operator bool() const { return count != 0; }
inline const size_t &size() const { return count; }
inline size_t vector_size() const { return vector.size(); }
inline qvec3d &at(const size_t &index)
{
#ifdef _DEBUG
@ -289,51 +660,40 @@ public:
using const_iterator = iterator_base<true>;
const const_iterator begin() const
inline const const_iterator begin() const
{
return const_iterator(0, this);
}
const const_iterator end() const
inline const const_iterator end() const
{
return const_iterator(count, this);
}
using iterator = iterator_base<false>;
iterator begin()
inline iterator begin()
{
return iterator(0, this);
}
iterator end()
inline iterator end()
{
return iterator(count, this);
}
template<typename... Args>
qvec3d &emplace_back(Args &&...vec)
inline qvec3d &emplace_back(const qvec3d &vec)
{
count++;
if (count > N) {
return vector.emplace_back(std::forward<Args>(vec)...);
return vector.emplace_back(vec);
}
return (array[count - 1] = qvec3d(std::forward<Args>(vec)...));
return (array[count - 1] = vec);
}
void push_back(qvec3d &&vec)
{
emplace_back(std::move(vec));
}
void push_back(const qvec3d &vec)
{
emplace_back(vec);
}
void resize(const size_t &new_size)
inline void resize(const size_t &new_size)
{
// resize vector if necessary
if (new_size > N) {
@ -343,19 +703,134 @@ public:
count = new_size;
}
void clear()
inline void clear()
{
count = 0;
}
};
// Winding type, with storage template. Doesn't inherit the storage,
// since that might slow things down with virtual destructor.
template<typename TStorage>
struct winding_base_t
{
protected:
TStorage storage;
public:
// default constructor does nothing
inline winding_base_t() { }
// construct winding with initial size; may allocate
// memory, and sets size, but does not initialize any
// of them.
inline winding_base_t(const size_t &initial_size) : storage(initial_size) { }
// construct winding from range.
// iterators must have operator+ and operator-.
template<typename Iter, std::enable_if_t<is_iterator_v<Iter>, int> = 0>
inline winding_base_t(Iter begin, Iter end) : storage(begin, end) { }
// initializer list constructor
inline winding_base_t(std::initializer_list<qvec3d> l) : storage(l.begin(), l.end()) { }
// copy constructor; uses optimized method of copying
// data over.
inline winding_base_t(const winding_base_t &copy) : storage(copy.storage) { }
// move constructor
inline winding_base_t(winding_base_t &&move) noexcept : storage(std::move(move.storage)) { }
// assignment copy
inline winding_base_t &operator=(const winding_base_t &copy)
{
storage = copy.storage;
return *this;
}
// assignment move
inline winding_base_t &operator=(winding_base_t &&move) noexcept
{
storage = std::move(move.storage);
return *this;
}
inline bool empty() const { return size() == 0; }
inline explicit operator bool() const { return !empty(); }
inline const size_t &size() const { return storage.size(); }
inline qvec3d &at(const size_t &index)
{
return storage.at(index);
}
inline const qvec3d &at(const size_t &index) const
{
return storage.at(index);
}
// un-bounds-checked
inline qvec3d &operator[](const size_t &index)
{
return storage[index];
}
// un-bounds-checked
inline const qvec3d &operator[](const size_t &index) const
{
return storage[index];
}
const auto begin() const
{
return storage.begin();
}
const auto end() const
{
return storage.end();
}
auto begin()
{
return storage.begin();
}
auto end()
{
return storage.end();
}
template<typename... Args>
qvec3d &emplace_back(Args &&...vec)
{
return storage.emplace_back(qvec3d(std::forward<Args>(vec)...));
}
void push_back(const qvec3d &vec)
{
storage.emplace_back(vec);
}
void resize(const size_t &new_size)
{
storage.resize(new_size);
}
void clear()
{
storage.clear();
}
// non-storage functions
vec_t area() const
{
// if (count < 3)
// throw std::domain_error("count");
vec_t total = 0;
for (size_t i = 2; i < count; i++) {
for (size_t i = 2; i < size(); i++) {
qvec3d d1 = at(i - 1) - at(0);
qvec3d d2 = at(i) - at(0);
total += 0.5 * qv::length(qv::cross(d1, d2));
@ -371,7 +846,7 @@ public:
for (auto &point : *this)
center += point;
return center * (1.0 / count);
return center * (1.0 / size());
}
aabb3d bounds() const
@ -396,9 +871,9 @@ public:
// CHECK: would this be more efficient to instead store a running
// list of indices that *are* collinear, so we can return sooner
// before copying points over?
for (size_t i = 0; i < count; i++) {
size_t j = (i + 1) % count;
size_t k = (i + count - 1) % count;
for (size_t i = 0; i < size(); i++) {
size_t j = (i + 1) % size();
size_t k = (i + size() - 1) % size();
qvec3d v1 = qv::normalize(at(j) - at(i));
qvec3d v2 = qv::normalize(at(i) - at(k));
@ -406,8 +881,9 @@ public:
temp.push_back(at(i));
}
if (count != temp.count)
if (size() != temp.size()) {
*this = std::move(temp);
}
}
qplane3d plane() const
@ -467,8 +943,8 @@ public:
void check(const vec_t &bogus_range = DEFAULT_BOGUS_RANGE, const vec_t &on_epsilon = DEFAULT_ON_EPSILON) const
{
if (count < 3)
FError("{} points", count);
if (size() < 3)
FError("{} points", size());
vec_t a = area();
if (a < 1)
@ -476,7 +952,7 @@ public:
qplane3d face = plane();
for (size_t i = 0; i < count; i++) {
for (size_t i = 0; i < size(); i++) {
const qvec3d &p1 = at(i);
size_t j = 0;
@ -490,7 +966,7 @@ public:
FError("point off plane");
/* check the edge isn't degenerate */
const qvec3d &p2 = at((i + 1) % count);
const qvec3d &p2 = at((i + 1) % size());
qvec3d dir = p2 - p1;
if (qv::length(dir) < on_epsilon)
@ -500,7 +976,7 @@ public:
vec_t edgedist = qv::dot(p1, edgenormal) + on_epsilon;
/* all other points must be on front side */
for (size_t j = 0; j < count; j++) {
for (size_t j = 0; j < size(); j++) {
if (j == i)
continue;
d = qv::dot(at(j), edgenormal);
@ -525,11 +1001,11 @@ public:
qplane3d p = plane();
winding_edges_t result;
result.reserve(count);
result.reserve(size());
for (size_t i = 0; i < count; i++) {
for (size_t i = 0; i < size(); i++) {
const qvec3d &v0 = at(i);
const qvec3d &v1 = at((i + 1) % count);
const qvec3d &v1 = at((i + 1) % size());
qvec3d edgevec = qv::normalize(v1 - v0);
qvec3d normal = qv::cross(edgevec, p.normal);
@ -549,7 +1025,7 @@ public:
/* determine sides for each point */
size_t i;
for (i = 0; i < count; i++) {
for (i = 0; i < size(); i++) {
vec_t dot = plane.distance_to(at(i));
if (dists) {
@ -594,8 +1070,8 @@ public:
std::array<std::optional<winding_base_t>, 2> clip(
const qplane3d &plane, const vec_t &on_epsilon = DEFAULT_ON_EPSILON, const bool &keepon = false) const
{
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (count + 1));
planeside_t *sides = (planeside_t *)alloca(sizeof(planeside_t) * (count + 1));
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (size() + 1));
planeside_t *sides = (planeside_t *)alloca(sizeof(planeside_t) * (size() + 1));
std::array<size_t, SIDE_TOTAL> counts = calc_sides(plane, dists, sides, on_epsilon);
@ -609,7 +1085,7 @@ public:
std::array<winding_base_t, 2> results{};
for (size_t i = 0; i < count; i++) {
for (size_t i = 0; i < size(); i++) {
const qvec3d &p1 = at(i);
if (sides[i] == SIDE_ON) {
@ -626,7 +1102,7 @@ public:
continue;
/* generate a split point */
const qvec3d &p2 = at((i + 1) % count);
const qvec3d &p2 = at((i + 1) % size());
vec_t dot = dists[i] / (dists[i] - dists[i + 1]);
qvec3d mid;
@ -644,7 +1120,7 @@ public:
results[SIDE_BACK].push_back(mid);
}
if (results[SIDE_FRONT].count > MAX_POINTS_ON_WINDING || results[SIDE_BACK].count > MAX_POINTS_ON_WINDING)
if (results[SIDE_FRONT].size() > MAX_POINTS_ON_WINDING || results[SIDE_BACK].size() > MAX_POINTS_ON_WINDING)
FError("MAX_POINTS_ON_WINDING");
return {std::move(results[SIDE_FRONT]), std::move(results[SIDE_BACK])};
@ -652,7 +1128,7 @@ public:
void dice(vec_t subdiv, std::function<void(winding_base_t &)> save_fn)
{
if (!count)
if (!size())
return;
aabb3d b = bounds();
@ -715,7 +1191,7 @@ public:
winding_base_t flip() const
{
winding_base_t result(count);
winding_base_t result(size());
std::reverse_copy(begin(), end(), result.begin());
@ -773,6 +1249,6 @@ public:
// the default amount of points to keep on stack
constexpr size_t STACK_POINTS_ON_WINDING = MAX_POINTS_ON_WINDING / 4;
using winding_t = winding_base_t<STACK_POINTS_ON_WINDING>;
using winding_t = winding_base_t<winding_storage_heap_t>;
}; // namespace polylib

View File

@ -26,7 +26,7 @@
constexpr size_t PRT_MAX_WINDING_FIXED = 24;
using prtfile_winding_t = polylib::winding_base_t<PRT_MAX_WINDING_FIXED>;
using prtfile_winding_t = polylib::winding_base_t<polylib::winding_storage_hybrid_t<PRT_MAX_WINDING_FIXED>>;
struct prtfile_portal_t
{

View File

@ -23,10 +23,6 @@
#include "common/polylib.hh"
// now much a winding will use on the stack
// before needing an overflow.
constexpr size_t STACK_WINDING_SIZE = 64;
using winding_t = polylib::winding_base_t<STACK_WINDING_SIZE>;
using winding_t = polylib::winding_t;
winding_t BaseWindingForPlane(const qplane3d &p);

View File

@ -39,23 +39,23 @@ enum pstatus_t
pstat_done
};
struct winding_t : polylib::winding_base_t<MAX_WINDING_FIXED>
struct winding_t : polylib::winding_base_t<polylib::winding_storage_hybrid_t<MAX_WINDING_FIXED>>
{
qvec3d origin; // Bounding sphere for fast clipping tests
vec_t radius; // Not updated, so won't shrink when clipping
inline winding_t() : polylib::winding_base_t<MAX_WINDING_FIXED>() { }
inline winding_t() : polylib::winding_base_t<polylib::winding_storage_hybrid_t<MAX_WINDING_FIXED>>() { }
// construct winding from range.
// iterators must have operator+ and operator-.
template<typename Iter, std::enable_if_t<is_iterator_v<Iter>, int> = 0>
inline winding_t(Iter begin, Iter end) : polylib::winding_base_t<MAX_WINDING_FIXED>(begin, end)
inline winding_t(Iter begin, Iter end) : polylib::winding_base_t<polylib::winding_storage_hybrid_t<MAX_WINDING_FIXED>>(begin, end)
{
set_winding_sphere();
}
// initializer list constructor
inline winding_t(std::initializer_list<qvec3d> l) : polylib::winding_base_t<MAX_WINDING_FIXED>(l)
inline winding_t(std::initializer_list<qvec3d> l) : polylib::winding_base_t<polylib::winding_storage_hybrid_t<MAX_WINDING_FIXED>>(l)
{
set_winding_sphere();
}

View File

@ -350,10 +350,10 @@ TEST_CASE("resetContainer", "[settings]")
#include "common/polylib.hh"
struct winding_check_t : polylib::winding_base_t<4>
struct winding_check_t : polylib::winding_base_t<polylib::winding_storage_hybrid_t<4>>
{
public:
inline size_t vector_size() { return vector.size(); }
inline size_t vector_size() { return storage.vector_size(); }
};
TEST_CASE("winding iterators", "[winding_base_t]")
@ -410,7 +410,7 @@ TEST_CASE("winding iterators", "[winding_base_t]")
// check that constructors work
{
polylib::winding_base_t<4> winding_other(winding);
polylib::winding_base_t<polylib::winding_storage_hybrid_t<4>> winding_other(winding);
{
auto it = winding_other.begin();
@ -430,7 +430,7 @@ TEST_CASE("winding iterators", "[winding_base_t]")
{
polylib::winding_base_t<4> winding_other({ { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 }, { 4, 4, 4 } });
polylib::winding_base_t<polylib::winding_storage_hybrid_t<4>> winding_other({ { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 }, { 4, 4, 4 } });
{
auto it = winding_other.begin();
@ -449,7 +449,7 @@ TEST_CASE("winding iterators", "[winding_base_t]")
}
{
polylib::winding_base_t<4> winding_other(std::move(winding));
polylib::winding_base_t<polylib::winding_storage_hybrid_t<4>> winding_other(std::move(winding));
CHECK(winding.size() == 0);
CHECK(winding.begin() == winding.end());

View File

@ -1788,7 +1788,7 @@ TEST_CASE("winding", "[benchmark][.releaseonly]") {
ankerl::nanobench::doNotOptimizeAway(temp);
});
bench.run("polylib::winding_base_t<6> construct", [&] {
polylib::winding_base_t<6> temp;
polylib::winding_base_t<polylib::winding_storage_hybrid_t<6>> temp;
ankerl::nanobench::doNotOptimizeAway(temp);
});
}