diff --git a/src/jumping/character.cpp b/src/jumping/character.cpp index e892935..cbf4488 100644 --- a/src/jumping/character.cpp +++ b/src/jumping/character.cpp @@ -43,7 +43,7 @@ namespace cloonel { Placeable(float2(0.0f)), Drawable(parSize), m_bottomBar(float2(0.0f), parSize.x()), - m_screenRatio(parMain, DeferredRegister(&m_screenRatio)), + m_screenRatio(parMain, DeferredRegister()), m_bounceCallback(&DoNothing), m_texture(new Texture(parPath, parMain, false)) #if defined(WITH_DEBUG_VISUALS) diff --git a/src/jumping/gameplaysceneclassic.cpp b/src/jumping/gameplaysceneclassic.cpp index 519bbfa..3220ece 100644 --- a/src/jumping/gameplaysceneclassic.cpp +++ b/src/jumping/gameplaysceneclassic.cpp @@ -28,7 +28,7 @@ #include "tiledwallpaper.hpp" #include "texture.hpp" #include "platformspawner.hpp" -#include "CloonelJumpConfig.h" +#include "CloonelJumpProjectConfig.h" #include #include #include diff --git a/src/jumping/platform.cpp b/src/jumping/platform.cpp index e3847ee..95adcb8 100644 --- a/src/jumping/platform.cpp +++ b/src/jumping/platform.cpp @@ -28,7 +28,7 @@ namespace cloonel { ///-------------------------------------------------------------------------- Platform::Platform (SDLMain* parSdlMain, const float2& parPos, Texture* parTexture, const float2& parSize) : Placeable(parPos), - m_screenRatio(parSdlMain, &m_screenRatio), + m_screenRatio(parSdlMain, DeferredRegister()), m_size(parSize), m_collisionTop(new HorzCollisionBar(parPos, parSize.x())), m_surface(parTexture) diff --git a/src/jumping/platformset.cpp b/src/jumping/platformset.cpp index ae6535f..495a051 100644 --- a/src/jumping/platformset.cpp +++ b/src/jumping/platformset.cpp @@ -20,7 +20,7 @@ #include "platformset.hpp" #include "platform.hpp" -#include "CloonelJumpConfig.h" +#include "CloonelJumpProjectConfig.h" #include "casts.hpp" #include #include diff --git a/src/jumping/platformspawner.cpp b/src/jumping/platformspawner.cpp index 26f1d13..382be6b 100644 --- a/src/jumping/platformspawner.cpp +++ b/src/jumping/platformspawner.cpp @@ -19,7 +19,7 @@ #include "platformspawner.hpp" #include "platform.hpp" -#include "CloonelJumpConfig.h" +#include "CloonelJumpProjectConfig.h" #include "texture.hpp" #include "gameplayscene.hpp" #include "mover.hpp" diff --git a/src/jumping/sizenotifiable.cpp b/src/jumping/sizenotifiable.cpp index 4cdf54e..11bd271 100644 --- a/src/jumping/sizenotifiable.cpp +++ b/src/jumping/sizenotifiable.cpp @@ -67,7 +67,7 @@ namespace cloonel { ///-------------------------------------------------------------------------- DeferredRegister::~DeferredRegister() { assert(m_call); - if (not std::uncaught_exception()) + if (m_call and not std::uncaught_exception()) m_call(); } } //namespace cloonel diff --git a/src/jumping/sizenotifiable.hpp b/src/jumping/sizenotifiable.hpp index c8dffb2..cfdfdbe 100644 --- a/src/jumping/sizenotifiable.hpp +++ b/src/jumping/sizenotifiable.hpp @@ -1,5 +1,5 @@ /* - Copyright 2014 Michele "King_DuckZ" Santullo + Copyright 2014-2016 Michele "King_DuckZ" Santullo This file is part of CloonelJump. @@ -25,6 +25,7 @@ #include #include #include +#include namespace cloonel { class SizeRatio; @@ -75,12 +76,14 @@ namespace cloonel { class DeferredRegister { public: - template - DeferredRegister ( SizeNotifiable* parObject ) noexcept; + DeferredRegister ( void ) noexcept = default; ~DeferredRegister ( void ); + template + void SetThis ( SizeNotifiable* parObject ) const noexcept; + private: - std::function m_call; + mutable std::function m_call; }; class SizeNotifiableBase { @@ -112,7 +115,7 @@ namespace cloonel { { } explicit SizeNotifiable ( const DeferredRegister& parRegisterFunctor ) { - static_cast(parRegisterFunctor); + parRegisterFunctor.SetThis(this); } virtual ~SizeNotifiable ( void ) noexcept { this->Unregister(); @@ -133,7 +136,7 @@ namespace cloonel { SizeNotifiable ( SDLMain* parSdlMain, const DeferredRegister& parRegisterFunctor ) : RegisterBehaviour(parSdlMain) { - static_cast(parRegisterFunctor); + parRegisterFunctor.SetThis(this); } virtual ~SizeNotifiable ( void ) noexcept { this->Unregister(); @@ -141,9 +144,9 @@ namespace cloonel { }; template - DeferredRegister::DeferredRegister (SizeNotifiable* parObject) noexcept : - m_call(std::bind(&R::Register, static_cast(parObject), parObject)) - { + void DeferredRegister::SetThis (SizeNotifiable* parObject) const noexcept { + assert(not m_call); + m_call = std::bind(&R::Register, static_cast(parObject), parObject); assert(m_call); } } //namespace cloonel diff --git a/src/jumping/tiledwallpaper.cpp b/src/jumping/tiledwallpaper.cpp index 55cf66c..1b1433d 100644 --- a/src/jumping/tiledwallpaper.cpp +++ b/src/jumping/tiledwallpaper.cpp @@ -98,7 +98,7 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- TiledWallpaper::TileCountNotifiable::TileCountNotifiable (SDLMain* parMain, const ushort2& parTileSize) : - BaseClass(parMain, this), + BaseClass(parMain, DeferredRegister()), m_tileCount(CountTilesInScreen(parMain->WidthHeight(), parTileSize)), m_tileSize(vector_cast(parTileSize)) #if defined(WITH_DEBUG_VISUALS) diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 18bbeb2..6408e94 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -2,6 +2,7 @@ project(clooneltest CXX) add_executable(${PROJECT_NAME} main.cpp + deferred_virtual_call.cpp ) target_include_directories(${PROJECT_NAME} diff --git a/test/unit/deferred_virtual_call.cpp b/test/unit/deferred_virtual_call.cpp new file mode 100644 index 0000000..15780ac --- /dev/null +++ b/test/unit/deferred_virtual_call.cpp @@ -0,0 +1,125 @@ +/* + Copyright 2014-2016 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#include "catch.hpp" +#include "sizenotifiable.hpp" +#include "sizeratio.hpp" +#include +#include + +class DummyRegister { +public: + enum { SDLMAIN_NEEDED = false }; + + DummyRegister() = default; + void Register (cloonel::SizeNotifiableBase* parNotifiable) { + using cloonel::SizeRatio; + using cloonel::float2; + + float2 orig(1024.0f, 768.0f); + float2 size(123.0f, 456.0f); + parNotifiable->NotifyResChanged(SizeRatio(orig, size)); + } + + void Unregister() {} +}; + +class NotifiableA : public cloonel::SizeNotifiable<::DummyRegister> { +public: + typedef cloonel::SizeNotifiable<::DummyRegister> BaseClass; + + NotifiableA (bool parThrow, bool* parOut, const cloonel::DeferredRegister& parDeferred) : + BaseClass(parDeferred), + notif_a_called(false), + m_out_a(parOut) + { + if (parThrow) + throw std::runtime_error("Throwing exception because parThrow=true"); + } + + bool notif_a_called; + +private: + bool* m_out_a; + + virtual void OnResChanged (const cloonel::SizeRatio&) override { + notif_a_called = true; + if (m_out_a) + *m_out_a = true; + } +}; + +class NotifiableB : public NotifiableA { +public: + NotifiableB (bool parThrow, bool* parOutA, bool* parOutB, const cloonel::DeferredRegister& parDeferred) : + NotifiableA(parThrow, parOutA, parDeferred), + notif_b_called(false), + m_out_b(parOutB) + {} + + bool notif_b_called; + +private: + bool* m_out_b; + + virtual void OnResChanged (const cloonel::SizeRatio&) override { + notif_b_called = true; + if (m_out_b) + *m_out_b = true; + } +}; + +TEST_CASE ("Check the deferred virtual call mechanism in SizeNotifiable", "[core]") { + using cloonel::DeferredRegister; + + { + NotifiableB b(false, nullptr, nullptr, DeferredRegister()); + REQUIRE( b.notif_b_called ); + REQUIRE( !b.notif_a_called ); + } + { + NotifiableA a(false, nullptr, DeferredRegister()); + REQUIRE( a.notif_a_called ); + } + + { + bool notif_a = false; + bool notif_b = false; + + //Check that the test mechanism works (sets the bool pointers) + { + NotifiableB b(false, ¬if_a, ¬if_b, DeferredRegister()); + REQUIRE( b.notif_b_called ); + REQUIRE( not notif_a ); + REQUIRE( notif_b ); + } + + notif_a = notif_b = false; + std::unique_ptr notifiable; + try { + notifiable.reset(new NotifiableB(true, ¬if_a, ¬if_b, DeferredRegister())); + REQUIRE( false ); //not reached, constructor should throw + } + catch (const std::runtime_error& e) { + REQUIRE( e.what() == std::string("Throwing exception because parThrow=true") ); + } + REQUIRE( not notif_a ); + REQUIRE( not notif_b ); + } +} diff --git a/test/unit/main.cpp b/test/unit/main.cpp index 0c7c351..40ddf54 100644 --- a/test/unit/main.cpp +++ b/test/unit/main.cpp @@ -1,2 +1,21 @@ +/* + Copyright 2014-2016 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + #define CATCH_CONFIG_MAIN #include "catch.hpp"