summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2023-05-07 01:41:31 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2023-05-07 01:41:31 +0100
commit9ab2aad4aa00afe3373b3a779377fa049459fb4d (patch)
tree18bf013e3be660b0769cd1a601e670eb79355324
parentRename strings.h to something that won't conflict with a system header (diff)
parentTemplated BufferedLocation and single buffer storage for RVC locations (diff)
downloadilt-9ab2aad4aa00afe3373b3a779377fa049459fb4d.tar.bz2
ilt-9ab2aad4aa00afe3373b3a779377fa049459fb4d.tar.xz
ilt-9ab2aad4aa00afe3373b3a779377fa049459fb4d.zip
Merge branch 'containers'
-rw-r--r--game/scenary/foliage.cpp4
-rw-r--r--game/vehicles/railVehicle.cpp11
-rw-r--r--game/vehicles/railVehicle.h12
-rw-r--r--game/vehicles/railVehicleClass.cpp25
-rw-r--r--game/vehicles/railVehicleClass.h8
-rw-r--r--gfx/gl/bufferedLocation.cpp16
-rw-r--r--gfx/gl/bufferedLocation.h32
-rw-r--r--gfx/gl/instanceVertices.h124
-rw-r--r--lib/glContainer.h525
-rw-r--r--lib/pack.h41
-rw-r--r--test/Jamfile.jam2
-rw-r--r--test/test-glContainer.cpp355
-rw-r--r--test/test-instancing.cpp65
-rw-r--r--test/test-pack.cpp41
-rw-r--r--test/test-render.cpp2
15 files changed, 1084 insertions, 179 deletions
diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp
index 9304842..702a52c 100644
--- a/game/scenary/foliage.cpp
+++ b/game/scenary/foliage.cpp
@@ -21,7 +21,7 @@ Foliage::postLoad()
void
Foliage::render(const SceneShader & shader) const
{
- if (const auto count = instances.count()) {
+ if (const auto count = instances.size()) {
shader.basicInst.use();
if (texture) {
texture->bind();
@@ -33,7 +33,7 @@ Foliage::render(const SceneShader & shader) const
void
Foliage::shadows(const ShadowMapper & mapper) const
{
- if (const auto count = instances.count()) {
+ if (const auto count = instances.size()) {
mapper.dynamicPointInst.use();
bodyMesh->DrawInstanced(instanceVAO, static_cast<GLsizei>(count));
}
diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp
index c4a9e96..2d820b6 100644
--- a/game/vehicles/railVehicle.cpp
+++ b/game/vehicles/railVehicle.cpp
@@ -12,13 +12,12 @@
#include <ray.h>
RailVehicle::RailVehicle(RailVehicleClassPtr rvc) :
- rvClass {std::move(rvc)}, location {rvClass->instancesBody}, bogies {
- rvClass->instancesBogies.front(),
- rvClass->instancesBogies.back(),
- }
+ RailVehicleClass::Instance {rvc->instances.acquire()}, rvClass {std::move(rvc)}, location {&LV::body, *this},
+ bogies {{
+ {&LV::front, *this, glm::vec3 {0, rvClass->wheelBase / 2.F, 0}},
+ {&LV::back, *this, glm::vec3 {0, -rvClass->wheelBase / 2.F, 0}},
+ }}
{
- bogies.front().setPosition({0, rvClass->wheelBase / 2.F, 0});
- bogies.back().setPosition({0, -bogies.front().position().y, 0});
}
void
diff --git a/game/vehicles/railVehicle.h b/game/vehicles/railVehicle.h
index 247bf66..f34643e 100644
--- a/game/vehicles/railVehicle.h
+++ b/game/vehicles/railVehicle.h
@@ -8,12 +8,10 @@
#include <memory>
#include <utility>
-class SceneShader;
-class ShadowMapper;
class Ray;
-
class Train;
-class RailVehicle : Selectable {
+
+class RailVehicle : Selectable, RailVehicleClass::Instance {
public:
explicit RailVehicle(RailVehicleClassPtr rvc);
@@ -22,7 +20,9 @@ public:
[[nodiscard]] bool intersectRay(const Ray &, glm::vec2 *, float *) const override;
RailVehicleClassPtr rvClass;
- BufferedLocation location;
- std::array<BufferedLocation, 2> bogies;
+ using LV = RailVehicleClass::LocationVertex;
+ using BLocation = BufferedLocationT<glm::mat4 LV::*, RailVehicleClass::Instance &>;
+ BLocation location;
+ std::array<BLocation, 2> bogies;
};
using RailVehiclePtr = std::unique_ptr<RailVehicle>;
diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp
index 64a21be..324148c 100644
--- a/game/vehicles/railVehicleClass.cpp
+++ b/game/vehicles/railVehicleClass.cpp
@@ -4,6 +4,7 @@
#include "gfx/gl/vertexArrayObject.h"
#include "gfx/models/mesh.h"
#include "gfx/models/texture.h"
+#include "stream_support.h"
#include <algorithm>
#include <array>
#include <cache.h>
@@ -34,38 +35,36 @@ void
RailVehicleClass::postLoad()
{
texture = getTexture();
- bodyMesh->configureVAO(instanceVAO).addAttribs<glm::mat4>(instancesBody.bufferName(), 1);
+ bodyMesh->configureVAO(instanceVAO).addAttribs<LocationVertex, &LocationVertex::body>(instances.bufferName(), 1);
bogies.front()
->configureVAO(instancesBogiesVAO.front())
- .addAttribs<glm::mat4>(instancesBogies.front().bufferName(), 1);
+ .addAttribs<LocationVertex, &LocationVertex::front>(instances.bufferName(), 1);
bogies.back()
->configureVAO(instancesBogiesVAO.back())
- .addAttribs<glm::mat4>(instancesBogies.back().bufferName(), 1);
+ .addAttribs<LocationVertex, &LocationVertex::back>(instances.bufferName(), 1);
}
void
RailVehicleClass::render(const SceneShader & shader) const
{
- if (const auto count = instancesBody.count()) {
+ if (const auto count = static_cast<GLsizei>(instances.size())) {
if (texture) {
texture->bind();
}
shader.basicInst.use();
- bodyMesh->DrawInstanced(instanceVAO, static_cast<GLsizei>(count));
- bogies.front()->DrawInstanced(
- instancesBogiesVAO.front(), static_cast<GLsizei>(instancesBogies.front().count()));
- bogies.back()->DrawInstanced(instancesBogiesVAO.back(), static_cast<GLsizei>(instancesBogies.back().count()));
+ bodyMesh->DrawInstanced(instanceVAO, count);
+ bogies.front()->DrawInstanced(instancesBogiesVAO.front(), count);
+ bogies.back()->DrawInstanced(instancesBogiesVAO.back(), count);
}
}
void
RailVehicleClass::shadows(const ShadowMapper & mapper) const
{
- if (const auto count = instancesBody.count()) {
+ if (const auto count = static_cast<GLsizei>(instances.size())) {
mapper.dynamicPointInst.use();
- bodyMesh->DrawInstanced(instanceVAO, static_cast<GLsizei>(count));
- bogies.front()->DrawInstanced(
- instancesBogiesVAO.front(), static_cast<GLsizei>(instancesBogies.front().count()));
- bogies.back()->DrawInstanced(instancesBogiesVAO.back(), static_cast<GLsizei>(instancesBogies.back().count()));
+ bodyMesh->DrawInstanced(instanceVAO, count);
+ bogies.front()->DrawInstanced(instanceVAO, count);
+ bogies.back()->DrawInstanced(instanceVAO, count);
}
}
diff --git a/game/vehicles/railVehicleClass.h b/game/vehicles/railVehicleClass.h
index 2fda8f7..80b3fda 100644
--- a/game/vehicles/railVehicleClass.h
+++ b/game/vehicles/railVehicleClass.h
@@ -18,6 +18,10 @@ public:
void render(const SceneShader & shader) const override;
void shadows(const ShadowMapper & shadowMapper) const override;
+ struct LocationVertex {
+ glm::mat4 body, front, back;
+ };
+
std::array<Mesh::Ptr, 2> bogies;
Mesh::Ptr bodyMesh;
std::shared_ptr<Texture> texture;
@@ -25,8 +29,8 @@ public:
float length;
float maxSpeed;
- mutable InstanceVertices<glm::mat4> instancesBody;
- mutable std::array<InstanceVertices<glm::mat4>, 2> instancesBogies;
+ mutable InstanceVertices<LocationVertex> instances;
+ using Instance = decltype(instances)::InstanceProxy;
protected:
friend Persistence::SelectionPtrBase<std::shared_ptr<RailVehicleClass>>;
diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp
index 7027b4c..eb3dac3 100644
--- a/gfx/gl/bufferedLocation.cpp
+++ b/gfx/gl/bufferedLocation.cpp
@@ -3,15 +3,9 @@
#include "maths.h"
#include <glm/gtx/transform.hpp>
-BufferedLocation::BufferedLocation(InstanceVertices<glm::mat4> & i, glm::vec3 p, glm::vec3 r) :
- BufferedLocation {i, Location {p, r}}
-{
-}
+BufferedLocation::BufferedLocation(glm::vec3 p, glm::vec3 r) : BufferedLocation {Location {p, r}} { }
-BufferedLocation::BufferedLocation(InstanceVertices<glm::mat4> & i, const Location & l) :
- loc {l}, buffer {i.acquire(getTransform())}
-{
-}
+BufferedLocation::BufferedLocation(const Location & l) : loc {l} { }
BufferedLocation::operator const Location &() const
{
@@ -64,12 +58,6 @@ BufferedLocation::setLocation(glm::vec3 p, glm::vec3 r)
updateBuffer();
}
-void
-BufferedLocation::updateBuffer()
-{
- buffer = getTransform();
-}
-
glm::mat4
BufferedLocation::getTransform() const
{
diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h
index 6d148cd..8096489 100644
--- a/gfx/gl/bufferedLocation.h
+++ b/gfx/gl/bufferedLocation.h
@@ -1,14 +1,16 @@
#pragma once
-#include "instanceVertices.h"
#include "location.h"
+#include <functional>
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
+#include <tuple>
class BufferedLocation {
public:
- BufferedLocation(InstanceVertices<glm::mat4> &, glm::vec3 = {}, glm::vec3 = {});
- BufferedLocation(InstanceVertices<glm::mat4> &, const Location &);
+ BufferedLocation(glm::vec3 = {}, glm::vec3 = {});
+ BufferedLocation(const Location &);
+ virtual ~BufferedLocation() = default;
BufferedLocation & operator=(const Location &);
@@ -23,8 +25,28 @@ public:
glm::mat4 getTransform() const;
private:
- void updateBuffer();
+ virtual void updateBuffer() = 0;
Location loc;
- InstanceVertices<glm::mat4>::InstanceProxy buffer;
+};
+
+template<typename... Target> class BufferedLocationT : public BufferedLocation {
+public:
+ template<typename... LocationArgs>
+ BufferedLocationT(Target &&... target, LocationArgs &&... t) :
+ BufferedLocation {std::forward<LocationArgs>(t)...}, target {std::forward<Target>(target)...}
+ {
+ updateBuffer();
+ }
+
+ using BufferedLocation::operator=;
+
+private:
+ void
+ updateBuffer() override
+ {
+ std::apply(std::invoke<const Target &...>, target) = getTransform();
+ }
+
+ std::tuple<Target...> target;
};
diff --git a/gfx/gl/instanceVertices.h b/gfx/gl/instanceVertices.h
index 9df6e12..7b0341b 100644
--- a/gfx/gl/instanceVertices.h
+++ b/gfx/gl/instanceVertices.h
@@ -1,20 +1,15 @@
#pragma once
-#include "glArrays.h"
+#include "glContainer.h"
+#include "pack.h"
#include <cassert>
-#include <iterator>
-#include <span>
#include <special_members.h>
#include <utility>
-#include <vector>
-template<typename T> class InstanceVertices {
-public:
- InstanceVertices(size_t initialSize = 16)
- {
- allocBuffer(initialSize);
- }
+template<typename T> class InstanceVertices : protected glContainer<T> {
+ using base = glContainer<T>;
+public:
class [[nodiscard]] InstanceProxy {
public:
InstanceProxy(InstanceVertices * iv, std::size_t idx) : instances {iv}, index {idx} { }
@@ -44,27 +39,27 @@ public:
T &
operator=(U && v)
{
- return instances->at(index) = std::forward<U>(v);
+ return instances->lookup(index) = std::forward<U>(v);
}
[[nodiscard]]
operator T &()
{
- return instances->at(index);
+ return instances->lookup(index);
}
[[nodiscard]] operator const T &() const
{
- return instances->at(index);
+ return instances->lookup(index);
}
[[nodiscard]] T *
get()
{
- return &instances->at(index);
+ return &instances->lookup(index);
}
[[nodiscard]] const T *
get() const
{
- return &instances->at(index);
+ return &instances->lookup(index);
}
[[nodiscard]] T *
operator->()
@@ -79,12 +74,12 @@ public:
[[nodiscard]] T &
operator*()
{
- return instances->at(index);
+ return instances->lookup(index);
}
[[nodiscard]] const T &
operator*() const
{
- return instances->at(index);
+ return instances->lookup(index);
}
private:
@@ -96,33 +91,25 @@ public:
[[nodiscard]] InstanceProxy
acquire(Params &&... params)
{
- map();
if (!unused.empty()) {
auto idx = unused.back();
unused.pop_back();
- index[idx] = next++;
- new (&at(idx)) T(std::forward<Params>(params)...);
+ index[idx] = base::size();
+ base::emplace_back(std::forward<Params>(params)...);
return InstanceProxy {this, idx};
}
- if (next >= capacity) {
- resize(capacity * 2);
- }
- index.emplace_back(next++);
- new (data + index.back()) T(std::forward<Params>(params)...);
+ index.emplace_back(base::size());
+ base::emplace_back(std::forward<Params>(params)...);
return InstanceProxy {this, index.size() - 1};
}
- [[nodiscard]] const auto &
- bufferName() const
- {
- return buffer;
- }
+ using base::bufferName;
[[nodiscard]] auto
- count() const
+ size() const
{
- unmap();
- return next;
+ base::unmap();
+ return base::size();
}
protected:
@@ -131,16 +118,13 @@ protected:
void
release(const size_t pidx)
{
- // Destroy p's object
- at(pidx).~T();
- if (--next != index[pidx]) {
- // Move last object into p's slot
- new (&at(pidx)) T {std::move(data[next])};
- (data[next]).~T();
- *std::find_if(index.begin(), index.end(), [this](const auto & i) {
- return i == next && !std::binary_search(unused.begin(), unused.end(), &i - index.data());
+ if (base::size() - 1 != index[pidx]) {
+ lookup(pidx) = std::move(base::back());
+ *std::find_if(index.begin(), index.end(), [this, old = base::size() - 1](const auto & i) {
+ return i == old && !std::binary_search(unused.begin(), unused.end(), &i - index.data());
}) = index[pidx];
}
+ base::pop_back();
if (pidx == index.size() - 1) {
index.pop_back();
}
@@ -150,64 +134,14 @@ protected:
}
}
- void
- allocBuffer(std::size_t newCapacity)
- {
- glBindBuffer(GL_ARRAY_BUFFER, buffer);
- glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(T) * newCapacity), nullptr, GL_DYNAMIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- capacity = newCapacity;
- data = nullptr;
- }
-
- void
- resize(size_t newCapacity)
- {
- const auto maintain = std::min(newCapacity, capacity);
- std::vector<T> existing;
- const auto maintaind = static_cast<typename decltype(existing)::difference_type>(maintain);
- existing.reserve(maintain);
- map();
- std::move(data, data + maintain, std::back_inserter(existing));
- allocBuffer(newCapacity);
- map();
- std::move(existing.begin(), existing.begin() + maintaind, data);
- capacity = newCapacity;
- }
-
[[nodiscard]] T &
- at(size_t pindex)
- {
- map();
- return data[index[pindex]];
- }
-
- void
- map() const
+ lookup(size_t pindex)
{
- if (!data) {
- data = static_cast<T *>(glMapNamedBuffer(buffer, GL_READ_WRITE));
- assert(data);
- }
- }
-
- void
- unmap() const
- {
- if (data) {
- glUnmapNamedBuffer(buffer);
- data = nullptr;
- }
+ return base::data()[index[pindex]];
}
- glBuffer buffer;
- mutable T * data {};
- // Size of buffer
- std::size_t capacity {};
- // # used of capacity
- std::size_t next {};
- // Index into buffer given to nth proxy
+ // Index into buffer given to nth proxy
std::vector<size_t> index;
- // List of free spaces in index
+ // List of free spaces in index
std::vector<size_t> unused;
};
diff --git a/lib/glContainer.h b/lib/glContainer.h
new file mode 100644
index 0000000..993170e
--- /dev/null
+++ b/lib/glContainer.h
@@ -0,0 +1,525 @@
+#pragma once
+
+#include "glArrays.h"
+#include <cassert>
+#include <stdexcept>
+#include <utility>
+#include <vector>
+
+template<typename I, typename Direction> class basic_glContainer_iterator {
+public:
+ explicit basic_glContainer_iterator(I * i) : i {i} { }
+ template<typename OtherI>
+ basic_glContainer_iterator(const basic_glContainer_iterator<OtherI, Direction> & other) : i {&*other}
+ {
+ }
+
+ auto &
+ operator++() noexcept
+ {
+ i = Direction {}(i, 1);
+ return *this;
+ }
+ auto
+ operator++(int) noexcept
+ {
+ return basic_glContainer_iterator<I, Direction> {std::exchange(i, Direction {}(i, 1))};
+ }
+ auto &
+ operator--() noexcept
+ {
+ i = Direction {}(i, -1);
+ return *this;
+ }
+ auto
+ operator--(int) noexcept
+ {
+ return basic_glContainer_iterator<I, Direction> {std::exchange(i, Direction {}(i, -1))};
+ }
+
+ [[nodiscard]] auto
+ operator-(const basic_glContainer_iterator & other) const noexcept
+ {
+ if constexpr (std::is_same_v<Direction, std::plus<>>) {
+ return this->i - other.i;
+ }
+ else {
+ return other.i - this->i;
+ }
+ }
+
+ [[nodiscard]] auto
+ operator<(const basic_glContainer_iterator & other) const noexcept
+ {
+ if constexpr (std::is_same_v<Direction, std::plus<>>) {
+ return this->i < other.i;
+ }
+ else {
+ return other.i < this->i;
+ }
+ }
+
+ auto
+ operator+(std::integral auto n) const noexcept
+ {
+ return basic_glContainer_iterator<I, Direction> {Direction {}(i, n)};
+ }
+
+ auto
+ operator-(std::integral auto n) const noexcept
+ {
+ return basic_glContainer_iterator<I, Direction> {Direction {}(i, -n)};
+ }
+
+ [[nodiscard]] bool
+ operator==(const basic_glContainer_iterator & other) const noexcept
+ {
+ return this->i == other.i;
+ }
+ [[nodiscard]] bool
+ operator!=(const basic_glContainer_iterator & other) const noexcept
+ {
+ return this->i != other.i;
+ }
+
+ [[nodiscard]] auto
+ operator->() const noexcept
+ {
+ return i;
+ }
+ [[nodiscard]] auto &
+ operator*() const noexcept
+ {
+ return *i;
+ }
+
+private:
+ I * i;
+};
+
+template<typename T> class glContainer {
+public:
+ using value_type = T;
+ using reference_type = T &;
+ using const_reference_type = const T &;
+ using pointer_type = T *;
+ using const_pointer_type = const T *;
+ using size_type = std::size_t;
+ using iterator = basic_glContainer_iterator<value_type, std::plus<>>;
+ using const_iterator = basic_glContainer_iterator<const value_type, std::plus<>>;
+ using reserve_iterator = basic_glContainer_iterator<value_type, std::minus<>>;
+ using const_reserve_iterator = basic_glContainer_iterator<const value_type, std::minus<>>;
+ static constexpr bool is_trivial_dest = std::is_trivially_destructible_v<T>;
+
+ glContainer()
+ {
+ allocBuffer(1);
+ }
+
+ ~glContainer() noexcept(is_trivial_dest)
+ {
+ if constexpr (!is_trivial_dest) {
+ clear();
+ }
+ }
+
+ [[nodiscard]] iterator
+ begin()
+ {
+ map();
+ return iterator {data_};
+ }
+
+ [[nodiscard]] iterator
+ end()
+ {
+ map();
+ return iterator {data_ + size_};
+ }
+
+ [[nodiscard]] const_iterator
+ begin() const
+ {
+ map();
+ return const_iterator {data_};
+ }
+
+ [[nodiscard]] const_iterator
+ end() const
+ {
+ map();
+ return const_iterator {data_ + size_};
+ }
+
+ [[nodiscard]] const_iterator
+ cbegin() const
+ {
+ map();
+ return const_iterator {data_};
+ }
+
+ [[nodiscard]] const_iterator
+ cend() const
+ {
+ map();
+ return const_iterator {data_ + size_};
+ }
+
+ [[nodiscard]] reserve_iterator
+ rbegin()
+ {
+ map();
+ return reserve_iterator {data_ + size_ - 1};
+ }
+
+ [[nodiscard]] reserve_iterator
+ rend()
+ {
+ map();
+ return reserve_iterator {data_ - 1};
+ }
+
+ [[nodiscard]] const_reserve_iterator
+ rbegin() const
+ {
+ map();
+ return const_reserve_iterator {data_ + size_ - 1};
+ }
+
+ [[nodiscard]] const_reserve_iterator
+ rend() const
+ {
+ map();
+ return const_reserve_iterator {data_ - 1};
+ }
+
+ [[nodiscard]] const_reserve_iterator
+ crbegin() const
+ {
+ map();
+ return const_reserve_iterator {data_ + size_ - 1};
+ }
+
+ [[nodiscard]] const_reserve_iterator
+ crend() const
+ {
+ map();
+ return const_reserve_iterator {data_ - 1};
+ }
+
+ [[nodiscard]] const auto &
+ bufferName() const
+ {
+ return buffer_;
+ }
+
+ [[nodiscard]] size_type
+ size() const
+ {
+ return size_;
+ }
+
+ [[nodiscard]] reference_type
+ at(size_type pos)
+ {
+ if (pos >= size()) {
+ throw std::out_of_range {__FUNCTION__};
+ }
+ map();
+ return data_[pos];
+ }
+
+ [[nodiscard]] const_reference_type
+ at(size_type pos) const
+ {
+ if (pos >= size()) {
+ throw std::out_of_range {__FUNCTION__};
+ }
+ map();
+ return data_[pos];
+ }
+
+ [[nodiscard]] reference_type
+ operator[](size_type pos)
+ {
+ map();
+ return data_[pos];
+ }
+
+ [[nodiscard]] const_reference_type
+ operator[](size_type pos) const
+ {
+ map();
+ return data_[pos];
+ }
+
+ [[nodiscard]] pointer_type
+ data()
+ {
+ map();
+ return data_;
+ }
+
+ [[nodiscard]] const_pointer_type
+ data() const
+ {
+ map();
+ return data_;
+ }
+
+ [[nodiscard]] reference_type
+ front()
+ {
+ map();
+ return *data_;
+ }
+
+ [[nodiscard]] reference_type
+ back()
+ {
+ map();
+ return *(data_ + size_ - 1);
+ }
+
+ [[nodiscard]] const_reference_type
+ front() const
+ {
+ map();
+ return *data_;
+ }
+
+ [[nodiscard]] const_reference_type
+ back() const
+ {
+ map();
+ return *(data_ + size_ - 1);
+ }
+
+ [[nodiscard]] bool
+ empty() const
+ {
+ return !size();
+ }
+
+ [[nodiscard]] size_type
+ capacity() const
+ {
+ return capacity_;
+ }
+
+ void
+ unmap() const
+ {
+ if (data_) {
+ glUnmapNamedBuffer(buffer_);
+ data_ = nullptr;
+ }
+ }
+
+ void
+ reserve(size_type newCapacity)
+ {
+ if (newCapacity <= capacity_) {
+ return;
+ }
+ newCapacity = std::max(newCapacity, capacity_ * 2);
+
+ std::vector<T> existing;
+ existing.reserve(size_);
+ map();
+ std::move(begin(), end(), std::back_inserter(existing));
+ allocBuffer(newCapacity);
+ map();
+ std::move(existing.begin(), existing.end(), begin());
+ }
+
+ void
+ resize(size_type newSize)
+ {
+ if (newSize == size_) {
+ return;
+ }
+
+ if (const auto maintain = std::min(newSize, size_)) {
+ std::vector<T> existing;
+ const auto maintaind = static_cast<typename decltype(existing)::difference_type>(maintain);
+ existing.reserve(maintain);
+ map();
+ std::move(data_, data_ + maintain, std::back_inserter(existing));
+ if constexpr (!is_trivial_dest) {
+ for (auto uninitialised = data_ + newSize; uninitialised < data_ + size_; ++uninitialised) {
+ uninitialised->~T();
+ }
+ }
+ allocBuffer(newSize);
+ mapForAdd();
+ std::move(existing.begin(), existing.begin() + maintaind, data_);
+ }
+ else {
+ allocBuffer(newSize);
+ mapForAdd();
+ }
+ for (auto uninitialised = data_ + size_; uninitialised < data_ + newSize; ++uninitialised) {
+ new (uninitialised) T {};
+ }
+ size_ = newSize;
+ }
+
+ void
+ shrink_to_fit()
+ {
+ if (capacity_ <= size_) {
+ return;
+ }
+
+ std::vector<T> existing;
+ existing.reserve(size_);
+ map();
+ std::move(begin(), end(), std::back_inserter(existing));
+ allocBuffer(size_);
+ map();
+ std::move(existing.begin(), existing.end(), begin());
+ }
+
+ void
+ clear() noexcept(is_trivial_dest)
+ {
+ if constexpr (!is_trivial_dest) {
+ map();
+ std::for_each(begin(), end(), [](auto && v) {
+ v.~T();
+ });
+ }
+ size_ = 0;
+ }
+
+ template<typename... P>
+ reference_type
+ emplace_back(P &&... ps)
+ {
+ auto newSize = size_ + 1;
+ reserve(newSize);
+ mapForAdd();
+ new (data_ + size_) T {std::forward<P>(ps)...};
+ size_ = newSize;
+ return back();
+ }
+
+ template<typename... P>
+ iterator
+ emplace(iterator pos, P &&... ps)
+ {
+ static_assert(std::is_nothrow_constructible_v<T, P...>);
+ auto newSize = size_ + 1;
+ const auto idx = pos - begin();
+ reserve(newSize);
+ mapForAdd();
+ std::move_backward(begin() + idx, end(), end() + 1);
+ (data_ + idx)->~T();
+ new (data_ + idx) T {std::forward<P>(ps)...};
+ size_ = newSize;
+ return pos;
+ }
+
+ reference_type
+ push_back(T p)
+ {
+ auto newSize = size_ + 1;
+ reserve(newSize);
+ mapForAdd();
+ new (data_ + size_) T {std::move(p)};
+ size_ = newSize;
+ return back();
+ }
+
+ iterator
+ insert(iterator pos, T p)
+ {
+ static_assert(std::is_nothrow_move_constructible_v<T>);
+ auto newSize = size_ + 1;
+ const auto idx = pos - begin();
+ reserve(newSize);
+ mapForAdd();
+ std::move_backward(begin() + idx, end(), end() + 1);
+ (data_ + idx)->~T();
+ new (data_ + idx) T {std::move(p)};
+ size_ = newSize;
+ return pos;
+ }
+
+ void
+ pop_back()
+ {
+ if constexpr (!is_trivial_dest) {
+ map();
+ data_[--size_].~T();
+ }
+ else {
+ --size_;
+ }
+ }
+
+ void
+ erase(iterator pos)
+ {
+ erase(pos, pos + 1);
+ }
+
+ void
+ erase(iterator pos, iterator to)
+ {
+ const auto eraseSize = to - pos;
+ map();
+ std::move(to, end(), pos);
+ if constexpr (!is_trivial_dest) {
+ std::for_each(end() - eraseSize, end(), [](auto && v) {
+ v.~T();
+ });
+ }
+ size_ -= static_cast<size_type>(eraseSize);
+ }
+
+protected:
+ void
+ allocBuffer(size_type newCapacity)
+ {
+ if (newCapacity == 0) {
+ return allocBuffer(1);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, buffer_);
+ glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(T) * newCapacity), nullptr, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ capacity_ = newCapacity;
+ data_ = nullptr;
+ }
+
+ void
+ map() const
+ {
+ if (size_ > 0) {
+ mapForAdd();
+ }
+ }
+
+ void
+ mapForAdd() const
+ {
+ if (!data_) {
+ data_ = static_cast<T *>(glMapNamedBuffer(buffer_, GL_READ_WRITE));
+ assert(data_);
+ }
+ }
+
+ glBuffer buffer_;
+ std::size_t capacity_ {};
+ std::size_t size_ {};
+ mutable T * data_ {};
+};
+
+template<typename T, typename D> struct std::iterator_traits<basic_glContainer_iterator<T, D>> {
+ using difference_type = ssize_t;
+ using value_type = T;
+ using pointer = T *;
+ using reference = T &;
+ using iterator_category = std::random_access_iterator_tag;
+};
diff --git a/lib/pack.h b/lib/pack.h
new file mode 100644
index 0000000..e63d7cc
--- /dev/null
+++ b/lib/pack.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <utility>
+
+template<typename T, template<typename... S> typename Container> class pack : protected Container<T> {
+public:
+ using Container<T>::Container;
+
+ using Container<T>::begin;
+ using Container<T>::end;
+ using Container<T>::rbegin;
+ using Container<T>::rend;
+ using Container<T>::cbegin;
+ using Container<T>::cend;
+ using Container<T>::crbegin;
+ using Container<T>::crend;
+ using Container<T>::clear;
+ using Container<T>::empty;
+ using Container<T>::size;
+ using Container<T>::capacity;
+ using Container<T>::shrink_to_fit;
+ using Container<T>::at;
+ using Container<T>::data;
+ using Container<T>::operator[];
+
+ template<typename... Ps>
+ decltype(auto)
+ emplace(Ps &&... ps)
+ {
+ return Container<T>::emplace_back(std::forward<Ps>(ps)...);
+ }
+
+ void
+ erase(typename Container<T>::iterator pos)
+ {
+ if (&*pos != &Container<T>::back()) {
+ *pos = std::move(Container<T>::back());
+ }
+ Container<T>::pop_back();
+ }
+};
diff --git a/test/Jamfile.jam b/test/Jamfile.jam
index 1ce73b7..3b4e891 100644
--- a/test/Jamfile.jam
+++ b/test/Jamfile.jam
@@ -58,6 +58,8 @@ run perf-assetFactory.cpp : -- : test-assetFactory : <library>benchmark <library
run perf-persistence.cpp : -- : test-persistence : <library>benchmark <library>test ;
run test-worker.cpp ;
run test-instancing.cpp : : : <library>test ;
+run test-glContainer.cpp : : : <library>test ;
+run test-pack.cpp : : : <library>test ;
compile test-static-enumDetails.cpp ;
compile test-static-stream_support.cpp ;
explicit perf-assetFactory ;
diff --git a/test/test-glContainer.cpp b/test/test-glContainer.cpp
new file mode 100644
index 0000000..33ec992
--- /dev/null
+++ b/test/test-glContainer.cpp
@@ -0,0 +1,355 @@
+#define BOOST_TEST_MODULE glContainer
+
+#include "testHelpers.h"
+#include "testMainWindow.h"
+#include "ui/applicationBase.h"
+#include <boost/test/data/test_case.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include "glContainer.h"
+
+BOOST_TEST_DONT_PRINT_LOG_VALUE(glContainer<int>::iterator);
+BOOST_TEST_DONT_PRINT_LOG_VALUE(glContainer<int>::const_iterator);
+BOOST_TEST_DONT_PRINT_LOG_VALUE(glContainer<int>::reserve_iterator);
+BOOST_TEST_DONT_PRINT_LOG_VALUE(glContainer<int>::const_reserve_iterator);
+
+BOOST_GLOBAL_FIXTURE(ApplicationBase);
+BOOST_GLOBAL_FIXTURE(TestMainWindow);
+
+BOOST_FIXTURE_TEST_SUITE(i, glContainer<int>)
+
+BOOST_AUTO_TEST_CASE(createDestroy, *boost::unit_test::timeout(1))
+{
+ BOOST_CHECK(!data_);
+ BOOST_CHECK_NO_THROW(map());
+ BOOST_REQUIRE(!data_);
+ BOOST_CHECK_NO_THROW(emplace_back(0));
+ BOOST_CHECK_NO_THROW(map());
+ BOOST_REQUIRE(data_);
+ BOOST_CHECK_NO_THROW(unmap());
+ BOOST_CHECK(!data_);
+}
+
+BOOST_AUTO_TEST_CASE(push_back_test, *boost::unit_test::timeout(1))
+{
+ BOOST_CHECK_EQUAL(capacity_, 1);
+ BOOST_CHECK_EQUAL(size_, 0);
+ BOOST_CHECK_NO_THROW(push_back(1));
+ BOOST_CHECK_NO_THROW(push_back(2));
+ BOOST_CHECK_NO_THROW(push_back(3));
+ BOOST_CHECK_NO_THROW(push_back(4));
+ BOOST_CHECK_EQUAL(capacity_, 4);
+ BOOST_CHECK_EQUAL(size_, 4);
+ {
+ std::array expected1 {1, 2, 3, 4};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ BOOST_CHECK_EQUAL_COLLECTIONS(rbegin(), rend(), expected1.rbegin(), expected1.rend());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(emplace_back_test, *boost::unit_test::timeout(1))
+{
+ BOOST_CHECK_EQUAL(capacity_, 1);
+ BOOST_CHECK_EQUAL(size_, 0);
+
+ BOOST_CHECK_NO_THROW(emplace_back(1));
+ BOOST_CHECK_NO_THROW(emplace_back(2));
+ BOOST_CHECK_EQUAL(capacity_, 2);
+ BOOST_CHECK_EQUAL(size_, 2);
+
+ BOOST_CHECK_NO_THROW(reserve(5));
+ BOOST_CHECK_EQUAL(capacity_, 5);
+ BOOST_CHECK_EQUAL(size_, 2);
+
+ BOOST_CHECK_NO_THROW(emplace_back(3));
+ BOOST_CHECK_NO_THROW(emplace_back(4));
+ BOOST_CHECK_EQUAL(capacity_, 5);
+ BOOST_CHECK_EQUAL(size_, 4);
+
+ {
+ std::array expected1 {1, 2, 3, 4};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ BOOST_CHECK_EQUAL_COLLECTIONS(rbegin(), rend(), expected1.rbegin(), expected1.rend());
+ }
+
+ BOOST_CHECK_NO_THROW(emplace_back(5));
+ BOOST_CHECK_EQUAL(capacity_, 5);
+ BOOST_CHECK_EQUAL(size_, 5);
+ BOOST_CHECK_NO_THROW(emplace_back(6));
+ BOOST_CHECK_NO_THROW(emplace_back(7));
+ BOOST_CHECK_EQUAL(capacity_, 10);
+ BOOST_CHECK_EQUAL(size_, 7);
+
+ {
+ std::array expected2 {1, 2, 3, 4, 5, 6, 7};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected2.begin(), expected2.end());
+ BOOST_CHECK_EQUAL_COLLECTIONS(rbegin(), rend(), expected2.rbegin(), expected2.rend());
+ }
+
+ BOOST_CHECK_EQUAL(7, end() - begin());
+ BOOST_CHECK_EQUAL(7, rend() - rbegin());
+}
+
+BOOST_AUTO_TEST_CASE(resize_test)
+{
+ BOOST_CHECK_NO_THROW(push_back(1));
+ BOOST_CHECK_NO_THROW(emplace_back(2));
+ BOOST_CHECK_NO_THROW(resize(4));
+ BOOST_CHECK_EQUAL(capacity_, 4);
+ BOOST_CHECK_EQUAL(size_, 4);
+ {
+ std::array expected1 {1, 2, 0, 0};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+
+ BOOST_CHECK_NO_THROW(resize(1));
+ BOOST_CHECK_EQUAL(capacity_, 1);
+ BOOST_CHECK_EQUAL(size_, 1);
+ {
+ std::array expected2 {1};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected2.begin(), expected2.end());
+ }
+
+ BOOST_CHECK_NO_THROW(resize(1));
+ BOOST_CHECK_EQUAL(capacity_, 1);
+ BOOST_CHECK_EQUAL(size_, 1);
+
+ BOOST_CHECK_NO_THROW(resize(0));
+ BOOST_CHECK_EQUAL(capacity_, 1);
+ BOOST_CHECK_EQUAL(size_, 0);
+ BOOST_CHECK_EQUAL(begin(), end());
+ BOOST_CHECK_EQUAL(rbegin(), rend());
+}
+
+BOOST_AUTO_TEST_CASE(shrink_to_fit_test)
+{
+ BOOST_CHECK_NO_THROW(reserve(4));
+ BOOST_CHECK_NO_THROW(emplace_back(1));
+ BOOST_CHECK_NO_THROW(emplace_back(2));
+ BOOST_CHECK_EQUAL(capacity_, 4);
+ BOOST_CHECK_EQUAL(size_, 2);
+ {
+ std::array expected1 {1, 2};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+ BOOST_CHECK_NO_THROW(shrink_to_fit());
+ BOOST_CHECK_EQUAL(capacity_, 2);
+ BOOST_CHECK_EQUAL(size_, 2);
+ {
+ std::array expected1 {1, 2};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+
+ BOOST_CHECK_NO_THROW(shrink_to_fit());
+ BOOST_CHECK_EQUAL(capacity(), 2);
+ BOOST_CHECK_EQUAL(size(), 2);
+
+ BOOST_CHECK_NO_THROW(clear());
+ BOOST_CHECK_EQUAL(capacity(), 2);
+ BOOST_CHECK_EQUAL(size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(getters)
+{
+ BOOST_CHECK(empty());
+ BOOST_CHECK_NO_THROW(emplace_back(1));
+ BOOST_CHECK(!empty());
+ BOOST_CHECK_NO_THROW(emplace_back(2));
+ BOOST_CHECK_EQUAL(1, front());
+ BOOST_CHECK_EQUAL(2, back());
+ BOOST_CHECK_EQUAL(1, at(0));
+ BOOST_CHECK_EQUAL(2, at(1));
+ BOOST_CHECK_EQUAL(1, (*this)[0]);
+ BOOST_CHECK_EQUAL(2, (*this)[1]);
+ BOOST_CHECK_EQUAL(data_, data());
+ BOOST_CHECK_THROW(std::ignore = at(2), std::out_of_range);
+
+ const auto & constCont {*this};
+ BOOST_CHECK_EQUAL(1, constCont.front());
+ BOOST_CHECK_EQUAL(2, constCont.back());
+ {
+ std::array expected1 {1, 2};
+ BOOST_CHECK_EQUAL_COLLECTIONS(constCont.begin(), constCont.end(), expected1.begin(), expected1.end());
+ BOOST_CHECK_EQUAL_COLLECTIONS(constCont.rbegin(), constCont.rend(), expected1.rbegin(), expected1.rend());
+ BOOST_CHECK_EQUAL_COLLECTIONS(constCont.cbegin(), constCont.cend(), expected1.cbegin(), expected1.cend());
+ BOOST_CHECK_EQUAL_COLLECTIONS(constCont.crbegin(), constCont.crend(), expected1.crbegin(), expected1.crend());
+ }
+ BOOST_CHECK_EQUAL(1, constCont.at(0));
+ BOOST_CHECK_EQUAL(2, constCont.at(1));
+ BOOST_CHECK_EQUAL(1, constCont[0]);
+ BOOST_CHECK_EQUAL(2, constCont[1]);
+ BOOST_CHECK_EQUAL(data_, constCont.data());
+ BOOST_CHECK_THROW(std::ignore = constCont.at(2), std::out_of_range);
+}
+
+BOOST_AUTO_TEST_CASE(random_access)
+{
+ BOOST_CHECK_NO_THROW(emplace_back(1));
+ BOOST_CHECK_NO_THROW(emplace_back(2));
+ BOOST_CHECK_NO_THROW(emplace_back(3));
+
+ auto i = begin();
+ BOOST_CHECK_EQUAL(1, *i);
+ BOOST_CHECK_EQUAL(2, *++i);
+ BOOST_CHECK_EQUAL(2, *i++);
+ BOOST_CHECK_EQUAL(3, *i);
+ BOOST_CHECK_EQUAL(3, *i--);
+ BOOST_CHECK_EQUAL(2, *i);
+ BOOST_CHECK_EQUAL(1, *--i);
+ BOOST_CHECK_EQUAL(1, *i);
+}
+
+BOOST_AUTO_TEST_CASE(insert_remove_test)
+{
+ BOOST_CHECK_NO_THROW(emplace_back(1));
+ BOOST_CHECK_NO_THROW(emplace_back(2));
+ BOOST_CHECK_NO_THROW(emplace_back(3));
+ BOOST_CHECK_NO_THROW(emplace_back(4));
+ BOOST_CHECK_NO_THROW(pop_back());
+ BOOST_CHECK_EQUAL(size_, 3);
+ BOOST_CHECK_EQUAL(capacity_, 4);
+
+ BOOST_CHECK_NO_THROW(emplace(begin(), 5));
+ BOOST_CHECK_EQUAL(size_, 4);
+ BOOST_CHECK_EQUAL(capacity_, 4);
+ {
+ std::array expected1 {5, 1, 2, 3};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+
+ {
+ std::array expected1 {2, 3};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin() + 2, end(), expected1.begin(), expected1.end());
+ }
+ BOOST_CHECK_NO_THROW(insert(begin() + 2, 6));
+ BOOST_CHECK_EQUAL(size_, 5);
+ BOOST_CHECK_EQUAL(capacity_, 8);
+ {
+ std::array expected1 {5, 1, 6, 2, 3};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+ erase(begin() + 1);
+ BOOST_CHECK_EQUAL(size_, 4);
+ BOOST_CHECK_EQUAL(capacity_, 8);
+ {
+ std::array expected1 {5, 6, 2, 3};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+ erase(begin() + 1, end() - 1);
+ BOOST_CHECK_EQUAL(size_, 2);
+ BOOST_CHECK_EQUAL(capacity_, 8);
+ {
+ std::array expected1 {5, 3};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(stl)
+{
+ BOOST_CHECK_NO_THROW(resize(10));
+ BOOST_CHECK_NO_THROW(std::generate(begin(), end(), [x = 0]() mutable {
+ return x++;
+ }));
+ BOOST_CHECK_NO_THROW(std::sort(rbegin(), rend()));
+ {
+ std::array expected1 {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+ const auto newend = std::remove_if(begin(), end(), [](const auto & x) {
+ return x % 2 == 0;
+ });
+ {
+ std::array expected1 {9, 7, 5, 3, 1};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), newend, expected1.begin(), expected1.end());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(iter_compare)
+{
+ BOOST_CHECK_EQUAL(begin(), end());
+ BOOST_CHECK_EQUAL(rbegin(), rend());
+ emplace_back();
+ BOOST_CHECK_LT(begin(), end());
+ BOOST_CHECK_LT(rbegin(), rend());
+ BOOST_CHECK_LT(cbegin(), cend());
+ BOOST_CHECK_LT(crbegin(), crend());
+}
+
+BOOST_AUTO_TEST_SUITE_END();
+
+struct C {
+ int x;
+ float y;
+};
+static_assert(std::is_trivially_destructible_v<C>);
+
+BOOST_FIXTURE_TEST_SUITE(c, glContainer<C>)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+ BOOST_CHECK_NO_THROW(emplace_back(1, 2.f));
+ BOOST_CHECK_EQUAL(1, begin()->x);
+ BOOST_CHECK_EQUAL(2.f, begin()->y);
+ BOOST_CHECK_NO_THROW(begin()->x = 3);
+ BOOST_CHECK_EQUAL(3, begin()->x);
+
+ BOOST_CHECK_NO_THROW(push_back(C {4, 5.f}));
+ BOOST_CHECK_EQUAL(3, begin()->x);
+ BOOST_CHECK_EQUAL(2.f, begin()->y);
+ BOOST_CHECK_EQUAL(4, rbegin()->x);
+ BOOST_CHECK_EQUAL(5.f, rbegin()->y);
+}
+
+BOOST_AUTO_TEST_SUITE_END();
+
+struct CC {
+ ~CC()
+ {
+ ++x;
+ }
+ int x;
+ float y;
+};
+static_assert(!std::is_trivially_destructible_v<CC>);
+
+BOOST_FIXTURE_TEST_SUITE(cc, glContainer<CC>)
+
+BOOST_AUTO_TEST_CASE(basic)
+{
+ BOOST_CHECK_NO_THROW(emplace_back(1, 2.f));
+ BOOST_CHECK_EQUAL(1, begin()->x);
+ BOOST_CHECK_EQUAL(2.f, begin()->y);
+ BOOST_CHECK_NO_THROW(begin()->x = 3);
+ BOOST_CHECK_EQUAL(3, begin()->x);
+
+ BOOST_CHECK_NO_THROW(push_back(CC {4, 5.f}));
+ BOOST_CHECK_EQUAL(3, begin()->x);
+ BOOST_CHECK_EQUAL(2.f, begin()->y);
+ BOOST_CHECK_EQUAL(4, rbegin()->x);
+ BOOST_CHECK_EQUAL(5.f, rbegin()->y);
+ BOOST_CHECK_NO_THROW(pop_back());
+ BOOST_CHECK_EQUAL(size(), 1);
+ BOOST_CHECK_EQUAL(capacity(), 2);
+ BOOST_CHECK_NO_THROW(resize(3));
+ BOOST_CHECK_EQUAL(size(), 3);
+ BOOST_CHECK_EQUAL(capacity(), 3);
+ BOOST_CHECK_NO_THROW(resize(1));
+ BOOST_CHECK_EQUAL(size(), 1);
+ BOOST_CHECK_EQUAL(capacity(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(insert_remove_test)
+{
+ BOOST_CHECK_NO_THROW(emplace_back(1, 2.f));
+ BOOST_CHECK_NO_THROW(emplace_back(3, 4.f));
+ BOOST_CHECK_NO_THROW(emplace(begin(), 5, 6.f));
+ BOOST_CHECK_NO_THROW(emplace(begin() + 1, 7, 8.f));
+ BOOST_CHECK_NO_THROW(emplace(begin() + 2, 9, 10.f));
+ BOOST_CHECK_EQUAL(capacity(), 8);
+ BOOST_CHECK_EQUAL(size(), 5);
+ BOOST_CHECK_NO_THROW(shrink_to_fit());
+ BOOST_CHECK_EQUAL(capacity(), 5);
+ BOOST_CHECK_EQUAL(size(), 5);
+}
+
+BOOST_AUTO_TEST_SUITE_END();
diff --git a/test/test-instancing.cpp b/test/test-instancing.cpp
index 8745484..7d8ea55 100644
--- a/test/test-instancing.cpp
+++ b/test/test-instancing.cpp
@@ -17,14 +17,8 @@ BOOST_FIXTURE_TEST_SUITE(i, InstanceVertices<int>)
BOOST_AUTO_TEST_CASE(createDestroy)
{
- BOOST_CHECK(!data);
- map();
- BOOST_REQUIRE(data);
- BOOST_CHECK_EQUAL(0, next);
BOOST_CHECK(unused.empty());
BOOST_CHECK(index.empty());
- unmap();
- BOOST_CHECK(!data);
}
BOOST_AUTO_TEST_CASE(acquireRelease)
@@ -32,12 +26,12 @@ BOOST_AUTO_TEST_CASE(acquireRelease)
{
auto proxy = acquire();
*proxy = 20;
- BOOST_CHECK_EQUAL(1, next);
+ BOOST_CHECK_EQUAL(1, size());
BOOST_REQUIRE_EQUAL(1, index.size());
BOOST_CHECK_EQUAL(0, index.front());
BOOST_CHECK(unused.empty());
}
- BOOST_CHECK_EQUAL(0, next);
+ BOOST_CHECK_EQUAL(0, size());
BOOST_CHECK(unused.empty());
BOOST_CHECK(index.empty());
}
@@ -47,13 +41,13 @@ BOOST_AUTO_TEST_CASE(acquireReleaseMove)
{
auto proxy1 = acquire();
*proxy1 = 20;
- BOOST_CHECK_EQUAL(1, next);
+ BOOST_CHECK_EQUAL(1, size());
auto proxy2 = std::move(proxy1);
proxy2 = 40;
- BOOST_CHECK_EQUAL(1, next);
- BOOST_CHECK_EQUAL(data[0], 40);
+ BOOST_CHECK_EQUAL(1, size());
+ BOOST_CHECK_EQUAL(at(0), 40);
}
- BOOST_CHECK_EQUAL(0, next);
+ BOOST_CHECK_EQUAL(0, size());
BOOST_CHECK(unused.empty());
BOOST_CHECK(index.empty());
}
@@ -62,13 +56,13 @@ BOOST_AUTO_TEST_CASE(autoMapUnmap)
{
{
auto proxy = acquire();
- BOOST_CHECK(data);
+ BOOST_CHECK(data_);
std::ignore = bufferName();
- BOOST_CHECK(data);
- BOOST_CHECK_EQUAL(1, count());
- BOOST_CHECK(!data);
+ BOOST_CHECK(data_);
+ BOOST_CHECK_EQUAL(1, size());
+ BOOST_CHECK(!data_);
}
- BOOST_CHECK_EQUAL(0, count());
+ BOOST_CHECK_EQUAL(0, size());
}
BOOST_AUTO_TEST_CASE(initialize)
@@ -89,7 +83,7 @@ BOOST_AUTO_TEST_CASE(resize)
proxies.push_back(acquire(n));
expected.emplace_back(n);
}
- BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), data, data + COUNT);
+ BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), data(), data() + COUNT);
BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), proxies.begin(), proxies.end());
}
@@ -100,11 +94,11 @@ BOOST_AUTO_TEST_CASE(shuffle)
BOOST_CHECK_EQUAL(1, proxies.emplace_back(acquire(1)));
BOOST_CHECK_EQUAL(2, proxies.emplace_back(acquire(2)));
BOOST_CHECK_EQUAL(3, proxies.emplace_back(acquire(3)));
- BOOST_CHECK_EQUAL(4, next);
- BOOST_CHECK_EQUAL(data + 0, proxies[0].get());
- BOOST_CHECK_EQUAL(data + 1, proxies[1].get());
- BOOST_CHECK_EQUAL(data + 2, proxies[2].get());
- BOOST_CHECK_EQUAL(data + 3, proxies[3].get());
+ BOOST_CHECK_EQUAL(4, size());
+ BOOST_CHECK_EQUAL(at(0), *proxies[0].get());
+ BOOST_CHECK_EQUAL(at(1), *proxies[1].get());
+ BOOST_CHECK_EQUAL(at(2), *proxies[2].get());
+ BOOST_CHECK_EQUAL(at(3), *proxies[3].get());
BOOST_CHECK(unused.empty());
BOOST_REQUIRE_EQUAL(4, index.size());
BOOST_CHECK_EQUAL(0, index[0]);
@@ -113,28 +107,29 @@ BOOST_AUTO_TEST_CASE(shuffle)
BOOST_CHECK_EQUAL(3, index[3]);
// Remove 1, 3 moves to [1]
proxies.erase(proxies.begin() + 1);
+ BOOST_REQUIRE_EQUAL(3, proxies.size());
BOOST_REQUIRE_EQUAL(4, index.size());
BOOST_REQUIRE_EQUAL(1, unused.size());
BOOST_CHECK_EQUAL(1, unused[0]);
- BOOST_CHECK_EQUAL(data + 0, proxies[0].get());
- BOOST_CHECK_EQUAL(data + 2, proxies[1].get());
- BOOST_CHECK_EQUAL(data + 1, proxies[2].get());
- // Remove 1, 2 moves to [1]
+ BOOST_CHECK_EQUAL(at(0), *proxies[0].get());
+ BOOST_CHECK_EQUAL(at(2), *proxies[1].get());
+ BOOST_CHECK_EQUAL(at(1), *proxies[2].get());
+ // Remove 1, 2 moves to [1]
proxies.erase(proxies.begin() + 1);
BOOST_REQUIRE_EQUAL(4, index.size());
BOOST_REQUIRE_EQUAL(2, unused.size());
BOOST_CHECK_EQUAL(1, unused[0]);
BOOST_CHECK_EQUAL(2, unused[1]);
- BOOST_CHECK_EQUAL(data + 0, proxies[0].get());
- BOOST_CHECK_EQUAL(data + 1, proxies[1].get());
+ BOOST_CHECK_EQUAL(at(0), *proxies[0].get());
+ BOOST_CHECK_EQUAL(at(1), *proxies[1].get());
// Add new, takes 2 at [2]
BOOST_CHECK_EQUAL(4, proxies.emplace_back(acquire(4)));
BOOST_REQUIRE_EQUAL(4, index.size());
BOOST_REQUIRE_EQUAL(1, unused.size());
BOOST_CHECK_EQUAL(1, unused[0]);
- BOOST_CHECK_EQUAL(data + 0, proxies[0].get());
- BOOST_CHECK_EQUAL(data + 1, proxies[1].get());
- BOOST_CHECK_EQUAL(data + 2, proxies[2].get());
+ BOOST_CHECK_EQUAL(at(0), *proxies[0].get());
+ BOOST_CHECK_EQUAL(at(1), *proxies[1].get());
+ BOOST_CHECK_EQUAL(at(2), *proxies[2].get());
}
BOOST_DATA_TEST_CASE(shuffle_random, boost::unit_test::data::xrange(0, 10), x)
@@ -158,7 +153,7 @@ BOOST_DATA_TEST_CASE(shuffle_random, boost::unit_test::data::xrange(0, 10), x)
break;
}
- BOOST_REQUIRE_EQUAL(next, proxies.size());
+ BOOST_REQUIRE_EQUAL(size(), proxies.size());
for (const auto & [n, p] : proxies) {
BOOST_REQUIRE_EQUAL(n, p);
}
@@ -169,10 +164,10 @@ BOOST_DATA_TEST_CASE(shuffle_random, boost::unit_test::data::xrange(0, 10), x)
}
}
BOOST_TEST_CONTEXT(index) {
- BOOST_REQUIRE_EQUAL(iused.size(), next);
+ BOOST_REQUIRE_EQUAL(iused.size(), size());
if (!iused.empty()) {
BOOST_REQUIRE_EQUAL(*iused.begin(), 0);
- BOOST_REQUIRE_EQUAL(*iused.rbegin(), next - 1);
+ BOOST_REQUIRE_EQUAL(*iused.rbegin(), size() - 1);
}
}
}
diff --git a/test/test-pack.cpp b/test/test-pack.cpp
new file mode 100644
index 0000000..1f9f061
--- /dev/null
+++ b/test/test-pack.cpp
@@ -0,0 +1,41 @@
+#define BOOST_TEST_MODULE pack
+
+#include <boost/test/data/test_case.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include "pack.h"
+#include <vector>
+
+using IntegerVectorPack = pack<int, std::vector>;
+
+BOOST_FIXTURE_TEST_SUITE(pint, IntegerVectorPack)
+
+BOOST_AUTO_TEST_CASE(basics)
+{
+ BOOST_CHECK_EQUAL(size(), 0);
+ BOOST_CHECK_NO_THROW(emplace(1));
+ BOOST_CHECK_NO_THROW(emplace(2));
+ BOOST_CHECK_NO_THROW(emplace(3));
+ BOOST_CHECK_NO_THROW(emplace(4));
+ BOOST_CHECK_EQUAL(size(), 4);
+ {
+ std::array expected1 {1, 2, 3, 4};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+
+ BOOST_CHECK_NO_THROW(erase(begin() + 1));
+ BOOST_CHECK_EQUAL(size(), 3);
+ {
+ std::array expected1 {1, 4, 3};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+
+ BOOST_CHECK_NO_THROW(erase(--end()));
+ BOOST_CHECK_EQUAL(size(), 2);
+ {
+ std::array expected1 {1, 4};
+ BOOST_CHECK_EQUAL_COLLECTIONS(begin(), end(), expected1.begin(), expected1.end());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/test-render.cpp b/test/test-render.cpp
index 4bfcad2..0d384a3 100644
--- a/test/test-render.cpp
+++ b/test/test-render.cpp
@@ -21,9 +21,9 @@
#include <ui/window.h>
class TestScene : public SceneProvider {
- std::shared_ptr<RailVehicle> train1, train2;
const RailVehicleClassPtr brush47rvc = std::dynamic_pointer_cast<RailVehicleClass>(
AssetFactory::loadXML(RESDIR "/brush47.xml")->assets.at("brush-47"));
+ std::shared_ptr<RailVehicle> train1, train2;
Terrain terrain {[]() {
auto gd = std::make_shared<GeoData>(GeoData::Limits {{0, 0}, {100, 100}});