summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--application/main.cpp11
-rw-r--r--assetFactory/asset.h3
-rw-r--r--assetFactory/assetFactory.cpp3
-rw-r--r--assetFactory/assetFactory.h2
-rw-r--r--game/gamestate.h3
-rw-r--r--game/network/network.h2
-rw-r--r--game/network/network.impl.h8
-rw-r--r--game/network/rail.cpp4
-rw-r--r--game/orders.h2
-rw-r--r--game/vehicles/train.h2
-rw-r--r--game/water.h2
-rw-r--r--gfx/gl/shadowMapper.cpp2
-rw-r--r--lib/collection.h263
-rw-r--r--lib/jsonParse.ll9
-rw-r--r--lib/manyPtr.h86
-rw-r--r--lib/persistence.h3
-rw-r--r--test/Jamfile.jam25
-rw-r--r--test/test-assetFactory.cpp24
-rw-r--r--test/test-collection.cpp287
-rw-r--r--test/test-network.cpp68
-rw-r--r--test/test-render.cpp13
-rw-r--r--ui/builders/freeExtend.cpp8
-rw-r--r--ui/builders/join.cpp6
-rw-r--r--ui/builders/straight.cpp8
-rw-r--r--ui/editNetwork.h2
-rw-r--r--ui/gameMainWindow.cpp20
-rw-r--r--ui/mainApplication.h2
-rw-r--r--ui/toolbar.h2
-rw-r--r--ui/windowContent.h2
29 files changed, 725 insertions, 147 deletions
diff --git a/application/main.cpp b/application/main.cpp
index 723f3d2..9120376 100644
--- a/application/main.cpp
+++ b/application/main.cpp
@@ -86,11 +86,11 @@ public:
}
const std::shared_ptr<Train> train = world.create<Train>(l3, 800000);
- auto b47 = std::dynamic_pointer_cast<RailVehicleClass>(assets.at("brush-47"));
+ auto b47 = assets.at("brush-47").dynamicCast<RailVehicleClass>();
for (int N = 0; N < 6; N++) {
train->create<RailVehicle>(b47);
}
- train->orders.removeAll();
+ train->orders.clear();
train->orders.create<FreeRoam>(&train->orders);
train->currentActivity = train->orders.current()->createActivity();
@@ -101,8 +101,9 @@ public:
std::uniform_int_distribution<int> treeVariantDistribution {1, 4};
for (auto x = 311000000; x < 311830000; x += 5000) {
for (auto y = 491100000; y < 491130000; y += 5000) {
- world.create<Plant>(std::dynamic_pointer_cast<Foliage>(assets.at(std::format("Tree-{:#02}-{}",
- treeDistribution(randomdev), treeVariantDistribution(randomdev)))),
+ world.create<Plant>(assets.at(std::format("Tree-{:#02}-{}", treeDistribution(randomdev),
+ treeVariantDistribution(randomdev)))
+ .dynamicCast<Foliage>(),
Location {terrain->positionAt({{x + positionOffsetDistribution(randomdev),
y + positionOffsetDistribution(randomdev)}}),
{0, rotationDistribution(randomdev), 0}});
@@ -112,7 +113,7 @@ public:
mainLoop();
- world.objects.clear();
+ world.clear();
return 0;
}
};
diff --git a/assetFactory/asset.h b/assetFactory/asset.h
index 5bdd2f2..b5de056 100644
--- a/assetFactory/asset.h
+++ b/assetFactory/asset.h
@@ -2,12 +2,15 @@
#include "factoryMesh.h"
#include "persistence.h"
+#include <manyPtr.h>
#include <stdTypeDefs.h>
class TextureAtlas;
+class Renderable;
class Asset : public Persistence::Persistable, public StdTypeDefs<Asset> {
public:
+ using ManyPtr = ManySharedPtr<Asset, const Renderable>;
using TexturePtr = std::shared_ptr<TextureAtlas>;
std::string id;
diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp
index 176e1f5..426fecc 100644
--- a/assetFactory/assetFactory.cpp
+++ b/assetFactory/assetFactory.cpp
@@ -5,6 +5,7 @@
#include "filesystem.h"
#include "gfx/image.h"
#include "gfx/models/texture.h"
+#include "gfx/renderable.h"
#include "object.h"
#include "plane.h"
#include "saxParse-persistence.h"
@@ -146,7 +147,7 @@ bool
AssetFactory::persist(Persistence::PersistenceStore & store)
{
using MapObjects = Persistence::MapByMember<Shapes, std::shared_ptr<Object>>;
- using MapAssets = Persistence::MapByMember<Assets>;
+ using MapAssets = Persistence::MapByMember<Assets, Asset::Ptr>;
using MapTextureFragments = Persistence::MapByMember<TextureFragments>;
using MapAssImp = Persistence::MapByMember<AssImps, std::shared_ptr<AssImp>, &AssImp::path>;
return STORE_TYPE && STORE_NAME_HELPER("object", shapes, MapObjects)
diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h
index 787f0a4..864e882 100644
--- a/assetFactory/assetFactory.h
+++ b/assetFactory/assetFactory.h
@@ -12,7 +12,7 @@ class Texture;
class AssetFactory : public Persistence::Persistable {
public:
using Shapes = std::map<std::string, Shape::Ptr, std::less<>>;
- using Assets = std::map<std::string, Asset::Ptr, std::less<>>;
+ using Assets = std::map<std::string, Asset::ManyPtr, std::less<>>;
using AssImps = std::map<std::string, AssImp::Ptr, std::less<>>;
using TextureFragments = std::map<std::string, TextureFragment::Ptr, std::less<>>;
using Colour = RGB;
diff --git a/game/gamestate.h b/game/gamestate.h
index 189417d..85cb5db 100644
--- a/game/gamestate.h
+++ b/game/gamestate.h
@@ -8,6 +8,7 @@
class WorldObject;
class Terrain;
class Environment;
+class Renderable;
class GameState {
public:
@@ -16,7 +17,7 @@ public:
NO_MOVE(GameState);
NO_COPY(GameState);
- Collection<WorldObject> world;
+ SharedCollection<WorldObject, Renderable> world;
std::shared_ptr<Terrain> terrain;
std::shared_ptr<Environment> environment;
AssetFactory::Assets assets;
diff --git a/game/network/network.h b/game/network/network.h
index 291c4ec..73c3788 100644
--- a/game/network/network.h
+++ b/game/network/network.h
@@ -77,7 +77,7 @@ class NetworkOf : public Network, public Renderable, public NetworkLinkHolder<Li
protected:
using Network::Network;
- Collection<T> links;
+ SharedCollection<T> links;
void joinLinks(const Link::Ptr &) const;
protected:
diff --git a/game/network/network.impl.h b/game/network/network.impl.h
index 0a2f9ca..294f696 100644
--- a/game/network/network.impl.h
+++ b/game/network/network.impl.h
@@ -8,7 +8,7 @@ template<typename T, typename... Links>
void
NetworkOf<T, Links...>::joinLinks(const Link::Ptr & l) const
{
- for (const auto & ol : links.objects) {
+ for (const auto & ol : links) {
Network::joinLinks(l, ol);
}
}
@@ -18,11 +18,11 @@ Link::Ptr
NetworkOf<T, Links...>::intersectRayLinks(const Ray<GlobalPosition3D> & ray) const
{
// Click link
- if (const auto link = std::find_if(links.objects.begin(), links.objects.end(),
+ if (const auto link = std::find_if(links.begin(), links.end(),
[&ray](const std::shared_ptr<T> & link) {
return link->intersectRay(ray);
});
- link != links.objects.end()) {
+ link != links.end()) {
return *link;
}
return {};
@@ -32,7 +32,7 @@ template<typename T, typename... Links>
float
NetworkOf<T, Links...>::findNodeDirection(Node::AnyCPtr n) const
{
- for (const auto & l : links.objects) {
+ for (const auto & l : links) {
for (const auto & e : l->ends) {
// cppcheck-suppress useStlAlgorithm
if (e.node.get() == n.get()) {
diff --git a/game/network/rail.cpp b/game/network/rail.cpp
index 2a18b9a..dfe1dca 100644
--- a/game/network/rail.cpp
+++ b/game/network/rail.cpp
@@ -168,7 +168,7 @@ namespace {
void
RailLinks::render(const SceneShader & shader, const Frustum &) const
{
- if (!links.objects.empty()) {
+ if (!links.empty()) {
texture->bind();
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1, 0);
@@ -182,7 +182,7 @@ RailLinks::render(const SceneShader & shader, const Frustum &) const
const Surface *
RailLinks::getBaseSurface() const
{
- return std::dynamic_pointer_cast<Surface>(gameState->assets.at("terrain.surface.gravel")).get();
+ return gameState->assets.at("terrain.surface.gravel").dynamicCast<const Surface>().get();
}
RelativeDistance
diff --git a/game/orders.h b/game/orders.h
index ca5cfdb..840aa3c 100644
--- a/game/orders.h
+++ b/game/orders.h
@@ -5,7 +5,7 @@
class Objective;
-class Orders : public Collection<Objective> {
+class Orders : public SharedCollection<Objective> {
public:
[[nodiscard]] Objective * current() const;
Objective * next();
diff --git a/game/vehicles/train.h b/game/vehicles/train.h
index 4933347..88e30f9 100644
--- a/game/vehicles/train.h
+++ b/game/vehicles/train.h
@@ -15,7 +15,7 @@ class SceneShader;
class ShadowMapper;
template<typename> class Ray;
-class Train : public Vehicle, public Collection<RailVehicle, false>, public Can<Go>, public Can<Idle> {
+class Train : public Vehicle, public UniqueCollection<RailVehicle>, public Can<Go>, public Can<Idle> {
public:
explicit Train(const Link::CPtr & link, float linkDist = 0) : Vehicle {link, linkDist} { }
diff --git a/game/water.h b/game/water.h
index f9fe080..07d9ae1 100644
--- a/game/water.h
+++ b/game/water.h
@@ -29,6 +29,6 @@ private:
void generateMeshes();
std::shared_ptr<GeoData> geoData;
- Collection<MeshT<Vertex>, false> meshes;
+ UniqueCollection<MeshT<Vertex>> meshes;
Texture::Ptr water;
};
diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp
index 6525f76..3cb73f7 100644
--- a/gfx/gl/shadowMapper.cpp
+++ b/gfx/gl/shadowMapper.cpp
@@ -88,7 +88,7 @@ ShadowMapper::update(const SceneProvider & scene, const LightDirection & dir, co
shadowStenciller.setLightDirection(dir);
for (const auto & [id, asset] : gameState->assets) {
- if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) {
+ if (const auto r = asset.getAs<const Renderable>()) {
r->updateStencil(shadowStenciller);
}
}
diff --git a/lib/collection.h b/lib/collection.h
index 6802bcb..1c77e1c 100644
--- a/lib/collection.h
+++ b/lib/collection.h
@@ -3,29 +3,62 @@
#include <algorithm>
#include <functional>
#include <memory>
+#include <special_members.h>
#include <type_traits>
#include <vector>
-template<typename Object, bool shared = true> class Collection {
+template<typename Ptr, typename... Others> class Collection {
public:
+ Collection() = default;
virtual ~Collection() = default;
- using Ptr = std::conditional_t<shared, std::shared_ptr<Object>, std::unique_ptr<Object>>;
+ DEFAULT_MOVE_NO_COPY(Collection);
+
+ using Object = Ptr::element_type;
using Objects = std::vector<Ptr>;
- Objects objects;
+ template<typename T> using OtherObjects = std::vector<T *>;
+
+ Collection &
+ operator=(Objects && other)
+ {
+ objects = std::move(other);
+ ((std::get<OtherObjects<Others>>(otherObjects).clear()), ...);
+ for (const auto & other : objects) {
+ addOthersPtr(other.get());
+ }
+ return *this;
+ }
+
+ const Ptr &
+ operator[](size_t idx) const
+ {
+ return objects[idx];
+ }
+
+ template<typename T = Object>
+ requires(std::is_same_v<T, Object> || (std::is_base_of_v<Others, T> || ...))
+ [[nodiscard]] auto
+ size() const noexcept
+ {
+ return containerFor<T>().size();
+ }
template<typename T = Object, typename... Params>
auto
create(Params &&... params)
requires std::is_base_of_v<Object, T>
{
- if constexpr (shared) {
+ if constexpr (requires(Ptr ptr) { ptr = std::make_shared<T>(std::forward<Params>(params)...); }) {
auto obj = std::make_shared<T>(std::forward<Params>(params)...);
objects.emplace_back(obj);
+ addOthersType<T>(obj.get());
return obj;
}
else {
- return static_cast<T *>(objects.emplace_back(std::make_unique<T>(std::forward<Params>(params)...)).get());
+ auto obj = static_cast<T *>(
+ objects.emplace_back(std::make_unique<T>(std::forward<Params>(params)...)).get());
+ addOthersType<T>(obj);
+ return obj;
}
}
@@ -33,12 +66,19 @@ public:
T *
find()
{
- if (auto i = std::find_if(objects.begin(), objects.end(),
- [](auto && o) {
- return (dynamic_cast<T *>(o.get()));
- });
- i != objects.end()) {
- return static_cast<T *>(i->get());
+ const auto & srcObjects = containerFor<T>();
+ if constexpr (std::is_convertible_v<typename std::remove_reference_t<decltype(srcObjects)>::value_type, T *>) {
+ if (srcObjects.empty()) {
+ return nullptr;
+ }
+ return srcObjects.front();
+ }
+ else if (auto i = std::find_if(srcObjects.begin(), srcObjects.end(),
+ [](auto && o) {
+ return dynamic_cast<T *>(std::to_address(o)) != nullptr;
+ });
+ i != srcObjects.end()) {
+ return static_cast<T *>(std::to_address(*i));
}
return nullptr;
}
@@ -58,74 +98,229 @@ public:
auto
apply(const auto & m, Params &&... params) const
{
- return apply_internal<T>(objects.begin(), objects.end(), m, std::forward<Params>(params)...);
+ const auto & srcObjects = containerFor<T>();
+ return apply_internal<T>(srcObjects.begin(), srcObjects.end(), m, std::forward<Params>(params)...);
}
template<typename T = Object, typename... Params>
auto
rapply(const auto & m, Params &&... params) const
{
- return apply_internal<T>(objects.rbegin(), objects.rend(), m, std::forward<Params>(params)...);
+ const auto & srcObjects = containerFor<T>();
+ return apply_internal<T>(srcObjects.rbegin(), srcObjects.rend(), m, std::forward<Params>(params)...);
}
template<typename T = Object, typename... Params>
auto
applyOne(const auto & m, Params &&... params) const
{
- return applyOne_internal<T>(objects.begin(), objects.end(), m, std::forward<Params>(params)...);
+ const auto & srcObjects = containerFor<T>();
+ return applyOne_internal<T>(srcObjects.begin(), srcObjects.end(), m, std::forward<Params>(params)...);
}
template<typename T = Object, typename... Params>
auto
rapplyOne(const auto & m, Params &&... params) const
{
- return applyOne_internal<T>(objects.rbegin(), objects.rend(), m, std::forward<Params>(params)...);
+ const auto & srcObjects = containerFor<T>();
+ return applyOne_internal<T>(srcObjects.rbegin(), srcObjects.rend(), m, std::forward<Params>(params)...);
}
- template<typename T = Object>
+ template<typename T>
+ requires std::is_base_of_v<Object, T>
auto
removeAll()
{
- return std::erase_if(objects, [](auto && op) {
- return dynamic_cast<T *>(op.get());
- });
+ auto removeAllFrom = [](auto & container) {
+ if constexpr (std::is_base_of_v<T, std::decay_t<decltype(*container.front())>>) {
+ const auto size = container.size();
+ container.clear();
+ return size;
+ }
+ else {
+ return std::erase_if(container, [](auto && objPtr) -> bool {
+ return dynamic_cast<const T *>(std::to_address(objPtr));
+ });
+ }
+ };
+ (removeAllFrom(std::get<OtherObjects<Others>>(otherObjects)), ...);
+ return removeAllFrom(objects);
+ }
+
+ void
+ clear()
+ {
+ ((std::get<OtherObjects<Others>>(otherObjects).clear()), ...);
+ objects.clear();
}
- auto
+ [[nodiscard]] auto
+ begin() const
+ {
+ return objects.begin();
+ }
+
+ [[nodiscard]] auto
end() const
{
return objects.end();
}
- auto
+ [[nodiscard]] auto
+ rbegin() const
+ {
+ return objects.rbegin();
+ }
+
+ [[nodiscard]] auto
rend() const
{
return objects.rend();
}
+ [[nodiscard]] bool
+ empty() const
+ {
+ return objects.empty();
+ }
+
+ decltype(auto)
+ emplace(Ptr && ptr)
+ {
+ const auto & object = objects.emplace_back(std::move(ptr));
+ addOthersPtr(object.get());
+ return object;
+ }
+
protected:
+ Objects objects;
+ std::tuple<OtherObjects<Others>...> otherObjects;
+
+ template<typename T>
+ void
+ addOthersType(T * obj)
+ {
+ applyToOthersType<T>(
+ [](auto & others, auto ptr) {
+ others.emplace_back(ptr);
+ },
+ obj);
+ }
+
+ void
+ addOthersPtr(Object * obj)
+ {
+ applyToOthersPtr(
+ [](auto & others, auto ptr) {
+ others.emplace_back(ptr);
+ },
+ obj);
+ }
+
+ template<typename T, typename... Params>
+ requires(sizeof...(Others) == 0)
+ void
+ applyToOthersType(const auto &, Params...)
+ {
+ }
+
+ void
+ applyToOthersPtr(const auto &, Object *)
+ requires(sizeof...(Others) == 0)
+ {
+ }
+
+ template<typename T, typename... Params>
+ requires(sizeof...(Others) > 0)
+ void
+ applyToOthersType(const auto & func, Params &&... params)
+ {
+ (
+ [&]() {
+ if constexpr (std::is_convertible_v<T *, Others *>) {
+ std::invoke(
+ func, std::get<OtherObjects<Others>>(otherObjects), std::forward<Params>(params)...);
+ }
+ }(),
+ ...);
+ }
+
+ void
+ applyToOthersPtr(const auto & func, Object * obj)
+ requires(sizeof...(Others) > 0)
+ {
+ (
+ [&]() {
+ if (auto ptr = dynamic_cast<Others *>(obj)) {
+ std::invoke(func, std::get<OtherObjects<Others>>(otherObjects), ptr);
+ }
+ }(),
+ ...);
+ }
+
+ template<typename T>
+ requires((std::is_base_of_v<Others, T> || ...))
+ [[nodiscard]] consteval static size_t
+ idx()
+ {
+ size_t typeIdx = 0;
+ auto found = ((++typeIdx && std::is_base_of_v<Others, T>) || ...);
+ return typeIdx - found;
+ }
+
+ template<typename T>
+ [[nodiscard]]
+ constexpr const auto &
+ containerFor() const
+ {
+ if constexpr ((std::is_base_of_v<Others, T> || ...)) {
+ return std::get<idx<T>()>(otherObjects);
+ }
+ else {
+ return objects;
+ }
+ }
+
template<typename T = Object, typename... Params>
auto
apply_internal(const auto begin, const auto end, const auto & m, Params &&... params) const
{
- return std::count_if(begin, end, [&m, &params...](auto && op) {
- if (auto o = dynamic_cast<T *>(op.get())) {
- std::invoke(m, o, std::forward<Params>(params)...);
- return true;
- }
- return false;
- });
+ if constexpr (std::is_convertible_v<decltype(std::to_address(*begin)), T *>) {
+ std::for_each(begin, end, [&m, &params...](auto && op) {
+ std::invoke(m, op, std::forward<Params>(params)...);
+ });
+ return std::distance(begin, end);
+ }
+ else {
+ return std::count_if(begin, end, [&m, &params...](auto && op) {
+ if (auto o = dynamic_cast<T *>(std::to_address(op))) {
+ std::invoke(m, o, std::forward<Params>(params)...);
+ return true;
+ }
+ return false;
+ });
+ }
}
template<typename T = Object, typename... Params>
auto
applyOne_internal(const auto begin, const auto end, const auto & m, Params &&... params) const
{
- return std::find_if(begin, end, [&m, &params...](auto && op) {
- if (auto o = dynamic_cast<T *>(op.get())) {
- return std::invoke(m, o, std::forward<Params>(params)...);
- }
- return false;
- });
+ if constexpr (std::is_convertible_v<decltype(std::to_address(*begin)), T *>) {
+ return std::find_if(begin, end, [&m, &params...](auto && op) {
+ return std::invoke(m, op, std::forward<Params>(params)...);
+ });
+ }
+ else {
+ return std::find_if(begin, end, [&m, &params...](auto && op) {
+ if (auto o = dynamic_cast<T *>(std::to_address(op))) {
+ return std::invoke(m, o, std::forward<Params>(params)...);
+ }
+ return false;
+ });
+ }
}
};
+
+template<typename T, typename... Others> using SharedCollection = Collection<std::shared_ptr<T>, Others...>;
+template<typename T, typename... Others> using UniqueCollection = Collection<std::unique_ptr<T>, Others...>;
diff --git a/lib/jsonParse.ll b/lib/jsonParse.ll
index 100bc46..abcd070 100644
--- a/lib/jsonParse.ll
+++ b/lib/jsonParse.ll
@@ -149,7 +149,10 @@ text [^\\\"]*
<*>. {
LexerError("Unexpected input");
- // Make iwyu think unistd.h is required
- [[maybe_unused]]static constexpr auto x=getpid;
- [[maybe_unused]]static constexpr auto y=printf;
}
+
+%%
+
+// Make iwyu think unistd.h is required
+[[maybe_unused]]static constexpr auto x=getpid;
+[[maybe_unused]]static constexpr auto y=printf;
diff --git a/lib/manyPtr.h b/lib/manyPtr.h
new file mode 100644
index 0000000..9e08452
--- /dev/null
+++ b/lib/manyPtr.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <memory>
+#include <tuple>
+
+template<typename Primary, typename... Others> class ManyPtr : Primary {
+public:
+ using element_type = typename Primary::element_type;
+
+ template<typename... Params> ManyPtr(Params &&... params) : Primary {std::forward<Params>(params)...}
+ {
+ updatePtrs();
+ }
+
+ using Primary::operator->;
+ using Primary::operator*;
+ using Primary::operator bool;
+ using Primary::get;
+
+ template<typename... Params>
+ void
+ reset(Params &&... params)
+ {
+ Primary::reset(std::forward<Params>(params)...);
+ updatePtrs();
+ }
+
+ template<typename Other>
+ [[nodiscard]] consteval static bool
+ couldBe()
+ {
+ return (std::is_convertible_v<Others *, Other *> || ...);
+ }
+
+ template<typename Other>
+ requires(couldBe<Other>())
+ [[nodiscard]] auto
+ getAs() const
+ {
+ return std::get<idx<Other>()>(others);
+ }
+
+ template<typename Other>
+ requires(!couldBe<Other>() && requires { std::dynamic_pointer_cast<Other>(std::declval<Primary>()); })
+ [[nodiscard]] auto
+ dynamicCast() const
+ {
+ return std::dynamic_pointer_cast<Other>(*this);
+ }
+
+ template<typename Other>
+ requires(!couldBe<Other>() && !requires { std::dynamic_pointer_cast<Other>(std::declval<Primary>()); })
+ [[nodiscard]] auto
+ dynamicCast() const
+ {
+ return dynamic_cast<Other *>(get());
+ }
+
+private:
+ using OtherPtrs = std::tuple<Others *...>;
+
+ template<typename Other>
+ requires(couldBe<Other>())
+ [[nodiscard]] consteval static bool
+ idx()
+ {
+ size_t typeIdx = 0;
+ return ((typeIdx++ && std::is_convertible_v<Others *, Other *>) || ...);
+ }
+
+ void
+ updatePtrs()
+ {
+ if (*this) {
+ others = {dynamic_cast<Others *>(get())...};
+ }
+ else {
+ others = {};
+ }
+ }
+
+ OtherPtrs others;
+};
+
+template<typename Primary, typename... Others> using ManySharedPtr = ManyPtr<std::shared_ptr<Primary>, Others...>;
+template<typename Primary, typename... Others> using ManyUniquePtr = ManyPtr<std::unique_ptr<Primary>, Others...>;
diff --git a/lib/persistence.h b/lib/persistence.h
index e385b20..75bcea6 100644
--- a/lib/persistence.h
+++ b/lib/persistence.h
@@ -1,5 +1,6 @@
#pragma once
+#include "manyPtr.h"
#include <charconv>
#include <format>
#include <functional>
@@ -200,7 +201,7 @@ namespace Persistence {
}
[[nodiscard]] virtual NameActionSelection setName(const std::string_view key, SelectionFactory &&) = 0;
- virtual void selHandler() {};
+ virtual void selHandler() { };
virtual void setType(const std::string_view, const Persistable *) = 0;
SelectionPtr sel {};
diff --git a/test/Jamfile.jam b/test/Jamfile.jam
index bedc2ad..5189add 100644
--- a/test/Jamfile.jam
+++ b/test/Jamfile.jam
@@ -43,6 +43,16 @@ project : requirements
<toolset>tidy:<librarydef>boost
;
lib test : [ glob *.cpp : test-*.cpp perf-*.cpp ] ;
+rule perfrun ( main + : extra-requirements * : runtime-dependency * : command-args * ) {
+ local name = $(main[0]:S=) ;
+ local benchmark = $(main[0]:S=.benchmark) ;
+ explicit $(name) ;
+ exe $(benchmark) : $(main) :
+ <library>benchmark
+ <library>test
+ $(extra-requirements) ;
+ run $(benchmark) : $(command-args) : : <dependency>$(runtime-dependency) : $(name) ;
+}
run test-collection.cpp ;
run test-maths.cpp ;
@@ -55,22 +65,17 @@ run test-enumDetails.cpp ;
run test-render.cpp : -- : test-assetFactory : <library>test ;
run test-glContextBhvr.cpp ;
run test-assetFactory.cpp : -- : [ sequence.insertion-sort [ glob-tree $(res) : *.* ] fixtures/rgb.txt test-instancing ] : <library>test ;
-run perf-assetFactory.cpp : \< : test-assetFactory : <library>benchmark <library>test ;
-run perf-geoData.cpp : \< : test-geoData : <library>test <library>benchmark ;
-run perf-terrain.cpp : \< : test-geoData : <library>test <library>benchmark ;
-run perf-persistence.cpp : \< : test-persistence : <library>benchmark <library>test ;
+perfrun perf-assetFactory.cpp : : test-assetFactory ;
+perfrun perf-geoData.cpp : : test-geoData ;
+perfrun perf-terrain.cpp : : test-geoData ;
+perfrun perf-persistence.cpp : : test-persistence ;
run test-worker.cpp ;
run test-instancing.cpp : -- : test-glContainer : <library>test ;
-run perf-instancing.cpp : \< : test-instancing : <library>benchmark <library>test ;
+perfrun perf-instancing.cpp : : test-instancing ;
run test-glContainer.cpp : : : <library>test ;
run test-pack.cpp : : : <library>test ;
run test-environment.cpp : : : <library>test ;
compile test-static-enumDetails.cpp ;
compile test-static-stream_support.cpp ;
-explicit perf-assetFactory ;
-explicit perf-persistence ;
-explicit perf-geoData ;
-explicit perf-instancing ;
-explicit perf-terrain ;
alias perf : perf-assetFactory perf-persistence perf-geoData perf-instancing perf-terrain ;
explicit perf ;
diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp
index 9bade82..68ce6a6 100644
--- a/test/test-assetFactory.cpp
+++ b/test/test-assetFactory.cpp
@@ -71,7 +71,7 @@ public:
sceneRenderer.render(*this);
}
- Collection<const Renderable> objects;
+ SharedCollection<const Renderable> objects;
private:
SceneRenderer sceneRenderer;
@@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(surfaces, *boost::unit_test::timeout(5))
BOOST_CHECK_EQUAL(4, mf->assets.size());
auto gravelAsset = mf->assets.at("terrain.surface.gravel");
BOOST_REQUIRE(gravelAsset);
- auto gravel = std::dynamic_pointer_cast<Surface>(gravelAsset);
+ auto gravel = gravelAsset.dynamicCast<Surface>();
BOOST_REQUIRE(gravel);
BOOST_REQUIRE_EQUAL(gravel->name, "Gravel");
BOOST_REQUIRE_EQUAL(gravel->colorBias, RGB {.9F});
@@ -111,14 +111,14 @@ BOOST_AUTO_TEST_CASE(brush47xml, *boost::unit_test::timeout(5))
BOOST_CHECK_EQUAL(1, mf->assets.size());
auto brush47 = mf->assets.at("brush-47");
BOOST_REQUIRE(brush47);
- auto brush47rvc = std::dynamic_pointer_cast<RailVehicleClass>(brush47);
+ auto brush47rvc = brush47.dynamicCast<RailVehicleClass>();
BOOST_REQUIRE(brush47rvc);
BOOST_REQUIRE(brush47rvc->bodyMesh);
BOOST_REQUIRE(brush47rvc->bogies.front());
BOOST_REQUIRE(brush47rvc->bogies.back());
auto railVehicle = std::make_shared<RailVehicle>(brush47rvc);
- objects.objects.push_back(brush47rvc);
+ objects.emplace(brush47rvc);
render(10000);
}
@@ -130,14 +130,14 @@ BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5))
gameState.assets = mf->assets;
auto tree_01_1 = mf->assets.at("Tree-01-1");
BOOST_REQUIRE(tree_01_1);
- auto tree_01_1_f = std::dynamic_pointer_cast<Foliage>(tree_01_1);
+ auto tree_01_1_f = tree_01_1.dynamicCast<Foliage>();
BOOST_REQUIRE(tree_01_1_f);
auto plant1 = std::make_shared<Plant>(tree_01_1_f, Location {{-2000, 2000, 0}, {0, 0, 0}});
auto plant2 = std::make_shared<Plant>(tree_01_1_f, Location {{3000, -4000, 0}, {0, 1, 0}});
auto plant3 = std::make_shared<Plant>(tree_01_1_f, Location {{-2000, -4000, 0}, {0, 2, 0}});
auto plant4 = std::make_shared<Plant>(tree_01_1_f, Location {{3000, 2000, 0}, {0, 3, 0}});
- objects.objects.push_back(tree_01_1_f);
+ objects.emplace(tree_01_1_f);
render(6000);
}
@@ -151,22 +151,22 @@ BOOST_AUTO_TEST_CASE(lights, *boost::unit_test::timeout(5))
BOOST_REQUIRE(rlight);
auto oldlamp = mf->assets.at("old-lamp");
BOOST_REQUIRE(oldlamp);
- auto rlight_f = std::dynamic_pointer_cast<Illuminator>(rlight);
+ auto rlight_f = rlight.dynamicCast<Illuminator>();
BOOST_REQUIRE(rlight_f);
- auto oldlamp_f = std::dynamic_pointer_cast<Illuminator>(oldlamp);
+ auto oldlamp_f = oldlamp.dynamicCast<Illuminator>();
BOOST_REQUIRE(oldlamp_f);
auto light1 = std::make_shared<Light>(oldlamp_f, Location {{0, 0, 0}, {0, 0, 0}});
auto light2 = std::make_shared<Light>(rlight_f, Location {{-4000, 0, 0}, {0, 2, 0}});
auto light3 = std::make_shared<Light>(rlight_f, Location {{-4000, -4000, 0}, {0, 1, 0}});
auto light4 = std::make_shared<Light>(oldlamp_f, Location {{3000, 4600, 0}, {0, 2, 0}});
- objects.objects.push_back(rlight_f);
- objects.objects.push_back(oldlamp_f);
+ objects.emplace(rlight_f);
+ objects.emplace(oldlamp_f);
// yes I'm hacking some floor to light up as though its a bush
- auto floorf = std::dynamic_pointer_cast<Foliage>(mf->assets.at("floor"));
+ auto floorf = mf->assets.at("floor").dynamicCast<Foliage>();
auto floor = std::make_shared<Plant>(floorf, Location {});
- objects.objects.push_back(floorf);
+ objects.emplace(floorf);
render(6000);
}
diff --git a/test/test-collection.cpp b/test/test-collection.cpp
index 00204fc..620d3ab 100644
--- a/test/test-collection.cpp
+++ b/test/test-collection.cpp
@@ -21,6 +21,12 @@ public:
return false;
}
+ [[nodiscard]] virtual bool
+ yes() const
+ {
+ return true;
+ }
+
unsigned int total {0};
};
@@ -34,27 +40,63 @@ public:
}
};
-using TestCollection = Collection<Base>;
+class Sub1 : public Sub { };
+
+class Sub2 : public Sub { };
+
+class Base2 {
+public:
+ virtual ~Base2() = default;
+};
+
+class Multi : public Sub1, public Base2 { };
+
+using TestCollection = SharedCollection<Base, Sub>;
-BOOST_TEST_DONT_PRINT_LOG_VALUE(Collection<Base>::Objects::const_iterator)
-BOOST_TEST_DONT_PRINT_LOG_VALUE(Collection<Base>::Objects::const_reverse_iterator)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestCollection::Objects::iterator)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestCollection::Objects::const_iterator)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestCollection::Objects::const_reverse_iterator)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestCollection::OtherObjects<Sub>::iterator)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestCollection::OtherObjects<Sub>::const_iterator)
BOOST_FIXTURE_TEST_SUITE(tc, TestCollection)
BOOST_AUTO_TEST_CASE(empty)
{
+ BOOST_CHECK(TestCollection::empty());
BOOST_REQUIRE(!apply(&Base::add));
const auto i = applyOne(&Base::add);
BOOST_CHECK_EQUAL(i, end());
+ BOOST_CHECK(!find<Base>());
+ BOOST_CHECK(!find<Sub>());
+ BOOST_CHECK(!find<Sub1>());
}
BOOST_AUTO_TEST_CASE(a_base)
{
auto b = create<Base>();
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
BOOST_REQUIRE(apply(&Base::add));
BOOST_CHECK_EQUAL(b->total, 1);
const auto i = applyOne(&Base::add);
BOOST_CHECK_EQUAL(i, end());
+ BOOST_CHECK_EQUAL(b.get(), find<Base>());
+ BOOST_CHECK(!find<Sub>());
+ BOOST_CHECK(!find<Sub1>());
+}
+
+BOOST_AUTO_TEST_CASE(emplace_others)
+{
+ auto b = emplace(std::make_shared<Base>());
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
+ auto s = emplace(std::make_shared<Sub>());
+ BOOST_CHECK_EQUAL(objects.size(), 2);
+ BOOST_CHECK_EQUAL(std::get<OtherObjects<Sub>>(otherObjects).size(), 1);
+ BOOST_CHECK_EQUAL(b.get(), find<Base>());
+ BOOST_CHECK_EQUAL(s.get(), find<Sub>());
+ BOOST_CHECK(!find<Sub1>());
}
BOOST_AUTO_TEST_CASE(a_rbase)
@@ -69,6 +111,8 @@ BOOST_AUTO_TEST_CASE(a_rbase)
BOOST_AUTO_TEST_CASE(a_sub)
{
auto s = create<Sub>();
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK_EQUAL(std::get<OtherObjects<Sub>>(otherObjects).size(), 1);
BOOST_REQUIRE(apply(&Base::add));
BOOST_CHECK_EQUAL(s->total, 2);
const auto i = applyOne(&Base::add);
@@ -76,6 +120,243 @@ BOOST_AUTO_TEST_CASE(a_sub)
BOOST_CHECK_EQUAL(*i, s);
}
+BOOST_AUTO_TEST_CASE(filter)
+{
+ static_assert(TestCollection::idx<Sub>() == 0);
+ static_assert(TestCollection::idx<const Sub>() == 0);
+ static_assert(TestCollection::idx<Sub1>() == 0);
+ static_assert(TestCollection::idx<const Sub1>() == 0);
+ create<Base>();
+ BOOST_CHECK_EQUAL(1, apply<Base>(&Base::yes));
+ BOOST_CHECK_EQUAL(0, apply<Sub>(&Base::yes));
+ BOOST_CHECK_EQUAL(0, apply<Sub1>(&Base::yes));
+ BOOST_CHECK_EQUAL(objects.begin(), applyOne<Base>(&Base::yes));
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).end(), applyOne<Sub>(&Base::yes));
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).end(), applyOne<Sub1>(&Base::yes));
+ create<Sub>();
+ BOOST_CHECK_EQUAL(2, apply<Base>(&Base::yes));
+ BOOST_CHECK_EQUAL(1, apply<Sub>(&Base::yes));
+ BOOST_CHECK_EQUAL(0, apply<Sub1>(&Base::yes));
+ BOOST_CHECK_EQUAL(objects.begin(), applyOne<Base>(&Base::yes));
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).begin(), applyOne<Sub>(&Base::yes));
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).end(), applyOne<Sub1>(&Base::yes));
+ create<Sub1>();
+ BOOST_CHECK_EQUAL(3, apply<Base>(&Base::yes));
+ BOOST_CHECK_EQUAL(2, apply<Sub>(&Base::yes));
+ BOOST_CHECK_EQUAL(1, apply<Sub1>(&Base::yes));
+ BOOST_CHECK_EQUAL(objects.begin(), applyOne<Base>(&Base::yes));
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).begin(), applyOne<Sub>(&Base::yes));
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).begin() + 1, applyOne<Sub1>(&Base::yes));
+
+ BOOST_CHECK_EQUAL(std::get<idx<Sub>()>(otherObjects).size(), 2);
+ BOOST_CHECK_EQUAL(std::get<idx<Sub1>()>(otherObjects).size(), 2);
+
+ BOOST_CHECK_EQUAL(&objects, &containerFor<Base>());
+ BOOST_CHECK_EQUAL(&std::get<0>(otherObjects), &containerFor<Sub>());
+ BOOST_CHECK_EQUAL(&std::get<0>(otherObjects), &containerFor<Sub1>());
+}
+
+BOOST_AUTO_TEST_CASE(begin_end)
+{
+ BOOST_CHECK_EQUAL(0, std::distance(begin(), end()));
+ create<Sub>();
+ create<Base>();
+ BOOST_CHECK_EQUAL(2, std::distance(begin(), end()));
+}
+
+BOOST_AUTO_TEST_CASE(rbegin_rend)
+{
+ BOOST_CHECK_EQUAL(0, std::distance(rbegin(), rend()));
+ create<Sub>();
+ create<Base>();
+ BOOST_CHECK_EQUAL(2, std::distance(rbegin(), rend()));
+}
+
+BOOST_AUTO_TEST_CASE(createCreate)
+{
+ auto b = findOrCreate<Base>();
+ BOOST_CHECK(b);
+ auto b2 = findOrCreate<Base>();
+ BOOST_CHECK_EQUAL(b, b2);
+ auto s = findOrCreate<Sub>();
+ BOOST_CHECK_NE(s, b);
+ auto s2 = findOrCreate<Sub>();
+ BOOST_CHECK_EQUAL(s, s2);
+}
+
+BOOST_AUTO_TEST_CASE(createCreateSub)
+{
+ auto s = findOrCreate<Sub>();
+ auto b = findOrCreate<Base>();
+ BOOST_CHECK_EQUAL(s, b);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+using TestUniqueCollection = UniqueCollection<Base, Sub>;
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestUniqueCollection::Objects::const_iterator)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestUniqueCollection::Objects::const_reverse_iterator)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestUniqueCollection::Objects::iterator)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(TestUniqueCollection::Objects::reverse_iterator)
+
+BOOST_FIXTURE_TEST_SUITE(utc, TestUniqueCollection)
+
+BOOST_AUTO_TEST_CASE(unique_create)
+{
+ create<Base>();
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
+ create<Sub>();
+ BOOST_CHECK_EQUAL(objects.size(), 2);
+ BOOST_CHECK_EQUAL(std::get<OtherObjects<Sub>>(otherObjects).size(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(move_assign)
+{
+ create<Base>();
+ create<Sub>();
+
+ TestUniqueCollection::Objects other;
+ TestUniqueCollection::operator=(std::move(other));
+ BOOST_CHECK(objects.empty());
+ BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
+
+ other.push_back(std::make_unique<Sub>());
+ other.push_back(std::make_unique<Base>());
+ TestUniqueCollection::operator=(std::move(other));
+ BOOST_CHECK_EQUAL(objects.size(), 2);
+ BOOST_CHECK_EQUAL(std::get<OtherObjects<Sub>>(otherObjects).size(), 1);
+ BOOST_CHECK(other.empty());
+}
+
+BOOST_AUTO_TEST_CASE(clearAll)
+{
+ create<Base>();
+ create<Sub>();
+ emplace(std::make_unique<Base>());
+ emplace(std::make_unique<Sub>());
+
+ clear();
+ BOOST_CHECK(objects.empty());
+ BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
+}
+
+BOOST_AUTO_TEST_CASE(removeAllOfSub)
+{
+ create<Base>();
+ create<Sub>();
+ emplace(std::make_unique<Base>());
+ emplace(std::make_unique<Sub>());
+ emplace(std::make_unique<Sub1>());
+
+ BOOST_CHECK_EQUAL(removeAll<Sub>(), 3);
+ BOOST_CHECK_EQUAL(objects.size(), 2);
+ BOOST_CHECK(std::get<OtherObjects<Sub>>(otherObjects).empty());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_FIXTURE_TEST_SUITE(btc, UniqueCollection<Base>)
+
+BOOST_AUTO_TEST_CASE(no_others)
+{
+ create<Base>();
+ create<Sub>();
+ emplace(std::make_unique<Base>());
+ emplace(std::make_unique<Sub>());
+}
+
+BOOST_AUTO_TEST_CASE(applyAll)
+{
+ create<Base>();
+ BOOST_CHECK_EQUAL(0, apply<Sub>(&Base::add));
+ BOOST_CHECK_EQUAL(1, apply<Base>(&Base::add));
+ create<Sub>();
+ BOOST_CHECK_EQUAL(1, apply<Sub>(&Base::add));
+ BOOST_CHECK_EQUAL(2, apply<Base>(&Base::add));
+}
+
+BOOST_AUTO_TEST_CASE(applyOneType)
+{
+ create<Base>();
+ BOOST_CHECK_EQUAL(objects.end(), applyOne<Sub>(&Base::yes));
+ BOOST_CHECK_EQUAL(objects.begin(), applyOne<Base>(&Base::yes));
+ create<Sub>();
+ BOOST_CHECK_EQUAL(objects.begin() + 1, applyOne<Sub>(&Base::yes));
+ BOOST_CHECK_EQUAL(objects.begin(), applyOne<Base>(&Base::yes));
+ create<Sub1>();
+ BOOST_CHECK_EQUAL(objects.begin() + 2, applyOne<Sub1>(&Base::yes));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+using MultiCollection = Collection<std::unique_ptr<Base>, Multi, Sub, Base2>;
+
+BOOST_FIXTURE_TEST_SUITE(multi, MultiCollection)
+
+BOOST_AUTO_TEST_CASE(addMulti)
+{
+ static_assert(MultiCollection::idx<Multi>() == 0);
+ static_assert(MultiCollection::idx<Sub>() == 1);
+ static_assert(MultiCollection::idx<Base2>() == 2);
+ create<Base>();
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<1>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<2>(otherObjects).size(), 0);
+ create<Sub>();
+ BOOST_CHECK_EQUAL(objects.size(), 2);
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<1>(otherObjects).size(), 1);
+ BOOST_CHECK_EQUAL(std::get<2>(otherObjects).size(), 0);
+ create<Sub1>();
+ BOOST_CHECK_EQUAL(objects.size(), 3);
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<1>(otherObjects).size(), 2);
+ BOOST_CHECK_EQUAL(std::get<2>(otherObjects).size(), 0);
+ create<Sub2>();
+ BOOST_CHECK_EQUAL(objects.size(), 4);
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<1>(otherObjects).size(), 3);
+ BOOST_CHECK_EQUAL(std::get<2>(otherObjects).size(), 0);
+ create<Multi>();
+ BOOST_CHECK_EQUAL(size(), 5);
+ BOOST_CHECK_EQUAL(size<Multi>(), 1);
+ BOOST_CHECK_EQUAL(size<Sub>(), 4);
+ BOOST_CHECK_EQUAL(size<Base2>(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(removeMulti)
+{
+ create<Base>();
+ create<Sub>();
+ create<Sub1>();
+ create<Sub2>();
+ create<Multi>();
+ BOOST_CHECK_EQUAL(objects.size(), 5);
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).size(), 1);
+ BOOST_CHECK_EQUAL(std::get<1>(otherObjects).size(), 4);
+ BOOST_CHECK_EQUAL(std::get<2>(otherObjects).size(), 1);
+
+ BOOST_CHECK_EQUAL(removeAll<Multi>(), 1);
+ BOOST_CHECK_EQUAL(objects.size(), 4);
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<1>(otherObjects).size(), 3);
+ BOOST_CHECK_EQUAL(std::get<2>(otherObjects).size(), 0);
+
+ BOOST_CHECK_EQUAL(removeAll<Sub>(), 3);
+ BOOST_CHECK_EQUAL(objects.size(), 1);
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<1>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<2>(otherObjects).size(), 0);
+
+ BOOST_CHECK_EQUAL(removeAll<Base>(), 1);
+ BOOST_CHECK_EQUAL(objects.size(), 0);
+ BOOST_CHECK_EQUAL(std::get<0>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<1>(otherObjects).size(), 0);
+ BOOST_CHECK_EQUAL(std::get<2>(otherObjects).size(), 0);
+}
+
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(wrapped_ptr_file_cons)
diff --git a/test/test-network.cpp b/test/test-network.cpp
index 51fea8b..19a740e 100644
--- a/test/test-network.cpp
+++ b/test/test-network.cpp
@@ -139,83 +139,83 @@ BOOST_DATA_TEST_CASE(newNodeAt_new, INVALID_NODES, p)
BOOST_AUTO_TEST_CASE(network_joins)
{
// Ends
- BOOST_CHECK(links.objects[2]->ends[1].nexts.empty());
+ BOOST_CHECK(links[2]->ends[1].nexts.empty());
// Join 0 <-> 1
- BOOST_REQUIRE_EQUAL(links.objects[0]->ends[1].nexts.size(), 2);
- BOOST_CHECK_EQUAL(links.objects[0]->ends[1].nexts[0].first.lock().get(), links.objects[1].get());
- BOOST_CHECK_EQUAL(links.objects[0]->ends[1].nexts[0].second, 0);
- BOOST_CHECK_EQUAL(links.objects[0]->ends[1].nexts[1].first.lock().get(), links.objects[5].get());
- BOOST_CHECK_EQUAL(links.objects[0]->ends[1].nexts[1].second, 0);
- BOOST_REQUIRE_EQUAL(links.objects[1]->ends[0].nexts.size(), 2);
- BOOST_CHECK_EQUAL(links.objects[1]->ends[0].nexts[0].first.lock().get(), links.objects[0].get());
- BOOST_CHECK_EQUAL(links.objects[1]->ends[0].nexts[0].second, 1);
- BOOST_CHECK_EQUAL(links.objects[1]->ends[0].nexts[1].first.lock().get(), links.objects[5].get());
- BOOST_CHECK_EQUAL(links.objects[1]->ends[0].nexts[1].second, 0);
+ BOOST_REQUIRE_EQUAL(links[0]->ends[1].nexts.size(), 2);
+ BOOST_CHECK_EQUAL(links[0]->ends[1].nexts[0].first.lock().get(), links[1].get());
+ BOOST_CHECK_EQUAL(links[0]->ends[1].nexts[0].second, 0);
+ BOOST_CHECK_EQUAL(links[0]->ends[1].nexts[1].first.lock().get(), links[5].get());
+ BOOST_CHECK_EQUAL(links[0]->ends[1].nexts[1].second, 0);
+ BOOST_REQUIRE_EQUAL(links[1]->ends[0].nexts.size(), 2);
+ BOOST_CHECK_EQUAL(links[1]->ends[0].nexts[0].first.lock().get(), links[0].get());
+ BOOST_CHECK_EQUAL(links[1]->ends[0].nexts[0].second, 1);
+ BOOST_CHECK_EQUAL(links[1]->ends[0].nexts[1].first.lock().get(), links[5].get());
+ BOOST_CHECK_EQUAL(links[1]->ends[0].nexts[1].second, 0);
// Join 1 <-> 2
- BOOST_REQUIRE_EQUAL(links.objects[1]->ends[1].nexts.size(), 2);
- BOOST_CHECK_EQUAL(links.objects[1]->ends[1].nexts[0].first.lock().get(), links.objects[2].get());
- BOOST_CHECK_EQUAL(links.objects[1]->ends[1].nexts[0].second, 0);
- BOOST_REQUIRE_EQUAL(links.objects[2]->ends[0].nexts.size(), 2);
- BOOST_CHECK_EQUAL(links.objects[2]->ends[0].nexts[0].first.lock().get(), links.objects[1].get());
- BOOST_CHECK_EQUAL(links.objects[2]->ends[0].nexts[0].second, 1);
+ BOOST_REQUIRE_EQUAL(links[1]->ends[1].nexts.size(), 2);
+ BOOST_CHECK_EQUAL(links[1]->ends[1].nexts[0].first.lock().get(), links[2].get());
+ BOOST_CHECK_EQUAL(links[1]->ends[1].nexts[0].second, 0);
+ BOOST_REQUIRE_EQUAL(links[2]->ends[0].nexts.size(), 2);
+ BOOST_CHECK_EQUAL(links[2]->ends[0].nexts[0].first.lock().get(), links[1].get());
+ BOOST_CHECK_EQUAL(links[2]->ends[0].nexts[0].second, 1);
}
BOOST_DATA_TEST_CASE(routeTo_nodeNotInNetwork, INVALID_NODES, dest)
{
- const auto & start = links.objects.front()->ends[1];
+ const auto & start = links[0]->ends[1];
BOOST_CHECK_THROW((void)routeFromTo(start, dest), std::out_of_range);
}
BOOST_AUTO_TEST_CASE(routeTo_noSteps)
{
- const auto & start = links.objects.front()->ends[1];
+ const auto & start = links[0]->ends[1];
auto r = this->routeFromTo(start, p100);
BOOST_CHECK(r.empty());
}
BOOST_AUTO_TEST_CASE(routeTo_upStream_to2)
{
- const auto & start = links.objects.front()->ends[1];
+ const auto & start = links[0]->ends[1];
auto r = this->routeFromTo(start, p200);
BOOST_REQUIRE_EQUAL(r.size(), 1);
- BOOST_CHECK_EQUAL(r[0].first.lock().get(), links.objects[1].get());
+ BOOST_CHECK_EQUAL(r[0].first.lock().get(), links[1].get());
}
BOOST_AUTO_TEST_CASE(routeTo_upStream_to3)
{
- const auto & start = links.objects[0]->ends[1];
+ const auto & start = links[0]->ends[1];
auto r = this->routeFromTo(start, p300);
BOOST_REQUIRE_EQUAL(r.size(), 2);
- BOOST_CHECK_EQUAL(r[0].first.lock().get(), links.objects[1].get());
- BOOST_CHECK_EQUAL(r[1].first.lock().get(), links.objects[2].get());
+ BOOST_CHECK_EQUAL(r[0].first.lock().get(), links[1].get());
+ BOOST_CHECK_EQUAL(r[1].first.lock().get(), links[2].get());
}
BOOST_AUTO_TEST_CASE(routeTo_downStream_to0)
{
- const auto & start = links.objects[2]->ends[0];
+ const auto & start = links[2]->ends[0];
auto r = this->routeFromTo(start, p000);
BOOST_REQUIRE_EQUAL(r.size(), 2);
- BOOST_CHECK_EQUAL(r[0].first.lock().get(), links.objects[1].get());
- BOOST_CHECK_EQUAL(r[1].first.lock().get(), links.objects[0].get());
+ BOOST_CHECK_EQUAL(r[0].first.lock().get(), links[1].get());
+ BOOST_CHECK_EQUAL(r[1].first.lock().get(), links[0].get());
}
BOOST_AUTO_TEST_CASE(routeTo_upStream_3to300)
{
- const auto & start = links.objects[3]->ends[1];
+ const auto & start = links[3]->ends[1];
auto r = this->routeFromTo(start, p300);
BOOST_REQUIRE_EQUAL(r.size(), 2);
- BOOST_CHECK_EQUAL(r[0].first.lock().get(), links.objects[4].get());
- BOOST_CHECK_EQUAL(r[1].first.lock().get(), links.objects[2].get());
+ BOOST_CHECK_EQUAL(r[0].first.lock().get(), links[4].get());
+ BOOST_CHECK_EQUAL(r[1].first.lock().get(), links[2].get());
}
BOOST_AUTO_TEST_CASE(routeTo_downStream_3to300)
{
- const auto & start = links.objects[3]->ends[0];
+ const auto & start = links[3]->ends[0];
auto r = this->routeFromTo(start, p300);
BOOST_REQUIRE_EQUAL(r.size(), 3);
- BOOST_CHECK_EQUAL(r[0].first.lock().get(), links.objects[0].get());
- BOOST_CHECK_EQUAL(r[1].first.lock().get(), links.objects[1].get());
- BOOST_CHECK_EQUAL(r[2].first.lock().get(), links.objects[2].get());
+ BOOST_CHECK_EQUAL(r[0].first.lock().get(), links[0].get());
+ BOOST_CHECK_EQUAL(r[1].first.lock().get(), links[1].get());
+ BOOST_CHECK_EQUAL(r[2].first.lock().get(), links[2].get());
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/test-render.cpp b/test/test-render.cpp
index 8390d25..a6e28bc 100644
--- a/test/test-render.cpp
+++ b/test/test-render.cpp
@@ -41,7 +41,7 @@ public:
terrain->point(GeoData::VertexHandle {517}).z = 100'000;
terrain->generateMeshes();
gameState->assets = AssetFactory::loadAll(RESDIR);
- brush47rvc = std::dynamic_pointer_cast<RailVehicleClass>(gameState->assets.at("brush-47"));
+ brush47rvc = gameState->assets.at("brush-47").dynamicCast<RailVehicleClass>();
std::random_device randomdev {};
std::uniform_real_distribution<Angle> rotationDistribution {0, two_pi};
std::uniform_int_distribution<GlobalDistance> positionOffsetDistribution {-1500, +1500};
@@ -57,9 +57,10 @@ public:
train2->bogies.back().setPosition(train2->bogies.back().position() + train2->location.position());
for (auto x = 40000; x < 100000; x += 5000) {
for (auto y = 65000; y < 125000; y += 5000) {
- gameState->world.create<Plant>(
- std::dynamic_pointer_cast<Foliage>(gameState->assets.at(std::format(
- "Tree-{:#02}-{}", treeDistribution(randomdev), treeVariantDistribution(randomdev)))),
+ gameState->world.create<Plant>(gameState->assets
+ .at(std::format("Tree-{:#02}-{}", treeDistribution(randomdev),
+ treeVariantDistribution(randomdev)))
+ .dynamicCast<Foliage>(),
Location {{x + positionOffsetDistribution(randomdev), y + positionOffsetDistribution(randomdev),
1},
{0, rotationDistribution(randomdev), 0}});
@@ -76,7 +77,7 @@ public:
water.render(shader, frustum);
rail.render(shader, frustum);
std::ranges::for_each(gameState->assets, [&shader, &frustum](const auto & asset) {
- if (const auto renderable = std::dynamic_pointer_cast<const Renderable>(asset.second)) {
+ if (const auto renderable = asset.second.template getAs<const Renderable>()) {
renderable->render(shader, frustum);
}
});
@@ -98,7 +99,7 @@ public:
{
terrain->shadows(shadowMapper, frustum);
std::ranges::for_each(gameState->assets, [&shadowMapper, &frustum](const auto & asset) {
- if (const auto renderable = std::dynamic_pointer_cast<const Renderable>(asset.second)) {
+ if (const auto renderable = asset.second.template getAs<const Renderable>()) {
renderable->shadows(shadowMapper, frustum);
}
});
diff --git a/ui/builders/freeExtend.cpp b/ui/builders/freeExtend.cpp
index ab5a998..aff7cd7 100644
--- a/ui/builders/freeExtend.cpp
+++ b/ui/builders/freeExtend.cpp
@@ -16,17 +16,17 @@ BuilderFreeExtend::move(
{
if (p1) {
if (const auto p = network->intersectRayNodes(ray)) {
- candidateLinks.objects = network->candidateJoins(*p1, p->pos);
+ candidateLinks = network->candidateJoins(*p1, p->pos);
}
else if (const auto p = geoData->intersectRay(ray)) {
- candidateLinks.objects = network->candidateExtend(*p1, p->first);
+ candidateLinks = network->candidateExtend(*p1, p->first);
}
else {
- candidateLinks.removeAll();
+ candidateLinks.clear();
}
}
else {
- candidateLinks.removeAll();
+ candidateLinks.clear();
}
}
diff --git a/ui/builders/join.cpp b/ui/builders/join.cpp
index 6941e23..f6cbce5 100644
--- a/ui/builders/join.cpp
+++ b/ui/builders/join.cpp
@@ -15,10 +15,10 @@ BuilderJoin::move(Network * network, const GeoData *, const SDL_MouseMotionEvent
{
if (p1) {
if (const auto p = network->intersectRayNodes(ray)) {
- candidateLinks.objects = network->candidateJoins(p1->pos, p->pos);
+ candidateLinks = network->candidateJoins(p1->pos, p->pos);
}
else {
- candidateLinks.removeAll();
+ candidateLinks.clear();
}
}
}
@@ -33,7 +33,7 @@ BuilderJoin::click(
if (p1) {
create(network, geoData, p1, p);
p1.reset();
- candidateLinks.removeAll();
+ candidateLinks.clear();
}
else {
p1 = p;
diff --git a/ui/builders/straight.cpp b/ui/builders/straight.cpp
index 338aa8a..e7d83b5 100644
--- a/ui/builders/straight.cpp
+++ b/ui/builders/straight.cpp
@@ -17,10 +17,10 @@ BuilderStraight::move(
{
if (p1) {
if (const auto p = geoData->intersectRay(ray)) {
- candidateLinks.objects = network->candidateStraight(*p1, p->first);
+ candidateLinks = network->candidateStraight(*p1, p->first);
}
else {
- candidateLinks.removeAll();
+ candidateLinks.clear();
}
}
}
@@ -34,7 +34,7 @@ BuilderStraight::click(
if (const auto p = geoData->intersectRay(ray)) {
if (p1) {
create(network, geoData, *p1, p->first);
- candidateLinks.removeAll();
+ candidateLinks.clear();
p1.reset();
}
else {
@@ -44,7 +44,7 @@ BuilderStraight::click(
return;
case SDL_BUTTON_MIDDLE:
p1.reset();
- candidateLinks.removeAll();
+ candidateLinks.clear();
return;
}
}
diff --git a/ui/editNetwork.h b/ui/editNetwork.h
index ae887bd..2fc102a 100644
--- a/ui/editNetwork.h
+++ b/ui/editNetwork.h
@@ -36,7 +36,7 @@ public:
using Ptr = std::unique_ptr<Builder>;
protected:
- Collection<const Link> candidateLinks;
+ SharedCollection<const Link> candidateLinks;
};
private:
diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp
index d88bab5..f8c568b 100644
--- a/ui/gameMainWindow.cpp
+++ b/ui/gameMainWindow.cpp
@@ -32,7 +32,7 @@ GameMainWindow::GameMainWindow(size_t w, size_t h) : WindowContent {w, h}, Scene
{
uiComponents.create<ManualCameraController>(glm::vec2 {310'727'624, 494'018'810});
auto gms = uiComponents.create<GameMainSelector>(&camera, ScreenAbsCoord {w, h});
- uiComponents.create<GameMainToolbar>(gms.get());
+ uiComponents.create<GameMainToolbar>(gms);
}
GameMainWindow::~GameMainWindow() { }
@@ -75,12 +75,12 @@ GameMainWindow::render() const
void
GameMainWindow::content(const SceneShader & shader, const Frustum & frustum) const
{
- for (const auto & [id, asset] : gameState->assets) {
- if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) {
- r->render(shader, frustum);
+ for (const auto & [assetId, asset] : gameState->assets) {
+ if (const auto renderable = asset.getAs<const Renderable>()) {
+ renderable->render(shader, frustum);
}
}
- gameState->world.apply<Renderable>(&Renderable::render, shader, frustum);
+ gameState->world.apply<const Renderable>(&Renderable::render, shader, frustum);
uiComponents.apply<WorldOverlay>(&WorldOverlay::render, shader, frustum);
}
@@ -93,16 +93,16 @@ GameMainWindow::environment(const SceneShader &, const SceneRenderer & r) const
void
GameMainWindow::lights(const SceneShader & shader) const
{
- gameState->world.apply<Renderable>(&Renderable::lights, shader);
+ gameState->world.apply<const Renderable>(&Renderable::lights, shader);
}
void
GameMainWindow::shadows(const ShadowMapper & shadowMapper, const Frustum & frustum) const
{
- for (const auto & [id, asset] : gameState->assets) {
- if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) {
- r->shadows(shadowMapper, frustum);
+ for (const auto & [assetId, asset] : gameState->assets) {
+ if (const auto renderable = asset.getAs<const Renderable>()) {
+ renderable->shadows(shadowMapper, frustum);
}
}
- gameState->world.apply<Renderable>(&Renderable::shadows, shadowMapper, frustum);
+ gameState->world.apply<const Renderable>(&Renderable::shadows, shadowMapper, frustum);
}
diff --git a/ui/mainApplication.h b/ui/mainApplication.h
index a6cb126..1489587 100644
--- a/ui/mainApplication.h
+++ b/ui/mainApplication.h
@@ -6,7 +6,7 @@
class MainApplication : public ApplicationBase {
public:
- using Windows = Collection<Window>;
+ using Windows = SharedCollection<Window>;
void mainLoop();
protected:
diff --git a/ui/toolbar.h b/ui/toolbar.h
index ea560f5..b0480e2 100644
--- a/ui/toolbar.h
+++ b/ui/toolbar.h
@@ -19,5 +19,5 @@ public:
bool handleInput(const SDL_Event & e, const Position & parentPos) override;
- Collection<IconButton, false> icons;
+ UniqueCollection<IconButton> icons;
};
diff --git a/ui/windowContent.h b/ui/windowContent.h
index 474445a..5437da6 100644
--- a/ui/windowContent.h
+++ b/ui/windowContent.h
@@ -21,6 +21,6 @@ public:
virtual bool handleInput(const SDL_Event & e);
protected:
- ::Collection<UIComponent> uiComponents;
+ UniqueCollection<UIComponent> uiComponents;
UIShader uiShader;
};