diff --git a/CMakeLists.txt b/CMakeLists.txt index baf500a..6abcb81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(cigus LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/cigus.hpp b/cigus.hpp index dfb8d7d..8e2b806 100644 --- a/cigus.hpp +++ b/cigus.hpp @@ -8,33 +8,103 @@ namespace cigus { using json = nlohmann::json; + template class Ref; + template class OriginRef; + template class MutRef; + template class ConstRef; + template class Ref { - T *ptr; + protected: + T *ptr = nullptr; public: - explicit Ref(T *ptr) : ptr(ptr) { - if (ptr == nullptr) { - spdlog::error("Ref cannot be null"); - throw std::runtime_error("Ref cannot be null"); + virtual ~Ref() {} + Ref() = delete; + Ref(const Ref &other) = delete; + Ref(Ref &&other) = delete; + + Ref(const OriginRef& ptr) : ptr(ptr.ptr) { + } + + Ref(T* ptr) : ptr(ptr) + { + + } + + virtual bool operator!() const { + return ptr == nullptr; + } + + virtual void check() const { + assert(ptr != nullptr || "Dereferencing null pointer"); + } + + virtual const T &operator*() const { + check(); + return *ptr; + } + + virtual const T *operator->() const { + check(); + return ptr; + } + + static Ref Null() + { + return Ref(nullptr); + } + }; + + template + class OriginRef final : public MutRef { + public: + friend class Ref; + + template + OriginRef(Args... args) : Ref(new G(std::forward(args)...)) { + } + + OriginRef(T* ptr) : MutRef(ptr) { + } + + ~OriginRef() override { + if (this->ptr != nullptr) { + delete this->ptr; } } - Ref(const Ref &other) : ptr(other.ptr) { - if (other.ptr == nullptr) { - spdlog::error("Ref cannot be null"); - throw std::runtime_error("Ref cannot be null"); - } + [[nodiscard]] MutRef mut() { + return MutRef(this->ptr); } - Ref(Ref &&other) noexcept : ptr(other.ptr) { - if (other.ptr == nullptr) { - spdlog::error("Ref cannot be null"); - throw std::runtime_error("Ref cannot be null"); - } + [[nodiscard]] ConstRef immute() const { + return ConstRef(this->ptr); + } + }; + + template + class MutRef : public Ref { + protected: + using Ref::ptr; + public: + friend class Ref; + + using Ref::check; + using Ref::operator*; + using Ref::operator->; + + MutRef(const OriginRef& other) : Ref(other.ptr) {} + + MutRef(T* ptr) : Ref(ptr) {} + + MutRef(const MutRef &other) : Ref(other.ptr) { } - Ref &operator=(Ref &&other) noexcept { + MutRef(MutRef &&other) noexcept : Ref(other.ptr) { + } + + MutRef &operator=(MutRef &&other) noexcept { if (this->ptr != other.ptr) { ptr = other.ptr; } @@ -42,52 +112,82 @@ namespace cigus { } T &operator*() { - return *ptr; - } - - const T &operator*() const { + check(); return *ptr; } T *operator->() { + check(); return ptr; } + }; - const T *operator->() const { - return ptr; + template + class ConstRef : public Ref + { + protected: + using Ref::ptr; + using Ref::check; + public: + friend class Ref; + + ConstRef(const OriginRef other) : Ref(other.ptr) { } - void free() { - delete ptr; - ptr = nullptr; + ConstRef(const MutRef other) : Ref(other.ptr) { + } + }; + + template + class NullRef + { + public: + friend class Ref; + + NullRef(const NullRef &other) = delete; + NullRef(NullRef &&other) = delete; + + NullRef &operator=(NullRef &&other) = delete; + + NullRef() : Ref(nullptr) { + } + + T *ptr = nullptr; + + bool operator!() const { + return false; } }; } namespace cigus::UI { class RenderCall { - sf::Drawable *drawable; + OriginRef drawable; sf::RenderStates states; public: - RenderCall(sf::Drawable *drawable, sf::RenderStates states) : drawable(drawable), states(states) { - } - - ~RenderCall() { - delete drawable; + explicit RenderCall(const sf::RenderStates& states, sf::Drawable *ptr) : drawable(ptr), states(states) { + drawable.check(); } void draw(sf::RenderTarget &target, const sf::RenderStates &states) const { target.draw(*drawable, states); } + + MutRef operator->() { + drawable.check(); + return drawable.mut(); + } }; class View { std::vector m_RenderCalls; protected: - void Rectangle() { - m_RenderCalls.emplace_back(new sf::RectangleShape(sf::Vector2f(100, 100)), sf::RenderStates()); + void Rectangle(const float x, const float y, sf::Color color = sf::Color::White) { + auto shape = new sf::RectangleShape(sf::Vector2f(x, y)); + shape->setFillColor(color); + m_RenderCalls.emplace_back(sf::RenderStates(), shape); } public: @@ -97,21 +197,30 @@ namespace cigus::UI { return m_RenderCalls; } + virtual bool update() + { + return false; + } + + void draw() { + if (!m_RenderCalls.empty()) + { + m_RenderCalls.clear(); + } + body(); + } virtual void body() = 0; }; class Renderer { public: - explicit Renderer(const Ref &_view) : view(_view) { view->body(); } + explicit Renderer(const MutRef &_view) : view(_view) { view->body(); } - void destroy() { - view.free(); - } - - Ref view; + MutRef view; void update() { - view->body(); + if (view->update()) + view->draw(); } void render(sf::RenderTarget &target, const sf::RenderStates &states) const { diff --git a/src/main.cpp b/src/main.cpp index a8b4d0a..8699510 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,9 +8,16 @@ class NewView : public cigus::UI::View { public: + bool update() override + { + std::cout << "Update...\n"; + return true; + } + void body() override { - std::cout << "Hello World!" << std::endl; - Rectangle(); + std::cout << "Body\n"; + //Rectangle(100, 100, sf::Color(250,250,250)); + Rectangle(10,20, sf::Color(120,120,120)); } }; @@ -20,7 +27,8 @@ int main(int argc, char** argv) { sf::RenderWindow window(sf::VideoMode({800, 600}), "Hello World!"); window.setFramerateLimit(60); - UI::Renderer renderer(cigus::Ref(new NewView())); + cigus::OriginRef view = cigus::OriginRef(new NewView); + UI::Renderer renderer(view); while (window.isOpen()) { @@ -32,12 +40,12 @@ int main(int argc, char** argv) { } } + renderer.update(); window.clear(); renderer.render(window, sf::RenderStates()); window.display(); } - renderer.destroy(); return 0; } \ No newline at end of file