mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-21 17:45:25 -04:00
90c3f4f72b
Lists of objects were wrongly initialized, creating a useless performance hit. All the objects of the "for each" were copied into arrays, before being emptied. And this, for every single object in the for each loop. This was particularly bad when a lot of objects were picked by the for each (if we have N objects, complexity was N*N copies of the array).
190 lines
7.3 KiB
C++
190 lines
7.3 KiB
C++
/*
|
|
* GDevelop Core
|
|
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
|
* reserved. This project is released under the MIT License.
|
|
*/
|
|
/**
|
|
* @file Tests covering events code generation context,
|
|
*/
|
|
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
|
#include <memory>
|
|
#include "GDCore/CommonTools.h"
|
|
#include "GDCore/Extensions/Platform.h"
|
|
#include "GDCore/Project/Layout.h"
|
|
#include "GDCore/Project/Project.h"
|
|
#include "GDCore/Tools/VersionWrapper.h"
|
|
#include "catch.hpp"
|
|
|
|
TEST_CASE("EventsCodeGenerationContext", "[common][events]") {
|
|
/**
|
|
* Generate a tree of contexts with declared objects as below:
|
|
* c1 -> c1.object1, c1.object2, c1.noPicking1 (no picking
|
|
* request)
|
|
* / \
|
|
* c2.object1 <- c2 c3 -> c3.object1, c1.object2
|
|
* / \
|
|
* c4 c5 -> c5.object1, c5.noPicking1 (no picking request),
|
|
* c1.object2, c5.empty1
|
|
*/
|
|
|
|
unsigned int maxDepth = 0;
|
|
gd::EventsCodeGenerationContext c1(&maxDepth);
|
|
c1.ObjectsListNeeded("c1.object1");
|
|
c1.ObjectsListNeeded("c1.object2");
|
|
c1.ObjectsListWithoutPickingNeeded("c1.noPicking1");
|
|
|
|
gd::EventsCodeGenerationContext c2;
|
|
c2.InheritsFrom(c1);
|
|
c2.ObjectsListNeeded("c2.object1");
|
|
|
|
gd::EventsCodeGenerationContext c3;
|
|
c3.InheritsFrom(c1);
|
|
c3.ObjectsListNeeded("c3.object1");
|
|
c3.ObjectsListNeeded("c1.object2");
|
|
|
|
gd::EventsCodeGenerationContext c4;
|
|
c4.InheritsFrom(c2);
|
|
|
|
gd::EventsCodeGenerationContext c5;
|
|
c5.InheritsFrom(c2);
|
|
c5.ObjectsListWithoutPickingNeeded("c5.noPicking1");
|
|
c5.ObjectsListNeeded("c5.object1");
|
|
c5.ObjectsListNeeded("c1.object2");
|
|
c5.EmptyObjectsListNeeded("c5.empty1");
|
|
|
|
SECTION("Parenting") {
|
|
REQUIRE(c2.GetParentContext() == &c1);
|
|
REQUIRE(c3.GetParentContext() == &c1);
|
|
REQUIRE(c4.GetParentContext() == &c2);
|
|
REQUIRE(c5.GetParentContext() == &c2);
|
|
}
|
|
|
|
SECTION("Depth") {
|
|
REQUIRE(maxDepth == 2);
|
|
|
|
REQUIRE(c1.GetContextDepth() == 0);
|
|
REQUIRE(c2.GetContextDepth() == 1);
|
|
REQUIRE(c3.GetContextDepth() == 1);
|
|
REQUIRE(c4.GetContextDepth() == 2);
|
|
REQUIRE(c5.GetContextDepth() == 2);
|
|
}
|
|
|
|
SECTION("Object list needed") {
|
|
REQUIRE(c1.GetObjectsListsAlreadyDeclared() == std::set<gd::String>());
|
|
REQUIRE(c1.GetObjectsListsToBeDeclared() ==
|
|
std::set<gd::String>({"c1.object1", "c1.object2"}));
|
|
REQUIRE(c1.GetObjectsListsToBeDeclaredWithoutPicking() ==
|
|
std::set<gd::String>({"c1.noPicking1"}));
|
|
REQUIRE(c1.GetAllObjectsToBeDeclared() ==
|
|
std::set<gd::String>({"c1.object1", "c1.object2", "c1.noPicking1"}));
|
|
|
|
REQUIRE(c2.GetObjectsListsAlreadyDeclared() ==
|
|
std::set<gd::String>({"c1.object1", "c1.object2", "c1.noPicking1"}));
|
|
REQUIRE(c2.GetObjectsListsToBeDeclared() ==
|
|
std::set<gd::String>({"c2.object1"}));
|
|
REQUIRE(c2.GetObjectsListsToBeDeclaredWithoutPicking() == std::set<gd::String>());
|
|
REQUIRE(c2.GetAllObjectsToBeDeclared() ==
|
|
std::set<gd::String>({"c2.object1"}));
|
|
|
|
REQUIRE(c3.GetObjectsListsAlreadyDeclared() ==
|
|
std::set<gd::String>({"c1.object1", "c1.object2", "c1.noPicking1"}));
|
|
REQUIRE(c3.GetObjectsListsToBeDeclared() ==
|
|
std::set<gd::String>({"c3.object1", "c1.object2"}));
|
|
REQUIRE(c3.GetObjectsListsToBeDeclaredWithoutPicking() == std::set<gd::String>());
|
|
REQUIRE(c3.GetAllObjectsToBeDeclared() ==
|
|
std::set<gd::String>({"c3.object1", "c1.object2"}));
|
|
|
|
REQUIRE(c5.GetObjectsListsAlreadyDeclared() ==
|
|
std::set<gd::String>(
|
|
{"c1.object1", "c1.object2", "c1.noPicking1", "c2.object1"}));
|
|
REQUIRE(c5.GetObjectsListsToBeDeclared() ==
|
|
std::set<gd::String>({"c5.object1", "c1.object2"}));
|
|
REQUIRE(c5.GetObjectsListsToBeDeclaredWithoutPicking() ==
|
|
std::set<gd::String>({"c5.noPicking1"}));
|
|
REQUIRE(c5.GetObjectsListsToBeDeclaredEmpty() ==
|
|
std::set<gd::String>({"c5.empty1"}));
|
|
REQUIRE(c5.GetAllObjectsToBeDeclared() ==
|
|
std::set<gd::String>({"c5.object1", "c5.noPicking1", "c1.object2", "c5.empty1"}));
|
|
}
|
|
|
|
SECTION("ObjectAlreadyDeclared") {
|
|
REQUIRE(c1.ObjectAlreadyDeclared("c1.object1") == false);
|
|
REQUIRE(c2.ObjectAlreadyDeclared("c1.object1") == true);
|
|
REQUIRE(c3.ObjectAlreadyDeclared("c1.object1") == true);
|
|
REQUIRE(c4.ObjectAlreadyDeclared("c1.object1") == true);
|
|
REQUIRE(c5.ObjectAlreadyDeclared("c1.object1") == true);
|
|
|
|
REQUIRE(c2.ObjectAlreadyDeclared("c2.object1") == false);
|
|
REQUIRE(c1.ObjectAlreadyDeclared("c2.object1") == false);
|
|
REQUIRE(c3.ObjectAlreadyDeclared("c2.object1") == false);
|
|
REQUIRE(c4.ObjectAlreadyDeclared("c2.object1") == true);
|
|
REQUIRE(c5.ObjectAlreadyDeclared("c2.object1") == true);
|
|
|
|
REQUIRE(c3.ObjectAlreadyDeclared("some object") == false);
|
|
c3.SetObjectDeclared("some object");
|
|
REQUIRE(c3.ObjectAlreadyDeclared("some object") == true);
|
|
}
|
|
|
|
SECTION("Object list last depth") {
|
|
REQUIRE(c1.GetLastDepthObjectListWasNeeded("c1.object1") == 0);
|
|
REQUIRE(c2.GetLastDepthObjectListWasNeeded("c2.object1") == 1);
|
|
REQUIRE(c3.GetLastDepthObjectListWasNeeded("c3.object1") == 1);
|
|
REQUIRE(c4.GetLastDepthObjectListWasNeeded("c2.object1") == 1);
|
|
REQUIRE(c5.GetLastDepthObjectListWasNeeded("c1.object2") == 2);
|
|
REQUIRE(c5.GetLastDepthObjectListWasNeeded("c2.object1") == 1);
|
|
REQUIRE(c5.GetLastDepthObjectListWasNeeded("c5.object1") == 2);
|
|
REQUIRE(c5.GetLastDepthObjectListWasNeeded("c5.empty1") == 2);
|
|
}
|
|
|
|
SECTION("SetCurrentObject") {
|
|
REQUIRE(c3.GetCurrentObject() == "");
|
|
c3.SetCurrentObject("current object");
|
|
REQUIRE(c3.GetCurrentObject() == "current object");
|
|
c3.SetNoCurrentObject();
|
|
REQUIRE(c3.GetCurrentObject() == "");
|
|
}
|
|
|
|
SECTION("Reuse") {
|
|
/**
|
|
* Generate a tree of contexts with declared objects as below:
|
|
* ...
|
|
* \
|
|
* c5 -> c5.object1, c5.noPicking1 (no picking request),
|
|
* c1.object2
|
|
* /
|
|
* c6 (reuse c5) -> c5.object1, c6.object3
|
|
* /
|
|
* c7 -> c5.object1, c5.empty1 (empty list request)
|
|
*/
|
|
gd::EventsCodeGenerationContext c6;
|
|
c6.Reuse(c5);
|
|
c6.ObjectsListNeeded("c5.object1");
|
|
c6.ObjectsListNeeded("c6.object3");
|
|
|
|
gd::EventsCodeGenerationContext c7;
|
|
c7.InheritsFrom(c6);
|
|
c7.ObjectsListNeeded("c5.object1");
|
|
c7.ObjectsListNeeded("c6.object3");
|
|
c7.EmptyObjectsListNeeded("c5.empty1");
|
|
|
|
// c6 is reusing c5 context so it has the same depth:
|
|
REQUIRE(c6.GetParentContext() == &c5);
|
|
REQUIRE(c6.GetContextDepth() == c5.GetContextDepth());
|
|
REQUIRE(c6.GetLastDepthObjectListWasNeeded("c6.object3") == 2);
|
|
|
|
// c6 reuse the objects lists from c5:
|
|
REQUIRE(c6.IsSameObjectsList("c5.object1", c5) == true);
|
|
REQUIRE(c6.IsSameObjectsList("c5.noPicking1", c5) == true);
|
|
REQUIRE(c6.GetLastDepthObjectListWasNeeded("c5.object1") ==
|
|
c5.GetLastDepthObjectListWasNeeded("c5.object1"));
|
|
REQUIRE(c6.GetLastDepthObjectListWasNeeded("c5.noPicking1") ==
|
|
c5.GetLastDepthObjectListWasNeeded("c5.noPicking1"));
|
|
|
|
REQUIRE(c7.GetParentContext() == &c6);
|
|
REQUIRE(c7.GetContextDepth() == 3);
|
|
REQUIRE(c7.IsSameObjectsList("c5.object1", c6) == false);
|
|
REQUIRE(c7.IsSameObjectsList("c6.object3", c6) == false);
|
|
REQUIRE(c7.IsSameObjectsList("c5.empty1", c5) == false);
|
|
}
|
|
}
|