diff options
-rw-r--r-- | application/main.cpp | 11 | ||||
-rw-r--r-- | assetFactory/asset.h | 3 | ||||
-rw-r--r-- | assetFactory/assetFactory.cpp | 3 | ||||
-rw-r--r-- | assetFactory/assetFactory.h | 2 | ||||
-rw-r--r-- | game/gamestate.h | 3 | ||||
-rw-r--r-- | game/network/network.h | 2 | ||||
-rw-r--r-- | game/network/network.impl.h | 8 | ||||
-rw-r--r-- | game/network/rail.cpp | 4 | ||||
-rw-r--r-- | game/orders.h | 2 | ||||
-rw-r--r-- | game/vehicles/train.h | 2 | ||||
-rw-r--r-- | game/water.h | 2 | ||||
-rw-r--r-- | gfx/gl/shadowMapper.cpp | 2 | ||||
-rw-r--r-- | lib/collection.h | 263 | ||||
-rw-r--r-- | lib/jsonParse.ll | 9 | ||||
-rw-r--r-- | lib/manyPtr.h | 86 | ||||
-rw-r--r-- | lib/persistence.h | 3 | ||||
-rw-r--r-- | test/Jamfile.jam | 25 | ||||
-rw-r--r-- | test/test-assetFactory.cpp | 24 | ||||
-rw-r--r-- | test/test-collection.cpp | 287 | ||||
-rw-r--r-- | test/test-network.cpp | 68 | ||||
-rw-r--r-- | test/test-render.cpp | 13 | ||||
-rw-r--r-- | ui/builders/freeExtend.cpp | 8 | ||||
-rw-r--r-- | ui/builders/join.cpp | 6 | ||||
-rw-r--r-- | ui/builders/straight.cpp | 8 | ||||
-rw-r--r-- | ui/editNetwork.h | 2 | ||||
-rw-r--r-- | ui/gameMainWindow.cpp | 20 | ||||
-rw-r--r-- | ui/mainApplication.h | 2 | ||||
-rw-r--r-- | ui/toolbar.h | 2 | ||||
-rw-r--r-- | ui/windowContent.h | 2 |
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, ¶ms...](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, ¶ms...](auto && op) { + std::invoke(m, op, std::forward<Params>(params)...); + }); + return std::distance(begin, end); + } + else { + return std::count_if(begin, end, [&m, ¶ms...](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, ¶ms...](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, ¶ms...](auto && op) { + return std::invoke(m, op, std::forward<Params>(params)...); + }); + } + else { + return std::find_if(begin, end, [&m, ¶ms...](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; }; |